summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms
diff options
context:
space:
mode:
authorChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
committerChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
commit08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch)
tree7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/geometry/algorithms
parentbb4dd8289b351fae6b55e303f189127a394a1edd (diff)
downloadboost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz
boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2
boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/geometry/algorithms')
-rw-r--r--boost/geometry/algorithms/append.hpp175
-rw-r--r--boost/geometry/algorithms/area.hpp182
-rw-r--r--boost/geometry/algorithms/assign.hpp250
-rw-r--r--boost/geometry/algorithms/buffer.hpp183
-rw-r--r--boost/geometry/algorithms/centroid.hpp434
-rw-r--r--boost/geometry/algorithms/clear.hpp59
-rw-r--r--boost/geometry/algorithms/comparable_distance.hpp69
-rw-r--r--boost/geometry/algorithms/convert.hpp201
-rw-r--r--boost/geometry/algorithms/convex_hull.hpp262
-rw-r--r--boost/geometry/algorithms/correct.hpp100
-rw-r--r--boost/geometry/algorithms/covered_by.hpp414
-rw-r--r--boost/geometry/algorithms/crosses.hpp194
-rw-r--r--boost/geometry/algorithms/detail/assign_box_corners.hpp22
-rw-r--r--boost/geometry/algorithms/detail/assign_indexed_point.hpp2
-rw-r--r--boost/geometry/algorithms/detail/assign_values.hpp164
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp940
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_policies.hpp171
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp954
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_ring.hpp238
-rw-r--r--boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp191
-rw-r--r--boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp88
-rw-r--r--boost/geometry/algorithms/detail/buffer/parallel_continue.hpp33
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_input.hpp98
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp246
-rw-r--r--boost/geometry/algorithms/detail/calculate_null.hpp2
-rw-r--r--boost/geometry/algorithms/detail/calculate_sum.hpp18
-rw-r--r--boost/geometry/algorithms/detail/centroid/translating_transformer.hpp119
-rw-r--r--boost/geometry/algorithms/detail/check_iterator_range.hpp71
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp147
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp250
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp196
-rw-r--r--boost/geometry/algorithms/detail/comparable_distance/implementation.hpp24
-rw-r--r--boost/geometry/algorithms/detail/comparable_distance/interface.hpp363
-rw-r--r--boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp20
-rw-r--r--boost/geometry/algorithms/detail/counting.hpp107
-rw-r--r--boost/geometry/algorithms/detail/course.hpp56
-rw-r--r--boost/geometry/algorithms/detail/disjoint.hpp225
-rw-r--r--boost/geometry/algorithms/detail/disjoint/areal_areal.hpp134
-rw-r--r--boost/geometry/algorithms/detail/disjoint/box_box.hpp114
-rw-r--r--boost/geometry/algorithms/detail/disjoint/implementation.hpp36
-rw-r--r--boost/geometry/algorithms/detail/disjoint/interface.hpp187
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_areal.hpp244
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_linear.hpp174
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp195
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_box.hpp94
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_geometry.hpp111
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_point.hpp112
-rw-r--r--boost/geometry/algorithms/detail/disjoint/segment_box.hpp291
-rw-r--r--boost/geometry/algorithms/detail/distance/backward_compatibility.hpp333
-rw-r--r--boost/geometry/algorithms/detail/distance/box_to_box.hpp60
-rw-r--r--boost/geometry/algorithms/detail/distance/default_strategies.hpp137
-rw-r--r--boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp462
-rw-r--r--boost/geometry/algorithms/detail/distance/implementation.hpp35
-rw-r--r--boost/geometry/algorithms/detail/distance/interface.hpp403
-rw-r--r--boost/geometry/algorithms/detail/distance/is_comparable.hpp45
-rw-r--r--boost/geometry/algorithms/detail/distance/iterator_selector.hpp70
-rw-r--r--boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp147
-rw-r--r--boost/geometry/algorithms/detail/distance/linear_to_linear.hpp123
-rw-r--r--boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp240
-rw-r--r--boost/geometry/algorithms/detail/distance/point_to_geometry.hpp518
-rw-r--r--boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp131
-rw-r--r--boost/geometry/algorithms/detail/distance/segment_to_box.hpp886
-rw-r--r--boost/geometry/algorithms/detail/distance/segment_to_segment.hpp150
-rw-r--r--boost/geometry/algorithms/detail/equals/collect_vectors.hpp43
-rw-r--r--boost/geometry/algorithms/detail/equals/point_point.hpp52
-rw-r--r--boost/geometry/algorithms/detail/extreme_points.hpp520
-rw-r--r--boost/geometry/algorithms/detail/for_each_range.hpp116
-rw-r--r--boost/geometry/algorithms/detail/get_left_turns.hpp487
-rw-r--r--boost/geometry/algorithms/detail/get_max_size.hpp64
-rw-r--r--boost/geometry/algorithms/detail/has_self_intersections.hpp53
-rw-r--r--boost/geometry/algorithms/detail/interior_iterator.hpp71
-rw-r--r--boost/geometry/algorithms/detail/intersection/box_box.hpp54
-rw-r--r--boost/geometry/algorithms/detail/intersection/implementation.hpp22
-rw-r--r--boost/geometry/algorithms/detail/intersection/interface.hpp309
-rw-r--r--boost/geometry/algorithms/detail/intersection/multi.hpp423
-rw-r--r--boost/geometry/algorithms/detail/is_simple/always_simple.hpp83
-rw-r--r--boost/geometry/algorithms/detail/is_simple/areal.hpp141
-rw-r--r--boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp82
-rw-r--r--boost/geometry/algorithms/detail/is_simple/implementation.hpp18
-rw-r--r--boost/geometry/algorithms/detail/is_simple/interface.hpp80
-rw-r--r--boost/geometry/algorithms/detail/is_simple/linear.hpp248
-rw-r--r--boost/geometry/algorithms/detail/is_simple/multipoint.hpp84
-rw-r--r--boost/geometry/algorithms/detail/is_valid/box.hpp86
-rw-r--r--boost/geometry/algorithms/detail/is_valid/complement_graph.hpp239
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp70
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp64
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp68
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp70
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_spikes.hpp139
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp93
-rw-r--r--boost/geometry/algorithms/detail/is_valid/implementation.hpp21
-rw-r--r--boost/geometry/algorithms/detail/is_valid/interface.hpp78
-rw-r--r--boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp144
-rw-r--r--boost/geometry/algorithms/detail/is_valid/linear.hpp125
-rw-r--r--boost/geometry/algorithms/detail/is_valid/multipolygon.hpp297
-rw-r--r--boost/geometry/algorithms/detail/is_valid/pointlike.hpp62
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp376
-rw-r--r--boost/geometry/algorithms/detail/is_valid/ring.hpp173
-rw-r--r--boost/geometry/algorithms/detail/is_valid/segment.hpp61
-rw-r--r--boost/geometry/algorithms/detail/multi_modify.hpp53
-rw-r--r--boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp52
-rw-r--r--boost/geometry/algorithms/detail/multi_sum.hpp52
-rw-r--r--boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp93
-rw-r--r--boost/geometry/algorithms/detail/occupation_info.hpp356
-rw-r--r--boost/geometry/algorithms/detail/overlay/add_rings.hpp35
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp4
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp160
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp58
-rw-r--r--boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp23
-rw-r--r--boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp64
-rw-r--r--boost/geometry/algorithms/detail/overlay/check_enrich.hpp2
-rw-r--r--boost/geometry/algorithms/detail/overlay/convert_ring.hpp21
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp94
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segments.hpp320
-rw-r--r--boost/geometry/algorithms/detail/overlay/do_reverse.hpp47
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp165
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrichment_info.hpp20
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp292
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp536
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp71
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_relative_order.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_ring.hpp37
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp528
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp657
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp329
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp805
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp720
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp422
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp347
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp84
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp571
-rw-r--r--boost/geometry/algorithms/detail/overlay/linear_linear.hpp326
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp76
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp435
-rw-r--r--boost/geometry/algorithms/detail/overlay/segment_identifier.hpp31
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp63
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp117
-rw-r--r--boost/geometry/algorithms/detail/overlay/stream_info.hpp3
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_info.hpp16
-rw-r--r--boost/geometry/algorithms/detail/overlay/traverse.hpp82
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp12
-rw-r--r--boost/geometry/algorithms/detail/overlay/visit_info.hpp54
-rw-r--r--boost/geometry/algorithms/detail/partition.hpp101
-rw-r--r--boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp126
-rw-r--r--boost/geometry/algorithms/detail/point_on_border.hpp64
-rw-r--r--boost/geometry/algorithms/detail/recalculate.hpp231
-rw-r--r--boost/geometry/algorithms/detail/relate/areal_areal.hpp823
-rw-r--r--boost/geometry/algorithms/detail/relate/boundary_checker.hpp134
-rw-r--r--boost/geometry/algorithms/detail/relate/follow_helpers.hpp401
-rw-r--r--boost/geometry/algorithms/detail/relate/less.hpp79
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_areal.hpp1115
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_linear.hpp768
-rw-r--r--boost/geometry/algorithms/detail/relate/point_geometry.hpp205
-rw-r--r--boost/geometry/algorithms/detail/relate/point_point.hpp242
-rw-r--r--boost/geometry/algorithms/detail/relate/relate.hpp339
-rw-r--r--boost/geometry/algorithms/detail/relate/result.hpp1390
-rw-r--r--boost/geometry/algorithms/detail/relate/topology_check.hpp241
-rw-r--r--boost/geometry/algorithms/detail/relate/turns.hpp253
-rw-r--r--boost/geometry/algorithms/detail/ring_identifier.hpp18
-rw-r--r--boost/geometry/algorithms/detail/sections/range_by_section.hpp65
-rw-r--r--boost/geometry/algorithms/detail/sections/sectionalize.hpp450
-rw-r--r--boost/geometry/algorithms/detail/signed_index_type.hpp29
-rw-r--r--boost/geometry/algorithms/detail/single_geometry.hpp95
-rw-r--r--boost/geometry/algorithms/detail/sub_range.hpp113
-rw-r--r--boost/geometry/algorithms/detail/throw_on_empty_input.hpp8
-rw-r--r--boost/geometry/algorithms/detail/turns/compare_turns.hpp113
-rw-r--r--boost/geometry/algorithms/detail/turns/debug_turn.hpp65
-rw-r--r--boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp78
-rw-r--r--boost/geometry/algorithms/detail/turns/print_turns.hpp96
-rw-r--r--boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp62
-rw-r--r--boost/geometry/algorithms/detail/within/point_in_geometry.hpp463
-rw-r--r--boost/geometry/algorithms/detail/within/within_no_turns.hpp221
-rw-r--r--boost/geometry/algorithms/difference.hpp45
-rw-r--r--boost/geometry/algorithms/disjoint.hpp298
-rw-r--r--boost/geometry/algorithms/dispatch/disjoint.hpp70
-rw-r--r--boost/geometry/algorithms/dispatch/distance.hpp82
-rw-r--r--boost/geometry/algorithms/dispatch/is_simple.hpp38
-rw-r--r--boost/geometry/algorithms/dispatch/is_valid.hpp46
-rw-r--r--boost/geometry/algorithms/distance.hpp587
-rw-r--r--boost/geometry/algorithms/envelope.hpp249
-rw-r--r--boost/geometry/algorithms/equals.hpp361
-rw-r--r--boost/geometry/algorithms/expand.hpp158
-rw-r--r--boost/geometry/algorithms/for_each.hpp339
-rw-r--r--boost/geometry/algorithms/intersection.hpp229
-rw-r--r--boost/geometry/algorithms/intersects.hpp44
-rw-r--r--boost/geometry/algorithms/is_simple.hpp16
-rw-r--r--boost/geometry/algorithms/is_valid.hpp16
-rw-r--r--boost/geometry/algorithms/length.hpp161
-rw-r--r--boost/geometry/algorithms/not_implemented.hpp1
-rw-r--r--boost/geometry/algorithms/num_geometries.hpp103
-rw-r--r--boost/geometry/algorithms/num_interior_rings.hpp88
-rw-r--r--boost/geometry/algorithms/num_points.hpp210
-rw-r--r--boost/geometry/algorithms/num_segments.hpp204
-rw-r--r--boost/geometry/algorithms/overlaps.hpp64
-rw-r--r--boost/geometry/algorithms/perimeter.hpp192
-rw-r--r--boost/geometry/algorithms/point_on_surface.hpp327
-rw-r--r--boost/geometry/algorithms/remove_spikes.hpp280
-rw-r--r--boost/geometry/algorithms/reverse.hpp109
-rw-r--r--boost/geometry/algorithms/simplify.hpp410
-rw-r--r--boost/geometry/algorithms/sym_difference.hpp56
-rw-r--r--boost/geometry/algorithms/touches.hpp585
-rw-r--r--boost/geometry/algorithms/transform.hpp251
-rw-r--r--boost/geometry/algorithms/union.hpp263
-rw-r--r--boost/geometry/algorithms/unique.hpp85
-rw-r--r--boost/geometry/algorithms/within.hpp515
205 files changed, 35281 insertions, 5651 deletions
diff --git a/boost/geometry/algorithms/append.hpp b/boost/geometry/algorithms/append.hpp
index 72b2bbadab..1a8828ba4b 100644
--- a/boost/geometry/algorithms/append.hpp
+++ b/boost/geometry/algorithms/append.hpp
@@ -1,8 +1,14 @@
// 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.
+// 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 2014.
+// Modifications copyright (c) 2014, 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.
@@ -14,17 +20,20 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
#define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
-#include <boost/range.hpp>
+#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
-
-#include <boost/geometry/algorithms/num_interior_rings.hpp>
-#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/geometries/variant.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -92,7 +101,7 @@ struct point_to_polygon
else if (ring_index < int(num_interior_rings(polygon)))
{
append_point<ring_type, Point>::apply(
- interior_rings(polygon)[ring_index], point);
+ range::at(interior_rings(polygon), ring_index), point);
}
}
};
@@ -104,7 +113,7 @@ struct range_to_polygon
typedef typename ring_type<Polygon>::type ring_type;
static inline void apply(Polygon& polygon, Range const& range,
- int ring_index, int )
+ int ring_index, int = 0)
{
if (ring_index == -1)
{
@@ -114,7 +123,7 @@ struct range_to_polygon
else if (ring_index < int(num_interior_rings(polygon)))
{
append_range<ring_type, Range>::apply(
- interior_rings(polygon)[ring_index], range);
+ range::at(interior_rings(polygon), ring_index), range);
}
}
};
@@ -174,7 +183,7 @@ struct append_range<polygon_tag, Polygon, Range>
: detail::append::range_to_polygon<Polygon, Range>
{};
-}
+} // namespace splitted_dispatch
// Default: append a range (or linestring or ring or whatever) to any geometry
@@ -193,12 +202,143 @@ struct append<Geometry, RangeOrPoint, point_tag>
: splitted_dispatch::append_point<typename tag<Geometry>::type, Geometry, RangeOrPoint>
{};
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace append
+{
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_to_multigeometry
+{
+ static inline void apply(MultiGeometry& multigeometry,
+ RangeOrPoint const& range_or_point,
+ int ring_index, int multi_index)
+ {
+
+ dispatch::append
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ RangeOrPoint
+ >::apply(range::at(multigeometry, multi_index), range_or_point, ring_index);
+ }
+};
+
+}} // namespace detail::append
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+namespace splitted_dispatch
+{
+
+template <typename Geometry, typename Point>
+struct append_point<multi_point_tag, Geometry, Point>
+ : detail::append::append_point<Geometry, Point>
+{};
+
+template <typename Geometry, typename Range>
+struct append_range<multi_point_tag, Geometry, Range>
+ : detail::append::append_range<Geometry, Range>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_point<multi_linestring_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_range<multi_linestring_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_point<multi_polygon_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+template <typename MultiGeometry, typename RangeOrPoint>
+struct append_range<multi_polygon_tag, MultiGeometry, RangeOrPoint>
+ : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
+{};
+
+} // namespace splitted_dispatch
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct append
+{
+ template <typename RangeOrPoint>
+ static inline void apply(Geometry& geometry,
+ RangeOrPoint const& range_or_point,
+ int ring_index,
+ int multi_index)
+ {
+ concept::check<Geometry>();
+ dispatch::append<Geometry, RangeOrPoint>::apply(geometry,
+ range_or_point,
+ ring_index,
+ multi_index);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct append<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename RangeOrPoint>
+ struct visitor: boost::static_visitor<void>
+ {
+ RangeOrPoint const& m_range_or_point;
+ int m_ring_index;
+ int m_multi_index;
+
+ visitor(RangeOrPoint const& range_or_point,
+ int ring_index,
+ int multi_index):
+ m_range_or_point(range_or_point),
+ m_ring_index(ring_index),
+ m_multi_index(multi_index)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ append<Geometry>::apply(geometry,
+ m_range_or_point,
+ m_ring_index,
+ m_multi_index);
+ }
+ };
+
+ template <typename RangeOrPoint>
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant_geometry,
+ RangeOrPoint const& range_or_point,
+ int ring_index,
+ int multi_index)
+ {
+ apply_visitor(
+ visitor<RangeOrPoint>(
+ range_or_point,
+ ring_index,
+ multi_index
+ ),
+ variant_geometry
+ );
+ }
+};
+
+} // namespace resolve_variant;
+
+
/*!
\brief Appends one or more points to a linestring, ring, polygon, multi-geometry
\ingroup append
@@ -208,22 +348,17 @@ struct append<Geometry, RangeOrPoint, point_tag>
\param range_or_point The point or range to add
\param ring_index The index of the ring in case of a polygon:
exterior ring (-1, the default) or interior ring index
-\param multi_index Reserved for multi polygons or multi linestrings
+\param multi_index The index of the geometry to which the points are appended
\qbk{[include reference/algorithms/append.qbk]}
}
*/
template <typename Geometry, typename RangeOrPoint>
inline void append(Geometry& geometry, RangeOrPoint const& range_or_point,
- int ring_index = -1, int multi_index = 0)
+ int ring_index = -1, int multi_index = 0)
{
- concept::check<Geometry>();
-
- dispatch::append
- <
- Geometry,
- RangeOrPoint
- >::apply(geometry, range_or_point, ring_index, multi_index);
+ resolve_variant::append<Geometry>
+ ::apply(geometry, range_or_point, ring_index, multi_index);
}
diff --git a/boost/geometry/algorithms/area.hpp b/boost/geometry/algorithms/area.hpp
index 8193200ab9..7377798719 100644
--- a/boost/geometry/algorithms/area.hpp
+++ b/boost/geometry/algorithms/area.hpp
@@ -18,18 +18,24 @@
#include <boost/mpl/if.hpp>
#include <boost/range/functions.hpp>
#include <boost/range/metafunctions.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.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/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/strategies/default_area_result.hpp>
@@ -49,41 +55,33 @@ namespace boost { namespace geometry
namespace detail { namespace area
{
-template<typename Box, typename Strategy>
struct box_area
{
- typedef typename coordinate_type<Box>::type return_type;
-
- static inline return_type apply(Box const& box, Strategy const&)
+ template <typename Box, typename Strategy>
+ static inline typename coordinate_type<Box>::type
+ apply(Box const& box, Strategy const&)
{
// Currently only works for 2D Cartesian boxes
assert_dimension<Box, 2>();
- return_type const dx = get<max_corner, 0>(box)
- - get<min_corner, 0>(box);
- return_type const dy = get<max_corner, 1>(box)
- - get<min_corner, 1>(box);
-
- return dx * dy;
+ return (get<max_corner, 0>(box) - get<min_corner, 0>(box))
+ * (get<max_corner, 1>(box) - get<min_corner, 1>(box));
}
};
template
<
- typename Ring,
iterate_direction Direction,
- closure_selector Closure,
- typename Strategy
+ closure_selector Closure
>
struct ring_area
{
- BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) );
-
- typedef typename Strategy::return_type type;
-
- static inline type apply(Ring const& ring, Strategy const& strategy)
+ template <typename Ring, typename Strategy>
+ static inline typename Strategy::return_type
+ apply(Ring const& ring, Strategy const& strategy)
{
+ BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy<Strategy>) );
assert_dimension<Ring, 2>();
// Ignore warning (because using static method sometimes) on strategy
@@ -92,10 +90,10 @@ struct ring_area
// An open ring has at least three points,
// A closed ring has at least four points,
// if not, there is no (zero) area
- if (int(boost::size(ring))
+ if (boost::size(ring)
< core_detail::closure::minimum_ring_size<Closure>::value)
{
- return type();
+ return typename Strategy::return_type();
}
typedef typename reversible_view<Ring const, Direction>::type rview_type;
@@ -136,77 +134,112 @@ namespace dispatch
template
<
typename Geometry,
- typename Strategy = typename strategy::area::services::default_strategy
- <
- typename cs_tag
- <
- typename point_type<Geometry>::type
- >::type,
- typename point_type<Geometry>::type
- >::type,
typename Tag = typename tag<Geometry>::type
>
-struct area
- : detail::calculate_null
- <
- typename Strategy::return_type,
- Geometry,
- Strategy
- > {};
+struct area : detail::calculate_null
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return calculate_null::apply<typename Strategy::return_type>(geometry, strategy);
+ }
+};
-template
-<
- typename Geometry,
- typename Strategy
->
-struct area<Geometry, Strategy, box_tag>
- : detail::area::box_area<Geometry, Strategy>
+template <typename Geometry>
+struct area<Geometry, box_tag> : detail::area::box_area
{};
-template
-<
- typename Ring,
- typename Strategy
->
-struct area<Ring, Strategy, ring_tag>
+template <typename Ring>
+struct area<Ring, ring_tag>
: detail::area::ring_area
<
- Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
- Strategy
+ geometry::closure<Ring>::value
>
{};
-template
-<
- typename Polygon,
- typename Strategy
->
-struct area<Polygon, Strategy, polygon_tag>
- : detail::calculate_polygon_sum
- <
+template <typename Polygon>
+struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type apply(Polygon const& polygon, Strategy const& strategy)
+ {
+ return calculate_polygon_sum::apply<
typename Strategy::return_type,
- Polygon,
- Strategy,
detail::area::ring_area
<
- typename ring_type<Polygon const>::type,
order_as_direction<geometry::point_order<Polygon>::value>::value,
- geometry::closure<Polygon>::value,
- Strategy
+ geometry::closure<Polygon>::value
>
- >
-{};
+ >(polygon, strategy);
+ }
+};
+
+
+template <typename MultiGeometry>
+struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type
+ apply(MultiGeometry const& multi, Strategy const& strategy)
+ {
+ return multi_sum::apply
+ <
+ typename Strategy::return_type,
+ area<typename boost::range_value<MultiGeometry>::type>
+ >(multi, strategy);
+ }
+};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct area
+{
+ template <typename Strategy>
+ static inline typename Strategy::return_type apply(Geometry const& geometry,
+ Strategy const& strategy)
+ {
+ return dispatch::area<Geometry>::apply(geometry, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<typename Strategy::return_type>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry>
+ typename Strategy::return_type operator()(Geometry const& geometry) const
+ {
+ return area<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename Strategy::return_type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
/*!
\brief \brief_calc{area}
@@ -234,6 +267,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr
{
concept::check<Geometry const>();
+ // TODO put this into a resolve_strategy stage
+ // (and take the return type from resolve_variant)
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
@@ -242,11 +277,8 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr
>::type strategy_type;
// detail::throw_on_empty_input(geometry);
-
- return dispatch::area
- <
- Geometry
- >::apply(geometry, strategy_type());
+
+ return resolve_variant::area<Geometry>::apply(geometry, strategy_type());
}
/*!
@@ -280,12 +312,8 @@ inline typename Strategy::return_type area(
concept::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
-
- return dispatch::area
- <
- Geometry,
- Strategy
- >::apply(geometry, strategy);
+
+ return resolve_variant::area<Geometry>::apply(geometry, strategy);
}
diff --git a/boost/geometry/algorithms/assign.hpp b/boost/geometry/algorithms/assign.hpp
index 8c153c878d..32f095b9ac 100644
--- a/boost/geometry/algorithms/assign.hpp
+++ b/boost/geometry/algorithms/assign.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -40,6 +41,8 @@
#include <boost/geometry/util/for_each_coordinate.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
namespace boost { namespace geometry
{
@@ -122,9 +125,232 @@ inline void assign_zero(Geometry& geometry)
}
/*!
+\brief Assign two coordinates to a geometry (usually a 2D point)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 \param_x
+\param c2 \param_y
+
+\qbk{distinguish, 2 coordinate values}
+\qbk{
+[heading Example]
+[assign_2d_point] [assign_2d_point_output]
+
+[heading See also]
+\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
+}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2);
+}
+
+/*!
+\brief Assign three values to a geometry (usually a 3D point)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 \param_x
+\param c2 \param_y
+\param c3 \param_z
+
+\qbk{distinguish, 3 coordinate values}
+\qbk{
+[heading Example]
+[assign_3d_point] [assign_3d_point_output]
+
+[heading See also]
+\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
+}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry,
+ Type const& c1, Type const& c2, Type const& c3)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2, c3);
+}
+
+/*!
+\brief Assign four values to a geometry (usually a box or segment)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 First coordinate (usually x1)
+\param c2 Second coordinate (usually y1)
+\param c3 Third coordinate (usually x2)
+\param c4 Fourth coordinate (usually y2)
+
+\qbk{distinguish, 4 coordinate values}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry,
+ Type const& c1, Type const& c2, Type const& c3, Type const& c4)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2, c3, c4);
+}
+
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct assign
+{
+ static inline void
+ apply(
+ Geometry1& geometry1,
+ const Geometry2& geometry2)
+ {
+ concept::check<Geometry1>();
+ concept::check<Geometry2 const>();
+ concept::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
+
+ bool const same_point_order =
+ point_order<Geometry1>::value == point_order<Geometry2>::value;
+ bool const same_closure =
+ closure<Geometry1>::value == closure<Geometry2>::value;
+
+ BOOST_MPL_ASSERT_MSG
+ (
+ same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER
+ , (types<Geometry1, Geometry2>)
+ );
+ BOOST_MPL_ASSERT_MSG
+ (
+ same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE
+ , (types<Geometry1, Geometry2>)
+ );
+
+ dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: static_visitor<void>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2)
+ : m_geometry2(geometry2)
+ {}
+
+ template <typename Geometry1>
+ result_type operator()(Geometry1& geometry1) const
+ {
+ return assign
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, m_geometry2);
+ }
+ };
+
+ static inline void
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: static_visitor<void>
+ {
+ Geometry1& m_geometry1;
+
+ visitor(Geometry1 const& geometry1)
+ : m_geometry1(geometry1)
+ {}
+
+ template <typename Geometry2>
+ result_type operator()(Geometry2 const& geometry2) const
+ {
+ return assign
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (m_geometry1, geometry2);
+ }
+ };
+
+ static inline void
+ apply(Geometry1& geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
+ {
+ return apply_visitor(visitor(geometry1), geometry2);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
+struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+{
+ struct visitor: static_visitor<void>
+ {
+ template <typename Geometry1, typename Geometry2>
+ result_type operator()(
+ Geometry1& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return assign
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, geometry2);
+ }
+ };
+
+ static inline void
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2)
+ {
+ return apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
\brief Assigns one geometry to another geometry
-\details The assign algorithm assigns one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only
-if it is possible and applicable.
+\details The assign algorithm assigns one geometry, e.g. a BOX, to another
+geometry, e.g. a RING. This only works if it is possible and applicable.
\ingroup assign
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
@@ -142,25 +368,7 @@ if it is possible and applicable.
template <typename Geometry1, typename Geometry2>
inline void assign(Geometry1& geometry1, Geometry2 const& geometry2)
{
- concept::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
-
- bool const same_point_order =
- point_order<Geometry1>::value == point_order<Geometry2>::value;
- bool const same_closure =
- closure<Geometry1>::value == closure<Geometry2>::value;
-
- BOOST_MPL_ASSERT_MSG
- (
- same_point_order, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER
- , (types<Geometry1, Geometry2>)
- );
- BOOST_MPL_ASSERT_MSG
- (
- same_closure, ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE
- , (types<Geometry1, Geometry2>)
- );
-
- dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1);
+ resolve_variant::assign<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
diff --git a/boost/geometry/algorithms/buffer.hpp b/boost/geometry/algorithms/buffer.hpp
index e22e36addc..b8b07ad4d9 100644
--- a/boost/geometry/algorithms/buffer.hpp
+++ b/boost/geometry/algorithms/buffer.hpp
@@ -17,15 +17,19 @@
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
-
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/clear.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
namespace boost { namespace geometry
{
@@ -75,29 +79,87 @@ inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
namespace dispatch
{
-template <typename TagIn, typename TagOut, typename Input, typename T, typename Output>
-struct buffer {};
+template
+<
+ typename Input,
+ typename Output,
+ typename TagIn = typename tag<Input>::type,
+ typename TagOut = typename tag<Output>::type
+>
+struct buffer: not_implemented<TagIn, TagOut>
+{};
-template <typename BoxIn, typename T, typename BoxOut>
-struct buffer<box_tag, box_tag, BoxIn, T, BoxOut>
+template <typename BoxIn, typename BoxOut>
+struct buffer<BoxIn, BoxOut, box_tag, box_tag>
{
- static inline void apply(BoxIn const& box_in, T const& distance,
- T const& , BoxIn& box_out)
+ template <typename Distance>
+ static inline void apply(BoxIn const& box_in, Distance const& distance,
+ Distance const& , BoxOut& box_out)
{
detail::buffer::buffer_box(box_in, distance, box_out);
}
};
-// Many things to do. Point is easy, other geometries require self intersections
-// For point, note that it should output as a polygon (like the rest). Buffers
-// of a set of geometries are often lateron combined using a "dissolve" operation.
-// Two points close to each other get a combined kidney shaped buffer then.
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct buffer
+{
+ template <typename Distance, typename GeometryOut>
+ static inline void apply(Geometry const& geometry,
+ Distance const& distance,
+ Distance const& chord_length,
+ GeometryOut& out)
+ {
+ dispatch::buffer<Geometry, GeometryOut>::apply(geometry, distance, chord_length, out);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct buffer<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Distance, typename GeometryOut>
+ struct visitor: boost::static_visitor<void>
+ {
+ Distance const& m_distance;
+ Distance const& m_chord_length;
+ GeometryOut& m_out;
+
+ visitor(Distance const& distance,
+ Distance const& chord_length,
+ GeometryOut& out)
+ : m_distance(distance),
+ m_chord_length(chord_length),
+ m_out(out)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ buffer<Geometry>::apply(geometry, m_distance, m_chord_length, m_out);
+ }
+ };
+
+ template <typename Distance, typename GeometryOut>
+ static inline void apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Distance const& distance,
+ Distance const& chord_length,
+ GeometryOut& out
+ )
+ {
+ boost::apply_visitor(visitor<Distance, GeometryOut>(distance, chord_length, out), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{buffer}
\ingroup buffer
@@ -109,7 +171,6 @@ struct buffer<box_tag, box_tag, BoxIn, T, BoxOut>
\param geometry_out \param_geometry
\param distance The distance to be used for the buffer
\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
-\note Currently only implemented for box, the trivial case, but still useful
\qbk{[include reference/algorithms/buffer.qbk]}
*/
@@ -120,14 +181,7 @@ inline void buffer(Input const& geometry_in, Output& geometry_out,
concept::check<Input const>();
concept::check<Output>();
- dispatch::buffer
- <
- typename tag<Input>::type,
- typename tag<Output>::type,
- Input,
- Distance,
- Output
- >::apply(geometry_in, distance, chord_length, geometry_out);
+ resolve_variant::buffer<Input>::apply(geometry_in, distance, chord_length, geometry_out);
}
/*!
@@ -139,29 +193,90 @@ inline void buffer(Input const& geometry_in, Output& geometry_out,
\tparam Distance \tparam_numeric
\param geometry \param_geometry
\param distance The distance to be used for the buffer
-\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
+\param chord_length (optional) The length of the chord's in the generated arcs
+ around points or bends (RESERVED, NOT YET USED)
\return \return_calc{buffer}
*/
-template <typename Output, typename Input, typename T>
-Output return_buffer(Input const& geometry, T const& distance, T const& chord_length = -1)
+template <typename Output, typename Input, typename Distance>
+Output return_buffer(Input const& geometry, Distance const& distance, Distance const& chord_length = -1)
{
concept::check<Input const>();
concept::check<Output>();
Output geometry_out;
- dispatch::buffer
- <
- typename tag<Input>::type,
- typename tag<Output>::type,
- Input,
- T,
- Output
- >::apply(geometry, distance, chord_length, geometry_out);
+ resolve_variant::buffer<Input>::apply(geometry, distance, chord_length, geometry_out);
return geometry_out;
}
+/*!
+\brief \brief_calc{buffer}
+\ingroup buffer
+\details \details_calc{buffer, \det_buffer}.
+\tparam GeometryIn \tparam_geometry
+\tparam MultiPolygon \tparam_geometry{MultiPolygon}
+\tparam DistanceStrategy A strategy defining distance (or radius)
+\tparam SideStrategy A strategy defining creation along sides
+\tparam JoinStrategy A strategy defining creation around convex corners
+\tparam EndStrategy A strategy defining creation at linestring ends
+\tparam PointStrategy A strategy defining creation around points
+\param geometry_in \param_geometry
+\param geometry_out output multi polygon (or std:: collection of polygons),
+ will contain a buffered version of the input geometry
+\param distance_strategy The distance strategy to be used
+\param side_strategy The side strategy to be used
+\param join_strategy The join strategy to be used
+\param end_strategy The end strategy to be used
+\param point_strategy The point strategy to be used
+
+\qbk{distinguish,with strategies}
+\qbk{[include reference/algorithms/buffer_with_strategies.qbk]}
+ */
+template
+<
+ typename GeometryIn,
+ typename MultiPolygon,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy
+>
+inline void buffer(GeometryIn const& geometry_in,
+ MultiPolygon& geometry_out,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy)
+{
+ typedef typename boost::range_value<MultiPolygon>::type polygon_type;
+ concept::check<GeometryIn const>();
+ concept::check<polygon_type>();
+
+ typedef typename point_type<GeometryIn>::type point_type;
+ typedef typename rescale_policy_type<point_type>::type rescale_policy_type;
+
+ geometry_out.clear();
+
+ model::box<point_type> box;
+ envelope(geometry_in, box);
+ buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy));
+
+ rescale_policy_type rescale_policy
+ = boost::geometry::get_rescale_policy<rescale_policy_type>(box);
+
+ detail::buffer::buffer_inserter<polygon_type>(geometry_in, std::back_inserter(geometry_out),
+ distance_strategy,
+ side_strategy,
+ join_strategy,
+ end_strategy,
+ point_strategy,
+ rescale_policy);
+}
+
+
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp
index 69ad9fe829..65dc9c3753 100644
--- a/boost/geometry/algorithms/centroid.hpp
+++ b/boost/geometry/algorithms/centroid.hpp
@@ -3,6 +3,12 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 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,7 +24,9 @@
#include <cstddef>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
@@ -27,17 +35,27 @@
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/convert.hpp>
-#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/concepts/centroid_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
namespace boost { namespace geometry
@@ -62,8 +80,15 @@ class centroid_exception : public geometry::exception
{
public:
+ /*!
+ \brief The default constructor
+ */
inline centroid_exception() {}
+ /*!
+ \brief Returns the explanatory string.
+ \return Pointer to a null-terminated string with explanatory information.
+ */
virtual char const* what() const throw()
{
return "Boost.Geometry Centroid calculation exception";
@@ -77,9 +102,9 @@ public:
namespace detail { namespace centroid
{
-template<typename Point, typename PointCentroid, typename Strategy>
struct centroid_point
{
+ template<typename Point, typename PointCentroid, typename Strategy>
static inline void apply(Point const& point, PointCentroid& centroid,
Strategy const&)
{
@@ -89,55 +114,56 @@ struct centroid_point
template
<
- typename Box,
+ typename Indexed,
typename Point,
std::size_t Dimension,
std::size_t DimensionCount
>
-struct centroid_box_calculator
+struct centroid_indexed_calculator
{
typedef typename select_coordinate_type
<
- Box, Point
+ Indexed, Point
>::type coordinate_type;
- static inline void apply(Box const& box, Point& centroid)
+ static inline void apply(Indexed const& indexed, Point& centroid)
{
- coordinate_type const c1 = get<min_corner, Dimension>(box);
- coordinate_type const c2 = get<max_corner, Dimension>(box);
+ coordinate_type const c1 = get<min_corner, Dimension>(indexed);
+ coordinate_type const c2 = get<max_corner, Dimension>(indexed);
coordinate_type m = c1 + c2;
- m /= 2.0;
+ coordinate_type const two = 2;
+ m /= two;
set<Dimension>(centroid, m);
- centroid_box_calculator
+ centroid_indexed_calculator
<
- Box, Point,
+ Indexed, Point,
Dimension + 1, DimensionCount
- >::apply(box, centroid);
+ >::apply(indexed, centroid);
}
};
-template<typename Box, typename Point, std::size_t DimensionCount>
-struct centroid_box_calculator<Box, Point, DimensionCount, DimensionCount>
+template<typename Indexed, typename Point, std::size_t DimensionCount>
+struct centroid_indexed_calculator<Indexed, Point, DimensionCount, DimensionCount>
{
- static inline void apply(Box const& , Point& )
+ static inline void apply(Indexed const& , Point& )
{
}
};
-template<typename Box, typename Point, typename Strategy>
-struct centroid_box
+struct centroid_indexed
{
- static inline void apply(Box const& box, Point& centroid,
+ template<typename Indexed, typename Point, typename Strategy>
+ static inline void apply(Indexed const& indexed, Point& centroid,
Strategy const&)
{
- centroid_box_calculator
+ centroid_indexed_calculator
<
- Box, Point,
- 0, dimension<Box>::type::value
- >::apply(box, centroid);
+ Indexed, Point,
+ 0, dimension<Indexed>::type::value
+ >::apply(indexed, centroid);
}
};
@@ -169,16 +195,19 @@ inline bool range_ok(Range const& range, Point& centroid)
return true;
}
-
/*!
- \brief Calculate the centroid of a ring.
+ \brief Calculate the centroid of a Ring or a Linestring.
*/
-template<typename Ring, closure_selector Closure, typename Strategy>
+template <closure_selector Closure>
struct centroid_range_state
{
+ template<typename Ring, typename PointTransformer, typename Strategy>
static inline void apply(Ring const& ring,
- Strategy const& strategy, typename Strategy::state_type& state)
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
{
+ typedef typename geometry::point_type<Ring const>::type point_type;
typedef typename closeable_view<Ring const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator_type;
@@ -187,31 +216,42 @@ struct centroid_range_state
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
- for (iterator_type previous = it++;
- it != end;
- ++previous, ++it)
+ typename PointTransformer::result_type
+ previous_pt = transformer.apply(*it);
+
+ for ( ++it ; it != end ; ++it)
{
- strategy.apply(*previous, *it, state);
+ typename PointTransformer::result_type
+ pt = transformer.apply(*it);
+
+ strategy.apply(static_cast<point_type const&>(previous_pt),
+ static_cast<point_type const&>(pt),
+ state);
+
+ previous_pt = pt;
}
}
};
-template<typename Range, typename Point, closure_selector Closure, typename Strategy>
+template <closure_selector Closure>
struct centroid_range
{
+ template<typename Range, typename Point, typename Strategy>
static inline void apply(Range const& range, Point& centroid,
- Strategy const& strategy)
+ Strategy const& strategy)
{
if (range_ok(range, centroid))
{
+ // prepare translation transformer
+ translating_transformer<Range> transformer(*boost::begin(range));
+
typename Strategy::state_type state;
- centroid_range_state
- <
- Range,
- Closure,
- Strategy
- >::apply(range, strategy, state);
+ centroid_range_state<Closure>::apply(range, transformer,
+ strategy, state);
strategy.result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
}
}
};
@@ -222,48 +262,112 @@ struct centroid_range
\note Because outer ring is clockwise, inners are counter clockwise,
triangle approach is OK and works for polygons with rings.
*/
-template<typename Polygon, typename Strategy>
struct centroid_polygon_state
{
- typedef typename ring_type<Polygon>::type ring_type;
-
+ template<typename Polygon, typename PointTransformer, typename Strategy>
static inline void apply(Polygon const& poly,
- Strategy const& strategy, typename Strategy::state_type& state)
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
{
- typedef centroid_range_state
- <
- ring_type,
- geometry::closure<ring_type>::value,
- Strategy
- > per_ring;
+ typedef typename ring_type<Polygon>::type ring_type;
+ typedef centroid_range_state<geometry::closure<ring_type>::value> per_ring;
- per_ring::apply(exterior_ring(poly), strategy, state);
+ per_ring::apply(exterior_ring(poly), transformer, strategy, state);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_ring::apply(*it, strategy, state);
+ per_ring::apply(*it, transformer, strategy, state);
}
}
};
-template<typename Polygon, typename Point, typename Strategy>
struct centroid_polygon
{
+ template<typename Polygon, typename Point, typename Strategy>
static inline void apply(Polygon const& poly, Point& centroid,
Strategy const& strategy)
{
if (range_ok(exterior_ring(poly), centroid))
{
+ // prepare translation transformer
+ translating_transformer<Polygon>
+ transformer(*boost::begin(exterior_ring(poly)));
+
typename Strategy::state_type state;
- centroid_polygon_state
- <
- Polygon,
- Strategy
- >::apply(poly, strategy, state);
+ centroid_polygon_state::apply(poly, transformer, strategy, state);
strategy.result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
+ }
+ }
+};
+
+
+/*!
+ \brief Building block of a multi-point, to be used as Policy in the
+ more generec centroid_multi
+*/
+struct centroid_multi_point_state
+{
+ template <typename Point, typename PointTransformer, typename Strategy>
+ static inline void apply(Point const& point,
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
+ {
+ strategy.apply(static_cast<Point const&>(transformer.apply(point)),
+ state);
+ }
+};
+
+
+/*!
+ \brief Generic implementation which calls a policy to calculate the
+ centroid of the total of its single-geometries
+ \details The Policy is, in general, the single-version, with state. So
+ detail::centroid::centroid_polygon_state is used as a policy for this
+ detail::centroid::centroid_multi
+
+*/
+template <typename Policy>
+struct centroid_multi
+{
+ template <typename Multi, typename Point, typename Strategy>
+ static inline void apply(Multi const& multi,
+ Point& centroid,
+ Strategy const& strategy)
+ {
+#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
+ // If there is nothing in any of the ranges, it is not possible
+ // to calculate the centroid
+ if (geometry::num_points(multi) == 0)
+ {
+ throw centroid_exception();
}
+#endif
+
+ // prepare translation transformer
+ translating_transformer<Multi> transformer(multi);
+
+ typename Strategy::state_type state;
+
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, transformer, strategy, state);
+ }
+ Strategy::result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
}
};
@@ -278,64 +382,153 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename Point,
- typename Strategy
+ typename Tag = typename tag<Geometry>::type
>
-struct centroid {};
+struct centroid: not_implemented<Tag>
+{};
-template
-<
- typename Geometry,
- typename Point,
- typename Strategy
->
-struct centroid<point_tag, Geometry, Point, Strategy>
- : detail::centroid::centroid_point<Geometry, Point, Strategy>
+template <typename Geometry>
+struct centroid<Geometry, point_tag>
+ : detail::centroid::centroid_point
{};
-template
-<
- typename Box,
- typename Point,
- typename Strategy
->
-struct centroid<box_tag, Box, Point, Strategy>
- : detail::centroid::centroid_box<Box, Point, Strategy>
+template <typename Box>
+struct centroid<Box, box_tag>
+ : detail::centroid::centroid_indexed
+{};
+
+template <typename Segment>
+struct centroid<Segment, segment_tag>
+ : detail::centroid::centroid_indexed
+{};
+
+template <typename Ring>
+struct centroid<Ring, ring_tag>
+ : detail::centroid::centroid_range<geometry::closure<Ring>::value>
+{};
+
+template <typename Linestring>
+struct centroid<Linestring, linestring_tag>
+ : detail::centroid::centroid_range<closed>
{};
-template <typename Ring, typename Point, typename Strategy>
-struct centroid<ring_tag, Ring, Point, Strategy>
- : detail::centroid::centroid_range
+template <typename Polygon>
+struct centroid<Polygon, polygon_tag>
+ : detail::centroid::centroid_polygon
+{};
+
+template <typename MultiLinestring>
+struct centroid<MultiLinestring, multi_linestring_tag>
+ : detail::centroid::centroid_multi
<
- Ring,
- Point,
- geometry::closure<Ring>::value,
- Strategy
+ detail::centroid::centroid_range_state<closed>
>
{};
-template <typename Linestring, typename Point, typename Strategy>
-struct centroid<linestring_tag, Linestring, Point, Strategy>
- : detail::centroid::centroid_range
+template <typename MultiPolygon>
+struct centroid<MultiPolygon, multi_polygon_tag>
+ : detail::centroid::centroid_multi
<
- Linestring,
- Point,
- closed,
- Strategy
+ detail::centroid::centroid_polygon_state
+ >
+{};
+
+template <typename MultiPoint>
+struct centroid<MultiPoint, multi_point_tag>
+ : detail::centroid::centroid_multi
+ <
+ detail::centroid::centroid_multi_point_state
>
- {};
+{};
-template <typename Polygon, typename Point, typename Strategy>
-struct centroid<polygon_tag, Polygon, Point, Strategy>
- : detail::centroid::centroid_polygon<Polygon, Point, Strategy>
- {};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+template <typename Geometry>
+struct centroid
+{
+ template <typename Point, typename Strategy>
+ static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
+ {
+ dispatch::centroid<Geometry>::apply(geometry, out, strategy);
+ }
+
+ template <typename Point>
+ static inline void apply(Geometry const& geometry, Point& out, default_strategy)
+ {
+ typedef typename strategy::centroid::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type,
+ typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ pointlike_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ dimension<Geometry>::type::value,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ dispatch::centroid<Geometry>::apply(geometry, out, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct centroid
+{
+ template <typename Point, typename Strategy>
+ static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
+ {
+ concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
+ resolve_strategy::centroid<Geometry>::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Point, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ Point& m_out;
+ Strategy const& m_strategy;
+
+ visitor(Point& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ centroid<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename Point, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Point& out,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
@@ -357,21 +550,7 @@ template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c,
Strategy const& strategy)
{
- //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
-
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
- typedef typename point_type<Geometry>::type point_type;
-
- // Call dispatch apply method. That one returns true if centroid
- // should be taken from state.
- dispatch::centroid
- <
- typename tag<Geometry>::type,
- Geometry,
- Point,
- Strategy
- >::apply(geometry, c, strategy);
+ resolve_variant::centroid<Geometry>::apply(geometry, c, strategy);
}
@@ -394,24 +573,7 @@ inline void centroid(Geometry const& geometry, Point& c,
template<typename Geometry, typename Point>
inline void centroid(Geometry const& geometry, Point& c)
{
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
- typedef typename strategy::centroid::services::default_strategy
- <
- typename cs_tag<Geometry>::type,
- typename tag_cast
- <
- typename tag<Geometry>::type,
- pointlike_tag,
- linear_tag,
- areal_tag
- >::type,
- dimension<Geometry>::type::value,
- Point,
- Geometry
- >::type strategy_type;
-
- centroid(geometry, c, strategy_type());
+ centroid(geometry, c, default_strategy());
}
@@ -429,8 +591,6 @@ inline void centroid(Geometry const& geometry, Point& c)
template<typename Point, typename Geometry>
inline Point return_centroid(Geometry const& geometry)
{
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
Point c;
centroid(geometry, c);
return c;
@@ -454,10 +614,6 @@ inline Point return_centroid(Geometry const& geometry)
template<typename Point, typename Geometry, typename Strategy>
inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
{
- //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
-
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
Point c;
centroid(geometry, c, strategy);
return c;
diff --git a/boost/geometry/algorithms/clear.hpp b/boost/geometry/algorithms/clear.hpp
index d7336587ee..1850816b1b 100644
--- a/boost/geometry/algorithms/clear.hpp
+++ b/boost/geometry/algorithms/clear.hpp
@@ -14,15 +14,19 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
-#include <boost/mpl/assert.hpp>
+
#include <boost/type_traits/remove_const.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/access.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/tag_cast.hpp>
-
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -72,6 +76,7 @@ struct no_action
}
};
+
}} // namespace detail::clear
#endif // DOXYGEN_NO_DETAIL
@@ -84,14 +89,8 @@ template
typename Geometry,
typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
-struct clear
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+struct clear: not_implemented<Tag>
+{};
// Point/box/segment do not have clear. So specialize to do nothing.
template <typename Geometry>
@@ -127,10 +126,48 @@ struct clear<Polygon, polygon_tag>
{};
+template <typename Geometry>
+struct clear<Geometry, multi_tag>
+ : detail::clear::collection_clear<Geometry>
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct clear
+{
+ static inline void apply(Geometry& geometry)
+ {
+ dispatch::clear<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct clear<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: static_visitor<void>
+ {
+ template <typename Geometry>
+ inline void operator()(Geometry& geometry) const
+ {
+ clear<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Clears a linestring, ring or polygon (exterior+interiors) or multi*
\details Generic function to clear a geometry. All points will be removed from the collection or collections
@@ -149,7 +186,7 @@ inline void clear(Geometry& geometry)
{
concept::check<Geometry>();
- dispatch::clear<Geometry>::apply(geometry);
+ resolve_variant::clear<Geometry>::apply(geometry);
}
diff --git a/boost/geometry/algorithms/comparable_distance.hpp b/boost/geometry/algorithms/comparable_distance.hpp
index 3467045ca2..6f009da3ed 100644
--- a/boost/geometry/algorithms/comparable_distance.hpp
+++ b/boost/geometry/algorithms/comparable_distance.hpp
@@ -1,8 +1,13 @@
// 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.
+// 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 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -14,61 +19,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
-
-#include <boost/geometry/algorithms/distance.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-/*!
-\brief \brief_calc2{comparable distance measurement}
-\ingroup distance
-\details The free function comparable_distance does not necessarily calculate the distance,
- but it calculates a distance measure such that two distances are comparable to each other.
- For example: for the Cartesian coordinate system, Pythagoras is used but the square root
- is not taken, which makes it faster and the results of two point pairs can still be
- compared to each other.
-\tparam Geometry1 first geometry type
-\tparam Geometry2 second geometry type
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_calc{comparable distance}
-
-\qbk{[include reference/algorithms/comparable_distance.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline typename default_distance_result<Geometry1, Geometry2>::type comparable_distance(
- Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- typedef typename point_type<Geometry1>::type point1_type;
- typedef typename point_type<Geometry2>::type point2_type;
-
- // Define a point-point-distance-strategy
- // for either the normal case, either the reversed case
-
- typedef typename strategy::distance::services::comparable_type
- <
- typename boost::mpl::if_c
- <
- geometry::reverse_dispatch
- <Geometry1, Geometry2>::type::value,
- typename strategy::distance::services::default_strategy
- <point_tag, point2_type, point1_type>::type,
- typename strategy::distance::services::default_strategy
- <point_tag, point1_type, point2_type>::type
- >::type
- >::type strategy_type;
-
- return distance(geometry1, geometry2, strategy_type());
-}
-
-
-}} // namespace boost::geometry
-
+#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp>
+#include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
diff --git a/boost/geometry/algorithms/convert.hpp b/boost/geometry/algorithms/convert.hpp
index fbbf74c17f..914ef8f420 100644
--- a/boost/geometry/algorithms/convert.hpp
+++ b/boost/geometry/algorithms/convert.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -20,6 +21,10 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_array.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
@@ -31,19 +36,32 @@
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/util/range.hpp>
+
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tags.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+// Silence warning C4512: assignment operator could not be generated
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127 4512)
+#endif
+
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
@@ -95,7 +113,7 @@ struct box_to_range
assign_box_corners_oriented<Reverse>(box, range);
if (Close)
{
- range[4] = range[0];
+ range::at(range, 4) = range::at(range, 0);
}
}
};
@@ -115,22 +133,22 @@ struct segment_to_range
}
};
-template
+template
<
- typename Range1,
- typename Range2,
+ typename Range1,
+ typename Range2,
bool Reverse = false
>
struct range_to_range
{
typedef typename reversible_view
<
- Range1 const,
+ Range1 const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
typedef typename closeable_view
<
- rview_type const,
+ rview_type const,
geometry::closure<Range1>::value
>::type view_type;
@@ -144,13 +162,17 @@ struct range_to_range
// point for open output.
view_type view(rview);
- int n = boost::size(view);
+ typedef typename boost::range_size<Range1>::type size_type;
+ size_type n = boost::size(view);
if (geometry::closure<Range2>::value == geometry::open)
{
n--;
}
- int i = 0;
+ // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
+ // but ok, sice below it == end()
+
+ size_type i = 0;
for (typename boost::range_iterator<view_type const>::type it
= boost::begin(view);
it != boost::end(view) && i < n;
@@ -166,7 +188,7 @@ struct polygon_to_polygon
{
typedef range_to_range
<
- typename geometry::ring_type<Polygon1>::type,
+ typename geometry::ring_type<Polygon1>::type,
typename geometry::ring_type<Polygon2>::type,
geometry::point_order<Polygon1>::value
!= geometry::point_order<Polygon2>::value
@@ -176,7 +198,7 @@ struct polygon_to_polygon
{
// Clearing managed per ring, and in the resizing of interior rings
- per_ring::apply(geometry::exterior_ring(source),
+ per_ring::apply(geometry::exterior_ring(source),
geometry::exterior_ring(destination));
// Container should be resizeable
@@ -188,13 +210,15 @@ struct polygon_to_polygon
>::type
>::apply(interior_rings(destination), num_interior_rings(source));
- typename interior_return_type<Polygon1 const>::type rings_source
- = interior_rings(source);
- typename interior_return_type<Polygon2>::type rings_dest
- = interior_rings(destination);
+ typename interior_return_type<Polygon1 const>::type
+ rings_source = interior_rings(source);
+ typename interior_return_type<Polygon2>::type
+ rings_dest = interior_rings(destination);
- BOOST_AUTO_TPL(it_source, boost::begin(rings_source));
- BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest));
+ typename detail::interior_iterator<Polygon1 const>::type
+ it_source = boost::begin(rings_source);
+ typename detail::interior_iterator<Polygon2>::type
+ it_dest = boost::begin(rings_dest);
for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
{
@@ -203,6 +227,37 @@ struct polygon_to_polygon
}
};
+template <typename Single, typename Multi, typename Policy>
+struct single_to_multi: private Policy
+{
+ static inline void apply(Single const& single, Multi& multi)
+ {
+ traits::resize<Multi>::apply(multi, 1);
+ Policy::apply(single, *boost::begin(multi));
+ }
+};
+
+
+
+template <typename Multi1, typename Multi2, typename Policy>
+struct multi_to_multi: private Policy
+{
+ static inline void apply(Multi1 const& multi1, Multi2& multi2)
+ {
+ traits::resize<Multi2>::apply(multi2, boost::size(multi1));
+
+ typename boost::range_iterator<Multi1 const>::type it1
+ = boost::begin(multi1);
+ typename boost::range_iterator<Multi2>::type it2
+ = boost::begin(multi2);
+
+ for (; it1 != boost::end(multi1); ++it1, ++it2)
+ {
+ Policy::apply(*it1, *it2);
+ }
+ }
+};
+
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
@@ -280,8 +335,8 @@ struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount,
template <typename Ring1, typename Ring2, std::size_t DimensionCount>
struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
: detail::conversion::range_to_range
- <
- Ring1,
+ <
+ Ring1,
Ring2,
geometry::point_order<Ring1>::value
!= geometry::point_order<Ring2>::value
@@ -302,8 +357,8 @@ template <typename Box, typename Ring>
struct convert<Box, Ring, box_tag, ring_tag, 2, false>
: detail::conversion::box_to_range
<
- Box,
- Ring,
+ Box,
+ Ring,
geometry::closure<Ring>::value == closed,
geometry::point_order<Ring>::value == counterclockwise
>
@@ -377,16 +432,108 @@ struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
};
+// Dispatch for multi <-> multi, specifying their single-version as policy.
+// Note that, even if the multi-types are mutually different, their single
+// version types might be the same and therefore we call boost::is_same again
+
+template <typename Multi1, typename Multi2, std::size_t DimensionCount>
+struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
+ : detail::conversion::multi_to_multi
+ <
+ Multi1,
+ Multi2,
+ convert
+ <
+ typename boost::range_value<Multi1>::type,
+ typename boost::range_value<Multi2>::type,
+ typename single_tag_of
+ <
+ typename tag<Multi1>::type
+ >::type,
+ typename single_tag_of
+ <
+ typename tag<Multi2>::type
+ >::type,
+ DimensionCount
+ >
+ >
+{};
+
+
+template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
+struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
+ : detail::conversion::single_to_multi
+ <
+ Single,
+ Multi,
+ convert
+ <
+ Single,
+ typename boost::range_value<Multi>::type,
+ typename tag<Single>::type,
+ typename single_tag_of
+ <
+ typename tag<Multi>::type
+ >::type,
+ DimensionCount,
+ false
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct convert
+{
+ static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
+ {
+ concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
+ dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: static_visitor<void>
+ {
+ Geometry2& m_geometry2;
+
+ visitor(Geometry2& geometry2)
+ : m_geometry2(geometry2)
+ {}
+
+ template <typename Geometry1>
+ inline void operator()(Geometry1 const& geometry1) const
+ {
+ convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
+ }
+ };
+
+ static inline void apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2& geometry2
+ )
+ {
+ apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+}
+
+
/*!
\brief Converts one geometry to another geometry
\details The convert algorithm converts one geometry, e.g. a BOX, to another
-geometry, e.g. a RING. This only if it is possible and applicable.
-If the point-order is different, or the closure is different between two
-geometry types, it will be converted correctly by explicitly reversing the
+geometry, e.g. a RING. This only works if it is possible and applicable.
+If the point-order is different, or the closure is different between two
+geometry types, it will be converted correctly by explicitly reversing the
points or closing or opening the polygon rings.
\ingroup convert
\tparam Geometry1 \tparam_geometry
@@ -399,13 +546,13 @@ points or closing or opening the polygon rings.
template <typename Geometry1, typename Geometry2>
inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
{
- concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
-
- dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
-
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
diff --git a/boost/geometry/algorithms/convex_hull.hpp b/boost/geometry/algorithms/convex_hull.hpp
index 56b87c8c15..09f4c5142d 100644
--- a/boost/geometry/algorithms/convex_hull.hpp
+++ b/boost/geometry/algorithms/convex_hull.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 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.
@@ -15,15 +20,20 @@
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP
#include <boost/array.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/strategies/concepts/convex_hull_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
@@ -40,45 +50,34 @@ namespace boost { namespace geometry
namespace detail { namespace convex_hull
{
-template
-<
- typename Geometry,
- order_selector Order,
- typename Strategy
->
+template <order_selector Order, closure_selector Closure>
struct hull_insert
{
// Member template function (to avoid inconvenient declaration
// of output-iterator-type, from hull_to_geometry)
- template <typename OutputIterator>
+ template <typename Geometry, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
typename Strategy::state_type state;
strategy.apply(geometry, state);
- strategy.result(state, out, Order == clockwise);
+ strategy.result(state, out, Order == clockwise, Closure != open);
return out;
}
};
-template
-<
- typename Geometry,
- typename Strategy
->
struct hull_to_geometry
{
- template <typename OutputGeometry>
+ template <typename Geometry, typename OutputGeometry, typename Strategy>
static inline void apply(Geometry const& geometry, OutputGeometry& out,
Strategy const& strategy)
{
hull_insert
<
- Geometry,
geometry::point_order<OutputGeometry>::value,
- Strategy
+ geometry::closure<OutputGeometry>::value
>::apply(geometry,
std::back_inserter(
// Handle linestring, ring and polygon the same:
@@ -89,18 +88,6 @@ struct hull_to_geometry
}
};
-
-// Helper metafunction for default strategy retrieval
-template <typename Geometry>
-struct default_strategy
- : strategy_convex_hull
- <
- Geometry,
- typename point_type<Geometry>::type
- >
-{};
-
-
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
@@ -113,21 +100,16 @@ namespace dispatch
template
<
typename Geometry,
- typename Strategy = typename detail::convex_hull::default_strategy<Geometry>::type,
typename Tag = typename tag<Geometry>::type
>
struct convex_hull
- : detail::convex_hull::hull_to_geometry<Geometry, Strategy>
+ : detail::convex_hull::hull_to_geometry
{};
-template
-<
- typename Box,
- typename Strategy
->
-struct convex_hull<Box, Strategy, box_tag>
+template <typename Box>
+struct convex_hull<Box, box_tag>
{
- template <typename OutputGeometry>
+ template <typename OutputGeometry, typename Strategy>
static inline void apply(Box const& box, OutputGeometry& out,
Strategy const& )
{
@@ -149,13 +131,9 @@ struct convex_hull<Box, Strategy, box_tag>
-template
-<
- order_selector Order,
- typename Geometry, typename Strategy
->
+template <order_selector Order, closure_selector Closure>
struct convex_hull_insert
- : detail::convex_hull::hull_insert<Geometry, Order, Strategy>
+ : detail::convex_hull::hull_insert<Order, Closure>
{};
@@ -163,29 +141,170 @@ struct convex_hull_insert
#endif // DOXYGEN_NO_DISPATCH
-template<typename Geometry, typename OutputGeometry, typename Strategy>
-inline void convex_hull(Geometry const& geometry,
- OutputGeometry& out, Strategy const& strategy)
+namespace resolve_strategy {
+
+struct convex_hull
{
- concept::check_concepts_and_equal_dimensions
- <
+ template <typename Geometry, typename OutputGeometry, typename Strategy>
+ static inline void apply(Geometry const& geometry,
+ OutputGeometry& out,
+ Strategy const& strategy)
+ {
+ BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
+ dispatch::convex_hull<Geometry>::apply(geometry, out, strategy);
+ }
+
+ template <typename Geometry, typename OutputGeometry>
+ static inline void apply(Geometry const& geometry,
+ OutputGeometry& out,
+ default_strategy)
+ {
+ typedef typename strategy_convex_hull<
+ Geometry,
+ typename point_type<Geometry>::type
+ >::type strategy_type;
+
+ apply(geometry, out, strategy_type());
+ }
+};
+
+struct convex_hull_insert
+{
+ template <typename Geometry, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Geometry const& geometry,
+ OutputIterator& out,
+ Strategy const& strategy)
+ {
+ BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
+
+ return dispatch::convex_hull_insert<
+ geometry::point_order<Geometry>::value,
+ geometry::closure<Geometry>::value
+ >::apply(geometry, out, strategy);
+ }
+
+ template <typename Geometry, typename OutputIterator>
+ static inline OutputIterator apply(Geometry const& geometry,
+ OutputIterator& out,
+ default_strategy)
+ {
+ typedef typename strategy_convex_hull<
+ Geometry,
+ typename point_type<Geometry>::type
+ >::type strategy_type;
+
+ return apply(geometry, out, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct convex_hull
+{
+ template <typename OutputGeometry, typename Strategy>
+ static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy)
+ {
+ concept::check_concepts_and_equal_dimensions<
const Geometry,
OutputGeometry
>();
- BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
+ resolve_strategy::convex_hull::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct convex_hull<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename OutputGeometry, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ OutputGeometry& m_out;
+ Strategy const& m_strategy;
+
+ visitor(OutputGeometry& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ convex_hull<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename OutputGeometry, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ OutputGeometry& out,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(visitor<OutputGeometry, Strategy>(out, strategy), geometry);
+ }
+};
+
+template <typename Geometry>
+struct convex_hull_insert
+{
+ template <typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy)
+ {
+ // Concept: output point type = point type of input geometry
+ concept::check<Geometry const>();
+ concept::check<typename point_type<Geometry>::type>();
+
+ return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename OutputIterator, typename Strategy>
+ struct visitor: boost::static_visitor<OutputIterator>
+ {
+ OutputIterator& m_out;
+ Strategy const& m_strategy;
+
+ visitor(OutputIterator& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+ template <typename Geometry>
+ OutputIterator operator()(Geometry const& geometry) const
+ {
+ return convex_hull_insert<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename OutputIterator, typename Strategy>
+ static inline OutputIterator
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ OutputIterator& out,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<OutputIterator, Strategy>(out, strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+template<typename Geometry, typename OutputGeometry, typename Strategy>
+inline void convex_hull(Geometry const& geometry,
+ OutputGeometry& out, Strategy const& strategy)
+{
if (geometry::num_points(geometry) == 0)
{
// Leave output empty
return;
}
- dispatch::convex_hull
- <
- Geometry,
- Strategy
- >::apply(geometry, out, strategy);
+ resolve_variant::convex_hull<Geometry>::apply(geometry, out, strategy);
}
@@ -193,8 +312,8 @@ inline void convex_hull(Geometry const& geometry,
\brief \brief_calc{convex hull}
\ingroup convex_hull
\details \details_calc{convex_hull,convex hull}.
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
+\tparam Geometry the input geometry type
+\tparam OutputGeometry the output geometry type
\param geometry \param_geometry, input geometry
\param hull \param_geometry \param_set{convex hull}
@@ -204,15 +323,7 @@ template<typename Geometry, typename OutputGeometry>
inline void convex_hull(Geometry const& geometry,
OutputGeometry& hull)
{
- concept::check_concepts_and_equal_dimensions
- <
- const Geometry,
- OutputGeometry
- >();
-
- typedef typename detail::convex_hull::default_strategy<Geometry>::type strategy_type;
-
- convex_hull(geometry, hull, strategy_type());
+ convex_hull(geometry, hull, default_strategy());
}
#ifndef DOXYGEN_NO_DETAIL
@@ -224,17 +335,8 @@ template<typename Geometry, typename OutputIterator, typename Strategy>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out, Strategy const& strategy)
{
- // Concept: output point type = point type of input geometry
- concept::check<Geometry const>();
- concept::check<typename point_type<Geometry>::type>();
-
- BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy<Strategy>) );
-
- return dispatch::convex_hull_insert
- <
- geometry::point_order<Geometry>::value,
- Geometry, Strategy
- >::apply(geometry, out, strategy);
+ return resolve_variant::convex_hull_insert<Geometry>
+ ::apply(geometry, out, strategy);
}
@@ -255,13 +357,7 @@ template<typename Geometry, typename OutputIterator>
inline OutputIterator convex_hull_insert(Geometry const& geometry,
OutputIterator out)
{
- // Concept: output point type = point type of input geometry
- concept::check<Geometry const>();
- concept::check<typename point_type<Geometry>::type>();
-
- typedef typename detail::convex_hull::default_strategy<Geometry>::type strategy_type;
-
- return convex_hull_insert(geometry, out, strategy_type());
+ return convex_hull_insert(geometry, out, default_strategy());
}
diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp
index 583e395f8e..3c61b2c0d2 100644
--- a/boost/geometry/algorithms/correct.hpp
+++ b/boost/geometry/algorithms/correct.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -21,25 +22,37 @@
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/mutable_range.hpp>
-#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
-
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace correct
{
@@ -119,10 +132,8 @@ struct correct_ring
typedef detail::area::ring_area
<
- Ring,
order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
- strategy_type
+ geometry::closure<Ring>::value
> ring_area_type;
@@ -139,7 +150,7 @@ struct correct_ring
{
geometry::append(r, *boost::begin(r));
}
- if (! disjoint && geometry::closure<Ring>::value != closed)
+ if (! disjoint && s != closed)
{
// Open it by removing last point
geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
@@ -172,9 +183,10 @@ struct correct_polygon
std::less<area_result_type>
>::apply(exterior_ring(poly));
- typename interior_return_type<Polygon>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
correct_ring
<
@@ -234,10 +246,69 @@ struct correct<Polygon, polygon_tag>
{};
+template <typename MultiPoint>
+struct correct<MultiPoint, multi_point_tag>
+ : detail::correct::correct_nop<MultiPoint>
+{};
+
+
+template <typename MultiLineString>
+struct correct<MultiLineString, multi_linestring_tag>
+ : detail::correct::correct_nop<MultiLineString>
+{};
+
+
+template <typename Geometry>
+struct correct<Geometry, multi_polygon_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::correct::correct_polygon
+ <
+ typename boost::range_value<Geometry>::type
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct correct
+{
+ static inline void apply(Geometry& geometry)
+ {
+ concept::check<Geometry const>();
+ dispatch::correct<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ correct<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
@@ -253,11 +324,12 @@ struct correct<Polygon, polygon_tag>
template <typename Geometry>
inline void correct(Geometry& geometry)
{
- concept::check<Geometry const>();
-
- dispatch::correct<Geometry>::apply(geometry);
+ resolve_variant::correct<Geometry>::apply(geometry);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp
index c3c406c4ca..e50dc338af 100644
--- a/boost/geometry/algorithms/covered_by.hpp
+++ b/boost/geometry/algorithms/covered_by.hpp
@@ -4,6 +4,9 @@
// 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.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,21 +14,52 @@
// 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_COVERED_BY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
#include <cstddef>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_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*/)
+ {
+ return Strategy::apply(geometry1, geometry2);
+ }
+};
+
+}} // namespace detail::covered_by
+#endif // DOXYGEN_NO_DETAIL
+
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -37,7 +71,8 @@ template
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
-struct covered_by: not_implemented<Tag1, Tag2>
+struct covered_by
+ : not_implemented<Tag1, Tag2>
{};
@@ -47,6 +82,7 @@ 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);
}
};
@@ -58,48 +94,332 @@ struct covered_by<Box1, Box2, box_tag, box_tag>
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 Strategy>
- static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy)
+ 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_ring
+ concept::within::check
<
- Point,
- Ring,
- order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
- >::apply(point, ring, strategy) >= 0;
+ >();
+ concept::check<Geometry1 const>();
+ concept::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 point_type<Geometry1>::type point_type1;
+ typedef typename point_type<Geometry2>::type point_type2;
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag<Geometry1>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return covered_by::apply(geometry1, geometry2, strategy_type());
}
};
-template <typename Point, typename Polygon>
-struct covered_by<Point, Polygon, point_tag, polygon_tag>
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct covered_by
{
template <typename Strategy>
- static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy)
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
{
- return detail::within::point_in_polygon
- <
- Point,
- Polygon,
- order_as_direction<geometry::point_order<Polygon>::value>::value,
- geometry::closure<Polygon>::value,
- Strategy
- >::apply(point, polygon, strategy) >= 0;
+ return resolve_strategy::covered_by
+ ::apply(geometry1, geometry2, strategy);
}
};
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+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
/*!
@@ -120,36 +440,8 @@ struct covered_by<Point, Polygon, point_tag, polygon_tag>
template<typename Geometry1, typename Geometry2>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- typedef typename point_type<Geometry1>::type point_type1;
- typedef typename point_type<Geometry2>::type point_type2;
-
- typedef typename strategy::covered_by::services::default_strategy
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<Geometry1>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- typename tag_cast
- <
- typename cs_tag<point_type1>::type, spherical_tag
- >::type,
- typename tag_cast
- <
- typename cs_tag<point_type2>::type, spherical_tag
- >::type,
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return dispatch::covered_by
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy_type());
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, default_strategy());
}
/*!
@@ -172,22 +464,8 @@ template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
- concept::within::check
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- Strategy
- >();
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- return dispatch::covered_by
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy);
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/crosses.hpp b/boost/geometry/algorithms/crosses.hpp
new file mode 100644
index 0000000000..91ed3e0806
--- /dev/null
+++ b/boost/geometry/algorithms/crosses.hpp
@@ -0,0 +1,194 @@
+// 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.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
+
+#include <cstddef>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/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 crosses
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_crosses_type,
+ Geometry1,
+ Geometry2
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+ template <typename Geometry1, typename Geometry2>
+ struct crosses
+ {
+ static inline bool
+ apply(
+ const Geometry1& geometry1,
+ const Geometry2& geometry2)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+ };
+
+
+ template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+ struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+ {
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2)
+ : m_geometry2(geometry2)
+ {}
+
+ template <typename Geometry1>
+ result_type operator()(Geometry1 const& geometry1) const
+ {
+ return crosses
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, m_geometry2);
+ }
+ };
+
+ static inline bool
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return apply_visitor(visitor(geometry2), geometry1);
+ }
+ };
+
+
+ template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+ struct crosses<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+ {
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1)
+ : m_geometry1(geometry1)
+ {}
+
+ template <typename Geometry2>
+ result_type operator()(Geometry2 const& geometry2) const
+ {
+ return crosses
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (m_geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(
+ Geometry1 const& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2)
+ {
+ return apply_visitor(visitor(geometry1), geometry2);
+ }
+ };
+
+
+ template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
+ struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+ {
+ struct visitor: static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ result_type operator()(
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return crosses
+ <
+ Geometry1,
+ Geometry2
+ >::apply
+ (geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(
+ const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2)
+ {
+ return apply_visitor(visitor(), geometry1, geometry2);
+ }
+ };
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check2{crosses}
+\ingroup crosses
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{crosses}
+
+\qbk{[include reference/algorithms/crosses.qbk]}
+*/
+template <typename Geometry1, typename Geometry2>
+inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
diff --git a/boost/geometry/algorithms/detail/assign_box_corners.hpp b/boost/geometry/algorithms/detail/assign_box_corners.hpp
index 1fd41733f2..669d6d3655 100644
--- a/boost/geometry/algorithms/detail/assign_box_corners.hpp
+++ b/boost/geometry/algorithms/detail/assign_box_corners.hpp
@@ -19,14 +19,14 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
-
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
-namespace detail
+namespace detail
{
// Note: this is moved to namespace detail because the names and parameter orders
// are not yet 100% clear.
@@ -67,20 +67,34 @@ inline void assign_box_corners(Box const& box,
<max_corner, max_corner>(box, upper_right);
}
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
+
template <bool Reverse, typename Box, typename Range>
inline void assign_box_corners_oriented(Box const& box, Range& corners)
{
if (Reverse)
{
// make counterclockwise ll,lr,ur,ul
- assign_box_corners(box, corners[0], corners[1], corners[3], corners[2]);
+ assign_box_corners(box,
+ range::at(corners, 0), range::at(corners, 1),
+ range::at(corners, 3), range::at(corners, 2));
}
else
{
// make clockwise ll,ul,ur,lr
- assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]);
+ assign_box_corners(box,
+ range::at(corners, 0), range::at(corners, 3),
+ range::at(corners, 1), range::at(corners, 2));
}
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
} // namespace detail
diff --git a/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/boost/geometry/algorithms/detail/assign_indexed_point.hpp
index a1cffb80a7..acfc37e250 100644
--- a/boost/geometry/algorithms/detail/assign_indexed_point.hpp
+++ b/boost/geometry/algorithms/detail/assign_indexed_point.hpp
@@ -25,7 +25,7 @@ namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
-namespace detail
+namespace detail
{
/*!
diff --git a/boost/geometry/algorithms/detail/assign_values.hpp b/boost/geometry/algorithms/detail/assign_values.hpp
index ed4713493f..5e4a1795b5 100644
--- a/boost/geometry/algorithms/detail/assign_values.hpp
+++ b/boost/geometry/algorithms/detail/assign_values.hpp
@@ -46,36 +46,30 @@ namespace detail { namespace assign
{
-template
-<
- typename Box, std::size_t Index,
- std::size_t Dimension, std::size_t DimensionCount
->
+template <std::size_t Index, std::size_t Dimension, std::size_t DimensionCount>
struct initialize
{
- typedef typename coordinate_type<Box>::type coordinate_type;
-
- static inline void apply(Box& box, coordinate_type const& value)
+ template <typename Box>
+ static inline void apply(Box& box, typename coordinate_type<Box>::type const& value)
{
geometry::set<Index, Dimension>(box, value);
- initialize<Box, Index, Dimension + 1, DimensionCount>::apply(box, value);
+ initialize<Index, Dimension + 1, DimensionCount>::apply(box, value);
}
};
-template <typename Box, std::size_t Index, std::size_t DimensionCount>
-struct initialize<Box, Index, DimensionCount, DimensionCount>
+template <std::size_t Index, std::size_t DimensionCount>
+struct initialize<Index, DimensionCount, DimensionCount>
{
- typedef typename coordinate_type<Box>::type coordinate_type;
-
- static inline void apply(Box&, coordinate_type const& )
+ template <typename Box>
+ static inline void apply(Box&, typename coordinate_type<Box>::type const&)
{}
};
-template <typename Point>
struct assign_zero_point
{
+ template <typename Point>
static inline void apply(Point& point)
{
geometry::assign_value(point, 0);
@@ -83,44 +77,38 @@ struct assign_zero_point
};
-template <typename BoxOrSegment>
struct assign_inverse_box_or_segment
{
- typedef typename point_type<BoxOrSegment>::type point_type;
+ template <typename BoxOrSegment>
static inline void apply(BoxOrSegment& geometry)
{
+ typedef typename point_type<BoxOrSegment>::type point_type;
typedef typename coordinate_type<point_type>::type bound_type;
- initialize
- <
- BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
- >::apply(
- geometry, boost::numeric::bounds<bound_type>::highest());
- initialize
- <
- BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
- >::apply(
- geometry, boost::numeric::bounds<bound_type>::lowest());
+ initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, boost::numeric::bounds<bound_type>::highest()
+ );
+ initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, boost::numeric::bounds<bound_type>::lowest()
+ );
}
};
-template <typename BoxOrSegment>
struct assign_zero_box_or_segment
{
+ template <typename BoxOrSegment>
static inline void apply(BoxOrSegment& geometry)
{
typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
- initialize
- <
- BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
- >::apply(geometry, coordinate_type());
- initialize
- <
- BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
- >::apply(geometry, coordinate_type());
+ initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, coordinate_type()
+ );
+ initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply(
+ geometry, coordinate_type()
+ );
}
};
@@ -312,17 +300,17 @@ struct assign_zero {};
template <typename Point>
struct assign_zero<point_tag, Point>
- : detail::assign::assign_zero_point<Point>
+ : detail::assign::assign_zero_point
{};
template <typename Box>
struct assign_zero<box_tag, Box>
- : detail::assign::assign_zero_box_or_segment<Box>
+ : detail::assign::assign_zero_box_or_segment
{};
template <typename Segment>
struct assign_zero<segment_tag, Segment>
- : detail::assign::assign_zero_box_or_segment<Segment>
+ : detail::assign::assign_zero_box_or_segment
{};
@@ -331,112 +319,18 @@ struct assign_inverse {};
template <typename Box>
struct assign_inverse<box_tag, Box>
- : detail::assign::assign_inverse_box_or_segment<Box>
+ : detail::assign::assign_inverse_box_or_segment
{};
template <typename Segment>
struct assign_inverse<segment_tag, Segment>
- : detail::assign::assign_inverse_box_or_segment<Segment>
+ : detail::assign::assign_inverse_box_or_segment
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
-
-/*!
-\brief Assign two coordinates to a geometry (usually a 2D point)
-\ingroup assign
-\tparam Geometry \tparam_geometry
-\tparam Type \tparam_numeric to specify the coordinates
-\param geometry \param_geometry
-\param c1 \param_x
-\param c2 \param_y
-
-\qbk{distinguish, 2 coordinate values}
-\qbk{
-[heading Example]
-[assign_2d_point] [assign_2d_point_output]
-
-[heading See also]
-\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
-}
- */
-template <typename Geometry, typename Type>
-inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
-{
- concept::check<Geometry>();
-
- dispatch::assign
- <
- typename tag<Geometry>::type,
- Geometry,
- geometry::dimension<Geometry>::type::value
- >::apply(geometry, c1, c2);
-}
-
-/*!
-\brief Assign three values to a geometry (usually a 3D point)
-\ingroup assign
-\tparam Geometry \tparam_geometry
-\tparam Type \tparam_numeric to specify the coordinates
-\param geometry \param_geometry
-\param c1 \param_x
-\param c2 \param_y
-\param c3 \param_z
-
-\qbk{distinguish, 3 coordinate values}
-\qbk{
-[heading Example]
-[assign_3d_point] [assign_3d_point_output]
-
-[heading See also]
-\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
-}
- */
-template <typename Geometry, typename Type>
-inline void assign_values(Geometry& geometry,
- Type const& c1, Type const& c2, Type const& c3)
-{
- concept::check<Geometry>();
-
- dispatch::assign
- <
- typename tag<Geometry>::type,
- Geometry,
- geometry::dimension<Geometry>::type::value
- >::apply(geometry, c1, c2, c3);
-}
-
-/*!
-\brief Assign four values to a geometry (usually a box or segment)
-\ingroup assign
-\tparam Geometry \tparam_geometry
-\tparam Type \tparam_numeric to specify the coordinates
-\param geometry \param_geometry
-\param c1 First coordinate (usually x1)
-\param c2 Second coordinate (usually y1)
-\param c3 Third coordinate (usually x2)
-\param c4 Fourth coordinate (usually y2)
-
-\qbk{distinguish, 4 coordinate values}
- */
-template <typename Geometry, typename Type>
-inline void assign_values(Geometry& geometry,
- Type const& c1, Type const& c2, Type const& c3, Type const& c4)
-{
- concept::check<Geometry>();
-
- dispatch::assign
- <
- typename tag<Geometry>::type,
- Geometry,
- geometry::dimension<Geometry>::type::value
- >::apply(geometry, c1, c2, c3, c4);
-}
-
-
-
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
new file mode 100644
index 0000000000..c959ee849b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -0,0 +1,940 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_BUFFER_INSERTER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
+
+#include <cstddef>
+#include <iterator>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
+#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
+#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
+
+#include <boost/geometry/algorithms/simplify.hpp>
+
+#include <boost/geometry/views/detail/normalized_view.hpp>
+
+#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
+#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template <typename Range, typename DistanceStrategy>
+inline void simplify_input(Range const& range,
+ DistanceStrategy const& distance,
+ Range& simplified)
+{
+ // We have to simplify the ring before to avoid very small-scaled
+ // features in the original (convex/concave/convex) being enlarged
+ // in a very large scale and causing issues (IP's within pieces).
+ // This might be reconsidered later. Simplifying with a very small
+ // distance (1%% of the buffer) will never be visible in the result,
+ // if it is using round joins. For miter joins they are even more
+ // sensitive to small scale input features, however the result will
+ // look better.
+ // It also gets rid of duplicate points
+#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
+ geometry::simplify(range, simplified, distance.simplify_distance());
+#else
+
+ typedef typename boost::range_value<Range>::type point_type;
+ typedef strategy::distance::detail::projected_point_ax<> ax_type;
+ typedef typename strategy::distance::services::return_type
+ <
+ strategy::distance::detail::projected_point_ax<>,
+ point_type,
+ point_type
+ >::type return_type;
+
+ typedef strategy::distance::detail::projected_point_ax_less
+ <
+ return_type
+ > comparator_type;
+
+ typedef strategy::simplify::detail::douglas_peucker
+ <
+ point_type,
+ strategy::distance::detail::projected_point_ax<>,
+ comparator_type
+ > dp_ax;
+
+ return_type max_distance(distance.simplify_distance() * 2.0,
+ distance.simplify_distance());
+ comparator_type comparator(max_distance);
+ dp_ax strategy(comparator);
+
+ geometry::simplify(range, simplified, max_distance, strategy);
+#endif
+
+ if (boost::size(simplified) == 2
+ && geometry::equals(geometry::range::front(simplified),
+ geometry::range::back(simplified)))
+ {
+ traits::resize<Range>::apply(simplified, 1);
+ }
+}
+
+
+template <typename RingOutput>
+struct buffer_range
+{
+ typedef typename point_type<RingOutput>::type output_point_type;
+ typedef typename coordinate_type<RingOutput>::type coordinate_type;
+
+ template
+ <
+ typename Collection,
+ typename Point,
+ typename DistanceStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline
+ void add_join(Collection& collection,
+ Point const& penultimate_input,
+ Point const& previous_input,
+ output_point_type const& prev_perp1,
+ output_point_type const& prev_perp2,
+ Point const& input,
+ output_point_type const& perp1,
+ output_point_type const& perp2,
+ strategy::buffer::buffer_side_selector side,
+ DistanceStrategy const& distance,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ RobustPolicy const& )
+ {
+ output_point_type intersection_point;
+
+ strategy::buffer::join_selector join
+ = get_join_type(penultimate_input, previous_input, input);
+ if (join == 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
+ // or spikey, we then change the join-type
+ join = line_line_intersection::apply(
+ perp1, perp2, prev_perp1, prev_perp2,
+ intersection_point);
+
+ }
+ switch(join)
+ {
+ case strategy::buffer::join_continue :
+ // No join, we get two consecutive sides
+ return;
+ case strategy::buffer::join_concave :
+ collection.add_piece(strategy::buffer::buffered_concave,
+ previous_input, prev_perp2, perp1);
+ return;
+ case strategy::buffer::join_spike :
+ {
+ // For linestrings, only add spike at one side to avoid
+ // duplicates
+ std::vector<output_point_type> range_out;
+ end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out);
+ collection.add_endcap(end_strategy, range_out, previous_input);
+ }
+ return;
+ case strategy::buffer::join_convex :
+ break; // All code below handles this
+ }
+
+ // The corner is convex, we create a join
+ // TODO (future) - avoid a separate vector, add the piece directly
+ std::vector<output_point_type> range_out;
+ if (join_strategy.apply(intersection_point,
+ previous_input, prev_perp2, perp1,
+ distance.apply(previous_input, input, side),
+ range_out))
+ {
+ collection.add_piece(strategy::buffer::buffered_join,
+ previous_input, range_out);
+ }
+ }
+
+ static inline strategy::buffer::join_selector get_join_type(
+ output_point_type const& p0,
+ output_point_type const& p1,
+ output_point_type const& p2)
+ {
+ 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
+ : 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;
+ }
+
+ template
+ <
+ typename Collection,
+ typename Iterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline bool iterate(Collection& collection,
+ Iterator begin, Iterator end,
+ 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,
+ output_point_type& first_p1,
+ output_point_type& first_p2,
+ output_point_type& last_p1,
+ output_point_type& last_p2)
+ {
+ typedef typename std::iterator_traits
+ <
+ Iterator
+ >::value_type point_type;
+
+ typedef typename robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type previous_robust_input;
+ point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
+
+ /*
+ * last.p1 last.p2 these are the "previous (last) perpendicular points"
+ * --------------
+ * | |
+ * *------------*____ <- *prev
+ * pup | | p1 "current perpendicular point 1"
+ * | |
+ * | | this forms a "side", a side is a piece
+ * | |
+ * *____| p2
+ *
+ * ^
+ * *it
+ *
+ * pup: penultimate_point
+ */
+
+ bool result = false;
+ bool first = true;
+
+ Iterator it = begin;
+
+ geometry::recalculate(previous_robust_input, *begin, robust_policy);
+
+ std::vector<output_point_type> generated_side;
+ generated_side.reserve(2);
+
+ for (Iterator prev = it++; it != end; ++it)
+ {
+ robust_point_type robust_input;
+ geometry::recalculate(robust_input, *it, robust_policy);
+ // Check on equality - however, if input is simplified, this is
+ // unlikely (though possible by rescaling or for degenerated pointlike polygons)
+ if (! detail::equals::equals_point_point(previous_robust_input, robust_input))
+ {
+ generated_side.clear();
+ side_strategy.apply(*prev, *it, side,
+ distance_strategy, generated_side);
+
+ if (generated_side.empty())
+ {
+ break;
+ }
+
+ result = true;
+
+ if (! first)
+ {
+ add_join(collection,
+ penultimate_point,
+ *prev, last_p1, last_p2,
+ *it, generated_side.front(), generated_side.back(),
+ side,
+ distance_strategy, join_strategy, end_strategy,
+ robust_policy);
+ }
+
+ collection.add_side_piece(*prev, *it, generated_side, first);
+
+ penultimate_point = *prev;
+ ultimate_point = *it;
+ last_p1 = generated_side.front();
+ last_p2 = generated_side.back();
+ prev = it;
+ if (first)
+ {
+ first = false;
+ second_point = *it;
+ first_p1 = generated_side.front();
+ first_p2 = generated_side.back();
+ }
+ }
+ previous_robust_input = robust_input;
+ }
+ return result;
+ }
+};
+
+template
+<
+ typename Multi,
+ typename PolygonOutput,
+ typename Policy
+>
+struct buffer_multi
+{
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(Multi const& multi,
+ Collection& collection,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+ {
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, collection,
+ distance_strategy, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ }
+ }
+};
+
+struct visit_pieces_default_policy
+{
+ template <typename Collection>
+ static inline void apply(Collection const&, int)
+ {}
+};
+
+template
+<
+ typename OutputPointType,
+ typename Point,
+ typename Collection,
+ typename DistanceStrategy,
+ typename PointStrategy
+>
+inline void buffer_point(Point const& point, Collection& collection,
+ DistanceStrategy const& distance_strategy,
+ PointStrategy const& point_strategy)
+{
+ 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.finish_ring();
+}
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Tag,
+ typename RingInput,
+ typename RingOutput
+>
+struct buffer_inserter
+{};
+
+
+
+template
+<
+ typename Point,
+ typename RingOutput
+>
+struct buffer_inserter<point_tag, Point, RingOutput>
+{
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(Point const& point, Collection& collection,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& ,
+ JoinStrategy const& ,
+ EndStrategy const& ,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& )
+ {
+ detail::buffer::buffer_point
+ <
+ typename point_type<RingOutput>::type
+ >(point, collection, distance_strategy, point_strategy);
+ }
+};
+
+
+template
+<
+ typename RingInput,
+ typename RingOutput
+>
+struct buffer_inserter<ring_tag, RingInput, RingOutput>
+{
+ typedef typename point_type<RingOutput>::type output_point_type;
+
+ template
+ <
+ typename Collection,
+ typename Iterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline bool iterate(Collection& collection,
+ Iterator begin, Iterator end,
+ 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)
+ {
+ output_point_type first_p1, first_p2, last_p1, last_p2;
+
+ typedef detail::buffer::buffer_range<RingOutput> buffer_range;
+
+ bool result = buffer_range::iterate(collection, begin, end,
+ side,
+ distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1, first_p2, last_p1, last_p2);
+
+ // Generate closing join
+ if (result)
+ {
+ buffer_range::add_join(collection,
+ *(end - 2),
+ *(end - 1), last_p1, last_p2,
+ *(begin + 1), first_p1, first_p2,
+ side,
+ distance_strategy, join_strategy, end_strategy,
+ robust_policy);
+ }
+
+ // Buffer is closed automatically by last closing corner
+ return result;
+ }
+
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void 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)
+ {
+ RingInput simplified;
+ detail::buffer::simplify_input(ring, distance, simplified);
+
+ bool has_output = false;
+
+ std::size_t n = boost::size(simplified);
+ std::size_t const min_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<RingInput>::value
+ >::value;
+
+ if (n >= min_points)
+ {
+ detail::normalized_view<RingInput const> view(simplified);
+ if (distance.negative())
+ {
+ // Walk backwards (rings will be reversed afterwards)
+ // It might be that this will be changed later.
+ // TODO: decide this.
+ has_output = iterate(collection, boost::rbegin(view), boost::rend(view),
+ strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ }
+ else
+ {
+ has_output = iterate(collection, boost::begin(view), boost::end(view),
+ strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ }
+ }
+
+ if (! has_output && n >= 1)
+ {
+ // Use point_strategy to buffer degenerated ring
+ detail::buffer::buffer_point<output_point_type>
+ (
+ geometry::range::front(simplified),
+ collection, distance, point_strategy
+ );
+ }
+ }
+};
+
+
+template
+<
+ typename Linestring,
+ typename Polygon
+>
+struct buffer_inserter<linestring_tag, Linestring, Polygon>
+{
+ typedef typename ring_type<Polygon>::type output_ring_type;
+ typedef typename point_type<output_ring_type>::type output_point_type;
+ typedef typename point_type<Linestring>::type input_point_type;
+
+ template
+ <
+ typename Collection,
+ typename Iterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename RobustPolicy
+ >
+ static inline bool iterate(Collection& collection,
+ Iterator begin, Iterator end,
+ 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,
+ output_point_type& first_p1)
+ {
+ input_point_type const& ultimate_point = *(end - 1);
+ input_point_type const& penultimate_point = *(end - 2);
+
+ // For the end-cap, we need to have the last perpendicular point on the
+ // other side of the linestring. If it is the second pass (right),
+ // 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)
+ {
+ reverse_p1 = first_p1;
+ }
+ else
+ {
+ std::vector<output_point_type> generated_side;
+ side_strategy.apply(ultimate_point, penultimate_point,
+ strategy::buffer::buffer_side_right,
+ distance_strategy, generated_side);
+ if (generated_side.empty())
+ {
+ return false;
+ }
+ reverse_p1 = generated_side.front();
+ }
+
+ output_point_type first_p2, last_p1, last_p2;
+
+ detail::buffer::buffer_range<output_ring_type>::iterate(collection,
+ begin, end, side,
+ distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1, first_p2, last_p1, last_p2);
+
+ std::vector<output_point_type> 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 true;
+ }
+
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void 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)
+ {
+ Linestring simplified;
+ detail::buffer::simplify_input(linestring, distance, simplified);
+
+ bool has_output = false;
+ std::size_t n = boost::size(simplified);
+ if (n > 1)
+ {
+ collection.start_new_ring();
+ output_point_type first_p1;
+ has_output = iterate(collection,
+ boost::begin(simplified), boost::end(simplified),
+ strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1);
+
+ if (has_output)
+ {
+ iterate(collection, boost::rbegin(simplified), boost::rend(simplified),
+ strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ first_p1);
+ }
+ collection.finish_ring();
+ }
+ if (! has_output && n >= 1)
+ {
+ // Use point_strategy to buffer degenerated linestring
+ detail::buffer::buffer_point<output_point_type>
+ (
+ geometry::range::front(simplified),
+ collection, distance, point_strategy
+ );
+ }
+ }
+};
+
+
+template
+<
+ typename PolygonInput,
+ typename PolygonOutput
+>
+struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
+{
+private:
+ typedef typename ring_type<PolygonInput>::type input_ring_type;
+ typedef typename ring_type<PolygonOutput>::type output_ring_type;
+
+ typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy;
+
+
+ template
+ <
+ typename Iterator,
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline
+ void iterate(Iterator begin, Iterator end,
+ 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,
+ bool is_interior)
+ {
+ for (Iterator it = begin; it != end; ++it)
+ {
+ collection.start_new_ring();
+ policy::apply(*it, collection, distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ collection.finish_ring(is_interior);
+ }
+ }
+
+ template
+ <
+ typename InteriorRings,
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline
+ void apply_interior_rings(InteriorRings const& interior_rings,
+ 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)
+ {
+ iterate(boost::begin(interior_rings), boost::end(interior_rings),
+ collection, distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy, true);
+ }
+
+public:
+ template
+ <
+ typename Collection,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+ >
+ static inline void apply(PolygonInput const& polygon,
+ 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)
+ {
+ {
+ collection.start_new_ring();
+ policy::apply(exterior_ring(polygon), collection,
+ distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ collection.finish_ring();
+ }
+
+ apply_interior_rings(interior_rings(polygon),
+ collection, distance, side_strategy,
+ join_strategy, end_strategy, point_strategy,
+ robust_policy);
+ }
+};
+
+
+template
+<
+ typename Multi,
+ typename PolygonOutput
+>
+struct buffer_inserter<multi_tag, Multi, PolygonOutput>
+ : public detail::buffer::buffer_multi
+ <
+ Multi,
+ PolygonOutput,
+ dispatch::buffer_inserter
+ <
+ typename single_tag_of
+ <
+ typename tag<Multi>::type
+ >::type,
+ typename boost::range_value<Multi const>::type,
+ typename geometry::ring_type<PolygonOutput>::type
+ >
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template
+<
+ typename GeometryOutput,
+ typename GeometryInput,
+ typename OutputIterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy,
+ typename VisitPiecesPolicy
+>
+inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy,
+ VisitPiecesPolicy& visit_pieces_policy
+ )
+{
+ typedef detail::buffer::buffered_piece_collection
+ <
+ typename geometry::ring_type<GeometryOutput>::type,
+ RobustPolicy
+ > collection_type;
+ collection_type collection(robust_policy);
+ collection_type const& const_collection = collection;
+
+ bool const areal = boost::is_same
+ <
+ typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
+ areal_tag
+ >::type::value;
+
+ dispatch::buffer_inserter
+ <
+ typename tag_cast
+ <
+ typename tag<GeometryInput>::type,
+ multi_tag
+ >::type,
+ GeometryInput,
+ GeometryOutput
+ >::apply(geometry_input, collection,
+ distance_strategy, side_strategy, join_strategy,
+ end_strategy, point_strategy,
+ robust_policy);
+
+ collection.get_turns();
+ if (areal)
+ {
+ collection.check_remaining_points(distance_strategy.factor());
+ }
+
+ // Visit the piece collection. This does nothing (by default), but
+ // optionally a debugging tool can be attached (e.g. console or svg),
+ // or the piece collection can be unit-tested
+ // phase 0: turns (before discarded)
+ visit_pieces_policy.apply(const_collection, 0);
+
+ collection.discard_rings();
+ collection.block_turns();
+ collection.enrich();
+ collection.traverse();
+
+ // Reverse all offsetted rings / traversed rings if:
+ // - they were generated on the negative side (deflate) of polygons
+ // - the output is counter clockwise
+ // and avoid reversing twice
+ bool reverse = distance_strategy.negative() && areal;
+ if (geometry::point_order<GeometryOutput>::value == counterclockwise)
+ {
+ reverse = ! reverse;
+ }
+ if (reverse)
+ {
+ collection.reverse();
+ }
+
+ collection.template assign<GeometryOutput>(out);
+
+ // Visit collection again
+ // phase 1: rings (after discarding and traversing)
+ visit_pieces_policy.apply(const_collection, 1);
+}
+
+template
+<
+ typename GeometryOutput,
+ typename GeometryInput,
+ typename OutputIterator,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename PointStrategy,
+ typename RobustPolicy
+>
+inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ PointStrategy const& point_strategy,
+ RobustPolicy const& robust_policy)
+{
+ detail::buffer::visit_pieces_default_policy visitor;
+ buffer_inserter<GeometryOutput>(geometry_input, out,
+ distance_strategy, side_strategy, join_strategy,
+ end_strategy, point_strategy,
+ robust_policy, visitor);
+}
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace detail::buffer
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
new file mode 100644
index 0000000000..6a2e6b32c5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
@@ -0,0 +1,171 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_BUFFER_POLICIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+enum intersection_location_type
+{
+ location_ok, inside_buffer, inside_original
+};
+
+class backtrack_for_buffer
+{
+public :
+ typedef detail::overlay::backtrack_state state_type;
+
+ template <typename Operation, typename Rings, typename Turns, typename Geometry, typename RobustPolicy>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, typename boost::range_value<Rings>::type& ring,
+ Turns& turns, Operation& operation,
+ std::string const& /*reason*/,
+ Geometry const& ,
+ Geometry const& ,
+ RobustPolicy const& ,
+ state_type& state
+ )
+ {
+#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS)
+extern int g_backtrack_warning_count;
+g_backtrack_warning_count++;
+#endif
+//std::cout << "!";
+//std::cout << "WARNING " << reason << std::endl;
+
+ state.m_good = false;
+
+ // Make bad output clean
+ rings.resize(size_at_start);
+ ring.clear();
+
+ // Reject this as a starting point
+ operation.visited.set_rejected();
+
+ // And clear all visit info
+ clear_visit_info(turns);
+ }
+};
+
+// Should follow traversal-turn-concept (enrichment, visit structure)
+// and adds index in piece vector to find it back
+template <typename Point, typename SegmentRatio>
+struct buffer_turn_operation
+ : public detail::overlay::traversal_turn_operation<Point, SegmentRatio>
+{
+ int piece_index;
+ int index_in_robust_ring;
+
+ inline buffer_turn_operation()
+ : piece_index(-1)
+ , index_in_robust_ring(-1)
+ {}
+};
+
+// Version for buffer including type of location, is_opposite, and helper variables
+template <typename Point, typename RobustPoint, typename SegmentRatio>
+struct buffer_turn_info
+ : public detail::overlay::turn_info
+ <
+ Point,
+ SegmentRatio,
+ buffer_turn_operation<Point, SegmentRatio>
+ >
+{
+ typedef Point point_type;
+ typedef RobustPoint robust_point_type;
+
+ int turn_index; // TODO: this might go if partition can operate on non-const input
+
+ RobustPoint robust_point;
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // Will (most probably) be removed later
+ RobustPoint mapped_robust_point; // alas... we still need to adapt our points, offsetting them 1 integer to be co-located with neighbours
+#endif
+
+
+ inline RobustPoint const& get_robust_point() const
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ return mapped_robust_point;
+#endif
+ return robust_point;
+ }
+
+
+ intersection_location_type location;
+
+ int count_within;
+ int count_on_offsetted;
+ int count_on_helper;
+ int count_within_near_offsetted;
+
+ bool remove_on_multi;
+
+ // Obsolete:
+ int count_on_occupied;
+ int count_on_multi;
+
+ inline buffer_turn_info()
+ : turn_index(-1)
+ , location(location_ok)
+ , count_within(0)
+ , count_on_offsetted(0)
+ , count_on_helper(0)
+ , count_within_near_offsetted(0)
+ , remove_on_multi(false)
+ , count_on_occupied(0)
+ , count_on_multi(0)
+ {}
+};
+
+struct buffer_operation_less
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.seg_id;
+ segment_identifier const& sr = right.seg_id;
+
+ // Sort them descending
+ return sl == sr
+ ? left.fraction < right.fraction
+ : sl < sr;
+ }
+};
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
new file mode 100644
index 0000000000..558a61fcb4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -0,0 +1,954 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
+
+#include <algorithm>
+#include <cstddef>
+#include <set>
+#include <boost/range.hpp>
+
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/geometries/ring.hpp>
+#include <boost/geometry/geometries/polygon.hpp>
+
+#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
+#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
+#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/occupation_info.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+enum segment_relation_code
+{
+ segment_relation_on_left,
+ segment_relation_on_right,
+ segment_relation_within,
+ segment_relation_disjoint
+};
+
+/*
+ * Terminology
+ *
+ * Suppose we make a buffer (using blocked corners) of this rectangle:
+ *
+ * +-------+
+ * | |
+ * | rect |
+ * | |
+ * +-------+
+ *
+ * For the sides we get these four buffered side-pieces (marked with s)
+ * and four buffered corner pieces (marked with c)
+ *
+ * c---+---s---+---c
+ * | | piece | | <- see below for details of the middle top-side-piece
+ * +---+-------+---+
+ * | | | |
+ * s | rect | s <- two side pieces left/right of rect
+ * | | | |
+ * +---+-------+---+
+ * | | piece | | <- one side-piece below, and two corner pieces
+ * c---+---s---+---c
+ *
+ * The outer part of the picture above, using all pieces,
+ * form together the offsetted ring (marked with o below)
+ * The 8 pieces are part of the piece collection and use for inside-checks
+ * The inner parts form (using 1 or 2 points per piece, often co-located)
+ * form together the robust_ring (marked with r below)
+ * The remaining piece-segments are helper-segments (marked with h)
+ *
+ * ooooooooooooooooo
+ * o h h o
+ * ohhhrrrrrrrrrhhho
+ * o r r o
+ * o r r o
+ * o r r o
+ * ohhhrrrrrrrrrhhho
+ * o h h o
+ * ooooooooooooooooo
+ *
+ */
+
+
+template <typename Ring, typename RobustPolicy>
+struct buffered_piece_collection
+{
+ typedef buffered_piece_collection<Ring, RobustPolicy> this_type;
+
+ typedef typename geometry::point_type<Ring>::type point_type;
+ typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
+ typedef typename geometry::robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // Robust ring/polygon type, always clockwise
+ typedef geometry::model::ring<robust_point_type> robust_ring_type;
+ typedef geometry::model::polygon<robust_point_type> robust_polygon_type;
+
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<point_type>::type
+ >::type side_strategy;
+
+ typedef typename geometry::rescale_policy_type
+ <
+ typename geometry::point_type<Ring>::type
+ >::type rescale_policy_type;
+
+ typedef typename geometry::segment_ratio_type
+ <
+ point_type,
+ RobustPolicy
+ >::type segment_ratio_type;
+
+ typedef buffer_turn_info
+ <
+ point_type,
+ robust_point_type,
+ segment_ratio_type
+ > buffer_turn_info_type;
+
+ typedef buffer_turn_operation
+ <
+ point_type,
+ segment_ratio_type
+ > buffer_turn_operation_type;
+
+ typedef std::vector<buffer_turn_info_type> turn_vector_type;
+
+ struct robust_turn
+ {
+ int turn_index;
+ int operation_index;
+ robust_point_type point;
+ segment_identifier seg_id;
+ segment_ratio_type fraction;
+ };
+
+ struct piece
+ {
+ strategy::buffer::piece_type type;
+ int index;
+
+ int left_index; // points to previous piece of same ring
+ int right_index; // points to next piece of same ring
+
+ // The next two members (1, 2) form together a complete clockwise ring
+ // for each piece (with one dupped point)
+ // The complete clockwise ring is also included as a robust ring (3)
+
+ // 1: half, part of offsetted_rings
+ segment_identifier first_seg_id;
+ int last_segment_index; // no segment-identifier - it is the same as first_seg_id
+ int offsetted_count; // part in robust_ring which is part of offsetted ring
+
+#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
+ // 2: half, not part of offsetted rings - part of robust ring
+ std::vector<point_type> helper_points; // 4 points for segment, 3 points for join - 0 points for flat-end
+#endif
+
+ // Robust representations
+ // 3: complete ring
+ robust_ring_type robust_ring;
+
+ geometry::model::box<robust_point_type> robust_envelope;
+
+ std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead
+ };
+
+ typedef std::vector<piece> piece_vector_type;
+
+ piece_vector_type m_pieces;
+ turn_vector_type m_turns;
+ int m_first_piece_index;
+
+ buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
+ buffered_ring_collection<robust_polygon_type> robust_polygons; // robust representation of the original(s)
+ robust_ring_type current_robust_ring;
+ buffered_ring_collection<Ring> traversed_rings;
+ segment_identifier current_segment_id;
+
+ RobustPolicy const& m_robust_policy;
+
+ struct redundant_turn
+ {
+ inline bool operator()(buffer_turn_info_type const& turn) const
+ {
+ return turn.remove_on_multi;
+ }
+ };
+
+ buffered_piece_collection(RobustPolicy const& robust_policy)
+ : m_first_piece_index(-1)
+ , m_robust_policy(robust_policy)
+ {}
+
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // Will (most probably) be removed later
+ template <typename OccupationMap>
+ inline void adapt_mapped_robust_point(OccupationMap const& map,
+ buffer_turn_info_type& turn, int distance) const
+ {
+ for (int x = -distance; x <= distance; x++)
+ {
+ for (int y = -distance; y <= distance; y++)
+ {
+ robust_point_type rp = turn.robust_point;
+ geometry::set<0>(rp, geometry::get<0>(rp) + x);
+ geometry::set<1>(rp, geometry::get<1>(rp) + y);
+ if (map.find(rp) != map.end())
+ {
+ turn.mapped_robust_point = rp;
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+ inline void get_occupation(
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ int distance = 0
+#endif
+ )
+ {
+ typedef occupation_info<angle_info<robust_point_type, coordinate_type> >
+ buffer_occupation_info;
+
+ typedef std::map
+ <
+ robust_point_type,
+ buffer_occupation_info,
+ geometry::less<robust_point_type>
+ > occupation_map_type;
+
+ occupation_map_type occupation_map;
+
+ // 1: Add all intersection points to occupation map
+ typedef typename boost::range_iterator<turn_vector_type>::type
+ iterator_type;
+
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ if (it->location == location_ok)
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ if (distance > 0 && ! occupation_map.empty())
+ {
+ adapt_mapped_robust_point(occupation_map, *it, distance);
+ }
+#endif
+ occupation_map[it->get_robust_point()].count++;
+ }
+ }
+
+ // Remove all points with one or more u/u points from the map
+ // (Alternatively, we could NOT do this here and change all u/u
+ // behaviour in overlay. Currently nothing is done: each polygon is
+ // just followed there. We could also always switch polygons there. For
+ // buffer behaviour, where 3 pieces might meet of which 2 (or more) form
+ // a u/u turn, this last option would have been better, probably).
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ if (it->both(detail::overlay::operation_union))
+ {
+ typename occupation_map_type::iterator mit =
+ occupation_map.find(it->get_robust_point());
+
+ if (mit != occupation_map.end())
+ {
+ occupation_map.erase(mit);
+ }
+ }
+ }
+
+ // 2: Remove all points from map which has only one
+ typename occupation_map_type::iterator it = occupation_map.begin();
+ while (it != occupation_map.end())
+ {
+ if (it->second.count <= 1)
+ {
+ typename occupation_map_type::iterator to_erase = it;
+ ++it;
+ occupation_map.erase(to_erase);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ if (occupation_map.empty())
+ {
+ return;
+ }
+
+ // 3: Add vectors (incoming->intersection-point,
+ // intersection-point -> outgoing)
+ // for all (co-located) points still present in the map
+
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ typename occupation_map_type::iterator mit =
+ occupation_map.find(it->get_robust_point());
+
+ if (mit != occupation_map.end())
+ {
+ buffer_occupation_info& info = mit->second;
+ for (int i = 0; i < 2; i++)
+ {
+ add_incoming_and_outgoing_angles(it->get_robust_point(), *it,
+ m_pieces,
+ i, it->operations[i].seg_id,
+ info);
+ }
+
+ it->count_on_multi++;
+ }
+ }
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // X: Check rounding issues
+ if (distance == 0)
+ {
+ for (typename occupation_map_type::const_iterator it = occupation_map.begin();
+ it != occupation_map.end(); ++it)
+ {
+ if (it->second.has_rounding_issues(it->first))
+ {
+ if(distance == 0)
+ {
+ get_occupation(distance + 1);
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+ // Get left turns from all clusters
+ for (typename occupation_map_type::iterator it = occupation_map.begin();
+ it != occupation_map.end(); ++it)
+ {
+ it->second.get_left_turns(it->first, m_turns);
+ }
+ }
+
+ inline void classify_turns()
+ {
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->count_within > 0)
+ {
+ it->location = inside_buffer;
+ }
+ if (it->count_within_near_offsetted > 0)
+ {
+ // Within can have in rare cases a rounding issue. We don't discard this
+ // point, so it can be used to continue started rings in traversal. But
+ // will never start a new ring from this type of points.
+ it->selectable_start = false;
+ }
+
+ }
+ }
+
+ inline void check_remaining_points(int factor)
+ {
+ // TODO: use partition
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location == location_ok)
+ {
+ int code = -1;
+ for (std::size_t i = 0; i < robust_polygons.size(); i++)
+ {
+ if (geometry::covered_by(it->robust_point, robust_polygons[i]))
+ {
+ code = 1;
+ break;
+ }
+ }
+ if (code * factor == 1)
+ {
+ it->location = inside_original;
+ }
+ }
+ }
+ }
+
+ inline bool assert_indices_in_robust_rings() const
+ {
+ geometry::equal_to<robust_point_type> comparator;
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ robust_point_type const &p1
+ = m_pieces[it->operations[i].piece_index].robust_ring
+ [it->operations[i].index_in_robust_ring];
+ robust_point_type const &p2 = it->robust_point;
+ if (! comparator(p1, p2))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ inline void insert_rescaled_piece_turns()
+ {
+ // Add rescaled turn points to corresponding pieces
+ // (after this, each turn occurs twice)
+ int index = 0;
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
+ {
+ geometry::recalculate(it->robust_point, it->point, m_robust_policy);
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ it->mapped_robust_point = it->robust_point;
+#endif
+
+ robust_turn turn;
+ it->turn_index = index;
+ turn.turn_index = index;
+ turn.point = it->robust_point;
+ for (int i = 0; i < 2; i++)
+ {
+ turn.operation_index = i;
+ turn.seg_id = it->operations[i].seg_id;
+ turn.fraction = it->operations[i].fraction;
+
+ piece& pc = m_pieces[it->operations[i].piece_index];
+ pc.robust_turns.push_back(turn);
+
+ // Take into account for the box (intersection points should fall inside,
+ // but in theory they can be one off because of rounding
+ geometry::expand(pc.robust_envelope, it->robust_point);
+ }
+ }
+
+ // Insert all rescaled turn-points into these rings, to form a
+ // reliable integer-based ring. All turns can be compared (inside) to this
+ // rings to see if they are inside.
+
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ piece& pc = *it;
+ int piece_segment_index = pc.first_seg_id.segment_index;
+ if (! pc.robust_turns.empty())
+ {
+ if (pc.robust_turns.size() > 1u)
+ {
+ std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
+ }
+ // Walk through them, in reverse to insert at right index
+ int index_offset = pc.robust_turns.size() - 1;
+ for (typename std::vector<robust_turn>::const_reverse_iterator
+ rit = pc.robust_turns.rbegin();
+ rit != pc.robust_turns.rend();
+ ++rit, --index_offset)
+ {
+ int const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
+ BOOST_ASSERT
+ (
+ index_in_vector > 0 && index_in_vector < pc.offsetted_count
+ );
+
+ pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
+ pc.offsetted_count++;
+
+ m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
+ }
+ }
+ }
+
+ BOOST_ASSERT(assert_indices_in_robust_rings());
+ }
+
+ inline void get_turns()
+ {
+ {
+ // Calculate the turns
+ piece_turn_visitor
+ <
+ buffered_ring_collection<buffered_ring<Ring> >,
+ turn_vector_type,
+ RobustPolicy
+ > visitor(offsetted_rings, m_turns, m_robust_policy);
+
+ geometry::partition
+ <
+ model::box<robust_point_type>, piece_get_box, piece_ovelaps_box
+ >::apply(m_pieces, visitor);
+ }
+
+ insert_rescaled_piece_turns();
+
+ {
+ // Check if it is inside any of the pieces
+ turn_in_piece_visitor
+ <
+ turn_vector_type, piece_vector_type
+ > visitor(m_turns, m_pieces);
+
+ geometry::partition
+ <
+ model::box<robust_point_type>,
+ turn_get_box, turn_ovelaps_box,
+ piece_get_box, piece_ovelaps_box
+ >::apply(m_turns, m_pieces, visitor);
+
+ }
+
+ classify_turns();
+
+ //get_occupation();
+ }
+
+ inline void start_new_ring()
+ {
+ int const n = offsetted_rings.size();
+ current_segment_id.source_index = 0;
+ current_segment_id.multi_index = n;
+ current_segment_id.ring_index = -1;
+ current_segment_id.segment_index = 0;
+
+ offsetted_rings.resize(n + 1);
+ current_robust_ring.clear();
+
+ m_first_piece_index = boost::size(m_pieces);
+ }
+
+ inline void finish_ring(bool is_interior = false)
+ {
+ if (m_first_piece_index == -1)
+ {
+ return;
+ }
+
+ if (m_first_piece_index < static_cast<int>(boost::size(m_pieces)))
+ {
+ // If piece was added
+ // Reassign left-of-first and right-of-last
+ geometry::range::at(m_pieces, m_first_piece_index).left_index
+ = boost::size(m_pieces) - 1;
+ geometry::range::back(m_pieces).right_index = m_first_piece_index;
+ }
+ m_first_piece_index = -1;
+
+ if (!current_robust_ring.empty())
+ {
+ BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back()));
+
+ if (is_interior)
+ {
+ if (!robust_polygons.empty())
+ {
+ robust_polygons.back().inners().push_back(current_robust_ring);
+ }
+ }
+ else
+ {
+ robust_polygons.resize(robust_polygons.size() + 1);
+ robust_polygons.back().outer() = current_robust_ring;
+ }
+ }
+ }
+
+ inline int add_point(point_type const& p)
+ {
+ BOOST_ASSERT
+ (
+ boost::size(offsetted_rings) > 0
+ );
+
+ current_segment_id.segment_index++;
+ offsetted_rings.back().push_back(p);
+ return offsetted_rings.back().size();
+ }
+
+ //-------------------------------------------------------------------------
+
+ inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one)
+ {
+ piece pc;
+ pc.type = type;
+ pc.index = boost::size(m_pieces);
+ pc.first_seg_id = current_segment_id;
+
+ // Assign left/right (for first/last piece per ring they will be re-assigned later)
+ pc.left_index = pc.index - 1;
+ pc.right_index = pc.index + 1;
+
+ std::size_t const n = boost::size(offsetted_rings.back());
+ pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
+
+ m_pieces.push_back(pc);
+ return m_pieces.back();
+ }
+
+ inline void init_rescale_piece(piece& pc, std::size_t helper_points_size)
+ {
+ pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
+ BOOST_ASSERT(pc.offsetted_count >= 0);
+
+ pc.robust_ring.reserve(pc.offsetted_count + helper_points_size);
+
+ // Add rescaled offsetted segments
+ {
+ buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];
+
+ typedef typename boost::range_iterator<const buffered_ring<Ring> >::type it_type;
+ for (it_type it = boost::begin(ring) + pc.first_seg_id.segment_index;
+ it != boost::begin(ring) + pc.last_segment_index;
+ ++it)
+ {
+ robust_point_type point;
+ geometry::recalculate(point, *it, m_robust_policy);
+ pc.robust_ring.push_back(point);
+ }
+ }
+ }
+
+ inline robust_point_type add_helper_point(piece& pc, const point_type& point)
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
+ pc.helper_points.push_back(point);
+#endif
+
+ robust_point_type rob_point;
+ geometry::recalculate(rob_point, point, m_robust_policy);
+ pc.robust_ring.push_back(rob_point);
+ return rob_point;
+ }
+
+ inline void calculate_robust_envelope(piece& pc)
+ {
+ geometry::detail::envelope::envelope_range::apply(pc.robust_ring,
+ pc.robust_envelope);
+ }
+
+ inline void finish_piece(piece& pc)
+ {
+ init_rescale_piece(pc, 0u);
+ calculate_robust_envelope(pc);
+ }
+
+ inline void finish_piece(piece& pc,
+ const point_type& point1,
+ const point_type& point2,
+ const point_type& point3)
+ {
+ init_rescale_piece(pc, 3u);
+ add_helper_point(pc, point1);
+ robust_point_type mid_point = add_helper_point(pc, point2);
+ add_helper_point(pc, point3);
+ calculate_robust_envelope(pc);
+
+ current_robust_ring.push_back(mid_point);
+ }
+
+ inline void finish_piece(piece& pc,
+ const point_type& point1,
+ const point_type& point2,
+ const point_type& point3,
+ const point_type& point4)
+ {
+ init_rescale_piece(pc, 4u);
+ add_helper_point(pc, point1);
+ robust_point_type mid_point2 = add_helper_point(pc, point2);
+ robust_point_type mid_point1 = add_helper_point(pc, point3);
+ add_helper_point(pc, point4);
+ calculate_robust_envelope(pc);
+
+ // Add mid-points in other order to current helper_ring
+ current_robust_ring.push_back(mid_point1);
+ current_robust_ring.push_back(mid_point2);
+ }
+
+ inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
+ point_type const& b1, point_type const& b2)
+ {
+ piece& pc = create_piece(type, false);
+ add_point(b1);
+ pc.last_segment_index = add_point(b2);
+ finish_piece(pc, b2, p, b1);
+ }
+
+ template <typename Range>
+ inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
+ {
+ if (boost::size(range) == 0u)
+ {
+ return;
+ }
+
+ typename Range::const_iterator it = boost::begin(range);
+
+ // If it follows a non-join (so basically the same piece-type) point b1 should be added.
+ // There should be two intersections later and it should be discarded.
+ // But for now we need it to calculate intersections
+ if (add_front)
+ {
+ add_point(*it);
+ }
+
+ for (++it; it != boost::end(range); ++it)
+ {
+ pc.last_segment_index = add_point(*it);
+ }
+ }
+
+
+ template <typename Range>
+ inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one)
+ {
+ piece& pc = create_piece(type, decrease_segment_index_by_one);
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ finish_piece(pc);
+ }
+
+ template <typename Range>
+ inline void add_side_piece(point_type const& p1, point_type const& p2,
+ Range const& range, bool first)
+ {
+ BOOST_ASSERT(boost::size(range) >= 2u);
+
+ piece& pc = create_piece(strategy::buffer::buffered_segment, ! first);
+ add_range_to_piece(pc, range, first);
+ finish_piece(pc, range.back(), p2, p1, range.front());
+ }
+
+ template <typename Range>
+ inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range)
+ {
+ piece& pc = create_piece(type, true);
+
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ if (boost::size(range) > 0)
+ {
+ finish_piece(pc, range.back(), p, range.front());
+ }
+ else
+ {
+ finish_piece(pc);
+ }
+ }
+
+ template <typename EndcapStrategy, typename Range>
+ inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point)
+ {
+ if (range.empty())
+ {
+ return;
+ }
+ strategy::buffer::piece_type pt = strategy.get_piece_type();
+ if (pt == strategy::buffer::buffered_flat_end)
+ {
+ // It is flat, should just be added, without helper segments
+ add_piece(pt, range, true);
+ }
+ else
+ {
+ // Normal case, it has an "inside", helper segments should be added
+ add_piece(pt, end_point, range);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+
+ inline void enrich()
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Ring>::type
+ >::type side_strategy_type;
+
+ enrich_intersection_points<false, false>(m_turns,
+ detail::overlay::operation_union,
+ offsetted_rings, offsetted_rings,
+ m_robust_policy, side_strategy_type());
+ }
+
+ // Discards all rings which do have not-OK intersection points only.
+ // Those can never be traversed and should not be part of the output.
+ inline void discard_rings()
+ {
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location != location_ok)
+ {
+ offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true;
+ offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true;
+ }
+ else if (! it->both(detail::overlay::operation_union))
+ {
+ offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true;
+ offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true;
+ }
+ }
+ }
+
+ inline void block_turns()
+ {
+ // To fix left-turn issues like #rt_u13
+ // But currently it causes more other issues than it fixes
+// m_turns.erase
+// (
+// std::remove_if(boost::begin(m_turns), boost::end(m_turns),
+// redundant_turn()),
+// boost::end(m_turns)
+// );
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location != location_ok)
+ {
+ // Set it to blocked. They should not be discarded, to avoid
+ // generating rings over these turns
+ // Performance goes down a tiny bit from 161 s to 173 because there
+ // are sometimes much more turns.
+ // We might speed it up a bit by keeping only one blocked
+ // intersection per segment, but that is complex to program
+ // because each turn involves two segments
+ it->operations[0].operation = detail::overlay::operation_blocked;
+ it->operations[1].operation = detail::overlay::operation_blocked;
+ }
+ }
+ }
+
+ inline void traverse()
+ {
+ typedef detail::overlay::traverse
+ <
+ false, false,
+ buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >,
+ backtrack_for_buffer
+ > traverser;
+
+ traversed_rings.clear();
+ traverser::apply(offsetted_rings, offsetted_rings,
+ detail::overlay::operation_union,
+ m_robust_policy, m_turns, traversed_rings);
+ }
+
+ inline void reverse()
+ {
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it)
+ {
+ if (! it->has_intersections())
+ {
+ std::reverse(it->begin(), it->end());
+ }
+ }
+ for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type
+ it = boost::begin(traversed_rings);
+ it != boost::end(traversed_rings);
+ ++it)
+ {
+ std::reverse(it->begin(), it->end());
+ }
+
+ }
+
+ template <typename GeometryOutput, typename OutputIterator>
+ inline OutputIterator assign(OutputIterator out) const
+ {
+ typedef detail::overlay::ring_properties<point_type> properties;
+
+ std::map<ring_identifier, properties> selected;
+
+ // Select all rings which do not have any self-intersection (other ones should be traversed)
+ int index = 0;
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it, ++index)
+ {
+ if (! it->has_intersections())
+ {
+ ring_identifier id(0, index, -1);
+ selected[id] = properties(*it, true);
+ }
+ }
+
+ // Select all created rings
+ index = 0;
+ for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type
+ it = boost::begin(traversed_rings);
+ it != boost::end(traversed_rings);
+ ++it, ++index)
+ {
+ ring_identifier id(2, index, -1);
+ selected[id] = properties(*it, true);
+ }
+
+ detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
+ return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
+ }
+
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
new file mode 100644
index 0000000000..03ec598c90
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
@@ -0,0 +1,238 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_BUFFERED_RING
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/multi/algorithms/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+struct buffered_ring_collection_tag : polygonal_tag, multi_tag
+{};
+
+
+template <typename Ring>
+struct buffered_ring : public Ring
+{
+ bool has_accepted_intersections;
+ bool has_discarded_intersections;
+
+ inline buffered_ring()
+ : has_accepted_intersections(false)
+ , has_discarded_intersections(false)
+ {}
+
+ inline bool discarded() const
+ {
+ return has_discarded_intersections && ! has_accepted_intersections;
+ }
+ inline bool has_intersections() const
+ {
+ return has_discarded_intersections || has_accepted_intersections;
+ }
+};
+
+// This is a collection now special for overlay (needs vector of rings)
+template <typename Ring>
+struct buffered_ring_collection : public std::vector<Ring>
+{
+};
+
+}} // namespace detail::buffer
+
+
+// Turn off concept checking (for now)
+namespace dispatch
+{
+template <typename Geometry, bool IsConst>
+struct check<Geometry, detail::buffer::buffered_ring_collection_tag, IsConst>
+{
+};
+
+}
+
+
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+// Register the types
+namespace traits
+{
+
+
+template <typename Ring>
+struct tag<detail::buffer::buffered_ring<Ring> >
+{
+ typedef ring_tag type;
+};
+
+
+template <typename Ring>
+struct point_order<detail::buffer::buffered_ring<Ring> >
+{
+ static const order_selector value = geometry::point_order<Ring>::value;
+};
+
+
+template <typename Ring>
+struct closure<detail::buffer::buffered_ring<Ring> >
+{
+ static const closure_selector value = geometry::closure<Ring>::value;
+};
+
+
+template <typename Ring>
+struct point_type<detail::buffer::buffered_ring_collection<Ring> >
+{
+ typedef typename geometry::point_type<Ring>::type type;
+};
+
+template <typename Ring>
+struct tag<detail::buffer::buffered_ring_collection<Ring> >
+{
+ typedef detail::buffer::buffered_ring_collection_tag type;
+};
+
+
+} // namespace traits
+
+
+
+
+namespace core_dispatch
+{
+
+template <typename Ring>
+struct ring_type
+<
+ detail::buffer::buffered_ring_collection_tag,
+ detail::buffer::buffered_ring_collection<Ring>
+>
+{
+ typedef Ring type;
+};
+
+}
+
+namespace dispatch
+{
+
+template
+<
+ typename MultiRing,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ detail::buffer::buffered_ring_collection_tag,
+ MultiRing,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiRing,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_range
+ <
+ typename boost::range_value<MultiRing>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
+
+template<bool Reverse>
+struct copy_segments
+ <
+ detail::buffer::buffered_ring_collection_tag,
+ Reverse
+ >
+ : detail::copy_segments::copy_segments_multi
+ <
+ detail::copy_segments::copy_segments_ring<Reverse>
+ >
+{};
+
+template <typename Point, typename MultiGeometry>
+struct within
+<
+ Point,
+ MultiGeometry,
+ point_tag,
+ detail::buffer::buffered_ring_collection_tag
+>
+{
+ template <typename Strategy>
+ static inline bool apply(Point const& point,
+ MultiGeometry const& multi, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(point, multi, strategy) == 1;
+ }
+};
+
+
+} // namespace dispatch
+
+namespace detail { namespace overlay
+{
+
+template<>
+struct get_ring<detail::buffer::buffered_ring_collection_tag>
+{
+ template<typename MultiGeometry>
+ static inline typename ring_type<MultiGeometry>::type const& apply(
+ ring_identifier const& id,
+ MultiGeometry const& multi_ring)
+ {
+ BOOST_ASSERT
+ (
+ id.multi_index >= 0
+ && id.multi_index < int(boost::size(multi_ring))
+ );
+ return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]);
+ }
+};
+
+}}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
new file mode 100644
index 0000000000..395921ccaa
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
@@ -0,0 +1,191 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_GET_PIECE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+struct piece_get_box
+{
+ template <typename Box, typename Piece>
+ static inline void apply(Box& total, Piece const& piece)
+ {
+ geometry::expand(total, piece.robust_envelope);
+ }
+};
+
+struct piece_ovelaps_box
+{
+ template <typename Box, typename Piece>
+ static inline bool apply(Box const& box, Piece const& piece)
+ {
+ return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
+ }
+};
+
+template
+<
+ typename Rings,
+ typename Turns,
+ typename RobustPolicy
+>
+class piece_turn_visitor
+{
+ Rings const& m_rings;
+ Turns& m_turns;
+ RobustPolicy const& m_robust_policy;
+
+ template <typename Piece>
+ inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const
+ {
+ if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
+ {
+ return false;
+ }
+
+ return piece1.index == piece2.left_index
+ || piece1.index == piece2.right_index;
+ }
+
+ template <typename Range, typename Iterator>
+ inline void move_to_next_point(Range const& range, Iterator& next) const
+ {
+ ++next;
+ if (next == boost::end(range))
+ {
+ next = boost::begin(range) + 1;
+ }
+ }
+
+ template <typename Range, typename Iterator>
+ inline Iterator next_point(Range const& range, Iterator it) const
+ {
+ Iterator result = it;
+ move_to_next_point(range, result);
+ // TODO: we could use either piece-boundaries, or comparison with
+ // robust points, to check if the point equals the last one
+ while(geometry::equals(*it, *result))
+ {
+ move_to_next_point(range, result);
+ }
+ return result;
+ }
+
+ template <typename Piece>
+ inline void calculate_turns(Piece const& piece1, Piece const& piece2)
+ {
+ typedef typename boost::range_value<Rings const>::type ring_type;
+ typedef typename boost::range_value<Turns const>::type turn_type;
+ typedef typename boost::range_iterator<ring_type const>::type iterator;
+
+ segment_identifier seg_id1 = piece1.first_seg_id;
+ segment_identifier seg_id2 = piece2.first_seg_id;
+
+ if (seg_id1.segment_index < 0 || seg_id2.segment_index < 0)
+ {
+ return;
+ }
+
+ ring_type const& ring1 = m_rings[seg_id1.multi_index];
+ iterator it1_first = boost::begin(ring1) + seg_id1.segment_index;
+ iterator it1_last = boost::begin(ring1) + piece1.last_segment_index;
+
+ ring_type const& ring2 = m_rings[seg_id2.multi_index];
+ iterator it2_first = boost::begin(ring2) + seg_id2.segment_index;
+ iterator it2_last = boost::begin(ring2) + piece2.last_segment_index;
+
+ turn_type the_model;
+ the_model.operations[0].piece_index = piece1.index;
+ the_model.operations[0].seg_id = piece1.first_seg_id;
+
+ iterator it1 = it1_first;
+ for (iterator prev1 = it1++;
+ it1 != it1_last;
+ prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
+ {
+ the_model.operations[1].piece_index = piece2.index;
+ the_model.operations[1].seg_id = piece2.first_seg_id;
+
+ iterator next1 = next_point(ring1, it1);
+
+ iterator it2 = it2_first;
+ for (iterator prev2 = it2++;
+ it2 != it2_last;
+ prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
+ {
+ iterator next2 = next_point(ring2, it2);
+
+ // TODO: internally get_turn_info calculates robust points.
+ // But they are already calculated.
+ // We should be able to use them.
+ // this means passing them to this visitor,
+ // and iterating in sync with them...
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+ turn_policy::apply(*prev1, *it1, *next1,
+ *prev2, *it2, *next2,
+ false, false, false, false,
+ the_model, m_robust_policy,
+ std::back_inserter(m_turns));
+ }
+ }
+ }
+
+public:
+
+ piece_turn_visitor(Rings const& ring_collection,
+ Turns& turns,
+ RobustPolicy const& robust_policy)
+ : m_rings(ring_collection)
+ , m_turns(turns)
+ , m_robust_policy(robust_policy)
+ {}
+
+ template <typename Piece>
+ inline void apply(Piece const& piece1, Piece const& piece2,
+ bool first = true)
+ {
+ boost::ignore_unused_variable_warning(first);
+ if ( is_adjacent(piece1, piece2)
+ || detail::disjoint::disjoint_box_box(piece1.robust_envelope,
+ piece2.robust_envelope))
+ {
+ return;
+ }
+ calculate_turns(piece1, piece2);
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp b/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
new file mode 100644
index 0000000000..618afe5fba
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
@@ -0,0 +1,88 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_LINE_LINE_INTERSECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
+
+
+#include <boost/geometry/arithmetic/determinant.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+// TODO: once change this to proper strategy
+// It is different from current segment intersection because these are not segments but lines
+// If we have the Line concept, we can create a strategy
+// Assumes a convex corner
+struct line_line_intersection
+{
+
+ template <typename Point>
+ static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj,
+ Point const& qi, Point const& qj, Point& ip)
+ {
+ // See http://mathworld.wolfram.com/Line-LineIntersection.html
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ coordinate_type const denominator
+ = determinant<coordinate_type>(get<0>(pi) - get<0>(pj),
+ get<1>(pi) - get<1>(pj),
+ get<0>(qi) - get<0>(qj),
+ get<1>(qi) - get<1>(qj));
+
+ // Even if the corner was checked before (so it is convex now), that
+ // was done on the original geometry. This function runs on the buffered
+ // geometries, where sides are generated and might be slightly off. In
+ // Floating Point, that slightly might just exceed the limit and we have
+ // to check it again.
+
+ // For round joins, it will not be used at all.
+ // For miter joints, there is a miter limit
+ // If segments are parallel/collinear we must be distinguish two cases:
+ // they continue each other, or they form a spike
+ if (math::equals(denominator, coordinate_type()))
+ {
+ return parallel_continue(get<0>(qj) - get<0>(qi),
+ get<1>(qj) - get<1>(qi),
+ get<0>(pj) - get<0>(pi),
+ get<1>(pj) - get<1>(pi))
+ ? strategy::buffer::join_continue
+ : strategy::buffer::join_spike
+ ;
+ }
+
+ coordinate_type d1 = determinant<coordinate_type>(get<0>(pi), get<1>(pi), get<0>(pj), get<1>(pj));
+ coordinate_type d2 = determinant<coordinate_type>(get<0>(qi), get<1>(qi), get<0>(qj), get<1>(qj));
+
+ double const multiplier = 1.0 / denominator;
+
+ set<0>(ip, determinant<coordinate_type>(d1, get<0>(pi) - get<0>(pj), d2, get<0>(qi) - get<0>(qj)) * multiplier);
+ set<1>(ip, determinant<coordinate_type>(d1, get<1>(pi) - get<1>(pj), d2, get<1>(qi) - get<1>(qj)) * multiplier);
+
+ return strategy::buffer::join_convex;
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp b/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp
new file mode 100644
index 0000000000..119d64de74
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp
@@ -0,0 +1,33 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_PARALLEL_CONTINUE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template <typename T>
+inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
+{
+ T const dot = dx1 * dx2 + dy1 * dy2;
+ return dot > 0;
+}
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp
new file mode 100644
index 0000000000..2b1c33d291
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp
@@ -0,0 +1,98 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_TURN_IN_INPUT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+// Checks if an turn/intersection point is inside (or covered by) the input geometry
+
+template <typename Tag>
+struct turn_in_input
+{
+};
+
+template <>
+struct turn_in_input<polygon_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& point, Geometry const& geometry)
+ {
+ return geometry::covered_by(point, geometry) ? 1 : -1;
+ }
+};
+
+template <>
+struct turn_in_input<linestring_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+template <>
+struct turn_in_input<point_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+template <>
+struct turn_in_input<multi_polygon_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& point, Geometry const& geometry)
+ {
+ return geometry::covered_by(point, geometry) ? 1 : -1;
+ }
+};
+
+template <>
+struct turn_in_input<multi_linestring_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+template <>
+struct turn_in_input<multi_point_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& , Geometry const& )
+ {
+ return 0;
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
new file mode 100644
index 0000000000..c02f56de3f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
@@ -0,0 +1,246 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 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_BUFFER_TURN_IN_PIECE_VISITOR
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/arithmetic/dot_product.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/geometries/linestring.hpp>
+#include <boost/geometry/algorithms/comparable_distance.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+struct turn_get_box
+{
+ template <typename Box, typename Turn>
+ static inline void apply(Box& total, Turn const& turn)
+ {
+ geometry::expand(total, turn.robust_point);
+ }
+};
+
+struct turn_ovelaps_box
+{
+ template <typename Box, typename Turn>
+ static inline bool apply(Box const& box, Turn const& turn)
+ {
+ return ! dispatch::disjoint
+ <
+ typename Turn::robust_point_type,
+ Box
+ >::apply(turn.robust_point, box);
+ }
+};
+
+template <typename Turns, typename Pieces>
+class turn_in_piece_visitor
+{
+ Turns& m_turns; // because partition is currently operating on const input only
+ Pieces const& m_pieces; // to check for piece-type
+
+ typedef boost::long_long_type calculation_type;
+
+ template <typename Point>
+ static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q)
+ {
+ typedef Point vector_type;
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+
+ vector_type v = q;
+ vector_type w = subject;
+ subtract_point(v, p);
+ subtract_point(w, p);
+
+ coordinate_type const zero = coordinate_type();
+ coordinate_type const c1 = dot_product(w, v);
+
+ if (c1 < zero)
+ {
+ return false;
+ }
+ coordinate_type const c2 = dot_product(v, v);
+ if (c2 < c1)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename Point, typename Piece>
+ inline bool on_offsetted(Point const& point, Piece const& piece) const
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type side_strategy;
+ geometry::equal_to<Point> comparator;
+
+ for (int i = 1; i < piece.offsetted_count; i++)
+ {
+ Point const& previous = piece.robust_ring[i - 1];
+ Point const& current = piece.robust_ring[i];
+
+ // The robust ring contains duplicates, avoid applying side on them (will be 0)
+ if (! comparator(previous, current))
+ {
+ int const side = side_strategy::apply(previous, current, point);
+ if (side == 0)
+ {
+ // Collinear, check if projection falls on it
+ if (projection_on_segment(point, previous, current))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ template <typename Point, typename Piece>
+ static inline
+ calculation_type comparable_distance_from_offsetted(Point const& point,
+ Piece const& piece)
+ {
+ // TODO: pass subrange to dispatch to avoid making copy
+ geometry::model::linestring<Point> ls;
+ std::copy(piece.robust_ring.begin(),
+ piece.robust_ring.begin() + piece.offsetted_count,
+ std::back_inserter(ls));
+ typename default_comparable_distance_result<Point, Point>::type
+ const comp = geometry::comparable_distance(point, ls);
+
+ return static_cast<calculation_type>(comp);
+ }
+
+public:
+
+ inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces)
+ : m_turns(turns)
+ , m_pieces(pieces)
+ {}
+
+ template <typename Turn, typename Piece>
+ inline void 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;
+ }
+
+ if (piece.type == strategy::buffer::buffered_flat_end
+ || piece.type == strategy::buffer::buffered_concave)
+ {
+ // Turns cannot be inside a flat end (though they can be on border)
+ // Neither we need to check if they are inside concave helper pieces
+ return;
+ }
+
+ bool neighbour = false;
+ for (int i = 0; i < 2; i++)
+ {
+ // Don't compare against one of the two source-pieces
+ if (turn.operations[i].piece_index == piece.index)
+ {
+ return;
+ }
+
+ typename boost::range_value<Pieces>::type const& pc
+ = m_pieces[turn.operations[i].piece_index];
+ if (pc.left_index == piece.index
+ || pc.right_index == piece.index)
+ {
+ if (pc.type == strategy::buffer::buffered_flat_end)
+ {
+ // If it is a flat end, don't compare against its neighbor:
+ // it will always be located on one of the helper segments
+ return;
+ }
+ neighbour = true;
+ }
+ }
+
+ int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
+
+ if (geometry_code == -1)
+ {
+ return;
+ }
+ if (geometry_code == 0 && neighbour)
+ {
+ return;
+ }
+
+ Turn& mutable_turn = m_turns[turn.turn_index];
+ if (geometry_code == 0)
+ {
+ // If it is on the border and they are not neighbours, it should be
+ // on the offsetted ring
+
+ if (! on_offsetted(turn.robust_point, piece))
+ {
+ // It is on the border but not on the offsetted ring.
+ // Then it is somewhere on the helper-segments
+ // Classify it as "within"
+ geometry_code = 1;
+ mutable_turn.count_on_helper++; // can still become "near_offsetted"
+ }
+ else
+ {
+ mutable_turn.count_on_offsetted++; // value is not used anymore
+ }
+ }
+
+ if (geometry_code == 1)
+ {
+ calculation_type const distance
+ = comparable_distance_from_offsetted(turn.robust_point, piece);
+ if (distance >= 4)
+ {
+ // This is too far from the border, it counts as "really within"
+ mutable_turn.count_within++;
+ }
+ else
+ {
+ // Other points count as still "on border" because they might be
+ // travelled through, but not used as starting point
+ mutable_turn.count_within_near_offsetted++;
+ }
+ }
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
diff --git a/boost/geometry/algorithms/detail/calculate_null.hpp b/boost/geometry/algorithms/detail/calculate_null.hpp
index 4b48d62fc2..3ebca83506 100644
--- a/boost/geometry/algorithms/detail/calculate_null.hpp
+++ b/boost/geometry/algorithms/detail/calculate_null.hpp
@@ -21,9 +21,9 @@ namespace boost { namespace geometry
namespace detail
{
-template<typename ReturnType, typename Geometry, typename Strategy>
struct calculate_null
{
+ template<typename ReturnType, typename Geometry, typename Strategy>
static inline ReturnType apply(Geometry const& , Strategy const&)
{
return ReturnType();
diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp
index 2ad349080b..b23e70171b 100644
--- a/boost/geometry/algorithms/detail/calculate_sum.hpp
+++ b/boost/geometry/algorithms/detail/calculate_sum.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -14,9 +15,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
-
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
namespace boost { namespace geometry
{
@@ -26,20 +25,14 @@ namespace detail
{
-template
-<
- typename ReturnType,
- typename Polygon,
- typename Strategy,
- typename Policy
->
class calculate_polygon_sum
{
- template <typename Rings>
+ template <typename ReturnType, typename Policy, typename Rings, typename Strategy>
static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy)
{
ReturnType sum = ReturnType();
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename boost::range_iterator<Rings const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
sum += Policy::apply(*it, strategy);
}
@@ -47,10 +40,11 @@ class calculate_polygon_sum
}
public :
+ template <typename ReturnType, typename Policy, typename Polygon, typename Strategy>
static inline ReturnType apply(Polygon const& poly, Strategy const& strategy)
{
return Policy::apply(exterior_ring(poly), strategy)
- + sum_interior_rings(interior_rings(poly), strategy)
+ + sum_interior_rings<ReturnType, Policy>(interior_rings(poly), strategy)
;
}
};
diff --git a/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp
new file mode 100644
index 0000000000..56a7e3ec91
--- /dev/null
+++ b/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp
@@ -0,0 +1,119 @@
+// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 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_CENTROID_TRANSLATING_TRANSFORMER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
+
+
+#include <cstddef>
+
+#include <boost/core/addressof.hpp>
+#include <boost/core/ref.hpp>
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace centroid
+{
+
+
+// NOTE: There is no need to translate in other coordinate systems than
+// cartesian. But if it was needed then one should translate using
+// CS-specific technique, e.g. in spherical/geographic a translation
+// vector should contain coordinates being multiplies of 2PI or 360 deg.
+template <typename Geometry,
+ typename CastedTag = typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ areal_tag
+ >::type,
+ typename CSTag = typename cs_tag<Geometry>::type>
+struct translating_transformer
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef boost::reference_wrapper<point_type const> result_type;
+
+ explicit translating_transformer(Geometry const&) {}
+ explicit translating_transformer(point_type const&) {}
+
+ result_type apply(point_type const& pt) const
+ {
+ return result_type(pt);
+ }
+
+ template <typename ResPt>
+ void apply_reverse(ResPt &) const {}
+};
+
+// Specialization for Areal Geometries in cartesian CS
+template <typename Geometry>
+struct translating_transformer<Geometry, areal_tag, cartesian_tag>
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef point_type result_type;
+
+ explicit translating_transformer(Geometry const& geom)
+ : m_origin(NULL)
+ {
+ geometry::point_iterator<Geometry const>
+ pt_it = geometry::points_begin(geom);
+ if ( pt_it != geometry::points_end(geom) )
+ {
+ m_origin = boost::addressof(*pt_it);
+ }
+ }
+
+ explicit translating_transformer(point_type const& origin)
+ : m_origin(boost::addressof(origin))
+ {}
+
+ result_type apply(point_type const& pt) const
+ {
+ point_type res = pt;
+ if ( m_origin )
+ geometry::subtract_point(res, *m_origin);
+ return res;
+ }
+
+ template <typename ResPt>
+ void apply_reverse(ResPt & res_pt) const
+ {
+ if ( m_origin )
+ geometry::add_point(res_pt, *m_origin);
+ }
+
+ const point_type * m_origin;
+};
+
+
+}} // namespace detail::centroid
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
diff --git a/boost/geometry/algorithms/detail/check_iterator_range.hpp b/boost/geometry/algorithms/detail/check_iterator_range.hpp
new file mode 100644
index 0000000000..09ea7f79a0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/check_iterator_range.hpp
@@ -0,0 +1,71 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+// Check whether (each element of) an iterator range satisfies a given
+// predicate.
+// The predicate must be implemented as having a static apply unary
+// method that returns a bool.
+// By default an empty range is accepted
+template <typename Predicate, bool AllowEmptyRange = true>
+struct check_iterator_range
+{
+ template <typename InputIterator>
+ static inline bool apply(InputIterator first, InputIterator beyond)
+ {
+ for (InputIterator it = first; it != beyond; ++it)
+ {
+ if ( !Predicate::apply(*it) )
+ {
+ return false;
+ }
+ }
+ return AllowEmptyRange || first != beyond;
+ }
+
+
+ // version where we can pass a predicate object
+ template <typename InputIterator>
+ static inline bool apply(InputIterator first,
+ InputIterator beyond,
+ Predicate const& predicate)
+ {
+ // in case predicate's apply method is static, MSVC will
+ // complain that predicate is not used
+ boost::ignore_unused(predicate);
+
+ for (InputIterator it = first; it != beyond; ++it)
+ {
+ if ( !predicate.apply(*it) )
+ {
+ return false;
+ }
+ }
+ return AllowEmptyRange || first != beyond;
+ }
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
new file mode 100644
index 0000000000..c7558b4ff1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
@@ -0,0 +1,147 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
+
+#include <iterator>
+
+#include <boost/assert.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace closest_feature
+{
+
+
+
+// returns the range iterator the realizes the closest
+// distance between the geometry and the element of the range
+class geometry_to_range
+{
+private:
+ template
+ <
+ typename Geometry,
+ typename RangeIterator,
+ typename Strategy,
+ typename Distance
+ >
+ static inline void apply(Geometry const& geometry,
+ RangeIterator first,
+ RangeIterator last,
+ Strategy const& strategy,
+ RangeIterator& it_min,
+ Distance& dist_min)
+ {
+ BOOST_ASSERT( first != last );
+
+ Distance const zero = Distance(0);
+
+ // start with first distance
+ it_min = first;
+ dist_min = dispatch::distance
+ <
+ Geometry,
+ typename std::iterator_traits<RangeIterator>::value_type,
+ Strategy
+ >::apply(geometry, *it_min, strategy);
+
+ // check if other elements in the range are closer
+ RangeIterator it = first;
+ for (++it; it != last; ++it)
+ {
+ Distance dist = dispatch::distance
+ <
+ Geometry,
+ typename std::iterator_traits<RangeIterator>::value_type,
+ Strategy
+ >::apply(geometry, *it, strategy);
+
+ if (geometry::math::equals(dist, zero))
+ {
+ dist_min = dist;
+ it_min = it;
+ return;
+ }
+ else if (dist < dist_min)
+ {
+ dist_min = dist;
+ it_min = it;
+ }
+ }
+ }
+
+public:
+ template
+ <
+ typename Geometry,
+ typename RangeIterator,
+ typename Strategy,
+ typename Distance
+ >
+ static inline RangeIterator apply(Geometry const& geometry,
+ RangeIterator first,
+ RangeIterator last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ RangeIterator it_min;
+ apply(geometry, first, last, strategy, it_min, dist_min);
+
+ return it_min;
+ }
+
+
+ template
+ <
+ typename Geometry,
+ typename RangeIterator,
+ typename Strategy
+ >
+ static inline RangeIterator apply(Geometry const& geometry,
+ RangeIterator first,
+ RangeIterator last,
+ Strategy const& strategy)
+ {
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry>::type,
+ typename point_type
+ <
+ typename std::iterator_traits
+ <
+ RangeIterator
+ >::value_type
+ >::type
+ >::type dist_min;
+
+ return apply(geometry, first, last, strategy, dist_min);
+ }
+};
+
+
+
+}} // namespace detail::closest_feature
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
new file mode 100644
index 0000000000..91be6b0ad0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
@@ -0,0 +1,250 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
+
+#include <utility>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/util/math.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace closest_feature
+{
+
+
+// returns the segment (pair of iterators) that realizes the closest
+// distance of the point to the range
+template
+<
+ typename Point,
+ typename Range,
+ closure_selector Closure,
+ typename Strategy
+>
+class point_to_point_range
+{
+protected:
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
+
+ template <typename Distance>
+ static inline void apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ iterator_type& it_min1,
+ iterator_type& it_min2,
+ Distance& dist_min)
+ {
+ BOOST_ASSERT( first != last );
+
+ Distance const zero = Distance(0);
+
+ iterator_type it = first;
+ iterator_type prev = it++;
+ if (it == last)
+ {
+ it_min1 = it_min2 = first;
+ dist_min = strategy.apply(point, *first, *first);
+ return;
+ }
+
+ // start with first segment distance
+ dist_min = strategy.apply(point, *prev, *it);
+ iterator_type prev_min_dist = prev;
+
+ // check if other segments are closer
+ for (++prev, ++it; it != last; ++prev, ++it)
+ {
+ Distance dist = strategy.apply(point, *prev, *it);
+ if (geometry::math::equals(dist, zero))
+ {
+ dist_min = zero;
+ it_min1 = prev;
+ it_min2 = it;
+ return;
+ }
+ else if (dist < dist_min)
+ {
+ dist_min = dist;
+ prev_min_dist = prev;
+ }
+ }
+
+ it_min1 = it_min2 = prev_min_dist;
+ ++it_min2;
+ }
+
+public:
+ typedef typename std::pair<iterator_type, iterator_type> return_type;
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ iterator_type it_min1, it_min2;
+ apply(point, first, last, strategy, it_min1, it_min2, dist_min);
+
+ return std::make_pair(it_min1, it_min2);
+ }
+
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy)
+ {
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename boost::range_value<Range>::type
+ >::type dist_min;
+
+ return apply(point, first, last, strategy, dist_min);
+ }
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ return apply(point,
+ boost::begin(range),
+ boost::end(range),
+ strategy,
+ dist_min);
+ }
+
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy)
+ {
+ return apply(point, boost::begin(range), boost::end(range), strategy);
+ }
+};
+
+
+
+// specialization for open ranges
+template <typename Point, typename Range, typename Strategy>
+class point_to_point_range<Point, Range, open, Strategy>
+ : point_to_point_range<Point, Range, closed, Strategy>
+{
+private:
+ typedef point_to_point_range<Point, Range, closed, Strategy> base_type;
+ typedef typename base_type::iterator_type iterator_type;
+
+ template <typename Distance>
+ static inline void apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ iterator_type& it_min1,
+ iterator_type& it_min2,
+ Distance& dist_min)
+ {
+ BOOST_ASSERT( first != last );
+
+ base_type::apply(point, first, last, strategy,
+ it_min1, it_min2, dist_min);
+
+ iterator_type it_back = --last;
+ Distance const zero = Distance(0);
+ Distance dist = strategy.apply(point, *it_back, *first);
+
+ if (geometry::math::equals(dist, zero))
+ {
+ dist_min = zero;
+ it_min1 = it_back;
+ it_min2 = first;
+ }
+ else if (dist < dist_min)
+ {
+ dist_min = dist;
+ it_min1 = it_back;
+ it_min2 = first;
+ }
+ }
+
+public:
+ typedef typename std::pair<iterator_type, iterator_type> return_type;
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ iterator_type it_min1, it_min2;
+
+ apply(point, first, last, strategy, it_min1, it_min2, dist_min);
+
+ return std::make_pair(it_min1, it_min2);
+ }
+
+ static inline return_type apply(Point const& point,
+ iterator_type first,
+ iterator_type last,
+ Strategy const& strategy)
+ {
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename boost::range_value<Range>::type
+ >::type distance_return_type;
+
+ distance_return_type dist_min;
+
+ return apply(point, first, last, strategy, dist_min);
+ }
+
+ template <typename Distance>
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ return apply(point,
+ boost::begin(range),
+ boost::end(range),
+ strategy,
+ dist_min);
+ }
+
+ static inline return_type apply(Point const& point,
+ Range const& range,
+ Strategy const& strategy)
+ {
+ return apply(point, boost::begin(range), boost::end(range), strategy);
+ }
+};
+
+
+}} // namespace detail::closest_feature
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
new file mode 100644
index 0000000000..90248767ec
--- /dev/null
+++ b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
@@ -0,0 +1,196 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
+
+#include <cstddef>
+
+#include <iterator>
+#include <utility>
+
+#include <boost/assert.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+#include <boost/geometry/index/rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace closest_feature
+{
+
+
+// returns a pair of a objects where the first is an object of the
+// r-tree range and the second an object of the query range that
+// realizes the closest feature of the two ranges
+class range_to_range_rtree
+{
+private:
+ template
+ <
+ typename RTreeRangeIterator,
+ typename QueryRangeIterator,
+ typename Strategy,
+ typename RTreeValueType,
+ typename Distance
+ >
+ static inline void apply(RTreeRangeIterator rtree_first,
+ RTreeRangeIterator rtree_last,
+ QueryRangeIterator queries_first,
+ QueryRangeIterator queries_last,
+ Strategy const& strategy,
+ RTreeValueType& rtree_min,
+ QueryRangeIterator& qit_min,
+ Distance& dist_min)
+ {
+ typedef index::rtree<RTreeValueType, index::linear<8> > rtree_type;
+
+ BOOST_ASSERT( rtree_first != rtree_last );
+ BOOST_ASSERT( queries_first != queries_last );
+
+ Distance const zero = Distance(0);
+
+ // create -- packing algorithm
+ rtree_type rt(rtree_first, rtree_last);
+
+ RTreeValueType t_v;
+ bool first = true;
+
+ for (QueryRangeIterator qit = queries_first;
+ qit != queries_last; ++qit, first = false)
+ {
+ std::size_t n = rt.query(index::nearest(*qit, 1), &t_v);
+
+ BOOST_ASSERT( n > 0 );
+ // n above is unused outside BOOST_ASSERT, hence the call
+ // to boost::ignore_unused below
+ //
+ // however, t_v (initialized by the call to rt.query(...))
+ // is used below, which is why we cannot put the call to
+ // rt.query(...) inside BOOST_ASSERT
+ boost::ignore_unused(n);
+
+ Distance dist = dispatch::distance
+ <
+ RTreeValueType,
+ typename std::iterator_traits
+ <
+ QueryRangeIterator
+ >::value_type,
+ Strategy
+ >::apply(t_v, *qit, strategy);
+
+ if (first || dist < dist_min)
+ {
+ dist_min = dist;
+ rtree_min = t_v;
+ qit_min = qit;
+ if ( math::equals(dist_min, zero) )
+ {
+ return;
+ }
+ }
+ }
+ }
+
+public:
+ template <typename RTreeRangeIterator, typename QueryRangeIterator>
+ struct return_type
+ {
+ typedef std::pair
+ <
+ typename std::iterator_traits<RTreeRangeIterator>::value_type,
+ QueryRangeIterator
+ > type;
+ };
+
+
+ template
+ <
+ typename RTreeRangeIterator,
+ typename QueryRangeIterator,
+ typename Strategy,
+ typename Distance
+ >
+ static inline typename return_type
+ <
+ RTreeRangeIterator, QueryRangeIterator
+ >::type apply(RTreeRangeIterator rtree_first,
+ RTreeRangeIterator rtree_last,
+ QueryRangeIterator queries_first,
+ QueryRangeIterator queries_last,
+ Strategy const& strategy,
+ Distance& dist_min)
+ {
+ typedef typename std::iterator_traits
+ <
+ RTreeRangeIterator
+ >::value_type rtree_value_type;
+
+ rtree_value_type rtree_min;
+ QueryRangeIterator qit_min;
+
+ apply(rtree_first, rtree_last, queries_first, queries_last,
+ strategy, rtree_min, qit_min, dist_min);
+
+ return std::make_pair(rtree_min, qit_min);
+ }
+
+
+ template
+ <
+ typename RTreeRangeIterator,
+ typename QueryRangeIterator,
+ typename Strategy
+ >
+ static inline typename return_type
+ <
+ RTreeRangeIterator, QueryRangeIterator
+ >::type apply(RTreeRangeIterator rtree_first,
+ RTreeRangeIterator rtree_last,
+ QueryRangeIterator queries_first,
+ QueryRangeIterator queries_last,
+ Strategy const& strategy)
+ {
+ typedef typename std::iterator_traits
+ <
+ RTreeRangeIterator
+ >::value_type rtree_value_type;
+
+ typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<rtree_value_type>::type,
+ typename point_type
+ <
+ typename std::iterator_traits
+ <
+ QueryRangeIterator
+ >::value_type
+ >::type
+ >::type dist_min;
+
+ return apply(rtree_first, rtree_last, queries_first, queries_last,
+ strategy, dist_min);
+ }
+};
+
+
+}} // namespace detail::closest_feature
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp b/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp
new file mode 100644
index 0000000000..b6eb7a27f1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/comparable_distance/implementation.hpp
@@ -0,0 +1,24 @@
+// 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 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
+
+#include <boost/geometry/algorithms/detail/distance/implementation.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
new file mode 100644
index 0000000000..1a57c8f4b3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
@@ -0,0 +1,363 @@
+// 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 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_COMPARABLE_DISTANCE_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/strategies/comparable_distance_result.hpp>
+#include <boost/geometry/strategies/default_comparable_distance_result.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/interface.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_strategy
+{
+
+struct comparable_distance
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline
+ typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy_type;
+
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, comparable_strategy_type
+ >::apply(geometry1,
+ geometry2,
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy));
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline typename comparable_distance_result
+ <
+ Geometry1, Geometry2, default_strategy
+ >::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::distance::services::comparable_type
+ <
+ typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type
+ >::type comparable_strategy_type;
+
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, comparable_strategy_type
+ >::apply(geometry1, geometry2, comparable_strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+
+template <typename Geometry1, typename Geometry2>
+struct comparable_distance
+{
+ template <typename Strategy>
+ static inline
+ typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return resolve_strategy::comparable_distance::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct comparable_distance
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ >
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2,
+ Strategy const& strategy)
+ : m_geometry2(geometry2),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ typename comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ operator()(Geometry1 const& geometry1) const
+ {
+ return comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct comparable_distance
+ <
+ Geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename comparable_distance_result
+ <
+ Geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ >
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1,
+ Strategy const& strategy)
+ : m_geometry1(geometry1),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ typename comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ operator()(Geometry2 const& geometry2) const
+ {
+ return comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename comparable_distance_result
+ <
+ Geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+
+template
+<
+ BOOST_VARIANT_ENUM_PARAMS(typename A),
+ BOOST_VARIANT_ENUM_PARAMS(typename B)
+>
+struct comparable_distance
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ >
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ typename comparable_distance_result
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const
+ {
+ return comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename comparable_distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_calc2{comparable distance measurement} \brief_strategy
+\ingroup distance
+\details The free function comparable_distance does not necessarily calculate the distance,
+ but it calculates a distance measure such that two distances are comparable to each other.
+ For example: for the Cartesian coordinate system, Pythagoras is used but the square root
+ is not taken, which makes it faster and the results of two point pairs can still be
+ compared to each other.
+\tparam Geometry1 first geometry type
+\tparam Geometry2 second geometry type
+\tparam Strategy \tparam_strategy{Distance}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{distance}
+\return \return_calc{comparable distance}
+
+\qbk{distinguish,with strategy}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
+comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return resolve_variant::comparable_distance
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+
+/*!
+\brief \brief_calc2{comparable distance measurement}
+\ingroup distance
+\details The free function comparable_distance does not necessarily calculate the distance,
+ but it calculates a distance measure such that two distances are comparable to each other.
+ For example: for the Cartesian coordinate system, Pythagoras is used but the square root
+ is not taken, which makes it faster and the results of two point pairs can still be
+ compared to each other.
+\tparam Geometry1 first geometry type
+\tparam Geometry2 second geometry type
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_calc{comparable distance}
+
+\qbk{[include reference/algorithms/comparable_distance.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline typename default_comparable_distance_result<Geometry1, Geometry2>::type
+comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return comparable_distance(geometry1, geometry2, default_strategy());
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
index d39824a61d..fccdf4bb1d 100644
--- a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
+++ b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
@@ -33,9 +33,9 @@ namespace detail { namespace conversion
template
<
- typename Source,
- typename Destination,
- std::size_t Dimension,
+ typename Source,
+ typename Destination,
+ std::size_t Dimension,
std::size_t DimensionCount
>
struct indexed_to_indexed
@@ -44,25 +44,25 @@ struct indexed_to_indexed
{
typedef typename coordinate_type<Destination>::type coordinate_type;
- geometry::set<min_corner, Dimension>(destination,
+ geometry::set<min_corner, Dimension>(destination,
boost::numeric_cast<coordinate_type>(
geometry::get<min_corner, Dimension>(source)));
- geometry::set<max_corner, Dimension>(destination,
+ geometry::set<max_corner, Dimension>(destination,
boost::numeric_cast<coordinate_type>(
geometry::get<max_corner, Dimension>(source)));
-
+
indexed_to_indexed
<
- Source, Destination,
+ Source, Destination,
Dimension + 1, DimensionCount
>::apply(source, destination);
}
};
-template
+template
<
- typename Source,
- typename Destination,
+ typename Source,
+ typename Destination,
std::size_t DimensionCount
>
struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount>
diff --git a/boost/geometry/algorithms/detail/counting.hpp b/boost/geometry/algorithms/detail/counting.hpp
new file mode 100644
index 0000000000..dc5bb26c10
--- /dev/null
+++ b/boost/geometry/algorithms/detail/counting.hpp
@@ -0,0 +1,107 @@
+// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_COUNTING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace counting
+{
+
+
+template <std::size_t D>
+struct other_count
+{
+ template <typename Geometry>
+ static inline std::size_t apply(Geometry const&)
+ {
+ return D;
+ }
+
+ template <typename Geometry>
+ static inline std::size_t apply(Geometry const&, bool)
+ {
+ return D;
+ }
+};
+
+
+template <typename RangeCount>
+struct polygon_count
+{
+ template <typename Polygon>
+ static inline std::size_t apply(Polygon const& poly)
+ {
+ std::size_t n = RangeCount::apply(exterior_ring(poly));
+
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ n += RangeCount::apply(*it);
+ }
+
+ return n;
+ }
+};
+
+
+template <typename SingleCount>
+struct multi_count
+{
+ template <typename MultiGeometry>
+ static inline std::size_t apply(MultiGeometry const& geometry)
+ {
+ std::size_t n = 0;
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(geometry);
+ it != boost::end(geometry);
+ ++it)
+ {
+ n += SingleCount::apply(*it);
+ }
+ return n;
+ }
+};
+
+
+}} // namespace detail::counting
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
diff --git a/boost/geometry/algorithms/detail/course.hpp b/boost/geometry/algorithms/detail/course.hpp
new file mode 100644
index 0000000000..e1a74c0fee
--- /dev/null
+++ b/boost/geometry/algorithms/detail/course.hpp
@@ -0,0 +1,56 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_COURSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+/// Calculate course (bearing) between two points.
+template <typename ReturnType, typename Point1, typename Point2>
+inline ReturnType course(Point1 const& p1, Point2 const& p2)
+{
+ // http://williams.best.vwh.net/avform.htm#Crs
+ ReturnType dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1);
+ ReturnType cos_p2lat = cos(get_as_radian<1>(p2));
+
+ // An optimization which should kick in often for Boxes
+ //if ( math::equals(dlon, ReturnType(0)) )
+ //if ( get<0>(p1) == get<0>(p2) )
+ //{
+ // return - sin(get_as_radian<1>(p1)) * cos_p2lat);
+ //}
+
+ // "An alternative formula, not requiring the pre-computation of d"
+ // In the formula below dlon is used as "d"
+ return atan2(sin(dlon) * cos_p2lat,
+ cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2))
+ - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon));
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint.hpp b/boost/geometry/algorithms/detail/disjoint.hpp
deleted file mode 100644
index 2ced5b1ce3..0000000000
--- a/boost/geometry/algorithms/detail/disjoint.hpp
+++ /dev/null
@@ -1,225 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
-
-// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
-// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
-
-// Note: contrary to most files, the geometry::detail::disjoint namespace
-// is partly implemented in a separate file, to avoid circular references
-// disjoint -> get_turns -> disjoint
-
-#include <cstddef>
-
-#include <boost/range.hpp>
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
-
-#include <boost/geometry/util/math.hpp>
-
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace disjoint
-{
-
-
-struct disjoint_interrupt_policy
-{
- static bool const enabled = true;
- bool has_intersections;
-
- inline disjoint_interrupt_policy()
- : has_intersections(false)
- {}
-
- template <typename Range>
- inline bool apply(Range const& range)
- {
- // If there is any IP in the range, it is NOT disjoint
- if (boost::size(range) > 0)
- {
- has_intersections = true;
- return true;
- }
- return false;
- }
-};
-
-
-
-template
-<
- typename Point1, typename Point2,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct point_point
-{
- static inline bool apply(Point1 const& p1, Point2 const& p2)
- {
- if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
- {
- return true;
- }
- return point_point
- <
- Point1, Point2,
- Dimension + 1, DimensionCount
- >::apply(p1, p2);
- }
-};
-
-
-template <typename Point1, typename Point2, std::size_t DimensionCount>
-struct point_point<Point1, Point2, DimensionCount, DimensionCount>
-{
- static inline bool apply(Point1 const& , Point2 const& )
- {
- return false;
- }
-};
-
-
-template
-<
- typename Point, typename Box,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct point_box
-{
- static inline bool apply(Point const& point, Box const& box)
- {
- if (get<Dimension>(point) < get<min_corner, Dimension>(box)
- || get<Dimension>(point) > get<max_corner, Dimension>(box))
- {
- return true;
- }
- return point_box
- <
- Point, Box,
- Dimension + 1, DimensionCount
- >::apply(point, box);
- }
-};
-
-
-template <typename Point, typename Box, std::size_t DimensionCount>
-struct point_box<Point, Box, DimensionCount, DimensionCount>
-{
- static inline bool apply(Point const& , Box const& )
- {
- return false;
- }
-};
-
-
-template
-<
- typename Box1, typename Box2,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct box_box
-{
- static inline bool apply(Box1 const& box1, Box2 const& box2)
- {
- if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
- {
- return true;
- }
- if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
- {
- return true;
- }
- return box_box
- <
- Box1, Box2,
- Dimension + 1, DimensionCount
- >::apply(box1, box2);
- }
-};
-
-
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct box_box<Box1, Box2, DimensionCount, DimensionCount>
-{
- static inline bool apply(Box1 const& , Box2 const& )
- {
- return false;
- }
-};
-
-
-
-/*!
- \brief Internal utility function to detect of boxes are disjoint
- \note Is used from other algorithms, declared separately
- to avoid circular references
- */
-template <typename Box1, typename Box2>
-inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
-{
- return box_box
- <
- Box1, Box2,
- 0, dimension<Box1>::type::value
- >::apply(box1, box2);
-}
-
-
-
-/*!
- \brief Internal utility function to detect of points are disjoint
- \note To avoid circular references
- */
-template <typename Point1, typename Point2>
-inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
-{
- return point_point
- <
- Point1, Point2,
- 0, dimension<Point1>::type::value
- >::apply(point1, point2);
-}
-
-
-}} // namespace detail::disjoint
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace equals
-{
-
-/*!
- \brief Internal utility function to detect of points are disjoint
- \note To avoid circular references
- */
-template <typename Point1, typename Point2>
-inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
-{
- return ! detail::disjoint::disjoint_point_point(point1, point2);
-}
-
-
-}} // namespace detail::equals
-#endif // DOXYGEN_NO_DETAIL
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp
new file mode 100644
index 0000000000..284858a130
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/areal_areal.hpp
@@ -0,0 +1,134 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_AREAL_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/detail/for_each_range.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template<typename Geometry>
+struct check_each_ring_for_within
+{
+ bool not_disjoint;
+ Geometry const& m_geometry;
+
+ inline check_each_ring_for_within(Geometry const& g)
+ : not_disjoint(false)
+ , m_geometry(g)
+ {}
+
+ template <typename Range>
+ inline void apply(Range const& range)
+ {
+ typename point_type<Range>::type pt;
+ not_disjoint = not_disjoint
+ || ( geometry::point_on_border(pt, range)
+ && geometry::covered_by(pt, m_geometry) );
+ }
+};
+
+
+
+template <typename FirstGeometry, typename SecondGeometry>
+inline bool rings_containing(FirstGeometry const& geometry1,
+ SecondGeometry const& geometry2)
+{
+ check_each_ring_for_within<FirstGeometry> checker(geometry1);
+ geometry::detail::for_each_range(geometry2, checker);
+ return checker.not_disjoint;
+}
+
+
+
+template <typename Geometry1, typename Geometry2>
+struct general_areal
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ if ( ! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2) )
+ {
+ return false;
+ }
+
+ // If there is no intersection of segments, they might located
+ // inside each other
+
+ // We check that using a point on the border (external boundary),
+ // and see if that is contained in the other geometry. And vice versa.
+
+ if ( rings_containing(geometry1, geometry2)
+ || rings_containing(geometry2, geometry1) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Areal1, typename Areal2>
+struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false>
+ : detail::disjoint::general_areal<Areal1, Areal2>
+{};
+
+
+template <typename Areal, typename Box>
+struct disjoint<Areal, Box, 2, areal_tag, box_tag, false>
+ : detail::disjoint::general_areal<Areal, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
new file mode 100644
index 0000000000..ccff9799fd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
@@ -0,0 +1,114 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template
+<
+ typename Box1, typename Box2,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct box_box
+{
+ static inline bool apply(Box1 const& box1, Box2 const& box2)
+ {
+ if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
+ {
+ return true;
+ }
+ if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
+ {
+ return true;
+ }
+ return box_box
+ <
+ Box1, Box2,
+ Dimension + 1, DimensionCount
+ >::apply(box1, box2);
+ }
+};
+
+
+template <typename Box1, typename Box2, std::size_t DimensionCount>
+struct box_box<Box1, Box2, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Box1 const& , Box2 const& )
+ {
+ return false;
+ }
+};
+
+
+/*!
+ \brief Internal utility function to detect of boxes are disjoint
+ \note Is used from other algorithms, declared separately
+ to avoid circular references
+ */
+template <typename Box1, typename Box2>
+inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
+{
+ return box_box
+ <
+ Box1, Box2,
+ 0, dimension<Box1>::type::value
+ >::apply(box1, box2);
+}
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Box1, typename Box2, std::size_t DimensionCount>
+struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false>
+ : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
new file mode 100644
index 0000000000..0c8079b8e4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
@@ -0,0 +1,36 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP
+
+
+#include <boost/geometry/algorithms/detail/disjoint/areal_areal.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_areal.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_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/disjoint/segment_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/interface.hpp b/boost/geometry/algorithms/detail/disjoint/interface.hpp
new file mode 100644
index 0000000000..ec9057ba0d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/interface.hpp
@@ -0,0 +1,187 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
+
+#include <cstddef>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ std::size_t DimensionCount,
+ typename Tag1, typename Tag2
+>
+struct disjoint<Geometry1, Geometry2, DimensionCount, Tag1, Tag2, true>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ return disjoint
+ <
+ Geometry2, Geometry1,
+ DimensionCount,
+ Tag2, Tag1
+ >::apply(g2, g1);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct disjoint
+{
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ concept::check_concepts_and_equal_dimensions
+ <
+ Geometry1 const,
+ Geometry2 const
+ >();
+
+ return dispatch::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct disjoint<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return disjoint<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct disjoint<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return disjoint<Geometry1, Geometry2>::apply(m_geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry1), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct disjoint<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_check2{are disjoint}
+\ingroup disjoint
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{are disjoint}
+
+\qbk{[include reference/algorithms/disjoint.qbk]}
+*/
+template <typename Geometry1, typename Geometry2>
+inline bool disjoint(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+{
+ return resolve_variant::disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
new file mode 100644
index 0000000000..eefd351b8d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
@@ -0,0 +1,244 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_LINEAR_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
+
+#include <iterator>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.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/segment_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template<typename Geometry1, typename Geometry2>
+struct disjoint_linear_areal
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ // if there are intersections - return false
+ if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2) )
+ return false;
+
+ typedef typename point_type<Geometry1>::type point1_type;
+ point1_type p;
+ geometry::point_on_border(p, g1);
+ return !geometry::covered_by(p, g2);
+ }
+};
+
+
+
+
+template
+<
+ typename Segment,
+ typename Areal,
+ typename Tag = typename tag<Areal>::type
+>
+struct disjoint_segment_areal
+ : not_implemented<Segment, Areal>
+{};
+
+
+template <typename Segment, typename Polygon>
+class disjoint_segment_areal<Segment, Polygon, polygon_tag>
+{
+private:
+ template <typename RingIterator>
+ static inline bool check_interior_rings(RingIterator first,
+ RingIterator beyond,
+ Segment const& segment)
+ {
+ for (RingIterator it = first; it != beyond; ++it)
+ {
+ if ( !disjoint_range_segment_or_box
+ <
+ typename std::iterator_traits
+ <
+ RingIterator
+ >::value_type,
+ closure<Polygon>::value,
+ Segment
+ >::apply(*it, segment) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ template <typename InteriorRings>
+ static inline
+ bool check_interior_rings(InteriorRings const& interior_rings,
+ Segment const& segment)
+ {
+ return check_interior_rings(boost::begin(interior_rings),
+ boost::end(interior_rings),
+ segment);
+ }
+
+
+public:
+ static inline bool apply(Segment const& segment, Polygon const& polygon)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring;
+
+ if ( !disjoint_range_segment_or_box
+ <
+ ring, closure<Polygon>::value, Segment
+ >::apply(geometry::exterior_ring(polygon), segment) )
+ {
+ return false;
+ }
+
+ if ( !check_interior_rings(geometry::interior_rings(polygon), segment) )
+ {
+ return false;
+ }
+
+ typename point_type<Segment>::type p;
+ detail::assign_point_from_index<0>(segment, p);
+
+ return !geometry::covered_by(p, polygon);
+ }
+};
+
+
+template <typename Segment, typename MultiPolygon>
+struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag>
+{
+ static inline
+ bool apply(Segment const& segment, MultiPolygon const& multipolygon)
+ {
+ return disjoint_multirange_segment_or_box
+ <
+ MultiPolygon, Segment
+ >::apply(multipolygon, segment);
+ }
+};
+
+
+template <typename Segment, typename Ring>
+struct disjoint_segment_areal<Segment, Ring, ring_tag>
+{
+ static inline bool apply(Segment const& segment, Ring const& ring)
+ {
+ if ( !disjoint_range_segment_or_box
+ <
+ Ring, closure<Ring>::value, Segment
+ >::apply(ring, segment) )
+ {
+ return false;
+ }
+
+ typename point_type<Segment>::type p;
+ detail::assign_point_from_index<0>(segment, p);
+
+ return !geometry::covered_by(p, ring);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear, typename Areal>
+struct disjoint<Linear, Areal, 2, linear_tag, areal_tag, false>
+ : public detail::disjoint::disjoint_linear_areal<Linear, Areal>
+{};
+
+
+template <typename Areal, typename Linear>
+struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false>
+{
+ static inline
+ bool apply(Areal const& areal, Linear const& linear)
+ {
+ return detail::disjoint::disjoint_linear_areal
+ <
+ Linear, Areal
+ >::apply(linear, areal);
+ }
+};
+
+
+template <typename Areal, typename Segment>
+struct disjoint<Areal, Segment, 2, areal_tag, segment_tag, false>
+{
+ static inline bool apply(Areal const& g1, Segment const& g2)
+ {
+ return detail::disjoint::disjoint_segment_areal
+ <
+ Segment, Areal
+ >::apply(g2, g1);
+ }
+};
+
+
+template <typename Segment, typename Areal>
+struct disjoint<Segment, Areal, 2, segment_tag, areal_tag, false>
+ : detail::disjoint::disjoint_segment_areal<Segment, Areal>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
new file mode 100644
index 0000000000..ad84d7191d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
@@ -0,0 +1,174 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
+
+#include <cstddef>
+#include <deque>
+
+#include <boost/range.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.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/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+template <typename Segment1, typename Segment2>
+struct disjoint_segment
+{
+ static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
+ {
+ typedef typename point_type<Segment1>::type point_type;
+
+ // We don't need to rescale to detect disjointness
+ typedef no_rescale_policy rescale_policy_type;
+ rescale_policy_type robust_policy;
+
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type,
+ rescale_policy_type
+ >::type
+ > intersection_return_type;
+
+ intersection_return_type is
+ = strategy::intersection::relate_cartesian_segments
+ <
+ policies::relate::segments_intersection_points
+ <
+ intersection_return_type
+ >
+ >::apply(segment1, segment2, robust_policy);
+
+ return is.count == 0;
+ }
+};
+
+
+struct assign_disjoint_policy
+{
+ // We want to include all points:
+ static bool const include_no_turn = true;
+ static bool const include_degenerate = true;
+ static bool const include_opposite = true;
+
+ // We don't assign extra info:
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(Info& , Point1 const& , Point2 const&,
+ IntersectionInfo const&, DirInfo const&)
+ {}
+};
+
+
+template <typename Geometry1, typename Geometry2>
+struct disjoint_linear
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+ std::deque<turn_info> turns;
+
+ static const bool reverse1 = overlay::do_reverse<geometry::point_order<Geometry1>::value>::value; // should be false
+ static const bool reverse2 = overlay::do_reverse<geometry::point_order<Geometry2>::value>::value; // should be false
+
+ // Specify two policies:
+ // 1) Stop at any intersection
+ // 2) In assignment, include also degenerate points (which are normally skipped)
+ disjoint_interrupt_policy policy;
+ rescale_policy_type robust_policy;
+ geometry::get_turns
+ <
+ reverse1, reverse2,
+ assign_disjoint_policy
+ >(geometry1, geometry2, robust_policy, turns, policy);
+
+ return !policy.has_intersections;
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear1, typename Linear2>
+struct disjoint<Linear1, Linear2, 2, linear_tag, linear_tag, false>
+ : detail::disjoint::disjoint_linear<Linear1, Linear2>
+{};
+
+
+template <typename Segment1, typename Segment2>
+struct disjoint<Segment1, Segment2, 2, segment_tag, segment_tag, false>
+ : detail::disjoint::disjoint_segment<Segment1, Segment2>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
new file mode 100644
index 0000000000..d181726e2e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
@@ -0,0 +1,195 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
+
+#include <boost/range.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+
+#include <boost/geometry/geometries/segment.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/views/closeable_view.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template <typename MultiRange, typename SegmentOrBox>
+struct disjoint_multirange_segment_or_box
+{
+ static inline
+ bool apply(MultiRange const& multirange, SegmentOrBox const& segment_or_box)
+ {
+ typedef typename boost::range_iterator
+ <
+ MultiRange const
+ >::type const_iterator;
+
+ for (const_iterator it = boost::begin(multirange);
+ it != boost::end(multirange); ++it)
+ {
+ if ( !dispatch::disjoint
+ <
+ typename boost::range_value<MultiRange>::type,
+ SegmentOrBox
+ >::apply(*it, segment_or_box) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+
+template
+<
+ typename Range,
+ closure_selector Closure,
+ typename SegmentOrBox
+>
+struct disjoint_range_segment_or_box
+{
+ static inline
+ bool apply(Range const& range, SegmentOrBox const& segment_or_box)
+ {
+ typedef typename closeable_view<Range const, Closure>::type view_type;
+
+ typedef typename ::boost::range_value<view_type>::type point_type;
+ typedef typename ::boost::range_iterator
+ <
+ view_type const
+ >::type const_iterator;
+
+ typedef typename ::boost::range_size<view_type>::type size_type;
+
+ typedef typename geometry::model::referring_segment
+ <
+ point_type const
+ > range_segment;
+
+ view_type view(range);
+
+ const size_type count = ::boost::size(view);
+
+ if ( count == 0 )
+ {
+ return false;
+ }
+ else if ( count == 1 )
+ {
+ return dispatch::disjoint
+ <
+ point_type, SegmentOrBox
+ >::apply(geometry::range::front<view_type const>(view),
+ segment_or_box);
+ }
+ else
+ {
+ const_iterator it0 = ::boost::begin(view);
+ const_iterator it1 = ::boost::begin(view) + 1;
+ const_iterator last = ::boost::end(view);
+
+ for ( ; it1 != last ; ++it0, ++it1 )
+ {
+ range_segment rng_segment(*it0, *it1);
+ if ( !dispatch::disjoint
+ <
+ range_segment, SegmentOrBox
+ >::apply(rng_segment, segment_or_box) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+};
+
+
+
+
+template
+<
+ typename Linear,
+ typename SegmentOrBox,
+ typename Tag = typename tag<Linear>::type
+>
+struct disjoint_linear_segment_or_box
+ : not_implemented<Linear, SegmentOrBox>
+{};
+
+
+template <typename Linestring, typename SegmentOrBox>
+struct disjoint_linear_segment_or_box<Linestring, SegmentOrBox, linestring_tag>
+ : disjoint_range_segment_or_box<Linestring, closed, SegmentOrBox>
+{};
+
+
+template <typename MultiLinestring, typename SegmentOrBox>
+struct disjoint_linear_segment_or_box
+ <
+ MultiLinestring, SegmentOrBox, multi_linestring_tag
+ > : disjoint_multirange_segment_or_box<MultiLinestring, SegmentOrBox>
+{};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear, typename Segment>
+struct disjoint<Linear, Segment, 2, linear_tag, segment_tag, false>
+ : detail::disjoint::disjoint_linear_segment_or_box<Linear, Segment>
+{};
+
+
+template <typename Linear, typename Box, std::size_t DimensionCount>
+struct disjoint<Linear, Box, DimensionCount, linear_tag, box_tag, false>
+ : detail::disjoint::disjoint_linear_segment_or_box<Linear, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp
new file mode 100644
index 0000000000..ea6609a153
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp
@@ -0,0 +1,94 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_POINT_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template
+<
+ typename Point, typename Box,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct point_box
+{
+ static inline bool apply(Point const& point, Box const& box)
+ {
+ if (get<Dimension>(point) < get<min_corner, Dimension>(box)
+ || get<Dimension>(point) > get<max_corner, Dimension>(box))
+ {
+ return true;
+ }
+ return point_box
+ <
+ Point, Box,
+ Dimension + 1, DimensionCount
+ >::apply(point, box);
+ }
+};
+
+
+template <typename Point, typename Box, std::size_t DimensionCount>
+struct point_box<Point, Box, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point const& , Box const& )
+ {
+ return false;
+ }
+};
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Point, typename Box, std::size_t DimensionCount>
+struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, false>
+ : detail::disjoint::point_box<Point, Box, 0, DimensionCount>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp
new file mode 100644
index 0000000000..a58bff41da
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/point_geometry.hpp
@@ -0,0 +1,111 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_POINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
+
+#include <boost/geometry/geometries/segment.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template<typename Point, typename Geometry>
+struct disjoint_point_linear
+{
+ static inline
+ bool apply(Point const& pt, Geometry const& g)
+ {
+ return !geometry::covered_by(pt, g);
+ }
+};
+
+
+template <typename Geometry1, typename Geometry2>
+struct reverse_covered_by
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ return !geometry::covered_by(geometry1, geometry2);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template<typename Point, typename Linear, std::size_t DimensionCount>
+struct disjoint<Point, Linear, DimensionCount, point_tag, linear_tag, false>
+ : public detail::disjoint::disjoint_point_linear<Point, Linear>
+{};
+
+
+template <typename Point, typename Areal, std::size_t DimensionCount>
+struct disjoint<Point, Areal, DimensionCount, point_tag, areal_tag, false>
+ : detail::disjoint::reverse_covered_by<Point, Areal>
+{};
+
+
+template<typename Point, typename Segment, std::size_t DimensionCount>
+struct disjoint<Point, Segment, DimensionCount, point_tag, segment_tag, false>
+{
+ static inline bool apply(Point const& point, Segment const& segment)
+ {
+ typedef geometry::model::referring_segment<Point const> other_segment;
+
+ other_segment other(point, point);
+ return detail::disjoint::disjoint_segment
+ <
+ Segment, other_segment
+ >::apply(segment, other);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_point.hpp b/boost/geometry/algorithms/detail/disjoint/point_point.hpp
new file mode 100644
index 0000000000..b1d32bf95e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/point_point.hpp
@@ -0,0 +1,112 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_POINT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+template
+<
+ typename Point1, typename Point2,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct point_point
+{
+ static inline bool apply(Point1 const& p1, Point2 const& p2)
+ {
+ if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
+ {
+ return true;
+ }
+ return point_point
+ <
+ Point1, Point2,
+ Dimension + 1, DimensionCount
+ >::apply(p1, p2);
+ }
+};
+
+
+template <typename Point1, typename Point2, std::size_t DimensionCount>
+struct point_point<Point1, Point2, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point1 const& , Point2 const& )
+ {
+ return false;
+ }
+};
+
+
+/*!
+ \brief Internal utility function to detect of points are disjoint
+ \note To avoid circular references
+ */
+template <typename Point1, typename Point2>
+inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
+{
+ return point_point
+ <
+ Point1, Point2,
+ 0, dimension<Point1>::type::value
+ >::apply(point1, point2);
+}
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Point1, typename Point2, std::size_t DimensionCount>
+struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false>
+ : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
new file mode 100644
index 0000000000..5368432ed4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
@@ -0,0 +1,291 @@
+// 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.
+// 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.
+
+// 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_DISJOINT_SEGMENT_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
+
+#include <cstddef>
+#include <utility>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/calculation_type.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template <std::size_t I>
+struct compute_tmin_tmax_per_dim
+{
+ template <typename SegmentPoint, typename Box, typename RelativeDistance>
+ static inline void apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ Box const& box,
+ RelativeDistance& ti_min,
+ RelativeDistance& ti_max,
+ RelativeDistance& diff)
+ {
+ typedef typename coordinate_type<Box>::type box_coordinate_type;
+ typedef typename coordinate_type
+ <
+ SegmentPoint
+ >::type point_coordinate_type;
+
+ RelativeDistance c_p0 = boost::numeric_cast
+ <
+ point_coordinate_type
+ >( geometry::get<I>(p0) );
+
+ RelativeDistance c_p1 = boost::numeric_cast
+ <
+ point_coordinate_type
+ >( geometry::get<I>(p1) );
+
+ RelativeDistance c_b_min = boost::numeric_cast
+ <
+ box_coordinate_type
+ >( geometry::get<geometry::min_corner, I>(box) );
+
+ RelativeDistance c_b_max = boost::numeric_cast
+ <
+ box_coordinate_type
+ >( geometry::get<geometry::max_corner, I>(box) );
+
+ if ( geometry::get<I>(p1) >= geometry::get<I>(p0) )
+ {
+ diff = c_p1 - c_p0;
+ ti_min = c_b_min - c_p0;
+ ti_max = c_b_max - c_p0;
+ }
+ else
+ {
+ diff = c_p0 - c_p1;
+ ti_min = c_p0 - c_b_max;
+ ti_max = c_p0 - c_b_min;
+ }
+ }
+};
+
+
+template
+<
+ typename RelativeDistance,
+ typename SegmentPoint,
+ typename Box,
+ std::size_t I,
+ std::size_t Dimension
+>
+struct disjoint_segment_box_impl
+{
+ template <typename RelativeDistancePair>
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ Box const& box,
+ RelativeDistancePair& t_min,
+ RelativeDistancePair& t_max)
+ {
+ RelativeDistance ti_min, ti_max, diff;
+
+ compute_tmin_tmax_per_dim<I>::apply(p0, p1, box, ti_min, ti_max, diff);
+
+ if ( geometry::math::equals(diff, 0) )
+ {
+ if ( (geometry::math::equals(t_min.second, 0)
+ && t_min.first > ti_max)
+ ||
+ (geometry::math::equals(t_max.second, 0)
+ && t_max.first < ti_min) )
+ {
+ return true;
+ }
+ }
+
+ RelativeDistance t_min_x_diff = t_min.first * diff;
+ RelativeDistance t_max_x_diff = t_max.first * diff;
+
+ if ( t_min_x_diff > ti_max * t_min.second
+ || t_max_x_diff < ti_min * t_max.second )
+ {
+ return true;
+ }
+
+ if ( ti_min * t_min.second > t_min_x_diff )
+ {
+ t_min.first = ti_min;
+ t_min.second = diff;
+ }
+ if ( ti_max * t_max.second < t_max_x_diff )
+ {
+ t_max.first = ti_max;
+ t_max.second = diff;
+ }
+
+ if ( t_min.first > t_min.second || t_max.first < 0 )
+ {
+ return true;
+ }
+
+ return disjoint_segment_box_impl
+ <
+ RelativeDistance,
+ SegmentPoint,
+ Box,
+ I + 1,
+ Dimension
+ >::apply(p0, p1, box, t_min, t_max);
+ }
+};
+
+
+template
+<
+ typename RelativeDistance,
+ typename SegmentPoint,
+ typename Box,
+ std::size_t Dimension
+>
+struct disjoint_segment_box_impl
+ <
+ RelativeDistance, SegmentPoint, Box, 0, Dimension
+ >
+{
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ Box const& box)
+ {
+ std::pair<RelativeDistance, RelativeDistance> t_min, t_max;
+ RelativeDistance diff;
+
+ compute_tmin_tmax_per_dim<0>::apply(p0, p1, box,
+ t_min.first, t_max.first, diff);
+
+ if ( geometry::math::equals(diff, 0) )
+ {
+ if ( geometry::math::equals(t_min.first, 0) ) { t_min.first = -1; }
+ if ( geometry::math::equals(t_max.first, 0) ) { t_max.first = 1; }
+ }
+
+ if ( t_min.first > diff || t_max.first < 0 )
+ {
+ return true;
+ }
+
+ t_min.second = t_max.second = diff;
+
+ return disjoint_segment_box_impl
+ <
+ RelativeDistance, SegmentPoint, Box, 1, Dimension
+ >::apply(p0, p1, box, t_min, t_max);
+ }
+};
+
+
+template
+<
+ typename RelativeDistance,
+ typename SegmentPoint,
+ typename Box,
+ std::size_t Dimension
+>
+struct disjoint_segment_box_impl
+ <
+ RelativeDistance, SegmentPoint, Box, Dimension, Dimension
+ >
+{
+ template <typename RelativeDistancePair>
+ static inline bool apply(SegmentPoint const&, SegmentPoint const&,
+ Box const&,
+ RelativeDistancePair&, RelativeDistancePair&)
+ {
+ return false;
+ }
+};
+
+
+//=========================================================================
+
+
+template <typename Segment, typename Box>
+struct disjoint_segment_box
+{
+ static inline bool apply(Segment const& segment, Box const& box)
+ {
+ assert_dimension_equal<Segment, Box>();
+
+ typedef typename util::calculation_type::geometric::binary
+ <
+ Segment, Box, void
+ >::type relative_distance_type;
+
+ typedef typename point_type<Segment>::type segment_point_type;
+ segment_point_type p0, p1;
+ geometry::detail::assign_point_from_index<0>(segment, p0);
+ geometry::detail::assign_point_from_index<1>(segment, p1);
+
+ return disjoint_segment_box_impl
+ <
+ relative_distance_type, segment_point_type, Box,
+ 0, dimension<Box>::value
+ >::apply(p0, p1, box);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+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<Segment, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp b/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp
new file mode 100644
index 0000000000..5b49e571dd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/backward_compatibility.hpp
@@ -0,0 +1,333 @@
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_DISTANCE_BACKWARD_COMPATIBILITY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
+#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template<typename Point, typename Segment, typename Strategy>
+struct point_to_segment
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename point_type<Segment>::type
+ >::type
+ apply(Point const& point, Segment const& segment, Strategy const& )
+ {
+ typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Segment>::type,
+ Strategy
+ >::type segment_strategy;
+
+ typename point_type<Segment>::type p[2];
+ geometry::detail::assign_point_from_index<0>(segment, p[0]);
+ geometry::detail::assign_point_from_index<1>(segment, p[1]);
+ return segment_strategy.apply(point, p[0], p[1]);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Point-segment version 1, with point-point strategy
+template <typename Point, typename Segment, typename Strategy>
+struct distance
+<
+ Point, Segment, Strategy,
+ point_tag, segment_tag, strategy_tag_distance_point_point,
+ false
+> : detail::distance::point_to_segment<Point, Segment, Strategy>
+{};
+
+
+// Point-line version 1, where point-point strategy is specified
+template <typename Point, typename Linestring, typename Strategy>
+struct distance
+<
+ Point, Linestring, Strategy,
+ point_tag, linestring_tag, strategy_tag_distance_point_point,
+ false
+>
+{
+
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Linestring>::type
+ >::type
+ apply(Point const& point,
+ Linestring const& linestring,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Linestring>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return detail::distance::point_to_range
+ <
+ Point, Linestring, closed, ps_strategy_type
+ >::apply(point, linestring, ps_strategy_type());
+ }
+};
+
+
+// Point-ring , where point-point strategy is specified
+template <typename Point, typename Ring, typename Strategy>
+struct distance
+<
+ Point, Ring, Strategy,
+ point_tag, ring_tag, strategy_tag_distance_point_point,
+ false
+>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Ring>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ Ring const& ring,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Ring>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return detail::distance::point_to_ring
+ <
+ Point, Ring,
+ geometry::closure<Ring>::value,
+ ps_strategy_type
+ >::apply(point, ring, ps_strategy_type());
+ }
+};
+
+
+// Point-polygon , where point-point strategy is specified
+template <typename Point, typename Polygon, typename Strategy>
+struct distance
+<
+ Point, Polygon, Strategy,
+ point_tag, polygon_tag, strategy_tag_distance_point_point,
+ false
+>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Polygon>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ Polygon const& polygon,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<Polygon>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return detail::distance::point_to_polygon
+ <
+ Point,
+ Polygon,
+ geometry::closure<Polygon>::value,
+ ps_strategy_type
+ >::apply(point, polygon, ps_strategy_type());
+ }
+};
+
+
+
+
+template
+<
+ typename Point,
+ typename MultiGeometry,
+ typename MultiGeometryTag,
+ typename Strategy
+>
+struct distance
+ <
+ Point, MultiGeometry, Strategy,
+ point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_point, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<MultiGeometry>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ MultiGeometry const& multigeometry,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ Point,
+ typename point_type<MultiGeometry>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return distance
+ <
+ Point, MultiGeometry, ps_strategy_type,
+ point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_segment, false
+ >::apply(point, multigeometry, ps_strategy_type());
+ }
+};
+
+
+template
+<
+ typename Geometry,
+ typename MultiPoint,
+ typename GeometryTag,
+ typename Strategy
+>
+struct distance
+ <
+ Geometry, MultiPoint, Strategy,
+ GeometryTag, multi_point_tag,
+ strategy_tag_distance_point_point, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<Geometry>::type
+ >::type return_type;
+
+ static inline return_type apply(Geometry const& geometry,
+ MultiPoint const& multipoint,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ typename point_type<MultiPoint>::type,
+ typename point_type<Geometry>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return distance
+ <
+ Geometry, MultiPoint, ps_strategy_type,
+ GeometryTag, multi_point_tag,
+ strategy_tag_distance_point_segment, false
+ >::apply(geometry, multipoint, ps_strategy_type());
+ }
+};
+
+
+template
+<
+ typename MultiPoint,
+ typename MultiGeometry,
+ typename MultiGeometryTag,
+ typename Strategy
+>
+struct distance
+ <
+ MultiPoint, MultiGeometry, Strategy,
+ multi_point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_point, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<MultiGeometry>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ MultiGeometry const& multigeometry,
+ Strategy const&)
+ {
+ typedef typename detail::distance::default_ps_strategy
+ <
+ typename point_type<MultiPoint>::type,
+ typename point_type<MultiGeometry>::type,
+ Strategy
+ >::type ps_strategy_type;
+
+ return distance
+ <
+ MultiPoint, MultiGeometry, ps_strategy_type,
+ multi_point_tag, MultiGeometryTag,
+ strategy_tag_distance_point_segment, false
+ >::apply(multipoint, multigeometry, ps_strategy_type());
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP
diff --git a/boost/geometry/algorithms/detail/distance/box_to_box.hpp b/boost/geometry/algorithms/detail/distance/box_to_box.hpp
new file mode 100644
index 0000000000..44778e9e06
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/box_to_box.hpp
@@ -0,0 +1,60 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Box1, typename Box2, typename Strategy>
+struct distance
+ <
+ Box1, Box2, Strategy, box_tag, box_tag,
+ strategy_tag_distance_box_box, false
+ >
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type
+ >::type
+ apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ boost::ignore_unused(strategy);
+ return strategy.apply(box1, box2);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/default_strategies.hpp b/boost/geometry/algorithms/detail/distance/default_strategies.hpp
new file mode 100644
index 0000000000..a01ace2b58
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/default_strategies.hpp
@@ -0,0 +1,137 @@
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_DISTANCE_DEFAULT_STRATEGIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+
+// Helper metafunction for default strategy retrieval
+template
+<
+ typename Geometry1,
+ typename Geometry2 = Geometry1,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type, pointlike_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type, pointlike_tag
+ >::type,
+ bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct default_strategy
+ : strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag,
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type
+ >
+{};
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1,
+ typename Tag2
+>
+struct default_strategy<Geometry1, Geometry2, Tag1, Tag2, true>
+ : default_strategy<Geometry2, Geometry1, Tag2, Tag1, false>
+{};
+
+
+template <typename Pointlike1, typename Pointlike2>
+struct default_strategy
+ <
+ Pointlike1, Pointlike2,
+ pointlike_tag, pointlike_tag, false
+ > : strategy::distance::services::default_strategy
+ <
+ point_tag, point_tag,
+ typename point_type<Pointlike1>::type,
+ typename point_type<Pointlike2>::type
+ >
+{};
+
+
+template <typename Pointlike, typename Box>
+struct default_strategy<Pointlike, Box, pointlike_tag, box_tag, false>
+ : strategy::distance::services::default_strategy
+ <
+ point_tag, box_tag,
+ typename point_type<Pointlike>::type,
+ typename point_type<Box>::type
+ >
+{};
+
+
+template <typename Box1, typename Box2>
+struct default_strategy<Box1, Box2, box_tag, box_tag, false>
+ : strategy::distance::services::default_strategy
+ <
+ box_tag, box_tag,
+ typename point_type<Box1>::type,
+ typename point_type<Box2>::type
+ >
+{};
+
+
+
+// Helper metafunction for default point-segment strategy retrieval
+template <typename Geometry1, typename Geometry2, typename Strategy>
+struct default_ps_strategy
+ : strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag,
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type,
+ typename cs_tag<typename point_type<Geometry1>::type>::type,
+ typename cs_tag<typename point_type<Geometry2>::type>::type,
+ Strategy
+ >
+{};
+
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP
diff --git a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
new file mode 100644
index 0000000000..04d1095cba
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
@@ -0,0 +1,462 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
+
+#include <iterator>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+#include <boost/geometry/iterators/segment_iterator.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
+#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+// closure of segment or box point range
+template
+<
+ typename SegmentOrBox,
+ typename Tag = typename tag<SegmentOrBox>::type
+>
+struct segment_or_box_point_range_closure
+ : not_implemented<SegmentOrBox>
+{};
+
+template <typename Segment>
+struct segment_or_box_point_range_closure<Segment, segment_tag>
+{
+ static const closure_selector value = closed;
+};
+
+template <typename Box>
+struct segment_or_box_point_range_closure<Box, box_tag>
+{
+ static const closure_selector value = open;
+};
+
+
+
+template
+<
+ typename Geometry,
+ typename SegmentOrBox,
+ typename Strategy,
+ typename Tag = typename tag<Geometry>::type
+>
+class geometry_to_segment_or_box
+{
+private:
+ typedef typename point_type<SegmentOrBox>::type segment_or_box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef detail::closest_feature::point_to_point_range
+ <
+ typename point_type<Geometry>::type,
+ std::vector<segment_or_box_point>,
+ segment_or_box_point_range_closure<SegmentOrBox>::value,
+ comparable_strategy
+ > point_to_point_range;
+
+ typedef detail::closest_feature::geometry_to_range geometry_to_range;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy,
+ typename point_type<Geometry>::type,
+ segment_or_box_point
+ >::type comparable_return_type;
+
+
+ // assign the new minimum value for an iterator of the point range
+ // of a segment or a box
+ template
+ <
+ typename SegOrBox,
+ typename SegOrBoxTag = typename tag<SegOrBox>::type
+ >
+ struct assign_new_min_iterator
+ : not_implemented<SegOrBox>
+ {};
+
+ template <typename Segment>
+ struct assign_new_min_iterator<Segment, segment_tag>
+ {
+ template <typename Iterator>
+ static inline void apply(Iterator&, Iterator)
+ {
+ }
+ };
+
+ template <typename Box>
+ struct assign_new_min_iterator<Box, box_tag>
+ {
+ template <typename Iterator>
+ static inline void apply(Iterator& it_min, Iterator it)
+ {
+ it_min = it;
+ }
+ };
+
+
+ // assign the points of a segment or a box to a range
+ template
+ <
+ typename SegOrBox,
+ typename PointRange,
+ typename SegOrBoxTag = typename tag<SegOrBox>::type
+ >
+ struct assign_segment_or_box_points
+ {};
+
+ template <typename Segment, typename PointRange>
+ struct assign_segment_or_box_points<Segment, PointRange, segment_tag>
+ {
+ static inline void apply(Segment const& segment, PointRange& range)
+ {
+ detail::assign_point_from_index<0>(segment, range[0]);
+ detail::assign_point_from_index<1>(segment, range[1]);
+ }
+ };
+
+ template <typename Box, typename PointRange>
+ struct assign_segment_or_box_points<Box, PointRange, box_tag>
+ {
+ static inline void apply(Box const& box, PointRange& range)
+ {
+ detail::assign_box_corners_oriented<true>(box, range);
+ }
+ };
+
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry>::type,
+ segment_or_box_point
+ >::type return_type;
+
+ static inline return_type apply(Geometry const& geometry,
+ SegmentOrBox const& segment_or_box,
+ Strategy const& strategy,
+ bool check_intersection = true)
+ {
+ typedef geometry::point_iterator<Geometry const> point_iterator_type;
+ typedef geometry::segment_iterator
+ <
+ Geometry const
+ > segment_iterator_type;
+
+ typedef typename std::vector
+ <
+ segment_or_box_point
+ >::const_iterator seg_or_box_iterator_type;
+
+ typedef assign_new_min_iterator<SegmentOrBox> assign_new_value;
+
+
+ if (check_intersection
+ && geometry::intersects(geometry, segment_or_box))
+ {
+ return 0;
+ }
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+
+ // get all points of the segment or the box
+ std::vector<segment_or_box_point>
+ seg_or_box_points(geometry::num_points(segment_or_box));
+
+ assign_segment_or_box_points
+ <
+ SegmentOrBox,
+ std::vector<segment_or_box_point>
+ >::apply(segment_or_box, seg_or_box_points);
+
+ // consider all distances of the points in the geometry to the
+ // segment or box
+ comparable_return_type cd_min1;
+ point_iterator_type pit_min;
+ seg_or_box_iterator_type it_min1 = seg_or_box_points.begin();
+ seg_or_box_iterator_type it_min2 = ++seg_or_box_points.begin();
+ bool first = true;
+
+ for (point_iterator_type pit = points_begin(geometry);
+ pit != points_end(geometry); ++pit, first = false)
+ {
+ comparable_return_type cd;
+ std::pair
+ <
+ seg_or_box_iterator_type, seg_or_box_iterator_type
+ > it_pair
+ = point_to_point_range::apply(*pit,
+ seg_or_box_points.begin(),
+ seg_or_box_points.end(),
+ cstrategy,
+ cd);
+
+ if (first || cd < cd_min1)
+ {
+ cd_min1 = cd;
+ pit_min = pit;
+ assign_new_value::apply(it_min1, it_pair.first);
+ assign_new_value::apply(it_min2, it_pair.second);
+ }
+ }
+
+ // consider all distances of the points in the segment or box to the
+ // segments of the geometry
+ comparable_return_type cd_min2;
+ segment_iterator_type sit_min;
+ typename std::vector<segment_or_box_point>::const_iterator it_min;
+
+ first = true;
+ for (typename std::vector<segment_or_box_point>::const_iterator it
+ = seg_or_box_points.begin();
+ it != seg_or_box_points.end(); ++it, first = false)
+ {
+ comparable_return_type cd;
+ segment_iterator_type sit
+ = geometry_to_range::apply(*it,
+ segments_begin(geometry),
+ segments_end(geometry),
+ cstrategy,
+ cd);
+
+ if (first || cd < cd_min2)
+ {
+ cd_min2 = cd;
+ it_min = it;
+ sit_min = sit;
+ }
+ }
+
+ if (is_comparable<Strategy>::value)
+ {
+ return (std::min)(cd_min1, cd_min2);
+ }
+
+ if (cd_min1 < cd_min2)
+ {
+ return strategy.apply(*pit_min, *it_min1, *it_min2);
+ }
+ else
+ {
+ return dispatch::distance
+ <
+ segment_or_box_point,
+ typename std::iterator_traits
+ <
+ segment_iterator_type
+ >::value_type,
+ Strategy
+ >::apply(*it_min, *sit_min, strategy);
+ }
+ }
+
+
+ static inline return_type
+ apply(SegmentOrBox const& segment_or_box, Geometry const& geometry,
+ Strategy const& strategy, bool check_intersection = true)
+ {
+ return apply(geometry, segment_or_box, strategy, check_intersection);
+ }
+};
+
+
+
+template <typename MultiPoint, typename SegmentOrBox, typename Strategy>
+class geometry_to_segment_or_box
+ <
+ MultiPoint, SegmentOrBox, Strategy, multi_point_tag
+ >
+{
+private:
+ typedef detail::closest_feature::geometry_to_range base_type;
+
+ typedef typename boost::range_iterator
+ <
+ MultiPoint const
+ >::type iterator_type;
+
+ typedef detail::closest_feature::geometry_to_range geometry_to_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<SegmentOrBox>::type,
+ typename point_type<MultiPoint>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ SegmentOrBox const& segment_or_box,
+ Strategy const& strategy)
+ {
+ namespace sds = strategy::distance::services;
+
+ typename sds::return_type
+ <
+ typename sds::comparable_type<Strategy>::type,
+ typename point_type<SegmentOrBox>::type,
+ typename point_type<MultiPoint>::type
+ >::type cd_min;
+
+ iterator_type it_min
+ = geometry_to_range::apply(segment_or_box,
+ boost::begin(multipoint),
+ boost::end(multipoint),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd_min);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd_min
+ :
+ dispatch::distance
+ <
+ typename point_type<MultiPoint>::type,
+ SegmentOrBox,
+ Strategy
+ >::apply(*it_min, segment_or_box, strategy);
+ }
+};
+
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Linear, typename Segment, typename Strategy>
+struct distance
+ <
+ Linear, Segment, Strategy, linear_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy>
+{};
+
+
+template <typename Areal, typename Segment, typename Strategy>
+struct distance
+ <
+ Areal, Segment, Strategy, areal_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy>
+{};
+
+
+template <typename Segment, typename Areal, typename Strategy>
+struct distance
+ <
+ Segment, Areal, Strategy, segment_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy>
+{};
+
+
+template <typename Linear, typename Box, typename Strategy>
+struct distance
+ <
+ Linear, Box, Strategy, linear_tag, box_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box
+ <
+ Linear, Box, Strategy
+ >
+{};
+
+
+template <typename Areal, typename Box, typename Strategy>
+struct distance
+ <
+ Areal, Box, Strategy, areal_tag, box_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy>
+{};
+
+
+template <typename MultiPoint, typename Segment, typename Strategy>
+struct distance
+ <
+ MultiPoint, Segment, Strategy,
+ multi_point_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::geometry_to_segment_or_box
+ <
+ MultiPoint, Segment, Strategy
+ >
+{};
+
+
+template <typename MultiPoint, typename Box, typename Strategy>
+struct distance
+ <
+ MultiPoint, Box, Strategy,
+ multi_point_tag, box_tag,
+ strategy_tag_distance_point_box, false
+ > : detail::distance::geometry_to_segment_or_box
+ <
+ MultiPoint, Box, Strategy
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/implementation.hpp b/boost/geometry/algorithms/detail/distance/implementation.hpp
new file mode 100644
index 0000000000..7c009f4d79
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/implementation.hpp
@@ -0,0 +1,35 @@
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_DISTANCE_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP
+
+// the implementation details
+#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
+#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp>
+#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
+#include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp>
+#include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp>
+#include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp>
+#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
+#include <boost/geometry/algorithms/detail/distance/box_to_box.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/backward_compatibility.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp
new file mode 100644
index 0000000000..9b377f524b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/interface.hpp
@@ -0,0 +1,403 @@
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_DISTANCE_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
+
+#include <boost/concept_check.hpp>
+
+#include <boost/mpl/always.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/vector.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/default_distance_result.hpp>
+#include <boost/geometry/strategies/distance_result.hpp>
+
+#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2, typename Strategy,
+ typename Tag1, typename Tag2, typename StrategyTag
+>
+struct distance
+<
+ Geometry1, Geometry2, Strategy,
+ Tag1, Tag2, StrategyTag,
+ true
+>
+ : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Geometry2>::type,
+ typename point_type<Geometry1>::type
+ >::type return_type;
+
+ static inline return_type apply(
+ Geometry1 const& g1,
+ Geometry2 const& g2,
+ Strategy const& strategy)
+ {
+ return distance
+ <
+ Geometry2, Geometry1, Strategy,
+ Tag2, Tag1, StrategyTag,
+ false
+ >::apply(g2, g1, strategy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct distance
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, Strategy
+ >::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline
+ typename distance_result<Geometry1, Geometry2, default_strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type strategy_type;
+
+ return dispatch::distance
+ <
+ Geometry1, Geometry2, strategy_type
+ >::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+
+template <typename Geometry1, typename Geometry2>
+struct distance
+{
+ template <typename Strategy>
+ static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
+ apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return
+ resolve_strategy::distance::apply(geometry1, geometry2, strategy);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename distance_result
+ <
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ >
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2,
+ Strategy const& strategy)
+ : m_geometry2(geometry2),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ typename distance_result<Geometry1, Geometry2, Strategy>::type
+ operator()(Geometry1 const& geometry1) const
+ {
+ return distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename distance_result
+ <
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Geometry2,
+ Strategy
+ >::type
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename distance_result
+ <
+ Geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ >
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1,
+ Strategy const& strategy)
+ : m_geometry1(geometry1),
+ m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ typename distance_result<Geometry1, Geometry2, Strategy>::type
+ operator()(Geometry2 const& geometry2) const
+ {
+ return distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename distance_result
+ <
+ Geometry1,
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
+ Strategy
+ >::type
+ apply(
+ Geometry1 const& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+
+template
+<
+ BOOST_VARIANT_ENUM_PARAMS(typename A),
+ BOOST_VARIANT_ENUM_PARAMS(typename B)
+>
+struct distance
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>
+ >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor
+ <
+ typename distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ >
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ typename distance_result<Geometry1, Geometry2, Strategy>::type
+ operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const
+ {
+ return distance
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ Strategy
+ >(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline typename distance_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ Strategy
+ >::type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_calc2{distance} \brief_strategy
+\ingroup distance
+\details
+\details \details_calc{area}. \brief_strategy. \details_strategy_reasons
+
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Distance}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{distance}
+\return \return_calc{distance}
+\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
+ it may also be a point-segment strategy.
+
+\qbk{distinguish,with strategy}
+
+\qbk{
+[heading Available Strategies]
+\* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
+\* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
+\* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
+\* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
+\* more (currently extensions): Vincenty\, Andoyer (geographic)
+}
+ */
+
+/*
+Note, in case of a Compilation Error:
+if you get:
+ - "Failed to specialize function template ..."
+ - "error: no matching function for call to ..."
+for distance, it is probably so that there is no specialization
+for return_type<...> for your strategy.
+*/
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline typename distance_result<Geometry1, Geometry2, Strategy>::type
+distance(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ detail::throw_on_empty_input(geometry1);
+ detail::throw_on_empty_input(geometry2);
+
+ return resolve_variant::distance
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+/*!
+\brief \brief_calc2{distance}
+\ingroup distance
+\details The default strategy is used, corresponding to the coordinate system of the geometries
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_calc{distance}
+
+\qbk{[include reference/algorithms/distance.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline typename default_distance_result<Geometry1, Geometry2>::type
+distance(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return distance(geometry1, geometry2, default_strategy());
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/distance/is_comparable.hpp b/boost/geometry/algorithms/detail/distance/is_comparable.hpp
new file mode 100644
index 0000000000..d13cc6c740
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/is_comparable.hpp
@@ -0,0 +1,45 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
+#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
+
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+// metafunction to determine is a strategy is comparable or not
+template <typename Strategy>
+struct is_comparable
+ : boost::is_same
+ <
+ Strategy,
+ typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type
+ >
+{};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
diff --git a/boost/geometry/algorithms/detail/distance/iterator_selector.hpp b/boost/geometry/algorithms/detail/distance/iterator_selector.hpp
new file mode 100644
index 0000000000..363ec465a4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/iterator_selector.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
+#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+#include <boost/geometry/iterators/segment_iterator.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+// class to choose between point_iterator and segment_iterator
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct iterator_selector
+{
+ typedef geometry::segment_iterator<Geometry> iterator_type;
+
+ static inline iterator_type begin(Geometry& geometry)
+ {
+ return segments_begin(geometry);
+ }
+
+ static inline iterator_type end(Geometry& geometry)
+ {
+ return segments_end(geometry);
+ }
+};
+
+template <typename MultiPoint>
+struct iterator_selector<MultiPoint, multi_point_tag>
+{
+ typedef geometry::point_iterator<MultiPoint> iterator_type;
+
+ static inline iterator_type begin(MultiPoint& multipoint)
+ {
+ return points_begin(multipoint);
+ }
+
+ static inline iterator_type end(MultiPoint& multipoint)
+ {
+ return points_end(multipoint);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
diff --git a/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp
new file mode 100644
index 0000000000..b63104da7d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp
@@ -0,0 +1,147 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename Linear, typename Areal, typename Strategy>
+struct linear_to_areal
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Linear>::type,
+ typename point_type<Areal>::type
+ >::type return_type;
+
+ static inline return_type apply(Linear const& linear,
+ Areal const& areal,
+ Strategy const& strategy)
+ {
+ if ( geometry::intersects(linear, areal) )
+ {
+ return 0;
+ }
+
+ return linear_to_linear
+ <
+ Linear, Areal, Strategy
+ >::apply(linear, areal, strategy, false);
+ }
+
+
+ static inline return_type apply(Areal const& areal,
+ Linear const& linear,
+ Strategy const& strategy)
+ {
+ return apply(linear, areal, strategy);
+ }
+};
+
+
+template <typename Areal1, typename Areal2, typename Strategy>
+struct areal_to_areal
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Areal1>::type,
+ typename point_type<Areal2>::type
+ >::type return_type;
+
+ static inline return_type apply(Areal1 const& areal1,
+ Areal2 const& areal2,
+ Strategy const& strategy)
+ {
+ if ( geometry::intersects(areal1, areal2) )
+ {
+ return 0;
+ }
+
+ return linear_to_linear
+ <
+ Areal1, Areal2, Strategy
+ >::apply(areal1, areal2, strategy, false);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Linear, typename Areal, typename Strategy>
+struct distance
+ <
+ Linear, Areal, Strategy,
+ linear_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::linear_to_areal
+ <
+ Linear, Areal, Strategy
+ >
+{};
+
+
+template <typename Areal, typename Linear, typename Strategy>
+struct distance
+ <
+ Areal, Linear, Strategy,
+ areal_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::linear_to_areal
+ <
+ Linear, Areal, Strategy
+ >
+{};
+
+
+template <typename Areal1, typename Areal2, typename Strategy>
+struct distance
+ <
+ Areal1, Areal2, Strategy,
+ areal_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::areal_to_areal
+ <
+ Areal1, Areal2, Strategy
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp
new file mode 100644
index 0000000000..e44b372842
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/linear_to_linear.hpp
@@ -0,0 +1,123 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+#include <boost/geometry/iterators/segment_iterator.hpp>
+
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/num_segments.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename Linear1, typename Linear2, typename Strategy>
+struct linear_to_linear
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Linear1>::type,
+ typename point_type<Linear2>::type
+ >::type return_type;
+
+ static inline return_type apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ Strategy const& strategy,
+ bool = false)
+ {
+ if (geometry::num_points(linear1) == 1)
+ {
+ return dispatch::distance
+ <
+ typename point_type<Linear1>::type,
+ Linear2,
+ Strategy
+ >::apply(*points_begin(linear1), linear2, strategy);
+ }
+
+ if (geometry::num_points(linear2) == 1)
+ {
+ return dispatch::distance
+ <
+ typename point_type<Linear2>::type,
+ Linear1,
+ Strategy
+ >::apply(*points_begin(linear2), linear1, strategy);
+ }
+
+ if (geometry::num_segments(linear2) < geometry::num_segments(linear1))
+ {
+ return point_or_segment_range_to_geometry_rtree
+ <
+ geometry::segment_iterator<Linear2 const>,
+ Linear1,
+ Strategy
+ >::apply(geometry::segments_begin(linear2),
+ geometry::segments_end(linear2),
+ linear1,
+ strategy);
+
+ }
+
+ return point_or_segment_range_to_geometry_rtree
+ <
+ geometry::segment_iterator<Linear1 const>,
+ Linear2,
+ Strategy
+ >::apply(geometry::segments_begin(linear1),
+ geometry::segments_end(linear1),
+ linear2,
+ strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Linear1, typename Linear2, typename Strategy>
+struct distance
+ <
+ Linear1, Linear2, Strategy,
+ linear_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::linear_to_linear
+ <
+ Linear1, Linear2, Strategy
+ >
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
new file mode 100644
index 0000000000..5f2c6e34fb
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
@@ -0,0 +1,240 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
+struct multipoint_to_multipoint
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint1>::type,
+ typename point_type<MultiPoint2>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2,
+ Strategy const& strategy)
+ {
+ if (boost::size(multipoint2) < boost::size(multipoint1))
+
+ {
+ return point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint2 const>::type,
+ MultiPoint1,
+ Strategy
+ >::apply(boost::begin(multipoint2),
+ boost::end(multipoint2),
+ multipoint1,
+ strategy);
+ }
+
+ return point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint1 const>::type,
+ MultiPoint2,
+ Strategy
+ >::apply(boost::begin(multipoint1),
+ boost::end(multipoint1),
+ multipoint2,
+ strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename Linear, typename Strategy>
+struct multipoint_to_linear
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<Linear>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ Linear const& linear,
+ Strategy const& strategy)
+ {
+ return detail::distance::point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint const>::type,
+ Linear,
+ Strategy
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ linear,
+ strategy);
+ }
+
+ static inline return_type apply(Linear const& linear,
+ MultiPoint const& multipoint,
+ Strategy const& strategy)
+ {
+ return apply(multipoint, linear, strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename Areal, typename Strategy>
+class multipoint_to_areal
+{
+private:
+ struct within_areal
+ {
+ within_areal(Areal const& areal)
+ : m_areal(areal)
+ {}
+
+ template <typename Point>
+ inline bool apply(Point const& point) const
+ {
+ return geometry::within(point, m_areal);
+ }
+
+ Areal const& m_areal;
+ };
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<MultiPoint>::type,
+ typename point_type<Areal>::type
+ >::type return_type;
+
+ static inline return_type apply(MultiPoint const& multipoint,
+ Areal const& areal,
+ Strategy const& strategy)
+ {
+ within_areal predicate(areal);
+
+ if (check_iterator_range
+ <
+ within_areal, false
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ predicate))
+ {
+ return 0;
+ }
+
+ return detail::distance::point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint const>::type,
+ Areal,
+ Strategy
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ areal,
+ strategy);
+ }
+
+ static inline return_type apply(Areal const& areal,
+ MultiPoint const& multipoint,
+ Strategy const& strategy)
+ {
+ return apply(multipoint, areal, strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
+struct distance
+ <
+ MultiPoint1, MultiPoint2, Strategy,
+ multi_point_tag, multi_point_tag,
+ strategy_tag_distance_point_point, false
+ > : detail::distance::multipoint_to_multipoint
+ <
+ MultiPoint1, MultiPoint2, Strategy
+ >
+{};
+
+template <typename MultiPoint, typename Linear, typename Strategy>
+struct distance
+ <
+ MultiPoint, Linear, Strategy, multi_point_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy>
+{};
+
+
+template <typename Linear, typename MultiPoint, typename Strategy>
+struct distance
+ <
+ Linear, MultiPoint, Strategy, linear_tag, multi_point_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy>
+{};
+
+
+template <typename MultiPoint, typename Areal, typename Strategy>
+struct distance
+ <
+ MultiPoint, Areal, Strategy, multi_point_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy>
+{};
+
+
+template <typename Areal, typename MultiPoint, typename Strategy>
+struct distance
+ <
+ Areal, MultiPoint, Strategy, areal_tag, multi_point_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
new file mode 100644
index 0000000000..ab5de3d9b2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
@@ -0,0 +1,518 @@
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_DISTANCE_POINT_TO_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
+
+#include <iterator>
+
+#include <boost/core/ignore_unused.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
+#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template <typename P1, typename P2, typename Strategy>
+struct point_to_point
+{
+ static inline
+ typename strategy::distance::services::return_type<Strategy, P1, P2>::type
+ apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
+ {
+ boost::ignore_unused(strategy);
+ return strategy.apply(p1, p2);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename Range,
+ closure_selector Closure,
+ typename Strategy
+>
+class point_to_range
+{
+private:
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef detail::closest_feature::point_to_point_range
+ <
+ Point, Range, Closure, comparable_strategy
+ > point_to_point_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename boost::range_value<Range>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point, Range const& range,
+ Strategy const& strategy)
+ {
+ return_type const zero = return_type(0);
+
+ if (boost::size(range) == 0)
+ {
+ return zero;
+ }
+
+ namespace sds = strategy::distance::services;
+
+ typename sds::return_type
+ <
+ comparable_strategy,
+ Point,
+ typename point_type<Range>::type
+ >::type cd_min;
+
+ std::pair
+ <
+ typename boost::range_iterator<Range const>::type,
+ typename boost::range_iterator<Range const>::type
+ > it_pair
+ = point_to_point_range::apply(point,
+ boost::begin(range),
+ boost::end(range),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd_min);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd_min
+ :
+ strategy.apply(point, *it_pair.first, *it_pair.second);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename Ring,
+ closure_selector Closure,
+ typename Strategy
+>
+struct point_to_ring
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Ring>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ Ring const& ring,
+ Strategy const& strategy)
+ {
+ if (geometry::within(point, ring))
+ {
+ return return_type(0);
+ }
+
+ return point_to_range
+ <
+ Point, Ring, closure<Ring>::value, Strategy
+ >::apply(point, ring, strategy);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename Polygon,
+ closure_selector Closure,
+ typename Strategy
+>
+class point_to_polygon
+{
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Polygon>::type
+ >::type return_type;
+
+private:
+ typedef point_to_range
+ <
+ Point, typename ring_type<Polygon>::type, Closure, Strategy
+ > per_ring;
+
+ struct distance_to_interior_rings
+ {
+ template <typename InteriorRingIterator>
+ static inline return_type apply(Point const& point,
+ InteriorRingIterator first,
+ InteriorRingIterator last,
+ Strategy const& strategy)
+ {
+ for (InteriorRingIterator it = first; it != last; ++it)
+ {
+ if (geometry::within(point, *it))
+ {
+ // the point is inside a polygon hole, so its distance
+ // to the polygon its distance to the polygon's
+ // hole boundary
+ return per_ring::apply(point, *it, strategy);
+ }
+ }
+ return 0;
+ }
+
+ template <typename InteriorRings>
+ static inline return_type apply(Point const& point,
+ InteriorRings const& interior_rings,
+ Strategy const& strategy)
+ {
+ return apply(point,
+ boost::begin(interior_rings),
+ boost::end(interior_rings),
+ strategy);
+ }
+ };
+
+
+public:
+ static inline return_type apply(Point const& point,
+ Polygon const& polygon,
+ Strategy const& strategy)
+ {
+ if (!geometry::covered_by(point, exterior_ring(polygon)))
+ {
+ // the point is outside the exterior ring, so its distance
+ // to the polygon is its distance to the polygon's exterior ring
+ return per_ring::apply(point, exterior_ring(polygon), strategy);
+ }
+
+ // Check interior rings
+ return distance_to_interior_rings::apply(point,
+ interior_rings(polygon),
+ strategy);
+ }
+};
+
+
+template
+<
+ typename Point,
+ typename MultiGeometry,
+ typename Strategy,
+ bool CheckCoveredBy = boost::is_same
+ <
+ typename tag<MultiGeometry>::type, multi_polygon_tag
+ >::value
+>
+class point_to_multigeometry
+{
+private:
+ typedef detail::closest_feature::geometry_to_range geometry_to_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename point_type<MultiGeometry>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ MultiGeometry const& multigeometry,
+ Strategy const& strategy)
+ {
+ typedef iterator_selector<MultiGeometry const> selector_type;
+
+ namespace sds = strategy::distance::services;
+
+ typename sds::return_type
+ <
+ typename sds::comparable_type<Strategy>::type,
+ Point,
+ typename point_type<MultiGeometry>::type
+ >::type cd;
+
+ typename selector_type::iterator_type it_min
+ = geometry_to_range::apply(point,
+ selector_type::begin(multigeometry),
+ selector_type::end(multigeometry),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd
+ :
+ dispatch::distance
+ <
+ Point,
+ typename std::iterator_traits
+ <
+ typename selector_type::iterator_type
+ >::value_type,
+ Strategy
+ >::apply(point, *it_min, strategy);
+ }
+};
+
+
+// this is called only for multipolygons, hence the change in the
+// template parameter name MultiGeometry to MultiPolygon
+template <typename Point, typename MultiPolygon, typename Strategy>
+struct point_to_multigeometry<Point, MultiPolygon, Strategy, true>
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ Point,
+ typename point_type<MultiPolygon>::type
+ >::type return_type;
+
+ static inline return_type apply(Point const& point,
+ MultiPolygon const& multipolygon,
+ Strategy const& strategy)
+ {
+ if (geometry::covered_by(point, multipolygon))
+ {
+ return 0;
+ }
+
+ return point_to_multigeometry
+ <
+ Point, MultiPolygon, Strategy, false
+ >::apply(point, multipolygon, strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Point-point
+template <typename P1, typename P2, typename Strategy>
+struct distance
+ <
+ P1, P2, Strategy, point_tag, point_tag,
+ strategy_tag_distance_point_point, false
+ > : detail::distance::point_to_point<P1, P2, Strategy>
+{};
+
+
+// Point-line version 2, where point-segment strategy is specified
+template <typename Point, typename Linestring, typename Strategy>
+struct distance
+ <
+ Point, Linestring, Strategy, point_tag, linestring_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_range<Point, Linestring, closed, Strategy>
+{};
+
+
+// Point-ring , where point-segment strategy is specified
+template <typename Point, typename Ring, typename Strategy>
+struct distance
+ <
+ Point, Ring, Strategy, point_tag, ring_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_ring
+ <
+ Point, Ring, closure<Ring>::value, Strategy
+ >
+{};
+
+
+// Point-polygon , where point-segment strategy is specified
+template <typename Point, typename Polygon, typename Strategy>
+struct distance
+ <
+ Point, Polygon, Strategy, point_tag, polygon_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_polygon
+ <
+ Point, Polygon, closure<Polygon>::value, Strategy
+ >
+{};
+
+
+// Point-segment version 2, with point-segment strategy
+template <typename Point, typename Segment, typename Strategy>
+struct distance
+ <
+ Point, Segment, Strategy, point_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ >
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Segment>::type
+ >::type apply(Point const& point,
+ Segment const& segment,
+ Strategy const& strategy)
+ {
+ typename point_type<Segment>::type p[2];
+ geometry::detail::assign_point_from_index<0>(segment, p[0]);
+ geometry::detail::assign_point_from_index<1>(segment, p[1]);
+
+ boost::ignore_unused(strategy);
+ return strategy.apply(point, p[0], p[1]);
+ }
+};
+
+
+template <typename Point, typename Box, typename Strategy>
+struct distance
+ <
+ Point, Box, Strategy, point_tag, box_tag,
+ strategy_tag_distance_point_box, false
+ >
+{
+ static inline typename strategy::distance::services::return_type
+ <
+ Strategy, Point, typename point_type<Box>::type
+ >::type
+ apply(Point const& point, Box const& box, Strategy const& strategy)
+ {
+ boost::ignore_unused(strategy);
+ return strategy.apply(point, box);
+ }
+};
+
+
+template<typename Point, typename MultiPoint, typename Strategy>
+struct distance
+ <
+ Point, MultiPoint, Strategy, point_tag, multi_point_tag,
+ strategy_tag_distance_point_point, false
+ > : detail::distance::point_to_multigeometry
+ <
+ Point, MultiPoint, Strategy
+ >
+{};
+
+
+template<typename Point, typename MultiLinestring, typename Strategy>
+struct distance
+ <
+ Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_multigeometry
+ <
+ Point, MultiLinestring, Strategy
+ >
+{};
+
+
+template<typename Point, typename MultiPolygon, typename Strategy>
+struct distance
+ <
+ Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag,
+ strategy_tag_distance_point_segment, false
+ > : detail::distance::point_to_multigeometry
+ <
+ Point, MultiPolygon, Strategy
+ >
+{};
+
+
+template <typename Point, typename Linear, typename Strategy>
+struct distance
+ <
+ Point, Linear, Strategy, point_tag, linear_tag,
+ strategy_tag_distance_point_segment, false
+ > : distance
+ <
+ Point, Linear, Strategy,
+ point_tag, typename tag<Linear>::type,
+ strategy_tag_distance_point_segment, false
+ >
+{};
+
+
+template <typename Point, typename Areal, typename Strategy>
+struct distance
+ <
+ Point, Areal, Strategy, point_tag, areal_tag,
+ strategy_tag_distance_point_segment, false
+ > : distance
+ <
+ Point, Areal, Strategy,
+ point_tag, typename tag<Areal>::type,
+ strategy_tag_distance_point_segment, false
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp
new file mode 100644
index 0000000000..78189794a1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp
@@ -0,0 +1,131 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
+
+#include <iterator>
+#include <utility>
+
+#include <boost/assert.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/iterators/has_one_element.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+#include <boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp>
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template
+<
+ typename PointOrSegmentIterator,
+ typename Geometry,
+ typename Strategy
+>
+class point_or_segment_range_to_geometry_rtree
+{
+private:
+ typedef typename std::iterator_traits
+ <
+ PointOrSegmentIterator
+ >::value_type point_or_segment_type;
+
+ typedef iterator_selector<Geometry const> selector_type;
+
+ typedef detail::closest_feature::range_to_range_rtree range_to_range;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<point_or_segment_type>::type,
+ typename point_type<Geometry>::type
+ >::type return_type;
+
+ static inline return_type apply(PointOrSegmentIterator first,
+ PointOrSegmentIterator last,
+ Geometry const& geometry,
+ Strategy const& strategy)
+ {
+ namespace sds = strategy::distance::services;
+
+ BOOST_ASSERT( first != last );
+
+ if ( geometry::has_one_element(first, last) )
+ {
+ return dispatch::distance
+ <
+ point_or_segment_type, Geometry, Strategy
+ >::apply(*first, geometry, strategy);
+ }
+
+ typename sds::return_type
+ <
+ typename sds::comparable_type<Strategy>::type,
+ typename point_type<point_or_segment_type>::type,
+ typename point_type<Geometry>::type
+ >::type cd_min;
+
+ std::pair
+ <
+ point_or_segment_type,
+ typename selector_type::iterator_type
+ > closest_features
+ = range_to_range::apply(first,
+ last,
+ selector_type::begin(geometry),
+ selector_type::end(geometry),
+ sds::get_comparable
+ <
+ Strategy
+ >::apply(strategy),
+ cd_min);
+
+ return
+ is_comparable<Strategy>::value
+ ?
+ cd_min
+ :
+ dispatch::distance
+ <
+ point_or_segment_type,
+ typename std::iterator_traits
+ <
+ typename selector_type::iterator_type
+ >::value_type,
+ Strategy
+ >::apply(closest_features.first,
+ *closest_features.second,
+ strategy);
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
new file mode 100644
index 0000000000..f64a3e9fca
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
@@ -0,0 +1,886 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
+
+#include <cstddef>
+
+#include <functional>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/core/ignore_unused.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/calculation_type.hpp>
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename Strategy,
+ bool UsePointBoxStrategy = false
+>
+class segment_to_box_2D_generic
+{
+private:
+ typedef typename point_type<Segment>::type segment_point;
+ typedef typename point_type<Box>::type box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef detail::closest_feature::point_to_point_range
+ <
+ segment_point,
+ std::vector<box_point>,
+ open,
+ comparable_strategy
+ > point_to_point_range;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy, segment_point, box_point
+ >::type comparable_return_type;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, segment_point, box_point
+ >::type return_type;
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy,
+ bool check_intersection = true)
+ {
+ if (check_intersection && geometry::intersects(segment, box))
+ {
+ return 0;
+ }
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+
+ // get segment points
+ segment_point p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ // get box points
+ std::vector<box_point> box_points(4);
+ detail::assign_box_corners_oriented<true>(box, box_points);
+
+ comparable_return_type cd[6];
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
+ }
+
+ std::pair
+ <
+ typename std::vector<box_point>::const_iterator,
+ typename std::vector<box_point>::const_iterator
+ > bit_min[2];
+
+ bit_min[0] = point_to_point_range::apply(p[0],
+ box_points.begin(),
+ box_points.end(),
+ cstrategy,
+ cd[4]);
+ bit_min[1] = point_to_point_range::apply(p[1],
+ box_points.begin(),
+ box_points.end(),
+ cstrategy,
+ cd[5]);
+
+ unsigned int imin = 0;
+ for (unsigned int i = 1; i < 6; ++i)
+ {
+ if (cd[i] < cd[imin])
+ {
+ imin = i;
+ }
+ }
+
+ if (is_comparable<Strategy>::value)
+ {
+ return cd[imin];
+ }
+
+ if (imin < 4)
+ {
+ return strategy.apply(box_points[imin], p[0], p[1]);
+ }
+ else
+ {
+ unsigned int bimin = imin - 4;
+ return strategy.apply(p[bimin],
+ *bit_min[bimin].first,
+ *bit_min[bimin].second);
+ }
+ }
+};
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename Strategy
+>
+class segment_to_box_2D_generic<Segment, Box, Strategy, true>
+{
+private:
+ typedef typename point_type<Segment>::type segment_point;
+ typedef typename point_type<Box>::type box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy, segment_point, box_point
+ >::type comparable_return_type;
+
+ typedef typename detail::distance::default_strategy
+ <
+ segment_point, Box
+ >::type point_box_strategy;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ point_box_strategy
+ >::type point_box_comparable_strategy;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy, segment_point, box_point
+ >::type return_type;
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy,
+ bool check_intersection = true)
+ {
+ if (check_intersection && geometry::intersects(segment, box))
+ {
+ return 0;
+ }
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+ boost::ignore_unused(cstrategy);
+
+ // get segment points
+ segment_point p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ // get box points
+ std::vector<box_point> box_points(4);
+ detail::assign_box_corners_oriented<true>(box, box_points);
+
+ comparable_return_type cd[6];
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
+ }
+
+ point_box_comparable_strategy pb_cstrategy;
+ boost::ignore_unused(pb_cstrategy);
+ cd[4] = pb_cstrategy.apply(p[0], box);
+ cd[5] = pb_cstrategy.apply(p[1], box);
+
+ unsigned int imin = 0;
+ for (unsigned int i = 1; i < 6; ++i)
+ {
+ if (cd[i] < cd[imin])
+ {
+ imin = i;
+ }
+ }
+
+ if (is_comparable<Strategy>::value)
+ {
+ return cd[imin];
+ }
+
+ if (imin < 4)
+ {
+ strategy.apply(box_points[imin], p[0], p[1]);
+ }
+ else
+ {
+ return point_box_strategy().apply(p[imin - 4], box);
+ }
+ }
+};
+
+
+
+
+template
+<
+ typename ReturnType,
+ typename SegmentPoint,
+ typename BoxPoint,
+ typename PPStrategy,
+ typename PSStrategy
+>
+class segment_to_box_2D
+{
+private:
+ template <typename Result>
+ struct cast_to_result
+ {
+ template <typename T>
+ static inline Result apply(T const& t)
+ {
+ return boost::numeric_cast<Result>(t);
+ }
+ };
+
+
+ template <typename T, bool IsLess /* true */>
+ struct compare_less_equal
+ {
+ typedef compare_less_equal<T, !IsLess> other;
+
+ template <typename T1, typename T2>
+ inline bool operator()(T1 const& t1, T2 const& t2) const
+ {
+ return std::less_equal<T>()(cast_to_result<T>::apply(t1),
+ cast_to_result<T>::apply(t2));
+ }
+ };
+
+ template <typename T>
+ struct compare_less_equal<T, false>
+ {
+ typedef compare_less_equal<T, true> other;
+
+ template <typename T1, typename T2>
+ inline bool operator()(T1 const& t1, T2 const& t2) const
+ {
+ return std::greater_equal<T>()(cast_to_result<T>::apply(t1),
+ cast_to_result<T>::apply(t2));
+ }
+ };
+
+
+ template <typename LessEqual>
+ struct other_compare
+ {
+ typedef typename LessEqual::other type;
+ };
+
+
+ // it is assumed here that p0 lies to the right of the box (so the
+ // entire segment lies to the right of the box)
+ template <typename LessEqual>
+ struct right_of_box
+ {
+ static inline ReturnType apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& bottom_right,
+ BoxPoint const& top_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ boost::ignore_unused(pp_strategy, ps_strategy);
+
+ // the implementation below is written for non-negative slope
+ // segments
+ //
+ // for negative slope segments swap the roles of bottom_right
+ // and top_right and use greater_equal instead of less_equal.
+
+ typedef cast_to_result<ReturnType> cast;
+
+ LessEqual less_equal;
+
+ if (less_equal(geometry::get<1>(top_right), geometry::get<1>(p0)))
+ {
+ // closest box point is the top-right corner
+ return cast::apply(pp_strategy.apply(p0, top_right));
+ }
+ else if (less_equal(geometry::get<1>(bottom_right),
+ geometry::get<1>(p0)))
+ {
+ // distance is realized between p0 and right-most
+ // segment of box
+ ReturnType diff = cast::apply(geometry::get<0>(p0))
+ - cast::apply(geometry::get<0>(bottom_right));
+ return strategy::distance::services::result_from_distance
+ <
+ PSStrategy, BoxPoint, SegmentPoint
+ >::apply(ps_strategy, math::abs(diff));
+ }
+ else
+ {
+ // distance is realized between the bottom-right
+ // corner of the box and the segment
+ return cast::apply(ps_strategy.apply(bottom_right, p0, p1));
+ }
+ }
+ };
+
+
+ // it is assumed here that p0 lies above the box (so the
+ // entire segment lies above the box)
+ template <typename LessEqual>
+ struct above_of_box
+ {
+ static inline ReturnType apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ PSStrategy const& ps_strategy)
+ {
+ boost::ignore_unused(ps_strategy);
+
+ // the segment lies above the box
+
+ typedef cast_to_result<ReturnType> cast;
+
+ LessEqual less_equal;
+
+ // p0 is above the upper segment of the box
+ // (and inside its band)
+ if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p0)))
+ {
+ ReturnType diff = cast::apply(geometry::get<1>(p0))
+ - cast::apply(geometry::get<1>(top_left));
+ return strategy::distance::services::result_from_distance
+ <
+ PSStrategy, SegmentPoint, BoxPoint
+ >::apply(ps_strategy, math::abs(diff));
+ }
+
+ // p0 is to the left of the box, but p1 is above the box
+ // in this case the distance is realized between the
+ // top-left corner of the box and the segment
+ return cast::apply(ps_strategy.apply(top_left, p0, p1));
+ }
+ };
+
+
+ template <typename LessEqual>
+ struct check_right_left_of_box
+ {
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy,
+ ReturnType& result)
+ {
+ // p0 lies to the right of the box
+ if (geometry::get<0>(p0) >= geometry::get<0>(top_right))
+ {
+ result = right_of_box
+ <
+ LessEqual
+ >::apply(p0, p1, bottom_right, top_right,
+ pp_strategy, ps_strategy);
+ return true;
+ }
+
+ // p1 lies to the left of the box
+ if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left))
+ {
+ result = right_of_box
+ <
+ typename other_compare<LessEqual>::type
+ >::apply(p1, p0, top_left, bottom_left,
+ pp_strategy, ps_strategy);
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+
+ template <typename LessEqual>
+ struct check_above_below_of_box
+ {
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PSStrategy const& ps_strategy,
+ ReturnType& result)
+ {
+ // the segment lies below the box
+ if (geometry::get<1>(p1) < geometry::get<1>(bottom_left))
+ {
+ result = above_of_box
+ <
+ typename other_compare<LessEqual>::type
+ >::apply(p1, p0, bottom_right, ps_strategy);
+ return true;
+ }
+
+ // the segment lies above the box
+ if (geometry::get<1>(p0) > geometry::get<1>(top_right))
+ {
+ result = above_of_box
+ <
+ LessEqual
+ >::apply(p0, p1, top_left, ps_strategy);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ struct check_generic_position
+ {
+ static inline bool apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& bottom_left0,
+ BoxPoint const& top_right0,
+ BoxPoint const& bottom_left1,
+ BoxPoint const& top_right1,
+ BoxPoint const& corner1,
+ BoxPoint const& corner2,
+ PSStrategy const& ps_strategy,
+ ReturnType& result)
+ {
+ typedef cast_to_result<ReturnType> cast;
+
+ ReturnType diff0 = cast::apply(geometry::get<0>(p1))
+ - cast::apply(geometry::get<0>(p0));
+ ReturnType t_min0 = cast::apply(geometry::get<0>(bottom_left0))
+ - cast::apply(geometry::get<0>(p0));
+ ReturnType t_max0 = cast::apply(geometry::get<0>(top_right0))
+ - cast::apply(geometry::get<0>(p0));
+
+ ReturnType diff1 = cast::apply(geometry::get<1>(p1))
+ - cast::apply(geometry::get<1>(p0));
+ ReturnType t_min1 = cast::apply(geometry::get<1>(bottom_left1))
+ - cast::apply(geometry::get<1>(p0));
+ ReturnType t_max1 = cast::apply(geometry::get<1>(top_right1))
+ - cast::apply(geometry::get<1>(p0));
+
+ if (diff1 < 0)
+ {
+ diff1 = -diff1;
+ t_min1 = -t_min1;
+ t_max1 = -t_max1;
+ }
+
+ // t_min0 > t_max1
+ if (t_min0 * diff1 > t_max1 * diff0)
+ {
+ result = cast::apply(ps_strategy.apply(corner1, p0, p1));
+ return true;
+ }
+
+ // t_max0 < t_min1
+ if (t_max0 * diff1 < t_min1 * diff0)
+ {
+ result = cast::apply(ps_strategy.apply(corner2, p0, p1));
+ return true;
+ }
+ return false;
+ }
+ };
+
+ static inline ReturnType
+ non_negative_slope_segment(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ typedef compare_less_equal<ReturnType, true> less_equal;
+
+ // assert that the segment has non-negative slope
+ BOOST_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1))
+ && geometry::get<1>(p0) < geometry::get<1>(p1))
+ ||
+ ( geometry::get<0>(p0) < geometry::get<0>(p1)
+ && geometry::get<1>(p0) <= geometry::get<1>(p1) )
+ );
+
+ ReturnType result(0);
+
+ if (check_right_left_of_box
+ <
+ less_equal
+ >::apply(p0, p1,
+ top_left, top_right, bottom_left, bottom_right,
+ pp_strategy, ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_above_below_of_box
+ <
+ less_equal
+ >::apply(p0, p1,
+ top_left, top_right, bottom_left, bottom_right,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_generic_position::apply(p0, p1,
+ bottom_left, top_right,
+ bottom_left, top_right,
+ top_left, bottom_right,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ // in all other cases the box and segment intersect, so return 0
+ return result;
+ }
+
+
+ static inline ReturnType
+ negative_slope_segment(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ typedef compare_less_equal<ReturnType, false> greater_equal;
+
+ // assert that the segment has negative slope
+ BOOST_ASSERT( geometry::get<0>(p0) < geometry::get<0>(p1)
+ && geometry::get<1>(p0) > geometry::get<1>(p1) );
+
+ ReturnType result(0);
+
+ if (check_right_left_of_box
+ <
+ greater_equal
+ >::apply(p0, p1,
+ bottom_left, bottom_right, top_left, top_right,
+ pp_strategy, ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_above_below_of_box
+ <
+ greater_equal
+ >::apply(p1, p0,
+ top_right, top_left, bottom_right, bottom_left,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ if (check_generic_position::apply(p0, p1,
+ bottom_left, top_right,
+ top_right, bottom_left,
+ bottom_left, top_right,
+ ps_strategy, result))
+ {
+ return result;
+ }
+
+ // in all other cases the box and segment intersect, so return 0
+ return result;
+ }
+
+public:
+ static inline ReturnType apply(SegmentPoint const& p0,
+ SegmentPoint const& p1,
+ BoxPoint const& top_left,
+ BoxPoint const& top_right,
+ BoxPoint const& bottom_left,
+ BoxPoint const& bottom_right,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ BOOST_ASSERT( geometry::less<SegmentPoint>()(p0, p1) );
+
+ if (geometry::get<0>(p0) < geometry::get<0>(p1)
+ && geometry::get<1>(p0) > geometry::get<1>(p1))
+ {
+ return negative_slope_segment(p0, p1,
+ top_left, top_right,
+ bottom_left, bottom_right,
+ pp_strategy, ps_strategy);
+ }
+
+ return non_negative_slope_segment(p0, p1,
+ top_left, top_right,
+ bottom_left, bottom_right,
+ pp_strategy, ps_strategy);
+ }
+};
+
+
+//=========================================================================
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename std::size_t Dimension,
+ typename PPStrategy,
+ typename PSStrategy
+>
+class segment_to_box
+ : not_implemented<Segment, Box>
+{};
+
+
+template
+<
+ typename Segment,
+ typename Box,
+ typename PPStrategy,
+ typename PSStrategy
+>
+class segment_to_box<Segment, Box, 2, PPStrategy, PSStrategy>
+{
+private:
+ typedef typename point_type<Segment>::type segment_point;
+ typedef typename point_type<Box>::type box_point;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ PPStrategy
+ >::type pp_comparable_strategy;
+
+ typedef typename strategy::distance::services::comparable_type
+ <
+ PSStrategy
+ >::type ps_comparable_strategy;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ ps_comparable_strategy, segment_point, box_point
+ >::type comparable_return_type;
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ PSStrategy, segment_point, box_point
+ >::type return_type;
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ PPStrategy const& pp_strategy,
+ PSStrategy const& ps_strategy)
+ {
+ segment_point p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ if (geometry::equals(p[0], p[1]))
+ {
+ typedef typename boost::mpl::if_
+ <
+ boost::is_same
+ <
+ ps_comparable_strategy,
+ PSStrategy
+ >,
+ typename strategy::distance::services::comparable_type
+ <
+ typename detail::distance::default_strategy
+ <
+ segment_point, Box
+ >::type
+ >::type,
+ typename detail::distance::default_strategy
+ <
+ segment_point, Box
+ >::type
+ >::type point_box_strategy_type;
+
+ return dispatch::distance
+ <
+ segment_point,
+ Box,
+ point_box_strategy_type
+ >::apply(p[0], box, point_box_strategy_type());
+ }
+
+ box_point top_left, top_right, bottom_left, bottom_right;
+ detail::assign_box_corners(box, bottom_left, bottom_right,
+ top_left, top_right);
+
+ if (geometry::less<segment_point>()(p[0], p[1]))
+ {
+ return segment_to_box_2D
+ <
+ return_type,
+ segment_point,
+ box_point,
+ PPStrategy,
+ PSStrategy
+ >::apply(p[0], p[1],
+ top_left, top_right, bottom_left, bottom_right,
+ pp_strategy,
+ ps_strategy);
+ }
+ else
+ {
+ return segment_to_box_2D
+ <
+ return_type,
+ segment_point,
+ box_point,
+ PPStrategy,
+ PSStrategy
+ >::apply(p[1], p[0],
+ top_left, top_right, bottom_left, bottom_right,
+ pp_strategy,
+ ps_strategy);
+ }
+ }
+};
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Segment, typename Box, typename Strategy>
+struct distance
+ <
+ Segment, Box, Strategy, segment_tag, box_tag,
+ strategy_tag_distance_point_segment, false
+ >
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Segment>::type,
+ typename point_type<Box>::type
+ >::type return_type;
+
+
+ static inline return_type apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy)
+ {
+ assert_dimension_equal<Segment, Box>();
+
+ typedef typename boost::mpl::if_
+ <
+ boost::is_same
+ <
+ typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type,
+ Strategy
+ >,
+ typename strategy::distance::services::comparable_type
+ <
+ typename detail::distance::default_strategy
+ <
+ typename point_type<Segment>::type,
+ typename point_type<Box>::type
+ >::type
+ >::type,
+ typename detail::distance::default_strategy
+ <
+ typename point_type<Segment>::type,
+ typename point_type<Box>::type
+ >::type
+ >::type pp_strategy_type;
+
+
+ return detail::distance::segment_to_box
+ <
+ Segment,
+ Box,
+ dimension<Segment>::value,
+ pp_strategy_type,
+ Strategy
+ >::apply(segment, box, pp_strategy_type(), strategy);
+ }
+};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
new file mode 100644
index 0000000000..2dcde64946
--- /dev/null
+++ b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
@@ -0,0 +1,150 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
+
+#include <algorithm>
+#include <iterator>
+
+#include <boost/core/addressof.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/strategies/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+
+#include <boost/geometry/algorithms/dispatch/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace distance
+{
+
+
+
+// compute segment-segment distance
+template<typename Segment1, typename Segment2, typename Strategy>
+class segment_to_segment
+{
+private:
+ typedef typename strategy::distance::services::comparable_type
+ <
+ Strategy
+ >::type comparable_strategy;
+
+ typedef typename strategy::distance::services::return_type
+ <
+ comparable_strategy,
+ typename point_type<Segment1>::type,
+ typename point_type<Segment2>::type
+ >::type comparable_return_type;
+
+public:
+ typedef typename strategy::distance::services::return_type
+ <
+ Strategy,
+ typename point_type<Segment1>::type,
+ typename point_type<Segment2>::type
+ >::type return_type;
+
+ static inline return_type
+ apply(Segment1 const& segment1, Segment2 const& segment2,
+ Strategy const& strategy)
+ {
+ if (geometry::intersects(segment1, segment2))
+ {
+ return 0;
+ }
+
+ typename point_type<Segment1>::type p[2];
+ detail::assign_point_from_index<0>(segment1, p[0]);
+ detail::assign_point_from_index<1>(segment1, p[1]);
+
+ typename point_type<Segment2>::type q[2];
+ detail::assign_point_from_index<0>(segment2, q[0]);
+ detail::assign_point_from_index<1>(segment2, q[1]);
+
+ comparable_strategy cstrategy =
+ strategy::distance::services::get_comparable
+ <
+ Strategy
+ >::apply(strategy);
+
+ comparable_return_type d[4];
+ d[0] = cstrategy.apply(q[0], p[0], p[1]);
+ d[1] = cstrategy.apply(q[1], p[0], p[1]);
+ d[2] = cstrategy.apply(p[0], q[0], q[1]);
+ d[3] = cstrategy.apply(p[1], q[0], q[1]);
+
+ std::size_t imin = std::distance(boost::addressof(d[0]),
+ std::min_element(d, d + 4));
+
+ if (is_comparable<Strategy>::value)
+ {
+ return d[imin];
+ }
+
+ switch (imin)
+ {
+ case 0:
+ return strategy.apply(q[0], p[0], p[1]);
+ case 1:
+ return strategy.apply(q[1], p[0], p[1]);
+ case 2:
+ return strategy.apply(p[0], q[0], q[1]);
+ default:
+ return strategy.apply(p[1], q[0], q[1]);
+ }
+ }
+};
+
+
+
+
+}} // namespace detail::distance
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+
+// segment-segment
+template <typename Segment1, typename Segment2, typename Strategy>
+struct distance
+ <
+ Segment1, Segment2, Strategy, segment_tag, segment_tag,
+ strategy_tag_distance_point_segment, false
+ >
+ : detail::distance::segment_to_segment<Segment1, Segment2, Strategy>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
index 9c2fe28057..5bcb5ffaa0 100644
--- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
+++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
@@ -1,8 +1,9 @@
// 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.
+// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,12 +18,13 @@
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
@@ -75,9 +77,9 @@ struct collected_vector
inline bool same_direction(collected_vector<T> const& other) const
{
- // For high precision arithmetic, we have to be
+ // For high precision arithmetic, we have to be
// more relaxed then using ==
- // Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) )
+ // Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) )
// is not always true (at least, it is not for ttmath)
return math::equals_with_epsilon(dx, other.dx)
&& math::equals_with_epsilon(dy, other.dy);
@@ -111,6 +113,9 @@ struct range_collect_vectors
return;
}
+ typedef typename boost::range_size<Collection>::type collection_size_t;
+ collection_size_t c_old_size = boost::size(collection);
+
typedef typename boost::range_iterator<Range const>::type iterator;
bool first = true;
@@ -131,7 +136,7 @@ struct range_collect_vectors
// Normalize the vector -> this results in points+direction
// and is comparible between geometries
- calculation_type magnitude = sqrt(
+ calculation_type magnitude = math::sqrt(
boost::numeric_cast<calculation_type>(v.dx * v.dx + v.dy * v.dy));
// Avoid non-duplicate points (AND division by zero)
@@ -150,10 +155,19 @@ struct range_collect_vectors
}
// If first one has same direction as last one, remove first one
- if (boost::size(collection) > 1
- && collection.front().same_direction(collection.back()))
+ collection_size_t collected_count = boost::size(collection) - c_old_size;
+ if ( collected_count > 1 )
{
- collection.erase(collection.begin());
+ typedef typename boost::range_iterator<Collection>::type c_iterator;
+ c_iterator first = collection.begin() + c_old_size;
+
+ if ( first->same_direction(collection.back()) )
+ {
+ //collection.erase(first);
+ // O(1) instead of O(N)
+ *first = collection.back();
+ collection.pop_back();
+ }
}
}
};
@@ -194,9 +208,10 @@ struct polygon_collect_vectors
typedef range_collect_vectors<ring_type, Collection> per_range;
per_range::apply(collection, exterior_ring(polygon));
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
per_range::apply(collection, *it);
}
diff --git a/boost/geometry/algorithms/detail/equals/point_point.hpp b/boost/geometry/algorithms/detail/equals/point_point.hpp
new file mode 100644
index 0000000000..12daa85e9d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/point_point.hpp
@@ -0,0 +1,52 @@
+// 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.
+// 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.
+
+// 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_POINT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP
+
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace equals
+{
+
+/*!
+ \brief Internal utility function to detect of points are disjoint
+ \note To avoid circular references
+ */
+template <typename Point1, typename Point2>
+inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
+{
+ return ! detail::disjoint::disjoint_point_point(point1, point2);
+}
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp
new file mode 100644
index 0000000000..61839d296a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/extreme_points.hpp
@@ -0,0 +1,520 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// 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_EXTREME_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/iterators/ever_circling_iterator.hpp>
+
+#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
+
+#include <boost/geometry/strategies/side.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace extreme_points
+{
+
+template <std::size_t Dimension>
+struct compare
+{
+ template <typename Point>
+ inline bool operator()(Point const& lhs, Point const& rhs)
+ {
+ return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs);
+ }
+};
+
+
+template <std::size_t Dimension, typename PointType, typename CoordinateType>
+inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value)
+{
+ // Moves a point along the vector (point, extreme) in the direction of the extreme point
+ // This adapts the possibly uneven legs of the triangle (or trapezium-like shape)
+ // _____extreme _____
+ // / \ / \ .
+ // /base \ => / \ point .
+ // \ point .
+ //
+ // For so-called intruders, it can be used to adapt both legs to the level of "base"
+ // For the base, it can be used to adapt both legs to the level of the max-value of the intruders
+ // If there are 2 or more extreme values, use the one close to 'point' to have a correct vector
+
+ CoordinateType const value = geometry::get<Dimension>(point);
+ //if (geometry::math::equals(value, base_value))
+ if (value >= base_value)
+ {
+ return;
+ }
+
+ PointType vector = point;
+ subtract_point(vector, extreme);
+
+ CoordinateType const diff = geometry::get<Dimension>(vector);
+
+ // diff should never be zero
+ // because of the way our triangle/trapezium is build.
+ // We just return if it would be the case.
+ if (geometry::math::equals(diff, 0))
+ {
+ return;
+ }
+
+ CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme);
+
+ multiply_value(vector, base_diff);
+ divide_value(vector, diff);
+
+ // The real move:
+ point = extreme;
+ add_point(point, vector);
+}
+
+
+template <std::size_t Dimension, typename Range, typename CoordinateType>
+inline void move_along_vector(Range& range, CoordinateType const& base_value)
+{
+ if (range.size() >= 3)
+ {
+ move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value);
+ move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value);
+ }
+}
+
+
+template<typename Ring, std::size_t Dimension>
+struct extreme_points_on_ring
+{
+
+ typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
+ 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,
+ coordinate_type max_coordinate_value,
+ Points& points, int direction)
+ {
+ std::size_t safe_index = 0;
+ do
+ {
+ it += direction;
+
+ points.push_back(*it);
+
+ if (safe_index++ >= n)
+ {
+ // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
+ return false;
+ }
+ } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
+
+ return true;
+ }
+
+ // Overload without adding to poinst
+ template <typename CirclingIterator>
+ static inline bool extend(CirclingIterator& it,
+ std::size_t n,
+ coordinate_type max_coordinate_value,
+ int direction)
+ {
+ std::size_t safe_index = 0;
+ do
+ {
+ it += direction;
+
+ if (safe_index++ >= n)
+ {
+ // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
+ return false;
+ }
+ } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
+
+ return true;
+ }
+
+ template <typename CirclingIterator>
+ static inline bool extent_both_sides(Ring const& ring,
+ point_type extreme,
+ CirclingIterator& left,
+ CirclingIterator& right)
+ {
+ std::size_t const n = boost::size(ring);
+ coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
+
+ if (! extend(left, n, max_coordinate_value, -1))
+ {
+ return false;
+ }
+ if (! extend(right, n, max_coordinate_value, +1))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename Collection, typename CirclingIterator>
+ static inline bool collect(Ring const& ring,
+ point_type extreme,
+ Collection& points,
+ CirclingIterator& left,
+ CirclingIterator& right)
+ {
+ std::size_t const n = boost::size(ring);
+ coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
+
+ // Collects first left, which is reversed (if more than one point) then adds the top itself, then right
+ if (! extend(left, n, max_coordinate_value, points, -1))
+ {
+ return false;
+ }
+ std::reverse(points.begin(), points.end());
+ points.push_back(extreme);
+ if (! extend(right, n, max_coordinate_value, points, +1))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename Extremes, typename Intruders, typename CirclingIterator>
+ static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
+ Extremes const& extremes,
+ Intruders& intruders)
+ {
+ if (boost::size(extremes) < 3)
+ {
+ return;
+ }
+ coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>()));
+
+ // Also select left/right (if Dimension=1)
+ coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
+ coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
+
+ std::size_t defensive_check_index = 0; // in case we skip over left/right check, collect modifies right too
+ std::size_t const n = boost::size(ring);
+ while (left != right && defensive_check_index < n)
+ {
+ coordinate_type const coordinate = geometry::get<Dimension>(*right);
+ coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right);
+ 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;
+
+ // If not lying left from any of the extemes side
+ if (first_side != 1 && last_side != 1)
+ {
+ //std::cout << "first " << first_side << " last " << last_side << std::endl;
+
+ // we start at this intrusion until it is handled, and don't affect our initial left iterator
+ CirclingIterator left_intrusion_it = right;
+ typename boost::range_value<Intruders>::type intruder;
+ collect(ring, *right, intruder, left_intrusion_it, right);
+
+ // Also moves these to base-level, makes sorting possible which can be done in case of self-tangencies
+ // (we might postpone this action, it is often not necessary. However it is not time-consuming)
+ move_along_vector<Dimension>(intruder, min_value);
+ intruders.push_back(intruder);
+ --right;
+ }
+ }
+ ++right;
+ defensive_check_index++;
+ }
+ }
+
+ template <typename Extremes, typename Intruders>
+ static inline void get_intruders(Ring const& ring,
+ Extremes const& extremes,
+ Intruders& intruders)
+ {
+ std::size_t const n = boost::size(ring);
+ if (n >= 3)
+ {
+ geometry::ever_circling_range_iterator<Ring const> left(ring);
+ geometry::ever_circling_range_iterator<Ring const> right(ring);
+ ++right;
+
+ get_intruders(ring, left, right, extremes, intruders);
+ }
+ }
+
+ template <typename Iterator>
+ static inline bool right_turn(Ring const& ring, Iterator it)
+ {
+ typename std::iterator_traits<Iterator>::difference_type const index
+ = std::distance(boost::begin(ring), it);
+ geometry::ever_circling_range_iterator<Ring const> left(ring);
+ geometry::ever_circling_range_iterator<Ring const> right(ring);
+ left += index;
+ right += index;
+
+ if (! extent_both_sides(ring, *it, left, right))
+ {
+ return false;
+ }
+
+ 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;
+
+//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
+
+ // Turn should not be left (actually, it should be right because extent removes horizontal/collinear cases)
+ return first_side != 1 && last_side != 1;
+ }
+
+
+ // 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)
+ {
+ std::size_t const n = boost::size(ring);
+ if (n < 3)
+ {
+ return false;
+ }
+
+ // Get all maxima, usually one. In case of self-tangencies, or self-crossings,
+ // the max might be is not valid. A valid max should make a right turn
+ range_iterator max_it = boost::begin(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))
+ {
+ max_it = it;
+ }
+ }
+
+ if (max_it == boost::end(ring))
+ {
+ return false;
+ }
+
+ typename std::iterator_traits<range_iterator>::difference_type const
+ index = std::distance(boost::begin(ring), max_it);
+//std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl;
+
+ geometry::ever_circling_range_iterator<Ring const> left(ring);
+ geometry::ever_circling_range_iterator<Ring const> right(ring);
+ left += index;
+ right += index;
+
+ // Collect all points (often 3) in a temporary vector
+ std::vector<point_type> points;
+ points.reserve(3);
+ if (! collect(ring, *max_it, points, left, right))
+ {
+ return false;
+ }
+
+//std::cout << "Built vector of " << points.size() << std::endl;
+
+ coordinate_type const front_value = geometry::get<Dimension>(points.front());
+ coordinate_type const back_value = geometry::get<Dimension>(points.back());
+ coordinate_type const base_value = (std::max)(front_value, back_value);
+ if (front_value < back_value)
+ {
+ move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value);
+ }
+ else
+ {
+ move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value);
+ }
+
+ std::copy(points.begin(), points.end(), std::back_inserter(extremes));
+
+ get_intruders(ring, left, right, extremes, intruders);
+
+ return true;
+ }
+};
+
+
+
+
+
+}} // namespace detail::extreme_points
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry,
+ std::size_t Dimension,
+ typename GeometryTag = typename tag<Geometry>::type
+>
+struct extreme_points
+{};
+
+
+template<typename Ring, std::size_t Dimension>
+struct extreme_points<Ring, Dimension, ring_tag>
+ : detail::extreme_points::extreme_points_on_ring<Ring, Dimension>
+{};
+
+
+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)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+ typedef detail::extreme_points::extreme_points_on_ring
+ <
+ ring_type, Dimension
+ > ring_implementation;
+
+ if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
+ {
+ return false;
+ }
+
+ // For a polygon, its interior rings can contain intruders
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ ring_implementation::get_intruders(*it, extremes, intruders);
+ }
+
+ return true;
+ }
+};
+
+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& )
+ {
+ extremes.resize(4);
+ geometry::detail::assign_box_corners_oriented<false>(box, extremes);
+ // ll,ul,ur,lr, contains too exactly the right info
+ return true;
+ }
+};
+
+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& )
+ {
+ extremes.resize(4);
+ geometry::detail::assign_box_corners_oriented<false>(box, extremes);
+ // ll,ul,ur,lr, rotate one to start with UL and end with LL
+ std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end());
+ return true;
+ }
+};
+
+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)
+ {
+ // 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
+ // (point_on_surface) it can just be this point.
+ if (boost::size(multi) >= 1)
+ {
+ return extreme_points
+ <
+ typename boost::range_value<MultiPolygon const>::type,
+ Dimension,
+ polygon_tag
+ >::apply(*boost::begin(multi), extremes, intruders);
+ }
+
+ return false;
+ }
+};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief Returns extreme points (for Edge=1 in dimension 1, so the top,
+ 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)
+{
+ concept::check<Geometry const>();
+
+ // Extremes is not required to follow a geometry concept (but it should support an output iterator),
+ // but its elements should fulfil the point-concept
+ concept::check<typename boost::range_value<Extremes>::type>();
+
+ // Intruders should contain collections which value type is point-concept
+ // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept
+ concept::check
+ <
+ typename boost::range_value
+ <
+ typename boost::range_value<Intruders>::type
+ >::type
+ const
+ >();
+
+ return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
+}
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/for_each_range.hpp b/boost/geometry/algorithms/detail/for_each_range.hpp
index 7cb01fa9b4..e8c92160f1 100644
--- a/boost/geometry/algorithms/detail/for_each_range.hpp
+++ b/boost/geometry/algorithms/detail/for_each_range.hpp
@@ -17,9 +17,13 @@
#include <boost/mpl/assert.hpp>
#include <boost/concept/requires.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/type_traits/remove_const.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
#include <boost/geometry/views/box_view.hpp>
@@ -34,24 +38,20 @@ namespace detail { namespace for_each
{
-template <typename Range, typename Actor, bool IsConst>
+template <typename Range, typename Actor>
struct fe_range_range
{
- static inline void apply(
- typename add_const_if_c<IsConst, Range>::type& range,
- Actor& actor)
+ static inline void apply(Range & range, Actor & actor)
{
actor.apply(range);
}
};
-template <typename Polygon, typename Actor, bool IsConst>
+template <typename Polygon, typename Actor>
struct fe_range_polygon
{
- static inline void apply(
- typename add_const_if_c<IsConst, Polygon>::type& polygon,
- Actor& actor)
+ static inline void apply(Polygon & polygon, Actor & actor)
{
actor.apply(exterior_ring(polygon));
@@ -60,17 +60,27 @@ struct fe_range_polygon
}
};
-template <typename Box, typename Actor, bool IsConst>
+template <typename Box, typename Actor>
struct fe_range_box
{
- static inline void apply(
- typename add_const_if_c<IsConst, Box>::type& box,
- Actor& actor)
+ static inline void apply(Box & box, Actor & actor)
{
- actor.apply(box_view<Box>(box));
+ actor.apply(box_view<typename boost::remove_const<Box>::type>(box));
}
};
+template <typename Multi, typename Actor, typename SinglePolicy>
+struct fe_range_multi
+{
+ static inline void apply(Multi & multi, Actor & actor)
+ {
+ for ( typename boost::range_iterator<Multi>::type
+ it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ SinglePolicy::apply(*it, actor);
+ }
+ }
+};
}} // namespace detail::for_each
#endif // DOXYGEN_NO_DETAIL
@@ -83,10 +93,9 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
typename Actor,
- bool IsConst
+ typename Tag = typename tag<Geometry>::type
>
struct for_each_range
{
@@ -98,26 +107,71 @@ struct for_each_range
};
-template <typename Linestring, typename Actor, bool IsConst>
-struct for_each_range<linestring_tag, Linestring, Actor, IsConst>
- : detail::for_each::fe_range_range<Linestring, Actor, IsConst>
+template <typename Linestring, typename Actor>
+struct for_each_range<Linestring, Actor, linestring_tag>
+ : detail::for_each::fe_range_range<Linestring, Actor>
+{};
+
+
+template <typename Ring, typename Actor>
+struct for_each_range<Ring, Actor, ring_tag>
+ : detail::for_each::fe_range_range<Ring, Actor>
+{};
+
+
+template <typename Polygon, typename Actor>
+struct for_each_range<Polygon, Actor, polygon_tag>
+ : detail::for_each::fe_range_polygon<Polygon, Actor>
+{};
+
+
+template <typename Box, typename Actor>
+struct for_each_range<Box, Actor, box_tag>
+ : detail::for_each::fe_range_box<Box, Actor>
{};
-template <typename Ring, typename Actor, bool IsConst>
-struct for_each_range<ring_tag, Ring, Actor, IsConst>
- : detail::for_each::fe_range_range<Ring, Actor, IsConst>
+template <typename MultiPoint, typename Actor>
+struct for_each_range<MultiPoint, Actor, multi_point_tag>
+ : detail::for_each::fe_range_range<MultiPoint, Actor>
{};
-template <typename Polygon, typename Actor, bool IsConst>
-struct for_each_range<polygon_tag, Polygon, Actor, IsConst>
- : detail::for_each::fe_range_polygon<Polygon, Actor, IsConst>
+template <typename Geometry, typename Actor>
+struct for_each_range<Geometry, Actor, multi_linestring_tag>
+ : detail::for_each::fe_range_multi
+ <
+ Geometry,
+ Actor,
+ detail::for_each::fe_range_range
+ <
+ typename add_const_if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::range_value<Geometry>::type
+ >::type,
+ Actor
+ >
+ >
{};
-template <typename Box, typename Actor, bool IsConst>
-struct for_each_range<box_tag, Box, Actor, IsConst>
- : detail::for_each::fe_range_box<Box, Actor, IsConst>
+
+template <typename Geometry, typename Actor>
+struct for_each_range<Geometry, Actor, multi_polygon_tag>
+ : detail::for_each::fe_range_multi
+ <
+ Geometry,
+ Actor,
+ detail::for_each::fe_range_polygon
+ <
+ typename add_const_if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::range_value<Geometry>::type
+ >::type,
+ Actor
+ >
+ >
{};
@@ -128,14 +182,12 @@ namespace detail
{
template <typename Geometry, typename Actor>
-inline void for_each_range(Geometry const& geometry, Actor& actor)
+inline void for_each_range(Geometry const& geometry, Actor & actor)
{
dispatch::for_each_range
<
- typename tag<Geometry>::type,
- Geometry,
- Actor,
- true
+ Geometry const,
+ Actor
>::apply(geometry, actor);
}
diff --git a/boost/geometry/algorithms/detail/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp
index 62f0f7f0f4..0fd243d8e3 100644
--- a/boost/geometry/algorithms/detail/get_left_turns.hpp
+++ b/boost/geometry/algorithms/detail/get_left_turns.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2012-2014 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
@@ -9,7 +9,12 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/iterators/closing_iterator.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
+#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
{
@@ -21,342 +26,286 @@ namespace detail
// TODO: move this to /util/
template <typename T>
-static inline std::pair<T, T> ordered_pair(T const& first, T const& second)
+inline std::pair<T, T> ordered_pair(T const& first, T const& second)
{
return first < second ? std::make_pair(first, second) : std::make_pair(second, first);
}
-template <typename AngleInfo>
-inline void debug_left_turn(AngleInfo const& ai, AngleInfo const& previous)
+namespace left_turns
{
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
- std::cout << "Angle: " << (ai.incoming ? "i" : "o")
- << " " << si(ai.seg_id)
- << " " << (math::r2d * (ai.angle) )
- << " turn: " << ai.turn_index << "[" << ai.operation_index << "]"
- ;
-
- if (ai.turn_index != previous.turn_index
- || ai.operation_index != previous.operation_index)
- {
- std::cout << " diff: " << math::r2d * math::abs(previous.angle - ai.angle);
- }
- std::cout << std::endl;
-#endif
-}
-
-template <typename AngleInfo>
-inline void debug_left_turn(std::string const& caption, AngleInfo const& ai, AngleInfo const& previous,
- int code = -99, int code2 = -99, int code3 = -99, int code4 = -99)
-{
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
- std::cout << " " << caption
- << " turn: " << ai.turn_index << "[" << ai.operation_index << "]"
- << " " << si(ai.seg_id)
- << " " << (ai.incoming ? "i" : "o")
- << " " << (math::r2d * (ai.angle) )
- << " turn: " << previous.turn_index << "[" << previous.operation_index << "]"
- << " " << si(previous.seg_id)
- << " " << (previous.incoming ? "i" : "o")
- << " " << (math::r2d * (previous.angle) )
- ;
- if (code != -99)
- {
- std::cout << " code: " << code << " , " << code2 << " , " << code3 << " , " << code4;
- }
- std::cout << std::endl;
-#endif
-}
-template <typename Operation>
-inline bool include_operation(Operation const& op,
- segment_identifier const& outgoing_seg_id,
- segment_identifier const& incoming_seg_id)
+template <typename Vector>
+inline int get_quadrant(Vector const& vector)
{
- return op.seg_id == outgoing_seg_id
- && op.other_id == incoming_seg_id
- && (op.operation == detail::overlay::operation_union
- ||op.operation == detail::overlay::operation_continue)
- ;
+ // Return quadrant as layouted in the code below:
+ // 3 | 0
+ // -----
+ // 2 | 1
+ return geometry::get<1>(vector) >= 0
+ ? (geometry::get<0>(vector) < 0 ? 3 : 0)
+ : (geometry::get<0>(vector) < 0 ? 2 : 1)
+ ;
}
-template <typename Turn>
-inline bool process_include(segment_identifier const& outgoing_seg_id, segment_identifier const& incoming_seg_id,
- int turn_index, Turn& turn,
- std::set<int>& keep_indices, int priority)
+template <typename Vector>
+inline int squared_length(Vector const& vector)
{
- bool result = false;
- for (int i = 0; i < 2; i++)
- {
- if (include_operation(turn.operations[i], outgoing_seg_id, incoming_seg_id))
- {
- turn.operations[i].include_in_occupation_map = true;
- if (priority > turn.priority)
- {
- turn.priority = priority;
- }
- keep_indices.insert(turn_index);
- result = true;
- }
- }
- return result;
+ return geometry::get<0>(vector) * geometry::get<0>(vector)
+ + geometry::get<1>(vector) * geometry::get<1>(vector)
+ ;
}
-template <typename AngleInfo, typename Turns, typename TurnSegmentIndices>
-inline bool include_left_turn_of_all(
- AngleInfo const& outgoing, AngleInfo const& incoming,
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices, int priority)
+
+template <typename Point>
+struct angle_less
{
- segment_identifier const& outgoing_seg_id = turns[outgoing.turn_index].operations[outgoing.operation_index].seg_id;
- segment_identifier const& incoming_seg_id = turns[incoming.turn_index].operations[incoming.operation_index].seg_id;
+ typedef Point vector_type;
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type side_strategy_type;
- if (outgoing.turn_index == incoming.turn_index)
- {
- return process_include(outgoing_seg_id, incoming_seg_id, outgoing.turn_index, turns[outgoing.turn_index], keep_indices, priority);
- }
+ angle_less(Point const& origin)
+ : m_origin(origin)
+ {}
- bool result = false;
- std::pair<segment_identifier, segment_identifier> pair = ordered_pair(outgoing_seg_id, incoming_seg_id);
- auto it = turn_segment_indices.find(pair);
- if (it != turn_segment_indices.end())
+ template <typename Angle>
+ inline bool operator()(Angle const& p, Angle const& q) const
{
- for (auto sit = it->second.begin(); sit != it->second.end(); ++sit)
+ // Vector origin -> p and origin -> q
+ vector_type pv = p.point;
+ vector_type qv = q.point;
+ geometry::subtract_point(pv, m_origin);
+ geometry::subtract_point(qv, m_origin);
+
+ int const quadrant_p = get_quadrant(pv);
+ int const quadrant_q = get_quadrant(qv);
+ if (quadrant_p != quadrant_q)
{
- if (process_include(outgoing_seg_id, incoming_seg_id, *sit, turns[*sit], keep_indices, priority))
- {
- result = true;
- }
+ 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);
+ if (side != 0)
+ {
+ return side == 1;
+ }
+ // Collinear, check if one is incoming, incoming angles come first
+ if (p.incoming != q.incoming)
+ {
+ return int(p.incoming) < int(q.incoming);
+ }
+ // Same quadrant/side/direction, return longest first
+ // TODO: maybe not necessary, decide this
+ int const length_p = squared_length(pv);
+ int const length_q = squared_length(qv);
+ if (length_p != length_q)
+ {
+ return squared_length(pv) > squared_length(qv);
+ }
+ // They are still the same. Just compare on seg_id
+ return p.seg_id < q.seg_id;
}
- return result;
-}
-template <std::size_t Index, typename Turn>
-inline bool corresponds(Turn const& turn, segment_identifier const& seg_id)
+private:
+ Point m_origin;
+};
+
+template <typename Point>
+struct angle_equal_to
{
- return turn.operations[Index].operation == detail::overlay::operation_union
- && turn.operations[Index].seg_id == seg_id;
-}
+ 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)
+ : m_origin(origin)
+ {}
-template <typename Turns, typename TurnSegmentIndices>
-inline bool prefer_by_other(Turns const& turns,
- TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& indices)
-{
- std::map<segment_identifier, int> map;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
+ template <typename Angle>
+ inline bool operator()(Angle const& p, Angle const& q) const
{
- map[turns[*sit].operations[0].seg_id]++;
- map[turns[*sit].operations[1].seg_id]++;
- }
+ // Vector origin -> p and origin -> q
+ vector_type pv = p.point;
+ vector_type qv = q.point;
+ geometry::subtract_point(pv, m_origin);
+ geometry::subtract_point(qv, m_origin);
- std::set<segment_identifier> segment_occuring_once;
- for (auto mit = map.begin(); mit != map.end(); ++mit)
- {
- if (mit->second == 1)
+ if (get_quadrant(pv) != get_quadrant(qv))
{
- segment_occuring_once.insert(mit->first);
+ return false;
}
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER
- std::cout << si(mit->first) << " " << mit->second << std::endl;
-#endif
+ // Same quadrant, check if p/q are collinear
+ int const side = side_strategy_type::apply(m_origin, q.point,
+ p.point);
+ return side == 0;
}
- if (segment_occuring_once.size() == 2)
- {
- // Try to find within all turns a turn with these two segments
+private:
+ Point m_origin;
+};
- std::set<segment_identifier>::const_iterator soo_it = segment_occuring_once.begin();
- segment_identifier front = *soo_it;
- soo_it++;
- segment_identifier back = *soo_it;
+template <typename AngleCollection, typename Turns>
+inline void get_left_turns(AngleCollection const& sorted_angles,
+ Turns& turns)
+{
+ std::set<int> good_incoming;
+ std::set<int> good_outgoing;
- std::pair<segment_identifier, segment_identifier> pair = ordered_pair(front, back);
- auto it = turn_segment_indices.find(pair);
- if (it != turn_segment_indices.end())
+ for (typename boost::range_iterator<AngleCollection const>::type it =
+ sorted_angles.begin(); it != sorted_angles.end(); ++it)
+ {
+ if (!it->blocked)
{
- // debug_turns_by_indices("Found", it->second);
- // Check which is the union/continue
- segment_identifier good;
- for (auto sit = it->second.begin(); sit != it->second.end(); ++sit)
+ if (it->incoming)
{
- if (turns[*sit].operations[0].operation == detail::overlay::operation_union)
- {
- good = turns[*sit].operations[0].seg_id;
- }
- else if (turns[*sit].operations[1].operation == detail::overlay::operation_union)
- {
- good = turns[*sit].operations[1].seg_id;
- }
+ good_incoming.insert(it->turn_index);
}
-
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER
- std::cout << "Good: " << si(good) << std::endl;
-#endif
-
- // Find in indexes-to-keep this segment with the union. Discard the other one
- std::set<int> ok_indices;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
+ else
{
- if (corresponds<0>(turns[*sit], good) || corresponds<1>(turns[*sit], good))
- {
- ok_indices.insert(*sit);
- }
- }
- if (ok_indices.size() > 0 && ok_indices.size() < indices.size())
- {
- indices = ok_indices;
- std::cout << "^";
- return true;
+ good_outgoing.insert(it->turn_index);
}
}
}
- return false;
-}
-template <typename Turns>
-inline void prefer_by_priority(Turns const& turns, std::set<int>& indices)
-{
- // Find max prio
- int min_prio = 1024, max_prio = 0;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
- {
- if (turns[*sit].priority > max_prio)
- {
- max_prio = turns[*sit].priority;
- }
- if (turns[*sit].priority < min_prio)
- {
- min_prio = turns[*sit].priority;
- }
- }
-
- if (min_prio == max_prio)
+ if (good_incoming.empty() || good_outgoing.empty())
{
return;
}
- // Only keep indices with high prio
- std::set<int> ok_indices;
- for (auto sit = indices.begin(); sit != indices.end(); ++sit)
+ for (typename boost::range_iterator<AngleCollection const>::type it =
+ sorted_angles.begin(); it != sorted_angles.end(); ++it)
{
- if (turns[*sit].priority >= max_prio)
+ if (good_incoming.count(it->turn_index) == 0
+ || good_outgoing.count(it->turn_index) == 0)
{
- ok_indices.insert(*sit);
+ turns[it->turn_index].remove_on_multi = true;
}
}
- if (ok_indices.size() > 0 && ok_indices.size() < indices.size())
- {
- indices = ok_indices;
- std::cout << "%";
- }
}
-template <typename AngleInfo, typename Angles, typename Turns, typename TurnSegmentIndices>
-inline void calculate_left_turns(Angles const& angles,
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices)
-{
- bool debug_indicate_size = false;
-
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<typename AngleInfo::point_type>::type
- >::type side_strategy;
- std::size_t i = 0;
- std::size_t n = boost::size(angles);
+//! Returns the number of clusters
+template <typename Point, typename AngleCollection>
+inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin)
+{
+ // Assign same cluster_index for all turns in same direction
+ BOOST_ASSERT(boost::size(sorted) >= 4u);
- typedef geometry::ever_circling_range_iterator<Angles const> circling_iterator;
- circling_iterator cit(angles);
+ angle_equal_to<Point> comparator(origin);
+ typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
- debug_left_turn(*cit, *cit);
- for(circling_iterator prev = cit++; i < n; prev = cit++, i++)
+ std::size_t cluster_index = 0;
+ it->cluster_index = cluster_index;
+ typename boost::range_iterator<AngleCollection>::type previous = it++;
+ for (; it != sorted.end(); ++it)
{
- debug_left_turn(*cit, *prev);
-
- bool const include = ! geometry::math::equals(prev->angle, cit->angle)
- && ! prev->incoming
- && cit->incoming;
-
- if (include)
+ if (!comparator(*previous, *it))
{
- // Go back to possibly include more same left outgoing angles:
- // Because we check on side too we can take a large "epsilon"
- circling_iterator back = prev - 1;
-
- typename AngleInfo::angle_type eps = 0.00001;
- int b = 1;
- for(std::size_t d = 0;
- math::abs(prev->angle - back->angle) < eps
- && ! back->incoming
- && d < n;
- d++)
- {
- --back;
- ++b;
- }
+ cluster_index++;
+ previous = it;
+ }
+ it->cluster_index = cluster_index;
+ }
+ return cluster_index + 1;
+}
- // Same but forward to possibly include more incoming angles
- int f = 1;
- circling_iterator forward = cit + 1;
- for(std::size_t d = 0;
- math::abs(cit->angle - forward->angle) < eps
- && forward->incoming
- && d < n;
- d++)
- {
- ++forward;
- ++f;
- }
+template <typename AngleCollection>
+inline void block_turns(AngleCollection& sorted, std::size_t cluster_size)
+{
+ BOOST_ASSERT(boost::size(sorted) >= 4u && cluster_size > 0);
-#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
- std::cout << "HANDLE " << b << "/" << f << " ANGLES" << std::endl;
-#endif
- for(circling_iterator bit = prev; bit != back; --bit)
- {
- int code = side_strategy::apply(bit->direction_point, prev->intersection_point, prev->direction_point);
- int code2 = side_strategy::apply(prev->direction_point, bit->intersection_point, bit->direction_point);
- for(circling_iterator fit = cit; fit != forward; ++fit)
- {
- int code3 = side_strategy::apply(fit->direction_point, cit->intersection_point, cit->direction_point);
- int code4 = side_strategy::apply(cit->direction_point, fit->intersection_point, fit->direction_point);
-
- int priority = 2;
- if (code == -1 && code2 == 1)
- {
- // This segment is lying right of the other one.
- // Cannot ignore it (because of robustness, see a.o. #rt_p21 from unit test).
- // But if we find more we can prefer later by priority
- // (a.o. necessary for #rt_o2 from unit test)
- priority = 1;
- }
-
- bool included = include_left_turn_of_all(*bit, *fit, turns, turn_segment_indices, keep_indices, priority);
- debug_left_turn(included ? "KEEP" : "SKIP", *fit, *bit, code, code2, code3, code4);
- }
- }
- }
+ std::vector<std::pair<bool, bool> > directions;
+ for (std::size_t i = 0; i < cluster_size; i++)
+ {
+ directions.push_back(std::make_pair(false, false));
}
- if (debug_indicate_size)
+ for (typename boost::range_iterator<AngleCollection const>::type it = sorted.begin();
+ it != sorted.end(); ++it)
{
- std::cout << " size=" << keep_indices.size();
+ if (it->incoming)
+ {
+ directions[it->cluster_index].first = true;
+ }
+ else
+ {
+ directions[it->cluster_index].second = true;
+ }
}
- if (keep_indices.size() >= 2)
+ for (typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
+ it != sorted.end(); ++it)
{
- prefer_by_other(turns, turn_segment_indices, keep_indices);
+ int cluster_index = it->cluster_index;
+ int previous_index = cluster_index - 1;
+ if (previous_index < 0)
+ {
+ previous_index = cluster_size - 1;
+ }
+ int next_index = cluster_index + 1;
+ if (next_index >= static_cast<int>(cluster_size))
+ {
+ next_index = 0;
+ }
+
+ if (directions[cluster_index].first
+ && directions[cluster_index].second)
+ {
+ it->blocked = true;
+ }
+ else if (!directions[cluster_index].first
+ && directions[cluster_index].second
+ && directions[previous_index].second)
+ {
+ // Only outgoing, previous was also outgoing: block this one
+ it->blocked = true;
+ }
+ else if (directions[cluster_index].first
+ && !directions[cluster_index].second
+ && !directions[previous_index].first
+ && directions[previous_index].second)
+ {
+ // Only incoming, previous was only outgoing: block this one
+ it->blocked = true;
+ }
+ else if (directions[cluster_index].first
+ && !directions[cluster_index].second
+ && directions[next_index].first
+ && !directions[next_index].second)
+ {
+ // Only incoming, next also incoming, block this one
+ it->blocked = true;
+ }
}
- if (keep_indices.size() >= 2)
+}
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+template <typename AngleCollection, typename Point>
+inline bool has_rounding_issues(AngleCollection const& angles, Point const& origin)
+{
+ for (typename boost::range_iterator<AngleCollection const>::type it =
+ angles.begin(); it != angles.end(); ++it)
{
- prefer_by_priority(turns, keep_indices);
+ // Vector origin -> p and origin -> q
+ typedef Point vector_type;
+ vector_type v = it->point;
+ geometry::subtract_point(v, origin);
+ return geometry::math::abs(geometry::get<0>(v)) <= 1
+ || geometry::math::abs(geometry::get<1>(v)) <= 1
+ ;
}
+ return false;
}
+#endif
+
+
+} // namespace left_turns
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/get_max_size.hpp b/boost/geometry/algorithms/detail/get_max_size.hpp
new file mode 100644
index 0000000000..8ac43e78b8
--- /dev/null
+++ b/boost/geometry/algorithms/detail/get_max_size.hpp
@@ -0,0 +1,64 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2014 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// 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_GET_MAX_SIZE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename Box, std::size_t Dimension>
+struct get_max_size_box
+{
+ static inline typename coordinate_type<Box>::type apply(Box const& box)
+ {
+ typename coordinate_type<Box>::type s
+ = geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box));
+
+ return (std::max)(s, get_max_size_box<Box, Dimension - 1>::apply(box));
+ }
+};
+
+template <typename Box>
+struct get_max_size_box<Box, 0>
+{
+ static inline typename coordinate_type<Box>::type apply(Box const& box)
+ {
+ return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box));
+ }
+};
+
+// This might be implemented later on for other geometries too.
+// Not dispatched yet.
+template <typename Box>
+inline typename coordinate_type<Box>::type get_max_size(Box const& box)
+{
+ return get_max_size_box<Box, dimension<Box>::value - 1>::apply(box);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp
index 1e6215ed93..24746ac627 100644
--- a/boost/geometry/algorithms/detail/has_self_intersections.hpp
+++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp
@@ -17,7 +17,10 @@
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
@@ -56,26 +59,33 @@ namespace detail { namespace overlay
{
-template <typename Geometry>
-inline bool has_self_intersections(Geometry const& geometry)
+template <typename Geometry, typename RobustPolicy>
+inline bool has_self_intersections(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
+ bool throw_on_self_intersection = true)
{
typedef typename point_type<Geometry>::type point_type;
- typedef detail::overlay::turn_info<point_type> turn_info;
+ typedef turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
- geometry::self_turns<detail::overlay::assign_null_policy>(geometry, turns, policy);
-
+
+ geometry::self_turns<detail::overlay::assign_null_policy>(geometry, robust_policy, turns, policy);
+
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
-#endif
- for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns);
+#endif
+ for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns);
it != boost::end(turns); ++it)
{
turn_info const& info = *it;
- bool const both_union_turn =
+ bool const both_union_turn =
info.operations[0].operation == detail::overlay::operation_union
&& info.operations[1].operation == detail::overlay::operation_union;
- bool const both_intersection_turn =
+ bool const both_intersection_turn =
info.operations[0].operation == detail::overlay::operation_intersection
&& info.operations[1].operation == detail::overlay::operation_intersection;
@@ -95,19 +105,40 @@ inline bool has_self_intersections(Geometry const& geometry)
for (int i = 0; i < 2; i++)
{
std::cout << " " << operation_char(info.operations[i].operation);
+ std::cout << " " << info.operations[i].seg_id;
}
std::cout << " " << geometry::dsv(info.point) << std::endl;
#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
- throw overlay_invalid_input_exception();
+ if (throw_on_self_intersection)
+ {
+ throw overlay_invalid_input_exception();
+ }
#endif
+ return true;
}
}
return false;
}
+// For backward compatibility
+template <typename Geometry>
+inline bool has_self_intersections(Geometry const& geometry,
+ bool throw_on_self_intersection = true)
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename geometry::rescale_policy_type<point_type>::type
+ rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry);
+
+ return has_self_intersections(geometry, robust_policy,
+ throw_on_self_intersection);
+}
+
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/interior_iterator.hpp b/boost/geometry/algorithms/detail/interior_iterator.hpp
new file mode 100644
index 0000000000..3582773c3d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/interior_iterator.hpp
@@ -0,0 +1,71 @@
+// Boost.Geometry
+
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// 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_INTERIOR_ITERATOR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP
+
+#include <boost/range/iterator.hpp>
+#include <boost/range/value_type.hpp>
+
+#include <boost/geometry/core/interior_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+/*!
+\brief Structure defining the type of interior rings iterator
+\note If the Geometry is const, const iterator is defined.
+\tparam Geometry \tparam_geometry
+ */
+template <typename Geometry>
+struct interior_iterator
+{
+ typedef typename boost::range_iterator
+ <
+ typename geometry::interior_type<Geometry>::type
+ >::type type;
+};
+
+template <typename BaseT, typename T>
+struct copy_const
+{
+ typedef T type;
+};
+
+template <typename BaseT, typename T>
+struct copy_const<BaseT const, T>
+{
+ typedef T const type;
+};
+
+template <typename Geometry>
+struct interior_ring_iterator
+{
+ typedef typename boost::range_iterator
+ <
+ typename copy_const
+ <
+ typename geometry::interior_type<Geometry>::type,
+ typename boost::range_value
+ <
+ typename geometry::interior_type<Geometry>::type
+ >::type
+ >::type
+ >::type type;
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/box_box.hpp b/boost/geometry/algorithms/detail/intersection/box_box.hpp
new file mode 100644
index 0000000000..30c31ff1e5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/box_box.hpp
@@ -0,0 +1,54 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_INTERSECTION_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP
+
+
+#include <boost/geometry/algorithms/detail/intersection/interface.hpp>
+#include <boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Box1, typename Box2, bool Reverse
+>
+struct intersection
+ <
+ Box1, Box2,
+ box_tag, box_tag,
+ Reverse
+ > : public detail::intersection::intersection_box_box
+ <
+ 0, geometry::dimension<Box1>::value
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/implementation.hpp b/boost/geometry/algorithms/detail/intersection/implementation.hpp
new file mode 100644
index 0000000000..d8fb2ec38c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/implementation.hpp
@@ -0,0 +1,22 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_INTERSECTION_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP
+
+
+#include <boost/geometry/algorithms/detail/intersection/box_box.hpp>
+#include <boost/geometry/algorithms/detail/intersection/multi.hpp>
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp
new file mode 100644
index 0000000000..323ab7c850
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/interface.hpp
@@ -0,0 +1,309 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_INTERSECTION_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP
+
+
+// TODO: those headers probably may be removed
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// By default, all is forwarded to the intersection_insert-dispatcher
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct intersection
+{
+ template <typename RobustPolicy, typename GeometryOut, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ GeometryOut& geometry_out,
+ Strategy const& strategy)
+ {
+ typedef typename boost::range_value<GeometryOut>::type OneOut;
+
+ intersection_insert
+ <
+ Geometry1, Geometry2, OneOut,
+ overlay_intersection
+ >::apply(geometry1, geometry2, robust_policy, std::back_inserter(geometry_out), strategy);
+
+ return true;
+ }
+
+};
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2
+>
+struct intersection
+<
+ Geometry1, Geometry2,
+ Tag1, Tag2,
+ true
+>
+ : intersection<Geometry2, Geometry1, Tag2, Tag1, false>
+{
+ template <typename RobustPolicy, typename GeometryOut, typename Strategy>
+ static inline bool apply(
+ Geometry1 const& g1,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ GeometryOut& out,
+ Strategy const& strategy)
+ {
+ return intersection<
+ Geometry2, Geometry1,
+ Tag2, Tag1,
+ false
+ >::apply(g2, g1, robust_policy, out, strategy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct intersection
+{
+ template <typename GeometryOut>
+ static inline bool
+ apply(
+ const Geometry1& geometry1,
+ const Geometry2& geometry2,
+ GeometryOut& geometry_out)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<Geometry1>::type,
+ Geometry1,
+ Geometry2,
+ typename geometry::point_type<Geometry1>::type,
+ rescale_policy_type
+ > strategy;
+
+ return dispatch::intersection
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy());
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename GeometryOut>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ GeometryOut& m_geometry_out;
+
+ visitor(Geometry2 const& geometry2,
+ GeometryOut& geometry_out)
+ : m_geometry2(geometry2),
+ m_geometry_out(geometry_out)
+ {}
+
+ template <typename Geometry1>
+ result_type operator()(Geometry1 const& geometry1) const
+ {
+ return intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (geometry1, m_geometry2, m_geometry_out);
+ }
+ };
+
+ template <typename GeometryOut>
+ static inline bool
+ apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ GeometryOut& geometry_out)
+ {
+ return apply_visitor(visitor<GeometryOut>(geometry2, geometry_out), geometry1);
+ }
+};
+
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename GeometryOut>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ GeometryOut& m_geometry_out;
+
+ visitor(Geometry1 const& geometry1,
+ GeometryOut& geometry_out)
+ : m_geometry1(geometry1),
+ m_geometry_out(geometry_out)
+ {}
+
+ template <typename Geometry2>
+ result_type operator()(Geometry2 const& geometry2) const
+ {
+ return intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (m_geometry1, geometry2, m_geometry_out);
+ }
+ };
+
+ template <typename GeometryOut>
+ static inline bool
+ apply(
+ Geometry1 const& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
+ GeometryOut& geometry_out)
+ {
+ return apply_visitor(visitor<GeometryOut>(geometry1, geometry_out), geometry2);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
+struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+{
+ template <typename GeometryOut>
+ struct visitor: static_visitor<bool>
+ {
+ GeometryOut& m_geometry_out;
+
+ visitor(GeometryOut& geometry_out)
+ : m_geometry_out(geometry_out)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ result_type operator()(
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (geometry1, geometry2, m_geometry_out);
+ }
+ };
+
+ template <typename GeometryOut>
+ static inline bool
+ apply(
+ const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2,
+ GeometryOut& geometry_out)
+ {
+ return apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_calc2{intersection}
+\ingroup intersection
+\details \details_calc2{intersection, spatial set theoretic intersection}.
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which
+ the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box)
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param geometry_out The output geometry, either a multi_point, multi_polygon,
+ multi_linestring, or a box (for intersection of two boxes)
+
+\qbk{[include reference/algorithms/intersection.qbk]}
+*/
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename GeometryOut
+>
+inline bool intersection(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ GeometryOut& geometry_out)
+{
+ return resolve_variant::intersection
+ <
+ Geometry1,
+ Geometry2
+ >::template apply
+ <
+ GeometryOut
+ >
+ (geometry1, geometry2, geometry_out);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/multi.hpp b/boost/geometry/algorithms/detail/intersection/multi.hpp
new file mode 100644
index 0000000000..b1f13862fc
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersection/multi.hpp
@@ -0,0 +1,423 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_INTERSECTION_MULTI_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/geometry_id.hpp>
+#include <boost/geometry/core/is_areal.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+// TODO: those headers probably may be removed
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
+
+#include <boost/geometry/algorithms/detail/intersection/interface.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+
+// TODO: remove this after moving num_point from multi directory
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+
+template <typename PointOut>
+struct intersection_multi_linestring_multi_linestring_point
+{
+ template
+ <
+ typename MultiLinestring1, typename MultiLinestring2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(MultiLinestring1 const& ml1,
+ MultiLinestring2 const& ml2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ // Note, this loop is quadratic w.r.t. number of linestrings per input.
+ // Future Enhancement: first do the sections of each, then intersect.
+ for (typename boost::range_iterator
+ <
+ MultiLinestring1 const
+ >::type it1 = boost::begin(ml1);
+ it1 != boost::end(ml1);
+ ++it1)
+ {
+ for (typename boost::range_iterator
+ <
+ MultiLinestring2 const
+ >::type it2 = boost::begin(ml2);
+ it2 != boost::end(ml2);
+ ++it2)
+ {
+ out = intersection_linestring_linestring_point<PointOut>
+ ::apply(*it1, *it2, robust_policy, out, strategy);
+ }
+ }
+
+ return out;
+ }
+};
+
+
+template <typename PointOut>
+struct intersection_linestring_multi_linestring_point
+{
+ template
+ <
+ typename Linestring, typename MultiLinestring,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linestring const& linestring,
+ MultiLinestring const& ml,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ for (typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type it = boost::begin(ml);
+ it != boost::end(ml);
+ ++it)
+ {
+ out = intersection_linestring_linestring_point<PointOut>
+ ::apply(linestring, *it, robust_policy, out, strategy);
+ }
+
+ return out;
+ }
+};
+
+
+// This loop is quite similar to the loop above, but beacuse the iterator
+// is second (above) or first (below) argument, it is not trivial to merge them.
+template
+<
+ bool ReverseAreal,
+ typename LineStringOut,
+ overlay_type OverlayType
+>
+struct intersection_of_multi_linestring_with_areal
+{
+ template
+ <
+ typename MultiLinestring, typename Areal,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ for (typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type it = boost::begin(ml);
+ it != boost::end(ml);
+ ++it)
+ {
+ out = intersection_of_linestring_with_areal
+ <
+ ReverseAreal, LineStringOut, OverlayType
+ >::apply(*it, areal, robust_policy, out, strategy);
+ }
+
+ return out;
+
+ }
+};
+
+// This one calls the one above with reversed arguments
+template
+<
+ bool ReverseAreal,
+ typename LineStringOut,
+ overlay_type OverlayType
+>
+struct intersection_of_areal_with_multi_linestring
+{
+ template
+ <
+ typename Areal, typename MultiLinestring,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ return intersection_of_multi_linestring_with_areal
+ <
+ ReverseAreal, LineStringOut, OverlayType
+ >::apply(ml, areal, robust_policy, out, strategy);
+ }
+};
+
+
+
+template <typename LinestringOut>
+struct clip_multi_linestring
+{
+ template
+ <
+ typename MultiLinestring, typename Box,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(MultiLinestring const& multi_linestring,
+ Box const& box,
+ RobustPolicy const& robust_policy,
+ OutputIterator out, Strategy const& )
+ {
+ typedef typename point_type<LinestringOut>::type point_type;
+ strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
+ for (typename boost::range_iterator<MultiLinestring const>::type it
+ = boost::begin(multi_linestring);
+ it != boost::end(multi_linestring); ++it)
+ {
+ out = detail::intersection::clip_range_with_box
+ <LinestringOut>(box, *it, robust_policy, out, lb_strategy);
+ }
+ return out;
+ }
+};
+
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Linear
+template
+<
+ typename MultiLinestring1, typename MultiLinestring2,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring1, MultiLinestring2,
+ GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_linestring_tag, multi_linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_multi_linestring_multi_linestring_point
+ <
+ GeometryOut
+ >
+{};
+
+
+template
+<
+ typename Linestring, typename MultiLinestring,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linestring, MultiLinestring,
+ GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ linestring_tag, multi_linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_linestring_multi_linestring_point
+ <
+ GeometryOut
+ >
+{};
+
+
+template
+<
+ typename MultiLinestring, typename Box,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, Box,
+ GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_linestring_tag, box_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::clip_multi_linestring
+ <
+ GeometryOut
+ >
+{};
+
+
+template
+<
+ typename Linestring, typename MultiPolygon,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseLinestring, bool ReverseMultiPolygon, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linestring, MultiPolygon,
+ GeometryOut,
+ OverlayType,
+ ReverseLinestring, ReverseMultiPolygon, ReverseOut,
+ linestring_tag, multi_polygon_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_linestring_with_areal
+ <
+ ReverseMultiPolygon,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+// Derives from areal/mls because runtime arguments are in that order.
+// areal/mls reverses it itself to mls/areal
+template
+<
+ typename Polygon, typename MultiLinestring,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReversePolygon, bool ReverseMultiLinestring, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Polygon, MultiLinestring,
+ GeometryOut,
+ OverlayType,
+ ReversePolygon, ReverseMultiLinestring, ReverseOut,
+ polygon_tag, multi_linestring_tag, linestring_tag,
+ true, false, false
+ > : detail::intersection::intersection_of_areal_with_multi_linestring
+ <
+ ReversePolygon,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiLinestring, typename Ring,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, Ring,
+ GeometryOut,
+ OverlayType,
+ ReverseMultiLinestring, ReverseRing, ReverseOut,
+ multi_linestring_tag, ring_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_multi_linestring_with_areal
+ <
+ ReverseRing,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+template
+<
+ typename MultiLinestring, typename Polygon,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseMultiLinestring, bool ReverseRing, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, Polygon,
+ GeometryOut,
+ OverlayType,
+ ReverseMultiLinestring, ReverseRing, ReverseOut,
+ multi_linestring_tag, polygon_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_multi_linestring_with_areal
+ <
+ ReverseRing,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+
+template
+<
+ typename MultiLinestring, typename MultiPolygon,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ bool ReverseMultiLinestring, bool ReverseMultiPolygon, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiLinestring, MultiPolygon,
+ GeometryOut,
+ OverlayType,
+ ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut,
+ multi_linestring_tag, multi_polygon_tag, linestring_tag,
+ false, true, false
+ > : detail::intersection::intersection_of_multi_linestring_with_areal
+ <
+ ReverseMultiPolygon,
+ GeometryOut,
+ OverlayType
+ >
+{};
+
+
+} // namespace dispatch
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP
+
diff --git a/boost/geometry/algorithms/detail/is_simple/always_simple.hpp b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp
new file mode 100644
index 0000000000..91e2ef76bd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/always_simple.hpp
@@ -0,0 +1,83 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP
+
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename Geometry>
+struct always_simple
+{
+ static inline bool apply(Geometry const&)
+ {
+ return true;
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A point is always simple
+template <typename Point>
+struct is_simple<Point, point_tag>
+ : detail::is_simple::always_simple<Point>
+{};
+
+
+// A valid segment is always simple.
+// A segment is a curve.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Segment>
+struct is_simple<Segment, segment_tag>
+ : detail::is_simple::always_simple<Segment>
+{};
+
+
+// A valid box is always simple
+// A box is a Polygon, and it satisfies the conditions for Polygon validity.
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Box>
+struct is_simple<Box, box_tag>
+ : detail::is_simple::always_simple<Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp
new file mode 100644
index 0000000000..9a1a16507a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp
@@ -0,0 +1,141 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename Ring>
+struct is_simple_ring
+{
+ static inline bool apply(Ring const& ring)
+ {
+ return
+ !detail::is_valid::has_duplicates
+ <
+ Ring, geometry::closure<Ring>::value
+ >::apply(ring);
+ }
+};
+
+
+template <typename Polygon>
+class is_simple_polygon
+{
+private:
+ template <typename InteriorRings>
+ static inline
+ bool are_simple_interior_rings(InteriorRings const& interior_rings)
+ {
+ return
+ detail::check_iterator_range
+ <
+ is_simple_ring
+ <
+ typename boost::range_value<InteriorRings>::type
+ >
+ >::apply(boost::begin(interior_rings),
+ boost::end(interior_rings));
+ }
+
+public:
+ static inline bool apply(Polygon const& polygon)
+ {
+ return
+ is_simple_ring
+ <
+ typename ring_type<Polygon>::type
+ >::apply(exterior_ring(polygon))
+ &&
+ are_simple_interior_rings(geometry::interior_rings(polygon));
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A Ring is a Polygon.
+// A Polygon is always a simple geometric object provided that it is valid.
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Ring>
+struct is_simple<Ring, ring_tag>
+ : detail::is_simple::is_simple_ring<Ring>
+{};
+
+
+// A Polygon is always a simple geometric object provided that it is valid.
+//
+// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1)
+template <typename Polygon>
+struct is_simple<Polygon, polygon_tag>
+ : detail::is_simple::is_simple_polygon<Polygon>
+{};
+
+
+// Not clear what the definition is.
+// Right now we consider a MultiPolygon as simple if it is valid.
+//
+// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14)
+template <typename MultiPolygon>
+struct is_simple<MultiPolygon, multi_polygon_tag>
+{
+ static inline bool apply(MultiPolygon const& multipolygon)
+ {
+ return
+ detail::check_iterator_range
+ <
+ detail::is_simple::is_simple_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type
+ >,
+ false // do not allow empty multi-polygon
+ >::apply(boost::begin(multipolygon), boost::end(multipolygon));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
new file mode 100644
index 0000000000..75c37c68f8
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
@@ -0,0 +1,82 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/io/dsv/write.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_simple
+{
+
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename MultiLinestring>
+inline void debug_print_boundary_points(MultiLinestring const& multilinestring)
+{
+ typedef typename point_type<MultiLinestring>::type point_type;
+ typedef std::vector<point_type> point_vector;
+
+ point_vector boundary_points;
+ for (typename boost::range_iterator<MultiLinestring const>::type it
+ = boost::begin(multilinestring);
+ it != boost::end(multilinestring); ++it)
+ {
+ if ( boost::size(*it) > 1
+ && !geometry::equals(range::front(*it), range::back(*it)) )
+ {
+ boundary_points.push_back( range::front(*it) );
+ boundary_points.push_back( range::back(*it) );
+ }
+ }
+
+ std::sort(boundary_points.begin(), boundary_points.end(),
+ geometry::less<point_type>());
+
+ std::cout << "boundary points: ";
+ for (typename point_vector::const_iterator pit = boundary_points.begin();
+ pit != boundary_points.end(); ++pit)
+ {
+ std::cout << " " << geometry::dsv(*pit);
+ }
+ std::cout << std::endl << std::endl;
+}
+#else
+template <typename MultiLinestring>
+inline void debug_print_boundary_points(MultiLinestring const&)
+{
+}
+#endif // BOOST_GEOMETRY_TEST_DEBUG
+
+
+}} // namespace detail::is_simple
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/implementation.hpp b/boost/geometry/algorithms/detail/is_simple/implementation.hpp
new file mode 100644
index 0000000000..e69b273ce3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/implementation.hpp
@@ -0,0 +1,18 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP
+
+#include <boost/geometry/algorithms/detail/is_simple/always_simple.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/areal.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/linear.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/multipoint.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/interface.hpp b/boost/geometry/algorithms/detail/is_simple/interface.hpp
new file mode 100644
index 0000000000..4239664ed1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/interface.hpp
@@ -0,0 +1,80 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct is_simple
+{
+ static inline bool apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+ return dispatch::is_simple<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor : boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return is_simple<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{is simple}
+\ingroup is_simple
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is simple}
+
+\qbk{[include reference/algorithms/is_simple.qbk]}
+*/
+template <typename Geometry>
+inline bool is_simple(Geometry const& geometry)
+{
+ return resolve_variant::is_simple<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp
new file mode 100644
index 0000000000..f2efcb309d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -0,0 +1,248 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
+
+#include <algorithm>
+#include <deque>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
+
+#include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename Linestring, bool CheckSelfIntersections = true>
+struct is_simple_linestring
+{
+ static inline bool apply(Linestring const& linestring)
+ {
+ return !detail::is_valid::has_duplicates
+ <
+ Linestring, closed
+ >::apply(linestring)
+ && !detail::is_valid::has_spikes
+ <
+ Linestring, closed
+ >::apply(linestring)
+ && !(CheckSelfIntersections && geometry::intersects(linestring));
+ }
+};
+
+
+
+template <typename MultiLinestring>
+class is_simple_multilinestring
+{
+private:
+ class is_acceptable_turn
+ {
+ private:
+ template <typename Point, typename Linestring>
+ static inline bool is_boundary_point_of(Point const& point,
+ Linestring const& linestring)
+ {
+ BOOST_ASSERT( boost::size(linestring) > 1 );
+ return
+ !geometry::equals(range::front(linestring),
+ range::back(linestring))
+ &&
+ ( geometry::equals(point, range::front(linestring))
+ || geometry::equals(point, range::back(linestring)) );
+ }
+
+ template <typename Linestring1, typename Linestring2>
+ static inline bool have_same_boundary_points(Linestring1 const& ls1,
+ Linestring2 const& ls2)
+ {
+ return
+ geometry::equals(range::front(ls1), range::front(ls2))
+ ?
+ geometry::equals(range::back(ls1), range::back(ls2))
+ :
+ (geometry::equals(range::front(ls1), range::back(ls2))
+ &&
+ geometry::equals(range::back(ls1), range::front(ls2))
+ )
+ ;
+ }
+
+ public:
+ is_acceptable_turn(MultiLinestring const& multilinestring)
+ : m_multilinestring(multilinestring)
+ {}
+
+ template <typename Turn>
+ inline bool apply(Turn const& turn) const
+ {
+ typedef typename boost::range_value
+ <
+ MultiLinestring
+ >::type linestring;
+
+ linestring const& ls1 =
+ range::at(m_multilinestring,
+ turn.operations[0].seg_id.multi_index);
+
+ linestring const& ls2 =
+ range::at(m_multilinestring,
+ turn.operations[1].seg_id.multi_index);
+
+ return
+ is_boundary_point_of(turn.point, ls1)
+ && is_boundary_point_of(turn.point, ls2)
+ &&
+ ( boost::size(ls1) != 2
+ || boost::size(ls2) != 2
+ || !have_same_boundary_points(ls1, ls2) );
+ }
+
+ private:
+ MultiLinestring const& m_multilinestring;
+ };
+
+
+public:
+ static inline bool apply(MultiLinestring const& multilinestring)
+ {
+ typedef typename boost::range_value<MultiLinestring>::type linestring;
+ typedef typename point_type<MultiLinestring>::type point_type;
+ typedef point_type point;
+
+
+ // check each of the linestrings for simplicity
+ if ( !detail::check_iterator_range
+ <
+ is_simple_linestring<linestring>,
+ false // do not allow empty multilinestring
+ >::apply(boost::begin(multilinestring),
+ boost::end(multilinestring))
+ )
+ {
+ return false;
+ }
+
+
+ // compute self turns
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ geometry::segment_ratio
+ <
+ typename geometry::coordinate_type<point>::type
+ >
+ > turn_info;
+
+ std::deque<turn_info> turns;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::disjoint::assign_disjoint_policy
+ > turn_policy;
+
+ is_acceptable_turn predicate(multilinestring);
+ detail::overlay::predicate_based_interrupt_policy
+ <
+ is_acceptable_turn
+ > interrupt_policy(predicate);
+
+ detail::self_get_turn_points::get_turns
+ <
+ turn_policy
+ >::apply(multilinestring,
+ detail::no_rescale_policy(),
+ turns,
+ interrupt_policy);
+
+ detail::is_valid::debug_print_turns(turns.begin(), turns.end());
+ debug_print_boundary_points(multilinestring);
+
+ return !interrupt_policy.has_intersections;
+ }
+
+};
+
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// A linestring is a curve.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Linestring>
+struct is_simple<Linestring, linestring_tag>
+ : detail::is_simple::is_simple_linestring<Linestring>
+{};
+
+
+// A MultiLinestring is a MultiCurve
+// A MultiCurve is simple if all of its elements are simple and the
+// only intersections between any two elements occur at Points that
+// are on the boundaries of both elements.
+//
+// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
+template <typename MultiLinestring>
+struct is_simple<MultiLinestring, multi_linestring_tag>
+ : detail::is_simple::is_simple_multilinestring<MultiLinestring>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
new file mode 100644
index 0000000000..d996eb64e9
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
@@ -0,0 +1,84 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP
+
+#include <algorithm>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+template <typename MultiPoint>
+struct is_simple_multipoint
+{
+ static inline bool apply(MultiPoint const& multipoint)
+ {
+ if ( boost::size(multipoint) == 0 )
+ {
+ return false;
+ }
+
+ MultiPoint mp(multipoint);
+ std::sort(boost::begin(mp), boost::end(mp),
+ geometry::less<typename point_type<MultiPoint>::type>());
+
+ return !detail::is_valid::has_duplicates<MultiPoint, closed>::apply(mp);
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A MultiPoint is simple if no two Points in the MultiPoint are equal
+// (have identical coordinate values in X and Y)
+//
+// Reference: OGC 06-103r4 (6.1.5)
+template <typename MultiPoint>
+struct is_simple<MultiPoint, multi_point_tag>
+ : detail::is_simple::is_simple_multipoint<MultiPoint>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp
new file mode 100644
index 0000000000..f82b3f9bf1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/box.hpp
@@ -0,0 +1,86 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+template <typename Box, std::size_t I>
+struct has_valid_corners
+{
+ static inline bool apply(Box const& box)
+ {
+ if ( geometry::get<geometry::max_corner, I-1>(box)
+ <=
+ geometry::get<geometry::min_corner, I-1>(box) )
+ {
+ return false;
+ }
+ return has_valid_corners<Box, I-1>::apply(box);
+ }
+};
+
+
+template <typename Box>
+struct has_valid_corners<Box, 0>
+{
+ static inline bool apply(Box const&)
+ {
+ return true;
+ }
+};
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A box is always simple
+// A box is a Polygon, and it satisfies the conditions for Polygon validity.
+//
+// The only thing we have to check is whether the max corner lies in
+// the upper-right quadrant as defined by the min corner
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Box>
+struct is_valid<Box, box_tag>
+ : detail::is_valid::has_valid_corners<Box, dimension<Box>::value>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
new file mode 100644
index 0000000000..c59139a92e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/complement_graph.hpp
@@ -0,0 +1,239 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
+
+#include <cstddef>
+
+#include <set>
+#include <stack>
+#include <utility>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/core/addressof.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+
+template <typename TurnPoint>
+class complement_graph_vertex
+{
+public:
+ complement_graph_vertex(std::size_t id)
+ : m_id(id)
+ , m_turn_point(NULL)
+ {}
+
+ complement_graph_vertex(TurnPoint const* turn_point,
+ std::size_t expected_id)
+ : m_id(expected_id)
+ , m_turn_point(turn_point)
+ {}
+
+ inline std::size_t id() const { return m_id; }
+
+ inline bool operator<(complement_graph_vertex const& other) const
+ {
+ if ( m_turn_point != NULL && other.m_turn_point != NULL )
+ {
+ return geometry::less
+ <
+ TurnPoint
+ >()(*m_turn_point, *other.m_turn_point);
+ }
+ if ( m_turn_point == NULL && other.m_turn_point == NULL )
+ {
+ return m_id < other.m_id;
+ }
+ return m_turn_point == NULL;
+ }
+
+private:
+ // the value of m_turn_point determines the type of the vertex
+ // non-NULL: vertex corresponds to an IP
+ // NULL : vertex corresponds to a hole or outer space, and the id
+ // is the ring id of the corresponding ring of the polygon
+ std::size_t m_id;
+ TurnPoint const* m_turn_point;
+};
+
+
+
+
+template <typename TurnPoint>
+class complement_graph
+{
+private:
+ typedef complement_graph_vertex<TurnPoint> vertex;
+ typedef std::set<vertex> vertex_container;
+
+public:
+ typedef typename vertex_container::const_iterator vertex_handle;
+
+private:
+ struct vertex_handle_less
+ {
+ inline bool operator()(vertex_handle v1, vertex_handle v2) const
+ {
+ return v1->id() < v2->id();
+ }
+ };
+
+ typedef std::set<vertex_handle, vertex_handle_less> neighbor_container;
+
+ class has_cycles_dfs_data
+ {
+ public:
+ has_cycles_dfs_data(std::size_t num_nodes)
+ : m_visited(num_nodes, false)
+ , m_parent_id(num_nodes, -1)
+ {}
+
+ inline signed_index_type parent_id(vertex_handle v) const
+ {
+ return m_parent_id[v->id()];
+ }
+
+ inline void set_parent_id(vertex_handle v, signed_index_type id)
+ {
+ m_parent_id[v->id()] = id;
+ }
+
+ inline bool visited(vertex_handle v) const
+ {
+ return m_visited[v->id()];
+ }
+
+ inline void set_visited(vertex_handle v, bool value)
+ {
+ m_visited[v->id()] = value;
+ }
+ private:
+ std::vector<bool> m_visited;
+ std::vector<signed_index_type> m_parent_id;
+ };
+
+
+ inline bool has_cycles(vertex_handle start_vertex,
+ has_cycles_dfs_data& data) const
+ {
+ std::stack<vertex_handle> stack;
+ stack.push(start_vertex);
+
+ while ( !stack.empty() )
+ {
+ vertex_handle v = stack.top();
+ stack.pop();
+
+ data.set_visited(v, true);
+ for (typename neighbor_container::const_iterator nit
+ = m_neighbors[v->id()].begin();
+ nit != m_neighbors[v->id()].end(); ++nit)
+ {
+ if ( static_cast<signed_index_type>((*nit)->id()) != data.parent_id(v) )
+ {
+ if ( data.visited(*nit) )
+ {
+ return true;
+ }
+ else
+ {
+ data.set_parent_id(*nit, static_cast<signed_index_type>(v->id()));
+ stack.push(*nit);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+public:
+ // num_rings: total number of rings, including the exterior ring
+ complement_graph(std::size_t num_rings)
+ : m_num_rings(num_rings)
+ , m_num_turns(0)
+ , m_vertices()
+ , m_neighbors(num_rings)
+ {}
+
+ // inserts a ring vertex in the graph and returns its handle
+ // ring id's are zero-based (so the first interior ring has id 1)
+ inline vertex_handle add_vertex(signed_index_type id)
+ {
+ return m_vertices.insert(vertex(static_cast<std::size_t>(id))).first;
+ }
+
+ // inserts an IP in the graph and returns its id
+ inline vertex_handle add_vertex(TurnPoint const& turn_point)
+ {
+ std::pair<vertex_handle, bool> res
+ = m_vertices.insert(vertex(boost::addressof(turn_point),
+ m_num_rings + m_num_turns)
+ );
+
+ if ( res.second )
+ {
+ // a new element is inserted
+ m_neighbors.push_back(neighbor_container());
+ ++m_num_turns;
+ }
+ return res.first;
+ }
+
+ inline void add_edge(vertex_handle v1, vertex_handle v2)
+ {
+ BOOST_ASSERT( v1 != m_vertices.end() );
+ BOOST_ASSERT( v2 != m_vertices.end() );
+ m_neighbors[v1->id()].insert(v2);
+ m_neighbors[v2->id()].insert(v1);
+ }
+
+ inline bool has_cycles() const
+ {
+ // initialize all vertices as non-visited and with no parent set
+ // this is done by the constructor of has_cycles_dfs_data
+ has_cycles_dfs_data data(m_num_rings + m_num_turns);
+
+ // for each non-visited vertex, start a DFS from that vertex
+ for (vertex_handle it = m_vertices.begin();
+ it != m_vertices.end(); ++it)
+ {
+ if ( !data.visited(it) && has_cycles(it, data) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template <typename OStream, typename TP>
+ friend inline
+ void debug_print_complement_graph(OStream&, complement_graph<TP> const&);
+
+private:
+ std::size_t m_num_rings, m_num_turns;
+ vertex_container m_vertices;
+ std::vector<neighbor_container> m_neighbors;
+};
+
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp
new file mode 100644
index 0000000000..60f597e296
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <iostream>
+#endif
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename OutputStream, typename TurnPoint>
+inline void
+debug_print_complement_graph(OutputStream& os,
+ complement_graph<TurnPoint> const& graph)
+{
+ typedef typename complement_graph<TurnPoint>::vertex_handle vertex_handle;
+
+ os << "num rings: " << graph.m_num_rings << std::endl;
+ os << "vertex ids: {";
+ for (vertex_handle it = graph.m_vertices.begin();
+ it != graph.m_vertices.end(); ++it)
+ {
+ os << " " << it->id();
+ }
+ os << " }" << std::endl;
+
+ for (vertex_handle it = graph.m_vertices.begin();
+ it != graph.m_vertices.end(); ++it)
+ {
+ os << "neighbors of " << it->id() << ": {";
+ for (typename complement_graph
+ <
+ TurnPoint
+ >::neighbor_container::const_iterator
+ nit = graph.m_neighbors[it->id()].begin();
+ nit != graph.m_neighbors[it->id()].end(); ++nit)
+ {
+ os << " " << (*nit)->id();
+ }
+ os << "}" << std::endl;
+ }
+}
+#else
+template <typename OutputStream, typename TurnPoint>
+inline void debug_print_complement_graph(OutputStream&,
+ complement_graph<TurnPoint> const&)
+{
+}
+#endif
+
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
new file mode 100644
index 0000000000..6824921b63
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
@@ -0,0 +1,64 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <iostream>
+
+#include <boost/geometry/io/dsv/write.hpp>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename TurnIterator>
+inline void debug_print_turns(TurnIterator first, TurnIterator beyond)
+{
+ std::cout << "turns:";
+ for (TurnIterator tit = first; tit != beyond; ++tit)
+ {
+ std::cout << " ["
+ << geometry::method_char(tit->method)
+ << ","
+ << geometry::operation_char(tit->operations[0].operation)
+ << "/"
+ << geometry::operation_char(tit->operations[1].operation)
+ << " {"
+ << tit->operations[0].seg_id.multi_index
+ << ", "
+ << tit->operations[1].seg_id.multi_index
+ << "} {"
+ << tit->operations[0].seg_id.ring_index
+ << ", "
+ << tit->operations[1].seg_id.ring_index
+ << "} "
+ << geometry::dsv(tit->point)
+ << "]";
+ }
+ std::cout << std::endl << std::endl;
+}
+#else
+template <typename TurnIterator>
+inline void debug_print_turns(TurnIterator, TurnIterator)
+{}
+#endif // BOOST_GEOMETRY_TEST_DEBUG
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
new file mode 100644
index 0000000000..6f1c263646
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
@@ -0,0 +1,68 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP
+
+#ifdef GEOMETRY_TEST_DEBUG
+#include <iostream>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace is_valid
+{
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct debug_validity_phase
+{
+ static inline void apply(int)
+ {
+ }
+};
+
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename Polygon>
+struct debug_validity_phase<Polygon, polygon_tag>
+{
+ static inline void apply(int phase)
+ {
+ switch (phase)
+ {
+ case 1:
+ std::cout << "checking exterior ring..." << std::endl;
+ break;
+ case 2:
+ std::cout << "checking interior rings..." << std::endl;
+ break;
+ case 3:
+ std::cout << "computing and analyzing turns..." << std::endl;
+ break;
+ case 4:
+ std::cout << "checking if holes are inside the exterior ring..."
+ << std::endl;
+ break;
+ case 5:
+ std::cout << "checking connectivity of interior..." << std::endl;
+ break;
+ }
+ }
+};
+#endif
+
+}} // namespace detail::is_valid
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
new file mode 100644
index 0000000000..dd0922bb2b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
+
+#include <boost/geometry/views/closeable_view.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+template <typename Range, closure_selector Closure>
+struct has_duplicates
+{
+ static inline bool apply(Range const& range)
+ {
+ typedef typename closeable_view<Range const, Closure>::type view_type;
+ typedef typename boost::range_iterator<view_type const>::type iterator;
+
+ view_type view(range);
+
+ if ( boost::size(view) < 2 )
+ {
+ return false;
+ }
+
+ geometry::equal_to<typename boost::range_value<Range>::type> equal;
+
+ iterator it = boost::begin(view);
+ iterator next = ++boost::begin(view);
+ for (; next != boost::end(view); ++it, ++next)
+ {
+ if ( equal(*it, *next) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
new file mode 100644
index 0000000000..9b95017482
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
@@ -0,0 +1,139 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
+
+#include <algorithm>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/views/closeable_view.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+template <typename Point>
+struct equal_to
+{
+ Point const& m_point;
+
+ equal_to(Point const& point)
+ : m_point(point)
+ {}
+
+ template <typename OtherPoint>
+ inline bool operator()(OtherPoint const& other) const
+ {
+ return geometry::equals(m_point, other);
+ }
+};
+
+template <typename Point>
+struct not_equal_to
+{
+ Point const& m_point;
+
+ not_equal_to(Point const& point)
+ : m_point(point)
+ {}
+
+ template <typename OtherPoint>
+ inline bool operator()(OtherPoint const& other) const
+ {
+ return !geometry::equals(other, m_point);
+ }
+};
+
+
+
+template <typename Range, closure_selector Closure>
+struct has_spikes
+{
+ static inline bool apply(Range const& range)
+ {
+ typedef not_equal_to<typename point_type<Range>::type> not_equal;
+
+ typedef typename closeable_view<Range const, Closure>::type view_type;
+ typedef typename boost::range_iterator<view_type const>::type iterator;
+
+ view_type const view(range);
+
+ iterator prev = boost::begin(view);
+
+ iterator cur = std::find_if(prev, boost::end(view), not_equal(*prev));
+ if ( cur == boost::end(view) )
+ {
+ // the range has only one distinct point, so it
+ // cannot have a spike
+ return false;
+ }
+
+ iterator next = std::find_if(cur, boost::end(view), not_equal(*cur));
+ if ( next == boost::end(view) )
+ {
+ // the range has only two distinct points, so it
+ // cannot have a spike
+ return false;
+ }
+
+ while ( next != boost::end(view) )
+ {
+ if ( geometry::detail::point_is_spike_or_equal(*prev,
+ *next,
+ *cur) )
+ {
+ return true;
+ }
+ prev = cur;
+ cur = next;
+ next = std::find_if(cur, boost::end(view), not_equal(*cur));
+ }
+
+ if ( geometry::equals(range::front(view), range::back(view)) )
+ {
+ iterator cur = boost::begin(view);
+ typename boost::range_reverse_iterator
+ <
+ view_type const
+ >::type prev = std::find_if(boost::rbegin(view),
+ boost::rend(view),
+ not_equal(range::back(view)));
+ iterator next =
+ std::find_if(cur, boost::end(view), not_equal(*cur));
+ return detail::point_is_spike_or_equal(*prev, *next, *cur);
+ }
+
+ return false;
+ }
+};
+
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
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
new file mode 100644
index 0000000000..220a67bcd1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
@@ -0,0 +1,93 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template
+<
+ typename Geometry,
+ typename IsAcceptableTurn = is_acceptable_turn<Geometry>
+>
+class has_valid_self_turns
+{
+private:
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename geometry::rescale_policy_type
+ <
+ point_type
+ >::type rescale_policy_type;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+public:
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type
+ <
+ point_type,
+ rescale_policy_type
+ >::type
+ > turn_type;
+
+ // returns true if all turns are valid
+ template <typename Turns>
+ static inline bool apply(Geometry const& geometry, Turns& turns)
+ {
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry);
+
+ detail::overlay::stateless_predicate_based_interrupt_policy
+ <
+ IsAcceptableTurn
+ > interrupt_policy;
+
+ geometry::self_turns<turn_policy>(geometry,
+ robust_policy,
+ turns,
+ interrupt_policy);
+
+ return !interrupt_policy.has_intersections;
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/implementation.hpp b/boost/geometry/algorithms/detail/is_valid/implementation.hpp
new file mode 100644
index 0000000000..4a515a3073
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/implementation.hpp
@@ -0,0 +1,21 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
+
+#include <boost/geometry/algorithms/detail/is_valid/pointlike.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/linear.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/multipolygon.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/segment.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/box.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp
new file mode 100644
index 0000000000..4b232fd436
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct is_valid
+{
+ static inline bool apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+ return dispatch::is_valid<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor : boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return is_valid<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{is valid (in the OGC sense)}
+\ingroup is_valid
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is valid (in the OGC sense)}
+
+\qbk{[include reference/algorithms/is_valid.qbk]}
+*/
+template <typename Geometry>
+inline bool is_valid(Geometry const& geometry)
+{
+ return resolve_variant::is_valid<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
new file mode 100644
index 0000000000..f9d926770e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
@@ -0,0 +1,144 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template
+<
+ typename Geometry,
+ order_selector Order = geometry::point_order<Geometry>::value,
+ typename Tag = typename tag<Geometry>::type
+>
+struct acceptable_operation
+{};
+
+template <typename Polygon>
+struct acceptable_operation<Polygon, counterclockwise, polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_union;
+};
+
+template <typename Polygon>
+struct acceptable_operation<Polygon, clockwise, polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_intersection;
+};
+
+template <typename MultiPolygon>
+struct acceptable_operation<MultiPolygon, counterclockwise, multi_polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_intersection;
+};
+
+template <typename MultiPolygon>
+struct acceptable_operation<MultiPolygon, clockwise, multi_polygon_tag>
+{
+ static const detail::overlay::operation_type value =
+ detail::overlay::operation_union;
+};
+
+
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct is_acceptable_turn
+{};
+
+template <typename Polygon>
+class is_acceptable_turn<Polygon, polygon_tag>
+{
+protected:
+ template <typename Turn, typename Method, typename Operation>
+ static inline bool check_turn(Turn const& turn,
+ Method method,
+ Operation operation)
+ {
+ return turn.method == method
+ && turn.operations[0].operation == operation
+ && turn.operations[1].operation == operation;
+ }
+
+
+public:
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ using namespace detail::overlay;
+
+ if ( turn.operations[0].seg_id.ring_index
+ == turn.operations[1].seg_id.ring_index )
+ {
+ return false;
+ }
+
+ operation_type const op = acceptable_operation<Polygon>::value;
+
+ return check_turn(turn, method_touch_interior, op)
+ || check_turn(turn, method_touch, op)
+ ;
+ }
+};
+
+template <typename MultiPolygon>
+class is_acceptable_turn<MultiPolygon, multi_polygon_tag>
+ : is_acceptable_turn<typename boost::range_value<MultiPolygon>::type>
+{
+private:
+ typedef typename boost::range_value<MultiPolygon>::type polygon;
+ typedef is_acceptable_turn<polygon> base;
+
+public:
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ using namespace detail::overlay;
+
+ if ( turn.operations[0].seg_id.multi_index
+ == turn.operations[1].seg_id.multi_index )
+ {
+ return base::apply(turn);
+ }
+
+ operation_type const op = acceptable_operation<MultiPolygon>::value;
+
+ return base::check_turn(turn, method_touch_interior, op)
+ || base::check_turn(turn, method_touch, op)
+ ;
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp
new file mode 100644
index 0000000000..244df9b035
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp
@@ -0,0 +1,125 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
+#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template <typename Linestring, bool AllowSpikes>
+struct is_valid_linestring
+{
+ static inline bool apply(Linestring const& linestring)
+ {
+ std::size_t num_distinct = detail::num_distinct_consecutive_points
+ <
+ Linestring,
+ 3u,
+ true,
+ not_equal_to<typename point_type<Linestring>::type>
+ >::apply(linestring);
+
+ if ( num_distinct < 2u )
+ {
+ return false;
+ }
+
+ return num_distinct == 2u
+ || AllowSpikes
+ || !has_spikes<Linestring, closed>::apply(linestring);
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A linestring is a curve.
+// A curve is 1-dimensional so it has to have at least two distinct
+// points.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+//
+// There is an option here as to whether spikes are allowed for linestrings;
+// here we pass this as an additional template parameter: allow_spikes
+// If allow_spikes is set to true, spikes are allowed, false otherwise.
+// By default, spikes are disallowed
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Linestring, bool AllowSpikes>
+struct is_valid<Linestring, linestring_tag, AllowSpikes>
+ : detail::is_valid::is_valid_linestring<Linestring, AllowSpikes>
+{};
+
+
+// A MultiLinestring is a MultiCurve
+// A MultiCurve is simple if all of its elements are simple and the
+// only intersections between any two elements occur at Points that
+// are on the boundaries of both elements.
+//
+// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
+template <typename MultiLinestring, bool AllowSpikes>
+struct is_valid<MultiLinestring, multi_linestring_tag, AllowSpikes>
+{
+ static inline bool apply(MultiLinestring const& multilinestring)
+ {
+ return detail::check_iterator_range
+ <
+ detail::is_valid::is_valid_linestring
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ AllowSpikes
+ >,
+ false // do not allow empty multilinestring
+ >::apply(boost::begin(multilinestring),
+ boost::end(multilinestring));
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
new file mode 100644
index 0000000000..3d0ebb5f82
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
@@ -0,0 +1,297 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
+
+#include <deque>
+#include <vector>
+
+#include <boost/iterator/filter_iterator.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/polygon.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template <typename MultiPolygon, bool AllowDuplicates>
+class is_valid_multipolygon
+ : is_valid_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ AllowDuplicates,
+ true // check only the validity of rings
+ >
+{
+private:
+ typedef is_valid_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ AllowDuplicates,
+ true
+ > base;
+
+
+
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline
+ bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ // collect all polygons that have turns
+ std::set<signed_index_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);
+ }
+
+ // put polygon iterators without turns in a vector
+ std::vector<PolygonIterator> polygon_iterators;
+ signed_index_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);
+ }
+ }
+
+ typename base::item_visitor visitor;
+
+ geometry::partition
+ <
+ geometry::model::box<typename point_type<MultiPolygon>::type>,
+ typename base::expand_box,
+ typename base::overlaps_box
+ >::apply(polygon_iterators, visitor);
+
+ return !visitor.items_overlap;
+ }
+
+
+
+ class has_multi_index
+ {
+ public:
+ has_multi_index(signed_index_type multi_index)
+ : m_multi_index(multi_index)
+ {}
+
+ template <typename Turn>
+ inline bool operator()(Turn const& turn) const
+ {
+ return turn.operations[0].seg_id.multi_index == m_multi_index
+ && turn.operations[1].seg_id.multi_index == m_multi_index;
+ }
+
+ private:
+ signed_index_type const m_multi_index;
+ };
+
+
+
+ template <typename Predicate>
+ struct has_property_per_polygon
+ {
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline bool apply(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ signed_index_type multi_index = 0;
+ for (PolygonIterator it = polygons_first; it != polygons_beyond;
+ ++it, ++multi_index)
+ {
+ has_multi_index index_predicate(multi_index);
+
+ typedef boost::filter_iterator
+ <
+ has_multi_index, TurnIterator
+ > filtered_turn_iterator;
+
+ filtered_turn_iterator filtered_turns_first(index_predicate,
+ turns_first,
+ turns_beyond);
+
+ filtered_turn_iterator filtered_turns_beyond(index_predicate,
+ turns_beyond,
+ turns_beyond);
+
+ if ( !Predicate::apply(*it,
+ filtered_turns_first,
+ filtered_turns_beyond) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+
+
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline bool have_holes_inside(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ return has_property_per_polygon
+ <
+ typename base::has_holes_inside
+ >::apply(polygons_first, polygons_beyond,
+ turns_first, turns_beyond);
+ }
+
+
+
+ template <typename PolygonIterator, typename TurnIterator>
+ static inline bool have_connected_interior(PolygonIterator polygons_first,
+ PolygonIterator polygons_beyond,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ return has_property_per_polygon
+ <
+ typename base::has_connected_interior
+ >::apply(polygons_first, polygons_beyond,
+ turns_first, turns_beyond);
+ }
+
+
+public:
+ static inline bool apply(MultiPolygon const& multipolygon)
+ {
+ typedef debug_validity_phase<MultiPolygon> debug_phase;
+
+ // check validity of all polygons ring
+ debug_phase::apply(1);
+
+ if ( !detail::check_iterator_range
+ <
+ base,
+ false // do not allow empty multi-polygons
+ >::apply(boost::begin(multipolygon),
+ boost::end(multipolygon)) )
+ {
+ return false;
+ }
+
+
+ // compute turns and check if all are acceptable
+ debug_phase::apply(2);
+
+ typedef has_valid_self_turns<MultiPolygon> has_valid_turns;
+
+ std::deque<typename has_valid_turns::turn_type> turns;
+ bool has_invalid_turns = !has_valid_turns::apply(multipolygon, turns);
+ debug_print_turns(turns.begin(), turns.end());
+
+ if ( has_invalid_turns )
+ {
+ return false;
+ }
+
+
+ // check if each polygon's interior rings are inside the
+ // exterior and not one inside the other
+ debug_phase::apply(3);
+
+ if ( !have_holes_inside(boost::begin(multipolygon),
+ boost::end(multipolygon),
+ turns.begin(),
+ turns.end()) )
+ {
+ return false;
+ }
+
+
+ // check that each polygon's interior is connected
+ debug_phase::apply(4);
+
+ if ( !have_connected_interior(boost::begin(multipolygon),
+ boost::end(multipolygon),
+ turns.begin(),
+ turns.end()) )
+ {
+ return false;
+ }
+
+
+ // check if polygon interiors are disjoint
+ debug_phase::apply(5);
+ return are_polygon_interiors_disjoint(boost::begin(multipolygon),
+ boost::end(multipolygon),
+ turns.begin(),
+ turns.end());
+ }
+};
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// Not clear what the definition is.
+// Right now we check that each element is simple (in fact valid), and
+// that the MultiPolygon is also valid.
+//
+// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14)
+template <typename MultiPolygon, bool AllowSpikes, bool AllowDuplicates>
+struct is_valid<MultiPolygon, multi_polygon_tag, AllowSpikes, AllowDuplicates>
+ : detail::is_valid::is_valid_multipolygon<MultiPolygon, AllowDuplicates>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
new file mode 100644
index 0000000000..8a4818ef15
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
@@ -0,0 +1,62 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// A point is always simple
+template <typename Point>
+struct is_valid<Point, point_tag>
+{
+ static inline bool apply(Point const&)
+ {
+ return true;
+ }
+};
+
+
+
+// A MultiPoint is simple if no two Points in the MultiPoint are equal
+// (have identical coordinate values in X and Y)
+//
+// Reference: OGC 06-103r4 (6.1.5)
+template <typename MultiPoint>
+struct is_valid<MultiPoint, multi_point_tag>
+{
+ static inline bool apply(MultiPoint const& multipoint)
+ {
+ return boost::size(multipoint) > 0;
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
new file mode 100644
index 0000000000..3a91999208
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
@@ -0,0 +1,376 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
+
+#include <cstddef>
+
+#include <algorithm>
+#include <deque>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
+
+#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+template
+<
+ typename Polygon,
+ bool AllowDuplicates,
+ bool CheckRingValidityOnly = false
+>
+class is_valid_polygon
+{
+protected:
+ typedef debug_validity_phase<Polygon> debug_phase;
+
+
+
+ template <typename InteriorRings>
+ static bool has_valid_interior_rings(InteriorRings const& interior_rings)
+ {
+ return
+ detail::check_iterator_range
+ <
+ detail::is_valid::is_valid_ring
+ <
+ typename boost::range_value<InteriorRings>::type,
+ AllowDuplicates,
+ false, // do not check self-intersections
+ true // indicate that the ring is interior
+ >
+ >::apply(boost::begin(interior_rings),
+ boost::end(interior_rings));
+ }
+
+ struct has_valid_rings
+ {
+ static inline bool apply(Polygon const& polygon)
+ {
+ typedef typename ring_type<Polygon>::type ring_type;
+
+ // check validity of exterior ring
+ debug_phase::apply(1);
+
+ if ( !detail::is_valid::is_valid_ring
+ <
+ ring_type,
+ AllowDuplicates,
+ false // do not check self intersections
+ >::apply(exterior_ring(polygon)) )
+ {
+ return false;
+ }
+
+ // check validity of interior rings
+ debug_phase::apply(2);
+
+ return has_valid_interior_rings(geometry::interior_rings(polygon));
+ }
+ };
+
+
+ // structs from partition -- start
+ struct expand_box
+ {
+ template <typename Box, typename Iterator>
+ static inline void apply(Box& total, Iterator const& it)
+ {
+ geometry::expand(total, geometry::return_envelope<Box>(*it));
+ }
+
+ };
+
+ struct overlaps_box
+ {
+ template <typename Box, typename Iterator>
+ static inline bool apply(Box const& box, Iterator const& it)
+ {
+ return !geometry::disjoint(*it, box);
+ }
+ };
+
+
+ struct item_visitor
+ {
+ bool items_overlap;
+
+ item_visitor() : items_overlap(false) {}
+
+ template <typename Item1, typename Item2>
+ inline void apply(Item1 const& item1, Item2 const& item2)
+ {
+ if ( !items_overlap
+ && (geometry::within(*points_begin(*item1), *item2)
+ || geometry::within(*points_begin(*item2), *item1))
+ )
+ {
+ items_overlap = true;
+ }
+ }
+ };
+ // structs for partition -- end
+
+
+ template
+ <
+ typename RingIterator,
+ typename ExteriorRing,
+ typename TurnIterator
+ >
+ static inline bool are_holes_inside(RingIterator rings_first,
+ RingIterator rings_beyond,
+ ExteriorRing const& exterior_ring,
+ TurnIterator turns_first,
+ TurnIterator turns_beyond)
+ {
+ // collect the interior ring indices that have turns with the
+ // exterior ring
+ std::set<signed_index_type> ring_indices;
+ for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
+ {
+ if ( tit->operations[0].seg_id.ring_index == -1 )
+ {
+ BOOST_ASSERT( tit->operations[1].seg_id.ring_index != -1 );
+ ring_indices.insert(tit->operations[1].seg_id.ring_index);
+ }
+ else if ( tit->operations[1].seg_id.ring_index == -1 )
+ {
+ BOOST_ASSERT( tit->operations[0].seg_id.ring_index != -1 );
+ ring_indices.insert(tit->operations[0].seg_id.ring_index);
+ }
+ }
+
+ signed_index_type ring_index = 0;
+ for (RingIterator it = rings_first; it != rings_beyond;
+ ++it, ++ring_index)
+ {
+ // 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) )
+ {
+ return false;
+ }
+ }
+
+ // collect all rings (exterior and/or interior) that have turns
+ for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
+ {
+ ring_indices.insert(tit->operations[0].seg_id.ring_index);
+ ring_indices.insert(tit->operations[1].seg_id.ring_index);
+ }
+
+ // put iterators for interior rings without turns in a vector
+ std::vector<RingIterator> 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);
+ }
+ }
+
+ // call partition to check is interior rings are disjoint from
+ // each other
+ item_visitor visitor;
+
+ geometry::partition
+ <
+ geometry::model::box<typename point_type<Polygon>::type>,
+ expand_box,
+ overlaps_box
+ >::apply(ring_iterators, visitor);
+
+ return !visitor.items_overlap;
+ }
+
+ template
+ <
+ typename InteriorRings,
+ typename ExteriorRing,
+ typename TurnIterator
+ >
+ static inline bool are_holes_inside(InteriorRings const& interior_rings,
+ ExteriorRing const& exterior_ring,
+ TurnIterator first,
+ TurnIterator beyond)
+ {
+ return are_holes_inside(boost::begin(interior_rings),
+ boost::end(interior_rings),
+ exterior_ring,
+ first,
+ beyond);
+ }
+
+ struct has_holes_inside
+ {
+ template <typename TurnIterator>
+ static inline bool apply(Polygon const& polygon,
+ TurnIterator first,
+ TurnIterator beyond)
+ {
+ return are_holes_inside(geometry::interior_rings(polygon),
+ geometry::exterior_ring(polygon),
+ first,
+ beyond);
+ }
+ };
+
+
+
+
+ struct has_connected_interior
+ {
+ template <typename TurnIterator>
+ static inline bool apply(Polygon const& polygon,
+ TurnIterator first,
+ TurnIterator beyond)
+ {
+ typedef typename std::iterator_traits
+ <
+ TurnIterator
+ >::value_type turn_type;
+ typedef complement_graph<typename turn_type::point_type> graph;
+
+ graph g(geometry::num_interior_rings(polygon) + 1);
+ for (TurnIterator tit = first; tit != beyond; ++tit)
+ {
+ typename graph::vertex_handle v1 = g.add_vertex
+ ( tit->operations[0].seg_id.ring_index + 1 );
+ typename graph::vertex_handle v2 = g.add_vertex
+ ( tit->operations[1].seg_id.ring_index + 1 );
+ typename graph::vertex_handle vip = g.add_vertex(tit->point);
+
+ g.add_edge(v1, vip);
+ g.add_edge(v2, vip);
+ }
+
+ debug_print_complement_graph(std::cout, g);
+
+ return !g.has_cycles();
+ }
+ };
+
+public:
+ static inline bool apply(Polygon const& polygon)
+ {
+ if ( !has_valid_rings::apply(polygon) )
+ {
+ return false;
+ }
+
+ if ( CheckRingValidityOnly )
+ {
+ return true;
+ }
+
+ // compute turns and check if all are acceptable
+ debug_phase::apply(3);
+
+ typedef has_valid_self_turns<Polygon> has_valid_turns;
+
+ std::deque<typename has_valid_turns::turn_type> turns;
+ bool has_invalid_turns = !has_valid_turns::apply(polygon, turns);
+ debug_print_turns(turns.begin(), turns.end());
+
+ if ( has_invalid_turns )
+ {
+ return false;
+ }
+
+ // check if all interior rings are inside the exterior ring
+ debug_phase::apply(4);
+
+ if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) )
+ {
+ return false;
+ }
+
+ // check whether the interior of the polygon is a connected set
+ debug_phase::apply(5);
+
+ return has_connected_interior::apply(polygon,
+ turns.begin(),
+ turns.end());
+ }
+};
+
+
+}} // namespace detail::is_valid
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A Polygon is always a simple geometric object provided that it is valid.
+//
+// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1)
+template <typename Polygon, bool AllowSpikes, bool AllowDuplicates>
+struct is_valid<Polygon, polygon_tag, AllowSpikes, AllowDuplicates>
+ : detail::is_valid::is_valid_polygon<Polygon, AllowDuplicates>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp
new file mode 100644
index 0000000000..c88df79b05
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp
@@ -0,0 +1,173 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/point_order.hpp>
+
+#include <boost/geometry/util/order_as_direction.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/equals.hpp>
+
+#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+
+#include <boost/geometry/strategies/area.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_valid
+{
+
+
+// struct to check whether a ring is topologically closed
+template <typename Ring, closure_selector Closure /* open */>
+struct is_topologically_closed
+{
+ static inline bool apply(Ring const&)
+ {
+ return true;
+ }
+};
+
+template <typename Ring>
+struct is_topologically_closed<Ring, closed>
+{
+ static inline bool apply(Ring const& ring)
+ {
+ return geometry::equals(range::front(ring), range::back(ring));
+ }
+};
+
+
+
+template <typename ResultType, bool IsInteriorRing /* false */>
+struct ring_area_predicate
+{
+ typedef std::greater<ResultType> type;
+};
+
+template <typename ResultType>
+struct ring_area_predicate<ResultType, true>
+{
+ typedef std::less<ResultType> type;
+};
+
+
+
+template <typename Ring, bool IsInteriorRing>
+struct is_properly_oriented
+{
+ typedef typename point_type<Ring>::type point_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,
+ geometry::closure<Ring>::value
+ > ring_area_type;
+
+ typedef typename default_area_result<Ring>::type area_result_type;
+
+ static inline bool apply(Ring const& ring)
+ {
+ typename ring_area_predicate
+ <
+ area_result_type, IsInteriorRing
+ >::type predicate;
+
+ // Check area
+ area_result_type const zero = area_result_type();
+ return predicate(ring_area_type::apply(ring, strategy_type()), zero);
+ }
+};
+
+
+
+template
+<
+ typename Ring,
+ bool AllowDuplicates,
+ bool CheckSelfIntersections = true,
+ bool IsInteriorRing = false
+>
+struct is_valid_ring
+{
+ static inline bool apply(Ring const& ring)
+ {
+ // return invalid if any of the following condition holds:
+ // (a) the ring's size is below the minimal one
+ // (b) the ring is not topologically closed
+ // (c) the ring has spikes
+ // (d) the ring has duplicate points (if AllowDuplicates is false)
+ // (e) the boundary of the ring has self-intersections
+ // (f) the order of the points is inconsistent with the defined order
+ //
+ // Note: no need to check if the area is zero. If this is the
+ // case, then the ring must have at least two spikes, which is
+ // checked by condition (c).
+
+ closure_selector const closure = geometry::closure<Ring>::value;
+
+ return
+ ( boost::size(ring)
+ >= core_detail::closure::minimum_ring_size<closure>::value )
+ && is_topologically_closed<Ring, closure>::apply(ring)
+ && (AllowDuplicates || !has_duplicates<Ring, closure>::apply(ring))
+ && !has_spikes<Ring, closure>::apply(ring)
+ && !(CheckSelfIntersections && geometry::intersects(ring))
+ && is_properly_oriented<Ring, IsInteriorRing>::apply(ring);
+ }
+};
+
+
+}} // namespace dispatch
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// A Ring is a Polygon with exterior boundary only.
+// The Ring's boundary must be a LinearRing (see OGC 06-103-r4,
+// 6.1.7.1, for the definition of LinearRing)
+//
+// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
+template <typename Ring, bool AllowSpikes, bool AllowDuplicates>
+struct is_valid<Ring, ring_tag, AllowSpikes, AllowDuplicates>
+ : detail::is_valid::is_valid_ring<Ring, AllowDuplicates>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp
new file mode 100644
index 0000000000..486289dabe
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_valid/segment.hpp
@@ -0,0 +1,61 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+
+#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+// A segment is a curve.
+// A curve is simple if it does not pass through the same point twice,
+// with the possible exception of its two endpoints
+// A curve is 1-dimensional, hence we have to check is the two
+// endpoints of the segment coincide, since in this case it is
+// 0-dimensional.
+//
+// Reference: OGC 06-103r4 (6.1.6.1)
+template <typename Segment>
+struct is_valid<Segment, segment_tag>
+{
+ static inline bool apply(Segment const& segment)
+ {
+ typename point_type<Segment>::type p[2];
+ detail::assign_point_from_index<0>(segment, p[0]);
+ detail::assign_point_from_index<1>(segment, p[1]);
+
+ return !geometry::equals(p[0], p[1]);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
diff --git a/boost/geometry/algorithms/detail/multi_modify.hpp b/boost/geometry/algorithms/detail/multi_modify.hpp
new file mode 100644
index 0000000000..f0b9ddd3e6
--- /dev/null
+++ b/boost/geometry/algorithms/detail/multi_modify.hpp
@@ -0,0 +1,53 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// 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_MULTI_MODIFY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP
+
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+template <typename MultiGeometry, typename Policy>
+struct multi_modify
+{
+ static inline void apply(MultiGeometry& multi)
+ {
+ typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it);
+ }
+ }
+};
+
+
+} // namespace detail
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP
diff --git a/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp
new file mode 100644
index 0000000000..c3787f9a10
--- /dev/null
+++ b/boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp
@@ -0,0 +1,52 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP
+
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename MultiGeometry, typename Predicate, typename Policy>
+struct multi_modify_with_predicate
+{
+ static inline void apply(MultiGeometry& multi, Predicate const& predicate)
+ {
+ typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, predicate);
+ }
+ }
+};
+
+
+} // namespace detail
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP
diff --git a/boost/geometry/algorithms/detail/multi_sum.hpp b/boost/geometry/algorithms/detail/multi_sum.hpp
new file mode 100644
index 0000000000..af3f425c9c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/multi_sum.hpp
@@ -0,0 +1,52 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+struct multi_sum
+{
+ template <typename ReturnType, typename Policy, typename MultiGeometry, typename Strategy>
+ static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy)
+ {
+ ReturnType sum = ReturnType();
+ for (typename boost::range_iterator
+ <
+ MultiGeometry const
+ >::type it = boost::begin(geometry);
+ it != boost::end(geometry);
+ ++it)
+ {
+ sum += Policy::apply(*it, strategy);
+ }
+ return sum;
+ }
+};
+
+
+} // namespace detail
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP
diff --git a/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp
new file mode 100644
index 0000000000..16fba72fe0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp
@@ -0,0 +1,93 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP
+
+#include <cstddef>
+
+#include <algorithm>
+
+#include <boost/range.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+// returns the number of distinct values in the range;
+// return values are 0u through MaximumNumber, where MaximumNumber
+// corresponds to MaximumNumber or more distinct values
+//
+// FUTURE: take into account topologically closed ranges;
+// add appropriate template parameter(s) to control whether
+// the closing point for topologically closed ranges is to be
+// accounted for separately or not
+template
+<
+ typename Range,
+ std::size_t MaximumNumber,
+ bool AllowDuplicates /* true */,
+ typename NotEqualTo
+>
+struct num_distinct_consecutive_points
+{
+ static inline std::size_t apply(Range const& range)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ std::size_t const size = boost::size(range);
+
+ if ( size < 2u )
+ {
+ return (size < MaximumNumber) ? size : MaximumNumber;
+ }
+
+ iterator current = boost::begin(range);
+ std::size_t counter(0);
+ do
+ {
+ ++counter;
+ iterator next = std::find_if(current,
+ boost::end(range),
+ NotEqualTo(*current));
+ current = next;
+ }
+ while ( current != boost::end(range) && counter <= MaximumNumber );
+
+ return counter;
+ }
+};
+
+
+template <typename Range, std::size_t MaximumNumber, typename NotEqualTo>
+struct num_distinct_consecutive_points<Range, MaximumNumber, false, NotEqualTo>
+{
+ static inline std::size_t apply(Range const& range)
+ {
+ std::size_t const size = boost::size(range);
+ return (size < MaximumNumber) ? size : MaximumNumber;
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp
index e147ba12d8..d90f3cf7cf 100644
--- a/boost/geometry/algorithms/detail/occupation_info.hpp
+++ b/boost/geometry/algorithms/detail/occupation_info.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2012-2014 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
@@ -9,17 +9,13 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
-#if ! defined(NDEBUG)
- #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
-#endif
-
#include <algorithm>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/iterators/closing_iterator.hpp>
#include <boost/geometry/algorithms/detail/get_left_turns.hpp>
@@ -33,291 +29,159 @@ namespace boost { namespace geometry
namespace detail
{
-template <typename P>
-class relaxed_less
-{
- typedef typename geometry::coordinate_type<P>::type coordinate_type;
-
- coordinate_type epsilon;
-
-public :
-
- inline relaxed_less()
- {
- // TODO: adapt for ttmath, and maybe build the map in another way
- // (e.g. exact constellations of segment-id's), maybe adaptive.
- epsilon = std::numeric_limits<double>::epsilon() * 100.0;
- }
-
- inline bool operator()(P const& a, P const& b) const
- {
- coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
- coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
-
-
- if (dx < epsilon && dy < epsilon)
- {
- return false;
- }
- if (dx < epsilon)
- {
- return geometry::get<1>(a) < geometry::get<1>(b);
- }
-
- return geometry::get<0>(a) < geometry::get<0>(b);
- }
-
- inline bool equals(P const& a, P const& b) const
- {
- typedef typename geometry::coordinate_type<P>::type coordinate_type;
-
- coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
- coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
-
- return dx < epsilon && dy < epsilon;
- };
-};
-
-
-template <typename T, typename P1, typename P2>
-inline T calculate_angle(P1 const& from_point, P2 const& to_point)
-{
- typedef P1 vector_type;
- vector_type v = from_point;
- geometry::subtract_point(v, to_point);
- return atan2(geometry::get<1>(v), geometry::get<0>(v));
-}
-
-template <typename Iterator, typename Vector>
-inline Iterator advance_circular(Iterator it, Vector const& vector, segment_identifier& seg_id, bool forward = true)
-{
- int const increment = forward ? 1 : -1;
- if (it == boost::begin(vector) && increment < 0)
- {
- it = boost::end(vector);
- seg_id.segment_index = boost::size(vector);
- }
- it += increment;
- seg_id.segment_index += increment;
- if (it == boost::end(vector))
- {
- seg_id.segment_index = 0;
- it = boost::begin(vector);
- }
- return it;
-}
-
template <typename Point, typename T>
struct angle_info
{
- typedef T angle_type;
+ typedef T angle_type;
typedef Point point_type;
segment_identifier seg_id;
int turn_index;
int operation_index;
+ std::size_t cluster_index;
Point intersection_point;
- Point direction_point;
- T angle;
+ Point point; // either incoming or outgoing point
bool incoming;
+ bool blocked;
+ bool included;
+
+ inline angle_info()
+ : blocked(false)
+ , included(false)
+ {}
};
template <typename AngleInfo>
class occupation_info
{
- typedef std::vector<AngleInfo> collection_type;
-
- struct angle_sort
- {
- inline bool operator()(AngleInfo const& left, AngleInfo const& right) const
- {
- // In this case we can compare even double using equals
- // return geometry::math::equals(left.angle, right.angle)
- return left.angle == right.angle
- ? int(left.incoming) < int(right.incoming)
- : left.angle < right.angle
- ;
- }
- };
-
-public :
- collection_type angles;
-private :
- bool m_occupied;
- bool m_calculated;
-
- inline bool is_occupied()
- {
- if (boost::size(angles) <= 1)
- {
- return false;
- }
-
- std::sort(angles.begin(), angles.end(), angle_sort());
-
- typedef geometry::closing_iterator<collection_type const> closing_iterator;
- closing_iterator vit(angles);
- closing_iterator end(angles, true);
-
- closing_iterator prev = vit++;
- for( ; vit != end; prev = vit++)
- {
- if (! geometry::math::equals(prev->angle, vit->angle)
- && ! prev->incoming
- && vit->incoming)
- {
- return false;
- }
- }
- return true;
- }
-
public :
- inline occupation_info()
- : m_occupied(false)
- , m_calculated(false)
- {}
+ typedef std::vector<AngleInfo> collection_type;
- template <typename PointC, typename Point1, typename Point2>
- inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point,
+ template <typename RobustPoint>
+ inline void add(RobustPoint const& incoming_point,
+ RobustPoint const& outgoing_point,
+ RobustPoint const& intersection_point,
int turn_index, int operation_index,
- segment_identifier const& seg_id, bool incoming)
- {
- //std::cout << "-> adding angle " << geometry::wkt(direction_point) << " .. " << geometry::wkt(intersection_point) << " " << int(incoming) << std::endl;
- if (geometry::equals(direction_point, intersection_point))
- {
- //std::cout << "EQUAL! Skipping" << std::endl;
- return;
- }
+ segment_identifier const& seg_id)
+ {
+ geometry::equal_to<RobustPoint> comparator;
+ if (comparator(incoming_point, intersection_point))
+ {
+ return;
+ }
+ if (comparator(outgoing_point, intersection_point))
+ {
+ return;
+ }
AngleInfo info;
- info.incoming = incoming;
- info.angle = calculate_angle<typename AngleInfo::angle_type>(direction_point, map_point);
info.seg_id = seg_id;
info.turn_index = turn_index;
info.operation_index = operation_index;
info.intersection_point = intersection_point;
- info.direction_point = direction_point;
- angles.push_back(info);
-
- m_calculated = false;
- }
-
- inline bool occupied()
- {
- if (! m_calculated)
- {
- m_occupied = is_occupied();
- m_calculated = true;
- }
- return m_occupied;
- }
-
- template <typename Turns, typename TurnSegmentIndices>
- inline void get_left_turns(
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices)
- {
- std::sort(angles.begin(), angles.end(), angle_sort());
- calculate_left_turns<AngleInfo>(angles, turns, turn_segment_indices, keep_indices);
- }
-};
-
-
-template <typename Point, typename Ring, typename Info>
-inline void add_incoming_and_outgoing_angles(Point const& map_point, Point const& intersection_point,
- Ring const& ring,
- int turn_index,
- int operation_index,
- segment_identifier seg_id,
- Info& info)
-{
- typedef typename boost::range_iterator
- <
- Ring const
- >::type iterator_type;
-
- int const n = boost::size(ring);
- if (seg_id.segment_index >= n || seg_id.segment_index < 0)
- {
- return;
- }
-
- segment_identifier real_seg_id = seg_id;
- iterator_type it = boost::begin(ring) + seg_id.segment_index;
- // TODO: if we use turn-info ("to", "middle"), we know if to advance without resorting to equals
- relaxed_less<Point> comparator;
+ {
+ info.point = incoming_point;
+ info.incoming = true;
+ m_angles.push_back(info);
+ }
+ {
+ info.point = outgoing_point;
+ info.incoming = false;
+ m_angles.push_back(info);
+ }
+ }
- if (comparator.equals(intersection_point, *it))
+ template <typename RobustPoint, typename Turns>
+ inline void get_left_turns(RobustPoint const& origin, Turns& turns)
{
- // It should be equal only once. But otherwise we skip it (in "add")
- it = advance_circular(it, ring, seg_id, false);
+ // Sort on angle
+ std::sort(m_angles.begin(), m_angles.end(),
+ detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
+
+ // Group same-angled elements
+ std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);
+ // Block all turns on the right side of any turn
+ detail::left_turns::block_turns(m_angles, cluster_size);
+ detail::left_turns::get_left_turns(m_angles, turns);
}
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, true);
-
- if (comparator.equals(intersection_point, *it))
- {
- it = advance_circular(it, ring, real_seg_id);
- }
- else
- {
- // Don't upgrade the ID
- it = advance_circular(it, ring, seg_id);
- }
- for (int defensive_check = 0;
- comparator.equals(intersection_point, *it) && defensive_check < n;
- defensive_check++)
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ template <typename RobustPoint>
+ inline bool has_rounding_issues(RobustPoint const& origin) const
{
- it = advance_circular(it, ring, real_seg_id);
+ return detail::left_turns::has_rounding_issues(angles, origin);
}
+#endif
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false);
-}
-
+private :
+ collection_type m_angles; // each turn splitted in incoming/outgoing vectors
+};
-// Map in two senses of the word: it is a std::map where the key is a point.
-// Per point an "occupation_info" record is kept
-// Used for the buffer (but will also be used for intersections/unions having complex self-tangencies)
-template <typename Point, typename OccupationInfo>
-class occupation_map
+template<typename Pieces>
+inline void move_index(Pieces const& pieces, int& index, int& piece_index, int direction)
{
-public :
- typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type;
+ BOOST_ASSERT(direction == 1 || direction == -1);
+ BOOST_ASSERT(piece_index >= 0 && piece_index < static_cast<int>(boost::size(pieces)) );
+ BOOST_ASSERT(index >= 0 && index < static_cast<int>(boost::size(pieces[piece_index].robust_ring)));
- map_type map;
- std::set<int> turn_indices;
-
- inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point)
+ index += direction;
+ if (direction == -1 && index < 0)
{
- typename map_type::iterator it = map.find(point);
- if (it == boost::end(map))
+ piece_index--;
+ if (piece_index < 0)
{
- std::pair<typename map_type::iterator, bool> pair
- = map.insert(std::make_pair(point, OccupationInfo()));
- it = pair.first;
+ piece_index = boost::size(pieces) - 1;
}
- mapped_point = it->first;
- return it->second;
+ index = boost::size(pieces[piece_index].robust_ring) - 1;
}
-
- inline bool contains(Point const& point) const
+ if (direction == 1
+ && index >= static_cast<int>(boost::size(pieces[piece_index].robust_ring)))
{
- typename map_type::const_iterator it = map.find(point);
- return it != boost::end(map);
+ piece_index++;
+ if (piece_index >= static_cast<int>(boost::size(pieces)))
+ {
+ piece_index = 0;
+ }
+ index = 0;
}
+}
- inline bool contains_turn_index(int index) const
- {
- return turn_indices.count(index) > 0;
- }
- inline void insert_turn_index(int index)
+template
+<
+ typename RobustPoint,
+ typename Turn,
+ typename Pieces,
+ typename Info
+>
+inline void add_incoming_and_outgoing_angles(
+ RobustPoint const& intersection_point, // rescaled
+ Turn const& turn,
+ Pieces const& pieces, // using rescaled offsets of it
+ int operation_index,
+ segment_identifier seg_id,
+ Info& info)
+{
+ segment_identifier real_seg_id = seg_id;
+ geometry::equal_to<RobustPoint> comparator;
+
+ // Move backward and forward
+ RobustPoint direction_points[2];
+ for (int i = 0; i < 2; i++)
{
- turn_indices.insert(index);
+ int index = turn.operations[operation_index].index_in_robust_ring;
+ int piece_index = turn.operations[operation_index].piece_index;
+ while(comparator(pieces[piece_index].robust_ring[index], intersection_point))
+ {
+ move_index(pieces, index, piece_index, i == 0 ? -1 : 1);
+ }
+ direction_points[i] = pieces[piece_index].robust_ring[index];
}
-};
+
+ info.add(direction_points[0], direction_points[1], intersection_point,
+ turn.turn_index, operation_index, real_seg_id);
+}
} // namespace detail
diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
index 74595fedd0..5ff0b57d6e 100644
--- a/boost/geometry/algorithms/detail/overlay/add_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
@@ -75,15 +75,15 @@ inline OutputIterator add_rings(SelectionMap const& map,
OutputIterator out)
{
typedef typename SelectionMap::const_iterator iterator;
- typedef typename SelectionMap::mapped_type property_type;
- typedef typename property_type::area_type area_type;
-
- area_type const zero = 0;
- std::size_t const min_num_points = core_detail::closure::minimum_ring_size
- <
- geometry::closure
- <
- typename boost::range_value
+ typedef typename SelectionMap::mapped_type property_type;
+ typedef typename property_type::area_type area_type;
+
+ area_type const zero = 0;
+ std::size_t const min_num_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure
+ <
+ typename boost::range_value
<
RingCollection const
>::type
@@ -117,15 +117,14 @@ inline OutputIterator add_rings(SelectionMap const& map,
}
}
- // Only add rings if they satisfy minimal requirements.
- // This cannot be done earlier (during traversal), not
- // everything is figured out yet (sum of positive/negative rings)
- // TODO: individual rings can still contain less than 3 points.
- if (geometry::num_points(result) >= min_num_points
- && math::larger(geometry::area(result), zero))
- {
- *out++ = result;
- }
+ // Only add rings if they satisfy minimal requirements.
+ // This cannot be done earlier (during traversal), not
+ // everything is figured out yet (sum of positive/negative rings)
+ if (geometry::num_points(result) >= min_num_points
+ && math::larger(geometry::area(result), zero))
+ {
+ *out++ = result;
+ }
}
}
return out;
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
index 2c0f88e2aa..0fd1fe4de9 100644
--- a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
+++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
@@ -13,7 +13,7 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/append.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
@@ -29,7 +29,7 @@ template <typename Range, typename Point>
inline void append_no_duplicates(Range& range, Point const& point, bool force = false)
{
if (boost::size(range) == 0
- || force
+ || force
|| ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point))
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
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
new file mode 100644
index 0000000000..d44db17ad3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
@@ -0,0 +1,160 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_APPEND_NO_DUPS_OR_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// TODO: move this / rename this
+template <typename Point1, typename Point2, typename RobustPolicy>
+inline bool points_equal_or_close(Point1 const& point1,
+ Point2 const& point2,
+ RobustPolicy const& robust_policy)
+{
+ if (detail::equals::equals_point_point(point1, point2))
+ {
+ return true;
+ }
+
+ if (! RobustPolicy::enabled)
+ {
+ return false;
+ }
+
+ // Try using specified robust policy
+ typedef typename geometry::robust_point_type
+ <
+ Point1,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type point1_rob, point2_rob;
+ geometry::recalculate(point1_rob, point1, robust_policy);
+ geometry::recalculate(point2_rob, point2, robust_policy);
+
+ return detail::equals::equals_point_point(point1_rob, point2_rob);
+}
+
+
+template <typename Range, typename Point, typename RobustPolicy>
+inline void append_no_dups_or_spikes(Range& range, Point const& point,
+ RobustPolicy const& robust_policy)
+{
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+ std::cout << " add: ("
+ << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
+ << std::endl;
+#endif
+ // The code below thies condition checks all spikes/dups
+ // for geometries >= 3 points.
+ // So we have to check the first potential duplicate differently
+ if (boost::size(range) == 1
+ && points_equal_or_close(*(boost::begin(range)), point, robust_policy))
+ {
+ return;
+ }
+
+ traits::push_back<Range>::apply(range, point);
+
+ // If a point is equal, or forming a spike, remove the pen-ultimate point
+ // because this one caused the spike.
+ // If so, the now-new-pen-ultimate point can again cause a spike
+ // (possibly at a corner). So keep doing this.
+ // Besides spikes it will also avoid adding duplicates.
+ while(boost::size(range) >= 3
+ && point_is_spike_or_equal(point,
+ *(boost::end(range) - 3),
+ *(boost::end(range) - 2),
+ robust_policy))
+ {
+ // Use the Concept/traits, so resize and append again
+ traits::resize<Range>::apply(range, boost::size(range) - 2);
+ traits::push_back<Range>::apply(range, point);
+ }
+}
+
+template <typename Range, typename RobustPolicy>
+inline void clean_closing_dups_and_spikes(Range& range,
+ RobustPolicy const& robust_policy)
+{
+ std::size_t const minsize
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Range>::value
+ >::value;
+
+ if (boost::size(range) <= minsize)
+ {
+ return;
+ }
+
+ typedef typename boost::range_iterator<Range>::type iterator_type;
+ static bool const closed = geometry::closure<Range>::value == geometry::closed;
+
+// TODO: the following algorithm could be rewritten to first look for spikes
+// and then erase some number of points from the beginning of the Range
+
+ bool found = false;
+ do
+ {
+ found = false;
+ iterator_type first = boost::begin(range);
+ iterator_type second = first + 1;
+ iterator_type ultimate = boost::end(range) - 1;
+ if (closed)
+ {
+ ultimate--;
+ }
+
+ // 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))
+ {
+ range::erase(range, first);
+ if (closed)
+ {
+ // Remove closing last point
+ range::resize(range, boost::size(range) - 1);
+ // Add new closing point
+ range::push_back(range, range::front(range));
+ }
+ found = true;
+ }
+ } while(found && boost::size(range) > minsize);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 5063f49eb4..67b48cc471 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -18,6 +18,10 @@
#include <boost/geometry/geometries/box.hpp>
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+# include <boost/timer.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -123,30 +127,30 @@ struct assign_visitor
template <typename Item>
inline void apply(Item const& outer, Item const& inner, bool first = true)
{
- if (first && outer.real_area < 0)
+ if (first && outer.abs_area < inner.abs_area)
{
- // Reverse arguments
+ // Apply with reversed arguments
apply(inner, outer, false);
return;
}
- if (math::larger(outer.real_area, 0))
+ if (m_check_for_orientation
+ || (math::larger(outer.real_area, 0)
+ && math::smaller(inner.real_area, 0)))
{
- if (inner.real_area < 0 || m_check_for_orientation)
- {
- ring_info_type& inner_in_map = m_ring_map[inner.id];
+ 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::within(inner_in_map.point, outer.envelope)
+ && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
+ )
+ {
+ // Assign a parent if there was no earlier parent, or the newly
+ // found parent is smaller than the previous one
+ if (inner_in_map.parent.source_index == -1
+ || outer.abs_area < inner_in_map.parent_area)
{
- // Only assign parent if that parent is smaller (or if it is the first)
- if (inner_in_map.parent.source_index == -1
- || outer.abs_area < inner_in_map.parent_area)
- {
- inner_in_map.parent = outer.id;
- inner_in_map.parent_area = outer.abs_area;
- }
+ inner_in_map.parent = outer.id;
+ inner_in_map.parent_area = outer.abs_area;
}
}
}
@@ -243,7 +247,7 @@ inline void assign_parents(Geometry1 const& geometry1,
// a dramatic improvement (factor 5 for star_comb testcase)
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
- std::size_t index = 0;
+ index = 0;
for (vector_iterator_type it = boost::begin(vector);
it != boost::end(vector); ++it, ++index)
{
@@ -284,13 +288,21 @@ inline void assign_parents(Geometry1 const& geometry1,
{
it->second.discarded = true;
}
- else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0)
+ else if (it->second.parent.source_index >= 0
+ && math::larger(it->second.get_area(), 0))
{
- // Discard positive inner ring with parent
- it->second.discarded = true;
+ const ring_info_type& parent = ring_map[it->second.parent];
+
+ if (math::larger(parent.area, 0))
+ {
+ // Discard positive inner ring with positive parent
+ it->second.discarded = true;
+ }
+ // Remove parent ID from any positive inner ring
it->second.parent.source_index = -1;
}
- else if (it->second.parent.source_index < 0 && it->second.get_area() < 0)
+ else if (it->second.parent.source_index < 0
+ && math::smaller(it->second.get_area(), 0))
{
// Reverse negative ring without parent
it->second.reversed = true;
@@ -309,6 +321,8 @@ inline void assign_parents(Geometry1 const& geometry1,
}
}
+
+// Version for one geometry (called by buffer)
template
<
typename Geometry,
@@ -320,7 +334,7 @@ inline void assign_parents(Geometry const& geometry,
RingMap& ring_map,
bool check_for_orientation)
{
- // Call it with an empty geometry
+ // Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
index 012b3aca30..90901dee70 100644
--- a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
+++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
@@ -55,8 +55,8 @@ inline void clear_visit_info(Turns& turns)
struct backtrack_state
{
bool m_good;
-
- inline backtrack_state() : m_good(true) {}
+
+ inline backtrack_state() : m_good(true) {}
inline void reset() { m_good = true; }
inline bool good() const { return m_good; }
};
@@ -79,29 +79,30 @@ class backtrack_check_self_intersections
public :
typedef state state_type;
- template <typename Operation, typename Rings, typename Turns>
- static inline void apply(std::size_t size_at_start,
- Rings& rings, typename boost::range_value<Rings>::type& ring,
+ template <typename Operation, typename Rings, typename Ring, typename Turns, typename RobustPolicy>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, Ring& ring,
Turns& turns, Operation& operation,
std::string const& ,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
state_type& state
)
{
state.m_good = false;
-
+
// Check self-intersections and throw exception if appropriate
if (! state.m_checked)
{
state.m_checked = true;
- has_self_intersections(geometry1);
- has_self_intersections(geometry2);
+ has_self_intersections(geometry1, robust_policy);
+ has_self_intersections(geometry2, robust_policy);
}
// Make bad output clean
rings.resize(size_at_start);
- ring.clear();
+ geometry::traits::clear<typename boost::range_value<Rings>::type>::apply(ring);
// Reject this as a starting point
operation.visited.set_rejected();
@@ -123,7 +124,7 @@ public :
typedef backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns>
- static inline void apply(std::size_t size_at_start,
+ static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& reason,
@@ -133,7 +134,7 @@ public :
)
{
std::cout << " REJECT " << reason << std::endl;
-
+
state.m_good = false;
rings.resize(size_at_start);
diff --git a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
deleted file mode 100644
index 2003d2350d..0000000000
--- a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
-
-
-#include <boost/geometry/algorithms/comparable_distance.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace overlay
-{
-
-
-/*!
- \brief Policy calculating distance
- \details get_turn_info has an optional policy to get some
- extra information.
- This policy calculates the distance (using default distance strategy)
- */
-struct calculate_distance_policy
-{
- static bool const include_no_turn = false;
- static bool const include_degenerate = false;
- static bool const include_opposite = false;
-
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
- static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
- IntersectionInfo const&, DirInfo const&)
- {
- info.operations[0].enriched.distance
- = geometry::comparable_distance(info.point, p1);
- info.operations[1].enriched.distance
- = geometry::comparable_distance(info.point, p2);
- }
-
-};
-
-
-}} // namespace detail::overlay
-#endif //DOXYGEN_NO_DETAIL
-
-
-}} // namespace boost::geometry
-
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
index b210fd04b1..03be18e07a 100644
--- a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
+++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
@@ -137,7 +137,7 @@ inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
it != boost::end(meta_turns);
++it)
{
- if (! (it->turn->blocked() || it->turn->is_discarded()))
+ if (! (it->turn->blocked() || it->turn->discarded))
{
for (int i = 0 ; i < 2; i++)
{
diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
index 05bd721e7f..51955b515d 100644
--- a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
+++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
@@ -77,12 +77,23 @@ struct convert_ring<polygon_tag>
}
else
{
- interior_rings(destination).resize(
- interior_rings(destination).size() + 1);
- geometry::convert(source, interior_rings(destination).back());
- if (reverse)
+ // Avoid adding interior rings which are invalid
+ // because of its number of points:
+ std::size_t const min_num_points
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Destination>::value
+ >::value;
+
+ if (geometry::num_points(source) >= min_num_points)
{
- boost::reverse(interior_rings(destination).back());
+ interior_rings(destination).resize(
+ interior_rings(destination).size() + 1);
+ geometry::convert(source, interior_rings(destination).back());
+ if (reverse)
+ {
+ boost::reverse(interior_rings(destination).back());
+ }
}
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
index 5e18d0453a..20a6d7f48d 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -17,8 +17,10 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
@@ -51,7 +53,7 @@ struct copy_segment_point_range
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
- int index = seg_id.segment_index;
+ signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
@@ -94,8 +96,8 @@ struct copy_segment_point_polygon
>::apply
(
seg_id.ring_index < 0
- ? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[seg_id.ring_index],
+ ? geometry::exterior_ring(polygon)
+ : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, second,
point
);
@@ -110,7 +112,7 @@ struct copy_segment_point_box
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
- int index = seg_id.segment_index;
+ signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
@@ -124,6 +126,30 @@ struct copy_segment_point_box
};
+template
+<
+ typename MultiGeometry,
+ typename SegmentIdentifier,
+ typename PointOut,
+ typename Policy
+>
+struct copy_segment_point_multi
+{
+ static inline bool apply(MultiGeometry const& multi,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point)
+ {
+
+ BOOST_ASSERT
+ (
+ seg_id.multi_index >= 0
+ && seg_id.multi_index < int(boost::size(multi))
+ );
+
+ // Call the single-version
+ return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, second, point);
+ }
+};
}} // namespace detail::copy_segments
@@ -188,6 +214,66 @@ struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
{};
+template
+<
+ typename MultiGeometry,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ multi_polygon_tag,
+ MultiGeometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiGeometry,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_polygon
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
+template
+<
+ typename MultiGeometry,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ multi_linestring_tag,
+ MultiGeometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiGeometry,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_range
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
index 805f3923e3..ceeb1a3b8b 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
@@ -1,6 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// 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.
+
+// 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
@@ -10,24 +16,32 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
-#include <boost/array.hpp>
-#include <boost/mpl/assert.hpp>
#include <vector>
+#include <boost/array.hpp>
#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
+#include <boost/type_traits/integral_constant.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
namespace boost { namespace geometry
{
@@ -38,34 +52,38 @@ namespace detail { namespace copy_segments
{
-template
-<
- typename Ring,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_ring
{
- typedef typename closeable_view
+ template
+ <
+ typename Ring,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
+ static inline void apply(Ring const& ring,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
+ RangeOut& current_output)
+ {
+ typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
- typedef typename reversible_view
+ typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
- typedef typename boost::range_iterator<rview_type const>::type iterator;
- typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+ typedef typename boost::range_iterator<rview_type const>::type iterator;
+ typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+
- static inline void apply(Ring const& ring,
- SegmentIdentifier const& seg_id, int to_index,
- RangeOut& current_output)
- {
cview_type cview(ring);
rview_type view(cview);
@@ -75,10 +93,10 @@ struct copy_segments_ring
// So we use the ever-circling iterator and determine when to step out
- int const from_index = seg_id.segment_index + 1;
+ signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
- BOOST_ASSERT(from_index < int(boost::size(view)));
+ BOOST_ASSERT(from_index < static_cast<signed_index_type>(boost::size(view)));
ec_iterator it(boost::begin(view), boost::end(view),
boost::begin(view) + from_index);
@@ -86,103 +104,130 @@ struct copy_segments_ring
// [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK
// [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK
// [1..1], travel the whole ring round
- typedef typename boost::range_difference<Ring>::type size_type;
- size_type const count = from_index <= to_index
+ signed_index_type const count = from_index <= to_index
? to_index - from_index + 1
- : int(boost::size(view)) - from_index + to_index + 1;
+ : static_cast<signed_index_type>(boost::size(view))
+ - from_index + to_index + 1;
- for (size_type i = 0; i < count; ++i, ++it)
+ for (signed_index_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_duplicates(current_output, *it);
+ detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
}
}
};
-template
-<
- typename LineString,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments_linestring
+template <bool Reverse, bool RemoveSpikes = true>
+class copy_segments_linestring
{
+private:
+ // remove spikes
+ template <typename RangeOut, typename Point, typename RobustPolicy>
+ static inline void append_to_output(RangeOut& current_output,
+ Point const& point,
+ RobustPolicy const& robust_policy,
+ boost::true_type const&)
+ {
+ detail::overlay::append_no_dups_or_spikes(current_output, point,
+ robust_policy);
+ }
- typedef typename boost::range_iterator<LineString const>::type iterator;
+ // keep spikes
+ template <typename RangeOut, typename Point, typename RobustPolicy>
+ static inline void append_to_output(RangeOut& current_output,
+ Point const& point,
+ RobustPolicy const&,
+ boost::false_type const&)
+ {
+ detail::overlay::append_no_duplicates(current_output, point);
+ }
+public:
+ template
+ <
+ typename LineString,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(LineString const& ls,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
- int const from_index = seg_id.segment_index + 1;
+ signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
- if (from_index > to_index || from_index < 0 || to_index >= int(boost::size(ls)))
+ if ( from_index > to_index
+ || from_index < 0
+ || to_index >= static_cast<signed_index_type>(boost::size(ls)) )
{
return;
}
- typedef typename boost::range_difference<LineString>::type size_type;
- size_type const count = to_index - from_index + 1;
+ signed_index_type const count = to_index - from_index + 1;
- typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index;
+ typename boost::range_iterator<LineString const>::type
+ it = boost::begin(ls) + from_index;
- for (size_type i = 0; i < count; ++i, ++it)
+ for (signed_index_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_duplicates(current_output, *it);
+ append_to_output(current_output, *it, robust_policy,
+ boost::integral_constant<bool, RemoveSpikes>());
}
}
};
-template
-<
- typename Polygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_polygon
{
+ template
+ <
+ typename Polygon,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(Polygon const& polygon,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
// Call ring-version with the right ring
- copy_segments_ring
- <
- typename geometry::ring_type<Polygon>::type,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >::apply
- (
- seg_id.ring_index < 0
+ copy_segments_ring<Reverse>::apply
+ (
+ seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[seg_id.ring_index],
- seg_id, to_index,
- current_output
- );
+ : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
+ seg_id, to_index,
+ robust_policy,
+ current_output
+ );
}
};
-template
-<
- typename Box,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_box
{
+ template
+ <
+ typename Box,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(Box const& box,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
- int index = seg_id.segment_index + 1;
+ signed_index_type index = seg_id.segment_index + 1;
BOOST_ASSERT(index < 5);
- int const count = index <= to_index
+ signed_index_type const count = index <= to_index
? to_index - index + 1
: 5 - index + to_index + 1;
@@ -193,15 +238,48 @@ struct copy_segments_box
// (possibly cyclic) copy to output
// (see comments in ring-version)
- for (int i = 0; i < count; i++, index++)
+ for (signed_index_type i = 0; i < count; i++, index++)
{
- detail::overlay::append_no_duplicates(current_output, bp[index % 5]);
+ detail::overlay::append_no_dups_or_spikes(current_output,
+ bp[index % 5], robust_policy);
}
}
};
+template<typename Policy>
+struct copy_segments_multi
+{
+ template
+ <
+ typename MultiGeometry,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
+ static inline void apply(MultiGeometry const& multi_geometry,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
+ RangeOut& current_output)
+ {
+
+ BOOST_ASSERT
+ (
+ seg_id.multi_index >= 0
+ && seg_id.multi_index < int(boost::size(multi_geometry))
+ );
+
+ // Call the single-version
+ Policy::apply(range::at(multi_geometry, seg_id.multi_index),
+ seg_id, to_index,
+ robust_policy,
+ current_output);
+ }
+};
+
+
}} // namespace detail::copy_segments
#endif // DOXYGEN_NO_DETAIL
@@ -213,82 +291,44 @@ namespace dispatch
template
<
typename Tag,
- typename GeometryIn,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
+ bool Reverse
>
-struct copy_segments
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<GeometryIn>)
- );
-};
+struct copy_segments : not_implemented<Tag>
+{};
-template
-<
- typename Ring,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<ring_tag, Ring, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_ring
- <
- Ring, Reverse, SegmentIdentifier, RangeOut
- >
+template <bool Reverse>
+struct copy_segments<ring_tag, Reverse>
+ : detail::copy_segments::copy_segments_ring<Reverse>
{};
+template <bool Reverse>
+struct copy_segments<linestring_tag, Reverse>
+ : detail::copy_segments::copy_segments_linestring<Reverse>
+{};
-template
-<
- typename LineString,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<linestring_tag, LineString, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_linestring
- <
- LineString, Reverse, SegmentIdentifier, RangeOut
- >
+template <bool Reverse>
+struct copy_segments<polygon_tag, Reverse>
+ : detail::copy_segments::copy_segments_polygon<Reverse>
{};
-template
-<
- typename Polygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<polygon_tag, Polygon, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_polygon
- <
- Polygon, Reverse, SegmentIdentifier, RangeOut
- >
+
+template <bool Reverse>
+struct copy_segments<box_tag, Reverse>
+ : detail::copy_segments::copy_segments_box<Reverse>
{};
-template
-<
- typename Box,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_box
+template<bool Reverse>
+struct copy_segments<multi_polygon_tag, Reverse>
+ : detail::copy_segments::copy_segments_multi
<
- Box, Reverse, SegmentIdentifier, RangeOut
+ detail::copy_segments::copy_segments_polygon<Reverse>
>
{};
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -303,10 +343,13 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
+ typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& range_out)
{
concept::check<Geometry const>();
@@ -314,11 +357,8 @@ inline void copy_segments(Geometry const& geometry,
dispatch::copy_segments
<
typename tag<Geometry>::type,
- Geometry,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >::apply(geometry, seg_id, to_index, range_out);
+ Reverse
+ >::apply(geometry, seg_id, to_index, robust_policy, range_out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/do_reverse.hpp b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp
new file mode 100644
index 0000000000..15100f8d0b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
+
+// 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_DO_REVERSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
+
+#include <boost/geometry/core/point_order.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// Metafunction helper for intersection and union
+template <order_selector Selector, bool Reverse = false>
+struct do_reverse {};
+
+template <>
+struct do_reverse<clockwise, false> : boost::false_type {};
+
+template <>
+struct do_reverse<clockwise, true> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, false> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, true> : boost::false_type {};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index e4842d35f1..9484479b45 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -27,8 +27,9 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_relative_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp>
+#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
@@ -47,17 +48,23 @@ struct indexed_turn_operation
{
typedef TurnOperation type;
- int index;
- int operation_index;
+ std::size_t turn_index;
+ std::size_t operation_index;
bool discarded;
- TurnOperation subject;
-
- inline indexed_turn_operation(int i, int oi, TurnOperation const& s)
- : index(i)
+ // use pointers to avoid copies, const& is not possible because of usage in vector
+ segment_identifier const* other_seg_id; // segment id of other segment of intersection of two segments
+ TurnOperation const* subject;
+
+ inline indexed_turn_operation(std::size_t ti, std::size_t oi,
+ TurnOperation const& s,
+ segment_identifier const& oid)
+ : turn_index(ti)
, operation_index(oi)
, discarded(false)
- , subject(s)
+ , other_seg_id(&oid)
+ , subject(&s)
{}
+
};
template <typename IndexedTurnOperation>
@@ -75,19 +82,22 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
-struct sort_on_segment_and_distance
+struct sort_on_segment_and_ratio
{
- inline sort_on_segment_and_distance(TurnPoints const& turn_points
+ inline sort_on_segment_and_ratio(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
+ , RobustPolicy const& robust_policy
, Strategy const& strategy
, bool* clustered)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
+ , m_robust_policy(robust_policy)
, m_strategy(strategy)
, m_clustered(clustered)
{
@@ -98,31 +108,47 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_robust_policy;
Strategy const& m_strategy;
mutable bool* m_clustered;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+
inline bool consider_relative_order(Indexed const& left,
Indexed const& right) const
{
- typedef typename geometry::point_type<Geometry1>::type point_type;
point_type pi, pj, ri, rj, si, sj;
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
+ left.subject->seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
+ *left.other_seg_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
+ *right.other_seg_id,
si, sj);
- int const order = get_relative_order
+ typedef typename strategy::side::services::default_strategy
<
- point_type
- >::apply(pi, pj,ri, rj, si, sj);
- //debug("r/o", order == -1);
- return order == -1;
+ 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);
+
+ // Put the one turning left (1; right == -1) as last
+ if (side_rj_p != side_sj_p)
+ {
+ 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);
+
+ // 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
+ return side_rj_s < side_sj_r;
}
public :
@@ -131,33 +157,30 @@ public :
// but to the "indexed_turn_operation"
inline bool operator()(Indexed const& left, Indexed const& right) const
{
- segment_identifier const& sl = left.subject.seg_id;
- segment_identifier const& sr = right.subject.seg_id;
+ segment_identifier const& sl = left.subject->seg_id;
+ segment_identifier const& sr = right.subject->seg_id;
- if (sl == sr
- && geometry::math::equals(left.subject.enriched.distance
- , right.subject.enriched.distance))
+ if (sl == sr)
{
// Both left and right are located on the SAME segment.
-
- // First check "real" intersection (crosses)
- // -> distance zero due to precision, solve it by sorting
- if (m_turn_points[left.index].method == method_crosses
- && m_turn_points[right.index].method == method_crosses)
+ if (left.subject->fraction == right.subject->fraction)
{
- return consider_relative_order(left, right);
- }
-
- // If that is not the case, cluster it later on.
- // Indicate that this is necessary.
- *m_clustered = true;
+ // First check "real" intersection (crosses)
+ // -> distance zero due to precision, solve it by sorting
+ if (m_turn_points[left.turn_index].method == method_crosses
+ && m_turn_points[right.turn_index].method == method_crosses)
+ {
+ return consider_relative_order(left, right);
+ }
- return left.index < right.index;
+ // If that is not the case, cluster it later on.
+ // Indicate that this is necessary.
+ *m_clustered = true;
+ }
}
return sl == sr
- ? left.subject.enriched.distance < right.subject.enriched.distance
+ ? left.subject->fraction < right.subject->fraction
: sl < sr;
-
}
};
@@ -171,13 +194,13 @@ inline void update_discarded(Turns& turn_points, Operations& operations)
it != boost::end(operations);
++it)
{
- if (turn_points[it->index].discarded)
+ if (turn_points[it->turn_index].discarded)
{
it->discarded = true;
}
else if (it->discarded)
{
- turn_points[it->index].discarded = true;
+ turn_points[it->turn_index].discarded = true;
}
}
}
@@ -195,12 +218,14 @@ template
typename Container,
typename TurnPoints,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void enrich_sort(Container& operations,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename IndexType::type operations_type;
@@ -208,14 +233,15 @@ inline void enrich_sort(Container& operations,
bool clustered = false;
std::sort(boost::begin(operations),
boost::end(operations),
- sort_on_segment_and_distance
+ sort_on_segment_and_ratio
<
TurnPoints,
IndexType,
Geometry1, Geometry2,
+ RobustPolicy,
Reverse1, Reverse2,
Strategy
- >(turn_points, geometry1, geometry2, strategy, &clustered));
+ >(turn_points, geometry1, geometry2, robust_policy, strategy, &clustered));
// DONT'T discard xx / (for union) ix / ii / (for intersection) ux / uu here
// It would give way to "lonely" ui turn points, traveling all
@@ -230,16 +256,15 @@ inline void enrich_sort(Container& operations,
it != boost::end(operations);
prev = it++)
{
- operations_type& prev_op = turn_points[prev->index]
+ operations_type& prev_op = turn_points[prev->turn_index]
.operations[prev->operation_index];
- operations_type& op = turn_points[it->index]
+ operations_type& op = turn_points[it->turn_index]
.operations[it->operation_index];
if (prev_op.seg_id == op.seg_id
- && (turn_points[prev->index].method != method_crosses
- || turn_points[it->index].method != method_crosses)
- && geometry::math::equals(prev_op.enriched.distance,
- op.enriched.distance))
+ && (turn_points[prev->turn_index].method != method_crosses
+ || turn_points[it->turn_index].method != method_crosses)
+ && prev_op.fraction == op.fraction)
{
if (begin_cluster == boost::end(operations))
{
@@ -249,14 +274,14 @@ inline void enrich_sort(Container& operations,
else if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
- for_operation, geometry1, geometry2, strategy);
+ for_operation, geometry1, geometry2, robust_policy, strategy);
begin_cluster = boost::end(operations);
}
}
if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
- for_operation, geometry1, geometry2, strategy);
+ for_operation, geometry1, geometry2, robust_policy, strategy);
}
}
@@ -315,19 +340,19 @@ inline void enrich_assign(Container& operations,
prev = it++)
{
operations_type& prev_op
- = turn_points[prev->index].operations[prev->operation_index];
+ = turn_points[prev->turn_index].operations[prev->operation_index];
operations_type& op
- = turn_points[it->index].operations[it->operation_index];
+ = turn_points[it->turn_index].operations[it->operation_index];
prev_op.enriched.travels_to_ip_index
- = it->index;
+ = static_cast<int>(it->turn_index);
prev_op.enriched.travels_to_vertex_index
- = it->subject.seg_id.segment_index;
+ = it->subject->seg_id.segment_index;
if (! first
&& prev_op.seg_id.segment_index == op.seg_id.segment_index)
{
- prev_op.enriched.next_ip_index = it->index;
+ prev_op.enriched.next_ip_index = static_cast<int>(it->turn_index);
}
first = false;
}
@@ -340,16 +365,16 @@ inline void enrich_assign(Container& operations,
it != boost::end(operations);
++it)
{
- operations_type& op = turn_points[it->index]
+ operations_type& op = turn_points[it->turn_index]
.operations[it->operation_index];
- std::cout << it->index
- << " meth: " << method_char(turn_points[it->index].method)
+ std::cout << it->turn_index
+ << " meth: " << method_char(turn_points[it->turn_index].method)
<< " seg: " << op.seg_id
- << " dst: " << boost::numeric_cast<double>(op.enriched.distance)
- << " op: " << operation_char(turn_points[it->index].operations[0].operation)
- << operation_char(turn_points[it->index].operations[1].operation)
- << " dsc: " << (turn_points[it->index].discarded ? "T" : "F")
+ << " dst: " << op.fraction // needs define
+ << " op: " << operation_char(turn_points[it->turn_index].operations[0].operation)
+ << operation_char(turn_points[it->turn_index].operations[1].operation)
+ << " dsc: " << (turn_points[it->turn_index].discarded ? "T" : "F")
<< " ->vtx " << op.enriched.travels_to_vertex_index
<< " ->ip " << op.enriched.travels_to_ip_index
<< " ->nxt ip " << op.enriched.next_ip_index
@@ -370,7 +395,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
- int index = 0;
+ std::size_t index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
@@ -379,7 +404,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
// Add operations on this ring, but skip discarded ones
if (! it->discarded)
{
- int op_index = 0;
+ std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
@@ -397,7 +422,8 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
);
mapped_vector[ring_id].push_back
(
- IndexedType(index, op_index, *op_it)
+ IndexedType(index, op_index, *op_it,
+ it->operations[1 - op_index].seg_id)
);
}
}
@@ -422,6 +448,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
\param for_operation operation_type (union or intersection)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
+\param robust_policy policy to handle robustness issues
\param strategy strategy
*/
template
@@ -429,11 +456,13 @@ template
bool Reverse1, bool Reverse2,
typename TurnPoints,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void enrich_intersection_points(TurnPoints& turn_points,
detail::overlay::operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
@@ -462,6 +491,10 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
{
it->discarded = true;
}
+ if (it->both(detail::overlay::operation_none))
+ {
+ it->discarded = true;
+ }
}
@@ -484,7 +517,7 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation,
- geometry1, geometry2, strategy);
+ geometry1, geometry2, robust_policy, strategy);
}
for (typename mapped_vector_type::iterator mit
diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
index 8c8ed96189..ef32edeefa 100644
--- a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
@@ -10,9 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
-#include <boost/geometry/strategies/distance.hpp>
-
-
namespace boost { namespace geometry
{
@@ -31,37 +28,22 @@ namespace detail { namespace overlay
template<typename P>
struct enrichment_info
{
- typedef typename strategy::distance::services::return_type
- <
- typename strategy::distance::services::comparable_type
- <
- typename strategy::distance::services::default_strategy
- <
- point_tag,
- P
- >::type
- >::type
- >::type distance_type;
-
inline enrichment_info()
: travels_to_vertex_index(-1)
, travels_to_ip_index(-1)
, next_ip_index(-1)
- , distance(distance_type())
{}
// vertex to which is free travel after this IP,
// so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
// can be -1
- int travels_to_vertex_index;
+ signed_index_type travels_to_vertex_index;
// same but now IP index, so "next IP index" but not on THIS segment
int travels_to_ip_index;
// index of next IP on this segment, -1 if there is no one
int next_ip_index;
-
- distance_type distance; // distance-measurement from segment.first to IP
};
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
index b110cc9602..acf38d09ab 100644
--- a/boost/geometry/algorithms/detail/overlay/follow.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// 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.
+
+// Contributed and/or modified by Menelaos Karavelas, 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
@@ -20,6 +25,7 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
namespace boost { namespace geometry
@@ -32,7 +38,7 @@ namespace detail { namespace overlay
namespace following
{
-
+
template <typename Turn, typename Operation>
static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
{
@@ -44,43 +50,43 @@ static inline bool is_entering(Turn const& /* TODO remove this parameter */, Ope
;
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool last_covered_by(Turn const& turn, Operation const& op,
+static inline bool last_covered_by(Turn const& turn, Operation const& op,
LineString const& linestring, Polygon const& polygon)
{
- // Check any point between the this one and the first IP
+ // Check any point between the this one and the first IP
typedef typename geometry::point_type<LineString>::type point_type;
point_type point_in_between;
detail::point_on_border::midpoint_helper
<
point_type,
0, dimension<point_type>::value
- >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point);
+ >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
return geometry::covered_by(point_in_between, polygon);
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool is_leaving(Turn const& turn, Operation const& op,
- bool entered, bool first,
+static inline bool is_leaving(Turn const& turn, Operation const& op,
+ bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
{
if (op.operation == operation_union)
{
- return entered
+ return entered
|| turn.method == method_crosses
|| (first && last_covered_by(turn, op, linestring, polygon))
;
@@ -89,20 +95,20 @@ static inline bool is_leaving(Turn const& turn, Operation const& op,
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool is_staying_inside(Turn const& turn, Operation const& op,
- bool entered, bool first,
+static inline bool is_staying_inside(Turn const& turn, Operation const& op,
+ bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
{
if (turn.method == method_crosses)
{
- // The normal case, this is completely covered with entering/leaving
+ // The normal case, this is completely covered with entering/leaving
// so stay out of this time consuming "covered_by"
return false;
}
@@ -115,11 +121,11 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op,
return false;
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename Linestring,
+ typename Turn,
+ typename Operation,
+ typename Linestring,
typename Polygon
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
@@ -134,7 +140,7 @@ static inline bool was_entered(Turn const& turn, Operation const& op, bool first
// Template specialization structure to call the right actions for the right type
-template<overlay_type OverlayType>
+template <overlay_type OverlayType, bool RemoveSpikes = true>
struct action_selector
{
// If you get here the overlay type is not intersection or difference
@@ -142,51 +148,86 @@ struct action_selector
};
// Specialization for intersection, containing the implementation
-template<>
-struct action_selector<overlay_intersection>
+template <bool RemoveSpikes>
+struct action_selector<overlay_intersection, RemoveSpikes>
{
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
- LineString const& ,
+ LineString const& ,
segment_identifier& segment_id,
- int , Point const& point,
- Operation const& operation, OutputIterator& )
+ signed_index_type , Point const& point,
+ Operation const& operation,
+ RobustPolicy const& ,
+ OutputIterator& )
{
// On enter, append the intersection point and remember starting point
+ // TODO: we don't check on spikes for linestrings (?). Consider this.
detail::overlay::append_no_duplicates(current_piece, point);
segment_id = operation.seg_id;
}
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& , OutputIterator& out)
+ signed_index_type index, Point const& point,
+ Operation const& ,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
// On leave, copy all segments from starting point, append the intersection point
// and add the output piece
- geometry::copy_segments<false>(linestring, segment_id, index, current_piece);
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, RemoveSpikes
+ >::apply(linestring, segment_id, index, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
- if (current_piece.size() > 1)
+ if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
}
- current_piece.clear();
+
+ geometry::clear(current_piece);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void isolated_point(LineStringOut&,
+ LineString const&,
+ segment_identifier&,
+ signed_index_type, Point const& point,
+ Operation const& , OutputIterator& out)
+ {
+ LineStringOut isolated_point_ls;
+ geometry::append(isolated_point_ls, point);
+
+#ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
+ geometry::append(isolated_point_ls, point);
+#endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
+
+ *out++ = isolated_point_ls;
}
static inline bool is_entered(bool entered)
@@ -194,8 +235,15 @@ struct action_selector<overlay_intersection>
return entered;
}
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& )
{
return geometry::covered_by(point, geometry);
}
@@ -203,45 +251,67 @@ struct action_selector<overlay_intersection>
};
// Specialization for difference, which reverses these actions
-template<>
-struct action_selector<overlay_difference>
+template <bool RemoveSpikes>
+struct action_selector<overlay_difference, RemoveSpikes>
{
- typedef action_selector<overlay_intersection> normal_action;
+ typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
- static inline void enter(LineStringOut& current_piece,
- LineString const& linestring,
- segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& operation, OutputIterator& out)
+ static inline void enter(LineStringOut& current_piece,
+ LineString const& linestring,
+ segment_identifier& segment_id,
+ signed_index_type index, Point const& point,
+ Operation const& operation,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
- normal_action::leave(current_piece, linestring, segment_id, index,
- point, operation, out);
+ normal_action::leave(current_piece, linestring, segment_id, index,
+ point, operation, robust_policy, out);
}
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& operation, OutputIterator& out)
+ signed_index_type index, Point const& point,
+ Operation const& operation,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
- point, operation, out);
+ point, operation, robust_policy, out);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void isolated_point(LineStringOut&,
+ LineString const&,
+ segment_identifier&,
+ signed_index_type, Point const&,
+ Operation const&, OutputIterator&)
+ {
}
static inline bool is_entered(bool entered)
@@ -249,10 +319,17 @@ struct action_selector<overlay_difference>
return ! normal_action::is_entered(entered);
}
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& robust_policy)
{
- return ! normal_action::included(point, geometry);
+ return ! normal_action::included(point, geometry, robust_policy);
}
};
@@ -269,12 +346,13 @@ template
typename LineStringOut,
typename LineString,
typename Polygon,
- overlay_type OverlayType
+ overlay_type OverlayType,
+ bool RemoveSpikes = true
>
class follow
{
- template<typename Turn>
+ template <typename Turn>
struct sort_on_segment
{
// In case of turn point at the same location, we want to have continue/blocked LAST
@@ -296,15 +374,15 @@ class follow
inline bool use_operation(Turn const& left, Turn const& right) const
{
- // If they are the same, OK.
+ // If they are the same, OK.
return operation_order(left) < operation_order(right);
}
inline bool use_distance(Turn const& left, Turn const& right) const
{
- return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance)
+ return left.operations[0].fraction == right.operations[0].fraction
? use_operation(left, right)
- : left.operations[0].enriched.distance < right.operations[0].enriched.distance
+ : left.operations[0].fraction < right.operations[0].fraction
;
}
@@ -325,16 +403,33 @@ class follow
public :
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& robust_policy)
{
- return following::action_selector<OverlayType>::included(point, geometry);
+ return following::action_selector
+ <
+ OverlayType, RemoveSpikes
+ >::included(point, geometry, robust_policy);
}
- template<typename Turns, typename OutputIterator>
+ template
+ <
+ typename Turns,
+ typename OutputIterator,
+ typename RobustPolicy
+ >
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
- Turns& turns, OutputIterator out)
+ Turns& turns,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -343,7 +438,7 @@ public :
typename turn_type::container_type
>::type turn_operation_iterator_type;
- typedef following::action_selector<OverlayType> action;
+ typedef following::action_selector<OverlayType, RemoveSpikes> action;
// Sort intersection points on segments-along-linestring, and distance
// (like in enrich is done for poly/poly)
@@ -376,27 +471,38 @@ public :
debug_traverse(*it, *iit, "-> Entering");
entered = true;
- action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ action::enter(current_piece, linestring, current_segment_id,
+ iit->seg_id.segment_index, it->point, *iit,
+ robust_policy,
+ out);
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
- action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ action::leave(current_piece, linestring, current_segment_id,
+ iit->seg_id.segment_index, it->point, *iit,
+ robust_policy,
+ out);
}
first = false;
}
if (action::is_entered(entered))
{
- geometry::copy_segments<false>(linestring, current_segment_id,
- boost::size(linestring) - 1,
- current_piece);
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, RemoveSpikes
+ >::apply(linestring,
+ current_segment_id,
+ static_cast<signed_index_type>(boost::size(linestring) - 1),
+ robust_policy,
+ current_piece);
}
// Output the last one, if applicable
- if (current_piece.size() > 1)
+ if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
}
diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
new file mode 100644
index 0000000000..85378e08b0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
@@ -0,0 +1,536 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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
+
+#include <cstddef>
+#include <algorithm>
+#include <iterator>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+namespace following { namespace linear
+{
+
+
+
+
+// follower for linear/linear geometries set operations
+
+template <typename Turn, typename Operation>
+static inline bool is_entering(Turn const& turn,
+ Operation const& operation)
+{
+ if ( turn.method != method_touch && turn.method != method_touch_interior )
+ {
+ return false;
+ }
+ return operation.operation == operation_intersection;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_staying_inside(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( !entered )
+ {
+ return false;
+ }
+
+ if ( turn.method != method_equal && turn.method != method_collinear )
+ {
+ return false;
+ }
+ return operation.operation == operation_continue;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_leaving(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( !entered )
+ {
+ return false;
+ }
+
+ if ( turn.method != method_touch
+ && turn.method != method_touch_interior
+ && turn.method != method_equal
+ && turn.method != method_collinear )
+ {
+ return false;
+ }
+
+ if ( operation.operation == operation_blocked )
+ {
+ return true;
+ }
+
+ if ( operation.operation != operation_union )
+ {
+ return false;
+ }
+
+ return operation.is_collinear;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_isolated_point(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( entered )
+ {
+ return false;
+ }
+
+ if ( turn.method == method_none )
+ {
+ BOOST_ASSERT( operation.operation == operation_continue );
+ return true;
+ }
+
+ if ( turn.method == method_crosses )
+ {
+ return true;
+ }
+
+ if ( turn.method != method_touch && turn.method != method_touch_interior )
+ {
+ return false;
+ }
+
+ if ( operation.operation == operation_blocked )
+ {
+ return true;
+ }
+
+ if ( operation.operation != operation_union )
+ {
+ return false;
+ }
+
+ return !operation.is_collinear;
+}
+
+
+
+
+
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Linestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+class follow_linestring_linear_linestring
+{
+protected:
+ // allow spikes (false indicates: do not remove spikes)
+ typedef following::action_selector<OverlayType, false> action;
+
+ template
+ <
+ typename TurnIterator,
+ typename TurnOperationIterator,
+ typename SegmentIdentifier,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ process_turn(TurnIterator it,
+ TurnOperationIterator op_it,
+ bool& entered,
+ std::size_t& enter_count,
+ Linestring const& linestring,
+ LinestringOut& current_piece,
+ SegmentIdentifier& current_segment_id,
+ OutputIterator oit)
+ {
+ // We don't rescale linear/linear
+ detail::no_rescale_policy robust_policy;
+
+ if ( is_entering(*it, *op_it) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Entering");
+
+ entered = true;
+ if ( enter_count == 0 )
+ {
+ action::enter(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, robust_policy, oit);
+ }
+ ++enter_count;
+ }
+ else if ( is_leaving(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Leaving");
+
+ --enter_count;
+ if ( enter_count == 0 )
+ {
+ entered = false;
+ action::leave(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, robust_policy, oit);
+ }
+ }
+ else if ( FollowIsolatedPoints
+ && is_isolated_point(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
+
+ action::isolated_point(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, oit);
+ }
+ else if ( FollowContinueTurns
+ && is_staying_inside(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
+
+ entered = true;
+ }
+ return oit;
+ }
+
+ template
+ <
+ typename SegmentIdentifier,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ process_end(bool entered,
+ Linestring const& linestring,
+ SegmentIdentifier const& current_segment_id,
+ LinestringOut& current_piece,
+ OutputIterator oit)
+ {
+ if ( action::is_entered(entered) )
+ {
+ // We don't rescale linear/linear
+ detail::no_rescale_policy robust_policy;
+
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, false // do not reverse; do not remove spikes
+ >::apply(linestring,
+ current_segment_id,
+ static_cast<signed_index_type>(boost::size(linestring) - 1),
+ robust_policy,
+ current_piece);
+ }
+
+ // Output the last one, if applicable
+ if (::boost::size(current_piece) > 1)
+ {
+ *oit++ = current_piece;
+ }
+
+ return oit;
+ }
+
+public:
+ template <typename TurnIterator, typename OutputIterator>
+ static inline OutputIterator
+ apply(Linestring const& linestring, Linear const&,
+ TurnIterator first, TurnIterator beyond,
+ OutputIterator oit)
+ {
+ // Iterate through all intersection points (they are
+ // ordered along the each line)
+
+ LinestringOut current_piece;
+ geometry::segment_identifier current_segment_id(0, -1, -1, -1);
+
+ bool entered = false;
+ std::size_t enter_count = 0;
+
+ for (TurnIterator it = first; it != beyond; ++it)
+ {
+ oit = process_turn(it, boost::begin(it->operations),
+ entered, enter_count,
+ linestring,
+ current_piece, current_segment_id,
+ oit);
+ }
+
+ BOOST_ASSERT( enter_count == 0 );
+
+ return process_end(entered, linestring,
+ current_segment_id, current_piece,
+ oit);
+ }
+};
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename MultiLinestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+class follow_multilinestring_linear_linestring
+ : follow_linestring_linear_linestring
+ <
+ LinestringOut,
+ typename boost::range_value<MultiLinestring>::type,
+ Linear,
+ OverlayType,
+ FollowIsolatedPoints,
+ FollowContinueTurns
+ >
+{
+protected:
+ typedef typename boost::range_value<MultiLinestring>::type Linestring;
+
+ typedef follow_linestring_linear_linestring
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ > Base;
+
+ typedef following::action_selector<OverlayType> action;
+
+ typedef typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type linestring_iterator;
+
+
+ template <typename OutputIt, overlay_type OT>
+ struct copy_linestrings_in_range
+ {
+ static inline OutputIt
+ apply(linestring_iterator, linestring_iterator, OutputIt oit)
+ {
+ return oit;
+ }
+ };
+
+ template <typename OutputIt>
+ struct copy_linestrings_in_range<OutputIt, overlay_difference>
+ {
+ static inline OutputIt
+ apply(linestring_iterator first, linestring_iterator beyond,
+ OutputIt oit)
+ {
+ for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
+ {
+ LinestringOut line_out;
+ geometry::convert(*ls_it, line_out);
+ *oit++ = line_out;
+ }
+ return oit;
+ }
+ };
+
+ template <typename TurnIterator>
+ static inline signed_index_type get_multi_index(TurnIterator it)
+ {
+ return boost::begin(it->operations)->seg_id.multi_index;
+ }
+
+ class has_other_multi_id
+ {
+ private:
+ signed_index_type m_multi_id;
+
+ public:
+ has_other_multi_id(signed_index_type multi_id)
+ : m_multi_id(multi_id) {}
+
+ template <typename Turn>
+ bool operator()(Turn const& turn) const
+ {
+ return boost::begin(turn.operations)->seg_id.multi_index
+ != m_multi_id;
+ }
+ };
+
+public:
+ template <typename TurnIterator, typename OutputIterator>
+ static inline OutputIterator
+ apply(MultiLinestring const& multilinestring, Linear const& linear,
+ TurnIterator first, TurnIterator beyond,
+ OutputIterator oit)
+ {
+ BOOST_ASSERT( first != beyond );
+
+ typedef copy_linestrings_in_range
+ <
+ OutputIterator, OverlayType
+ > copy_linestrings;
+
+ linestring_iterator ls_first = boost::begin(multilinestring);
+ linestring_iterator ls_beyond = boost::end(multilinestring);
+
+ // Iterate through all intersection points (they are
+ // ordered along the each linestring)
+
+ signed_index_type current_multi_id = get_multi_index(first);
+
+ oit = copy_linestrings::apply(ls_first,
+ ls_first + current_multi_id,
+ oit);
+
+ TurnIterator per_ls_next = first;
+ do {
+ TurnIterator per_ls_current = per_ls_next;
+
+ // find turn with different multi-index
+ per_ls_next = std::find_if(per_ls_current, beyond,
+ has_other_multi_id(current_multi_id));
+
+ oit = Base::apply(*(ls_first + current_multi_id),
+ linear, per_ls_current, per_ls_next, oit);
+
+ signed_index_type next_multi_id(-1);
+ linestring_iterator ls_next = ls_beyond;
+ if ( per_ls_next != beyond )
+ {
+ next_multi_id = get_multi_index(per_ls_next);
+ ls_next = ls_first + next_multi_id;
+ }
+ oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
+ ls_next,
+ oit);
+
+ current_multi_id = next_multi_id;
+ }
+ while ( per_ls_next != beyond );
+
+ return oit;
+ }
+};
+
+
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Geometry1,
+ typename Geometry2,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns,
+ typename TagOut = typename tag<LinestringOut>::type,
+ typename TagIn1 = typename tag<Geometry1>::type
+>
+struct follow
+ : not_implemented<LinestringOut, Geometry1>
+{};
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Linestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+struct follow
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns,
+ linestring_tag, linestring_tag
+ > : follow_linestring_linear_linestring
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ >
+{};
+
+
+template
+<
+ typename LinestringOut,
+ typename MultiLinestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+struct follow
+ <
+ LinestringOut, MultiLinestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns,
+ linestring_tag, multi_linestring_tag
+ > : follow_multilinestring_linear_linestring
+ <
+ LinestringOut, MultiLinestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ >
+{};
+
+
+
+}} // namespace following::linear
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
index 019c3ba3f9..63011c7d48 100644
--- a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
@@ -17,6 +17,7 @@
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
namespace boost { namespace geometry
{
@@ -35,32 +36,45 @@ template
>
struct get_turn_without_info
{
- typedef strategy_intersection
- <
- typename cs_tag<typename TurnInfo::point_type>::type,
- Point1,
- Point2,
- typename TurnInfo::point_type
- > si;
-
- typedef typename si::segment_intersection_strategy_type strategy;
-
-
-
- template <typename OutputIterator>
+ template <typename RobustPolicy, typename OutputIterator>
static inline OutputIterator apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/,
+ Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/,
+ bool /*is_p_first*/, bool /*is_p_last*/,
+ bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& ,
+ RobustPolicy const& robust_policy,
OutputIterator out)
{
+ typedef strategy_intersection
+ <
+ typename cs_tag<typename TurnInfo::point_type>::type,
+ Point1,
+ Point2,
+ typename TurnInfo::point_type,
+ RobustPolicy
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point1 const> segment_type2;
- segment_type1 p1(pi, pj), p2(pj, pk);
- segment_type2 q1(qi, qj), q2(qj, qk);
+ segment_type1 p1(pi, pj);
+ segment_type2 q1(qi, qj);
- //
- typename strategy::return_type result = strategy::apply(p1, q1);
+ typedef typename geometry::robust_point_type
+ <
+ Point1, RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
+ geometry::recalculate(pi_rob, pi, robust_policy);
+ geometry::recalculate(pj_rob, pj, robust_policy);
+ geometry::recalculate(qi_rob, qi, robust_policy);
+ geometry::recalculate(qj_rob, qj, robust_policy);
+ typename strategy::return_type result
+ = strategy::apply(p1, q1, robust_policy,
+ pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < result.template get<0>().count; i++)
{
@@ -84,10 +98,12 @@ template
<
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Turns
>
inline void get_intersection_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Turns& turns)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
@@ -99,14 +115,6 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename boost::range_value<Turns>::type
> TurnPolicy;
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
-
detail::get_turns::no_interrupt_policy interrupt_policy;
boost::mpl::if_c
@@ -118,9 +126,7 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
- Turns, TurnPolicy,
- //segment_intersection_strategy_type,
- detail::get_turns::no_interrupt_policy
+ TurnPolicy
>,
dispatch::get_turns
<
@@ -128,13 +134,12 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
- Turns, TurnPolicy,
- //segment_intersection_strategy_type,
- detail::get_turns::no_interrupt_policy
+ TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
+ robust_policy,
turns, interrupt_policy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
index 522ef68382..d71f4ad51f 100644
--- a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
@@ -10,8 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
-#include <boost/geometry/algorithms/distance.hpp>
-
#include <boost/geometry/strategies/intersection.hpp>
@@ -36,15 +34,10 @@ namespace detail { namespace overlay
template <typename Point1>
struct get_relative_order
{
- typedef strategy_intersection
+ typedef typename strategy::side::services::default_strategy
<
- typename cs_tag<Point1>::type,
- Point1,
- Point1,
- Point1
- > si;
-
- typedef typename si::side_strategy_type strategy;
+ typename cs_tag<Point1>::type
+ >::type strategy;
template <typename Point>
static inline int value_via_product(Point const& ti, Point const& tj,
diff --git a/boost/geometry/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
index c2c6980577..131d58d582 100644
--- a/boost/geometry/algorithms/detail/overlay/get_ring.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
@@ -13,11 +13,13 @@
#include <boost/assert.hpp>
#include <boost/range.hpp>
-
-#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -33,16 +35,16 @@ template<typename Tag>
struct get_ring
{};
-// A container of rings (multi-ring but that does not exist)
+// A range of rings (multi-ring but that does not exist)
// gets the "void" tag and is dispatched here.
template<>
struct get_ring<void>
{
- template<typename Container>
- static inline typename boost::range_value<Container>::type const&
- apply(ring_identifier const& id, Container const& container)
+ template<typename Range>
+ static inline typename boost::range_value<Range>::type const&
+ apply(ring_identifier const& id, Range const& container)
{
- return container[id.multi_index];
+ return range::at(container, id.multi_index);
}
};
@@ -87,7 +89,26 @@ struct get_ring<polygon_tag>
);
return id.ring_index < 0
? exterior_ring(polygon)
- : interior_rings(polygon)[id.ring_index];
+ : range::at(interior_rings(polygon), id.ring_index);
+ }
+};
+
+
+template<>
+struct get_ring<multi_polygon_tag>
+{
+ template<typename MultiPolygon>
+ static inline typename ring_type<MultiPolygon>::type const& apply(
+ ring_identifier const& id,
+ MultiPolygon const& multi_polygon)
+ {
+ BOOST_ASSERT
+ (
+ id.multi_index >= 0
+ && id.multi_index < int(boost::size(multi_polygon))
+ );
+ return get_ring<polygon_tag>::apply(id,
+ range::at(multi_polygon, id.multi_index));
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index b8320d9b7b..240b6de036 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -16,9 +16,19 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
+
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
namespace boost { namespace geometry
{
@@ -30,7 +40,7 @@ class turn_info_exception : public geometry::exception
public:
// NOTE: "char" will be replaced by enum in future version
- inline turn_info_exception(char const method)
+ inline turn_info_exception(char const method)
{
message = "Boost.Geometry Turn exception: ";
message += method;
@@ -50,7 +60,6 @@ public:
namespace detail { namespace overlay
{
-
struct base_turn_handler
{
// Returns true if both sides are opposite
@@ -91,13 +100,32 @@ struct base_turn_handler
{
both(ti, condition ? operation_union : operation_intersection);
}
+
+ template <typename TurnInfo, typename IntersectionInfo>
+ static inline void assign_point(TurnInfo& ti,
+ method_type method,
+ IntersectionInfo const& info, int index)
+ {
+ ti.method = method;
+ BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this
+ geometry::convert(info.intersections[index], ti.point);
+ ti.operations[0].fraction = info.fractions[index].robust_ra;
+ ti.operations[1].fraction = info.fractions[index].robust_rb;
+ }
+
+ template <typename IntersectionInfo>
+ static inline int non_opposite_to_index(IntersectionInfo const& info)
+ {
+ return info.fractions[0].robust_rb < info.fractions[1].robust_rb
+ ? 1 : 0;
+ }
+
};
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct touch_interior : public base_turn_handler
{
@@ -108,17 +136,18 @@ struct touch_interior : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& ,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_touch_interior;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_touch_interior, intersection_info, 0);
// Both segments of q touch segment p somewhere in its interior
// 1) We know: if q comes from LEFT or RIGHT
@@ -130,7 +159,7 @@ struct touch_interior : public base_turn_handler
static int const index_q = 1 - Index;
int const side_qi_p = dir_info.sides.template get<index_q, 0>();
- int const side_qk_p = SideStrategy::apply(pi, pj, qk);
+ int const side_qk_p = side.qk_wrt_p1();
if (side_qi_p == -side_qk_p)
{
@@ -143,7 +172,7 @@ struct touch_interior : public base_turn_handler
return;
}
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
+ int const side_qk_q = side.qk_wrt_q1();
if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
{
@@ -203,8 +232,7 @@ struct touch_interior : public base_turn_handler
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct touch : public base_turn_handler
{
@@ -227,37 +255,34 @@ struct touch : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_touch;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_touch, intersection_info, 0);
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
- int const side_qk_p1 = SideStrategy::apply(pi, pj, qk);
+ int const side_qk_p1 = side.qk_wrt_p1();
// If Qi and Qk are both at same side of Pi-Pj,
// or collinear (so: not opposite sides)
if (! opposite(side_qi_p1, side_qk_p1))
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
-
- bool const both_continue = side_pk_p == 0 && side_qk_q == 0;
- bool const robustness_issue_in_continue = both_continue && side_pk_q2 != 0;
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_q = side.qk_wrt_q1();
bool const q_turns_left = side_qk_q == 1;
bool const block_q = side_qk_p1 == 0
&& ! same(side_qi_p1, side_qk_q)
- && ! robustness_issue_in_continue
;
// If Pk at same side as Qi/Qk
@@ -276,7 +301,7 @@ struct touch : public base_turn_handler
return;
}
- int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+ int const side_pk_q1 = side.pk_wrt_q1();
// Collinear opposite case -> block P
@@ -329,9 +354,6 @@ struct touch : public base_turn_handler
else
{
// Pk at other side than Qi/Pk
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
- bool const q_turns_left = side_qk_q == 1;
-
ti.operations[0].operation = q_turns_left
? operation_intersection
: operation_union;
@@ -347,13 +369,13 @@ struct touch : public base_turn_handler
else
{
// From left to right or from right to left
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
+ int const side_pk_p = side.pk_wrt_p1();
bool const right_to_left = side_qk_p1 == 1;
// If p turns into direction of qi (1,2)
if (side_pk_p == side_qi_p1)
{
- int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+ int const side_pk_q1 = side.pk_wrt_q1();
// Collinear opposite case -> block P
if (side_pk_q1 == 0)
@@ -374,7 +396,7 @@ struct touch : public base_turn_handler
// If p turns into direction of qk (4,5)
if (side_pk_p == side_qk_p1)
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+ int const side_pk_q2 = side.pk_wrt_q2();
// Collinear case -> lines join, continue
if (side_pk_q2 == 0)
@@ -413,8 +435,7 @@ struct touch : public base_turn_handler
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct equal : public base_turn_handler
{
@@ -423,22 +444,24 @@ struct equal : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& , Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
- IntersectionInfo const& intersection_info,
- DirInfo const& )
+ IntersectionInfo const& info,
+ DirInfo const& ,
+ SidePolicy const& side)
{
- ti.method = method_equal;
- // Copy the SECOND intersection point
- geometry::convert(intersection_info.intersections[1], ti.point);
+ // Copy the intersection point in TO direction
+ assign_point(ti, method_equal, info, non_opposite_to_index(info));
+
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_p = side.qk_wrt_p1();
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
- int const side_qk_p = SideStrategy::apply(pi, pj, qk);
// If pk is collinear with qj-qk, they continue collinearly.
// This can be on either side of p1 (== q1), or collinear
@@ -447,6 +470,7 @@ struct equal : public base_turn_handler
if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
{
both(ti, operation_continue);
+
return;
}
@@ -454,8 +478,6 @@ struct equal : public base_turn_handler
// If they turn to same side (not opposite sides)
if (! opposite(side_pk_p, side_qk_p))
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
-
// If pk is left of q2 or collinear: p: union, q: intersection
ui_else_iu(side_pk_q2 != -1, ti);
}
@@ -485,33 +507,32 @@ struct equal_opposite : public base_turn_handler
typename DirInfo
>
static inline void apply(Point1 const& pi, Point2 const& qi,
- /* by value: */ TurnInfo tp,
+ /* by value: */ TurnInfo tp,
OutputIterator& out,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
// For equal-opposite segments, normally don't do anything.
- if (AssignPolicy::include_opposite)
- {
- tp.method = method_equal;
- for (int i = 0; i < 2; i++)
- {
- tp.operations[i].operation = operation_opposite;
- }
- for (unsigned int i = 0; i < intersection_info.count; i++)
- {
- geometry::convert(intersection_info.intersections[i], tp.point);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
- *out++ = tp;
- }
- }
+ if (AssignPolicy::include_opposite)
+ {
+ tp.method = method_equal;
+ for (int i = 0; i < 2; i++)
+ {
+ tp.operations[i].operation = operation_opposite;
+ }
+ for (unsigned int i = 0; i < intersection_info.count; i++)
+ {
+ assign_point(tp, method_none, intersection_info, i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ *out++ = tp;
+ }
+ }
}
};
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct collinear : public base_turn_handler
{
@@ -543,7 +564,7 @@ struct collinear : public base_turn_handler
ROBUSTNESS: p and q are collinear, so you would expect
that side qk//p1 == pk//q1. But that is not always the case
in near-epsilon ranges. Then decision logic is different.
- If p arrives, q is further, so the angle qk//p1 is (normally)
+ If p arrives, q is further, so the angle qk//p1 is (normally)
more precise than pk//p1
*/
@@ -552,24 +573,26 @@ struct collinear : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
- IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ IntersectionInfo const& info,
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_collinear;
- geometry::convert(intersection_info.intersections[1], ti.point);
+ // Copy the intersection point in TO direction
+ assign_point(ti, method_collinear, info, non_opposite_to_index(info));
int const arrival = dir_info.arrival[0];
// Should not be 0, this is checked before
BOOST_ASSERT(arrival != 0);
- int const side_p = SideStrategy::apply(pi, pj, pk);
- int const side_q = SideStrategy::apply(qi, qj, qk);
+ int const side_p = side.pk_wrt_p1();
+ int const side_q = side.qk_wrt_q1();
// If p arrives, use p, else use q
int const side_p_or_q = arrival == 1
@@ -577,9 +600,6 @@ struct collinear : public base_turn_handler
: side_q
;
- int const side_pk = SideStrategy::apply(qi, qj, pk);
- int const side_qk = SideStrategy::apply(pi, pj, qk);
-
// See comments above,
// resulting in a strange sort of mathematic rule here:
// The arrival-info multiplied by the relevant side
@@ -587,15 +607,7 @@ struct collinear : public base_turn_handler
int const product = arrival * side_p_or_q;
- // Robustness: side_p is supposed to be equal to side_pk (because p/q are collinear)
- // and side_q to side_qk
- bool const robustness_issue = side_pk != side_p || side_qk != side_q;
-
- if (robustness_issue)
- {
- handle_robustness(ti, arrival, side_p, side_q, side_pk, side_qk);
- }
- else if(product == 0)
+ if(product == 0)
{
both(ti, operation_continue);
}
@@ -605,43 +617,11 @@ struct collinear : public base_turn_handler
}
}
- static inline void handle_robustness(TurnInfo& ti, int arrival,
- int side_p, int side_q, int side_pk, int side_qk)
- {
- // We take the longer one, i.e. if q arrives in p (arrival == -1),
- // then p exceeds q and we should take p for a union...
-
- bool use_p_for_union = arrival == -1;
-
- // ... unless one of the sides consistently directs to the other side
- int const consistent_side_p = side_p == side_pk ? side_p : 0;
- int const consistent_side_q = side_q == side_qk ? side_q : 0;
- if (arrival == -1 && (consistent_side_p == -1 || consistent_side_q == 1))
- {
- use_p_for_union = false;
- }
- if (arrival == 1 && (consistent_side_p == 1 || consistent_side_q == -1))
- {
- use_p_for_union = true;
- }
-
- //std::cout << "ROBUSTNESS -> Collinear "
- // << " arr: " << arrival
- // << " dir: " << side_p << " " << side_q
- // << " rev: " << side_pk << " " << side_qk
- // << " cst: " << cside_p << " " << cside_q
- // << std::boolalpha << " " << use_p_for_union
- // << std::endl;
-
- ui_else_iu(use_p_for_union, ti);
- }
-
};
template
<
typename TurnInfo,
- typename SideStrategy,
typename AssignPolicy
>
struct collinear_opposite : public base_turn_handler
@@ -674,14 +654,19 @@ private :
template
<
int Index,
- typename Point,
+ typename Point1,
+ typename Point2,
typename IntersectionInfo
>
- static inline bool set_tp(Point const& ri, Point const& rj, Point const& rk,
+ static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r,
+ bool const handle_robustness,
+ Point2 const& , Point2 const& , int side_rk_s,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
- int const side_rk_r = SideStrategy::apply(ri, rj, rk);
- operation_type blocked = operation_blocked;
+ boost::ignore_unused_variable_warning(handle_robustness);
+ boost::ignore_unused_variable_warning(side_rk_s);
+
+ operation_type blocked = operation_blocked;
switch(side_rk_r)
{
@@ -699,16 +684,16 @@ private :
// two operations blocked, so the whole point does not need
// to be generated.
// So return false to indicate nothing is to be done.
- if (AssignPolicy::include_opposite)
- {
- tp.operations[Index].operation = operation_opposite;
- blocked = operation_opposite;
- }
- else
- {
- return false;
- }
- break;
+ if (AssignPolicy::include_opposite)
+ {
+ tp.operations[Index].operation = operation_opposite;
+ blocked = operation_opposite;
+ }
+ else
+ {
+ return false;
+ }
+ break;
}
// The other direction is always blocked when collinear opposite
@@ -717,18 +702,21 @@ private :
// If P arrives within Q, set info on P (which is done above, index=0),
// this turn-info belongs to the second intersection point, index=1
// (see e.g. figure CLO1)
- geometry::convert(intersection_info.intersections[1 - Index], tp.point);
+ assign_point(tp, method_collinear, intersection_info, 1 - Index);
return true;
}
public:
+ static inline void empty_transformer(TurnInfo &) {}
+
template
<
typename Point1,
typename Point2,
typename OutputIterator,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
@@ -739,46 +727,79 @@ public:
OutputIterator& out,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- TurnInfo tp = tp_model;
+ apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer);
+ }
- tp.method = method_collinear;
+public:
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename OutputIterator,
+ typename IntersectionInfo,
+ typename DirInfo,
+ typename SidePolicy,
+ typename TurnTransformer
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+
+ // Opposite collinear can deliver 2 intersection points,
+ TurnInfo const& tp_model,
+ OutputIterator& out,
+
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info,
+ SidePolicy const& side,
+ TurnTransformer turn_transformer,
+ bool const is_pk_valid = true, bool const is_qk_valid = true)
+ {
+ TurnInfo tp = tp_model;
// If P arrives within Q, there is a turn dependent on P
- if (dir_info.arrival[0] == 1
- && set_tp<0>(pi, pj, pk, tp, intersection_info))
+ if ( dir_info.arrival[0] == 1
+ && is_pk_valid
+ && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) )
{
+ turn_transformer(tp);
+
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
// If Q arrives within P, there is a turn dependent on Q
- if (dir_info.arrival[1] == 1
- && set_tp<1>(qi, qj, qk, tp, intersection_info))
+ if ( dir_info.arrival[1] == 1
+ && is_qk_valid
+ && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) )
{
+ turn_transformer(tp);
+
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
- if (AssignPolicy::include_opposite)
- {
- // Handle cases not yet handled above
- if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
- || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
- {
- for (int i = 0; i < 2; i++)
- {
- tp.operations[i].operation = operation_opposite;
- }
- for (unsigned int i = 0; i < intersection_info.count; i++)
- {
- geometry::convert(intersection_info.intersections[i], tp.point);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
- *out++ = tp;
- }
- }
- }
+ if (AssignPolicy::include_opposite)
+ {
+ // Handle cases not yet handled above
+ if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
+ || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ tp.operations[i].operation = operation_opposite;
+ }
+ for (unsigned int i = 0; i < intersection_info.count; i++)
+ {
+ assign_point(tp, method_collinear, intersection_info, i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ *out++ = tp;
+ }
+ }
+ }
}
};
@@ -786,8 +807,7 @@ public:
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct crosses : public base_turn_handler
{
@@ -805,8 +825,7 @@ struct crosses : public base_turn_handler
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
- ti.method = method_crosses;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_crosses, intersection_info, 0);
// In all casees:
// If Q crosses P from left to right
@@ -820,14 +839,12 @@ struct crosses : public base_turn_handler
}
};
-template<typename TurnInfo>
-struct only_convert
+struct only_convert : public base_turn_handler
{
- template<typename IntersectionInfo>
+ template<typename TurnInfo, typename IntersectionInfo>
static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
{
- ti.method = method_collinear;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_none, intersection_info, 0); // was collinear
ti.operations[0].operation = operation_continue;
ti.operations[1].operation = operation_continue;
}
@@ -845,14 +862,14 @@ struct assign_null_policy
static bool const include_degenerate = false;
static bool const include_opposite = false;
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&)
{}
@@ -873,48 +890,39 @@ struct assign_null_policy
It also defines if a certain class of points
(degenerate, non-turns) should be included.
*/
-template
-<
- typename Point1,
- typename Point2,
- typename TurnInfo,
- typename AssignPolicy
->
+template<typename AssignPolicy>
struct get_turn_info
{
- typedef strategy_intersection
- <
- typename cs_tag<typename TurnInfo::point_type>::type,
- Point1,
- Point2,
- typename TurnInfo::point_type
- > si;
-
- typedef typename si::segment_intersection_strategy_type strategy;
-
// Intersect pi-pj with qi-qj
- // The points pk and qk are only used do determine more information
- // about the turn.
- template <typename OutputIterator>
+ // The points pk and qk are used do determine more information
+ // about the turn (turn left/right)
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool /*is_p_first*/, bool /*is_p_last*/,
+ bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
OutputIterator out)
{
- typedef model::referring_segment<Point1 const> segment_type1;
- typedef model::referring_segment<Point1 const> segment_type2;
- segment_type1 p1(pi, pj), p2(pj, pk);
- segment_type2 q1(qi, qj), q2(qj, qk);
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
- typename strategy::return_type result = strategy::apply(p1, q1);
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
- char const method = result.template get<1>().how;
+ char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
-
// Select method and apply
switch(method)
{
@@ -922,11 +930,10 @@ struct get_turn_info
case 'f' : // collinear, "from"
case 's' : // starts from the middle
if (AssignPolicy::include_no_turn
- && result.template get<0>().count > 0)
+ && inters.i_info().count > 0)
{
- only_convert<TurnInfo>::apply(tp,
- result.template get<0>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ only_convert::apply(tp, inters.i_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -938,113 +945,94 @@ struct get_turn_info
{
typedef touch_interior
<
- TurnInfo,
- typename si::side_strategy_type
+ TurnInfo
> policy;
// If Q (1) arrives (1)
- if (result.template get<1>().arrival[1] == 1)
+ if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
}
else
{
// Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
- tp, result.template get<0>(), result.template get<1>());
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'i' :
{
- typedef crosses
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 't' :
{
// Both touch (both arrive there)
- typedef touch
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'e':
{
- if (! result.template get<1>().opposite)
+ if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
- typedef equal
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
- else
- {
+ else
+ {
equal_opposite
<
TurnInfo,
AssignPolicy
>::apply(pi, qi,
- tp, out, result.template get<0>(), result.template get<1>());
- }
+ tp, out, inters.i_info(), inters.d_info());
+ }
}
break;
case 'c' :
{
// Collinear
- if (! result.template get<1>().opposite)
+ if ( ! inters.d_info().opposite )
{
- if (result.template get<1>().arrival[0] == 0)
+ if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
- equal
- <
- TurnInfo,
- typename si::side_strategy_type
- >::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
// override assigned method
tp.method = method_collinear;
}
else
{
- collinear
- <
- TurnInfo,
- typename si::side_strategy_type
- >::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
else
@@ -1052,10 +1040,9 @@ struct get_turn_info
collinear_opposite
<
TurnInfo,
- typename si::side_strategy_type,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
- tp, out, result.template get<0>(), result.template get<1>());
+ tp, out, inters.i_info(), inters.d_info(), inters.sides());
}
}
break;
@@ -1064,14 +1051,17 @@ struct get_turn_info
// degenerate points
if (AssignPolicy::include_degenerate)
{
- only_convert<TurnInfo>::apply(tp, result.template get<0>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ only_convert::apply(tp, inters.i_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
break;
default :
{
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
throw turn_info_exception(method);
#endif
@@ -1091,4 +1081,8 @@ struct get_turn_info
}} // namespace boost::geometry
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
new file mode 100644
index 0000000000..ca1b9d9d0c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
@@ -0,0 +1,657 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+// SEGMENT_INTERSECTION RESULT
+
+// C H0 H1 A0 A1 O IP1 IP2
+
+// D0 and D1 == 0
+
+// |--------> 2 0 0 0 0 F i/i x/x
+// |-------->
+//
+// |--------> 2 0 0 0 0 T i/x x/i
+// <--------|
+//
+// |-----> 1 0 0 0 0 T x/x
+// <-----|
+//
+
+// |---------> 2 0 0 0 1 T i/x x/i
+// <----|
+//
+// |---------> 2 0 0 0 0 F i/i x/x
+// |---->
+//
+// |---------> 2 0 0 -1 1 F i/i u/x
+// |---->
+//
+// |---------> 2 0 0 -1 0 T i/x u/i
+// <----|
+
+// |-------> 2 0 0 1 -1 F and i/i x/u
+// |-------> 2 0 0 -1 1 F symetric i/i u/x
+// |------->
+//
+// |-------> 2 0 0 -1 -1 T i/u u/i
+// <-------|
+//
+// |-------> 2 0 0 1 1 T i/x x/i
+// <-------|
+//
+// |--------> 2 0 0 -1 1 F i/i u/x
+// |---->
+//
+// |--------> 2 0 0 -1 1 T i/x u/i
+// <----|
+
+// |-----> 1 -1 -1 -1 -1 T u/u
+// <-----|
+//
+// |-----> 1 -1 0 -1 0 F and u/x
+// |-----> 1 0 -1 0 -1 F symetric x/u
+// |----->
+
+// D0 or D1 != 0
+
+// ^
+// |
+// + 1 -1 1 -1 1 F and u/x (P is vertical)
+// |--------> 1 1 -1 1 -1 F symetric x/u (P is horizontal)
+// ^
+// |
+// +
+//
+// +
+// |
+// v
+// |--------> 1 1 1 1 1 F x/x (P is vertical)
+//
+// ^
+// |
+// +
+// |--------> 1 -1 -1 -1 -1 F u/u (P is vertical)
+//
+// ^
+// |
+// +
+// |--------> 1 0 -1 0 -1 F u/u (P is vertical)
+//
+// +
+// |
+// v
+// |--------> 1 0 1 0 1 F u/x (P is vertical)
+//
+
+class linear_intersections
+{
+public:
+ template <typename Point1, typename Point2, typename IntersectionResult>
+ linear_intersections(Point1 const& pi,
+ Point2 const& qi,
+ IntersectionResult const& result,
+ bool is_p_last, bool is_q_last)
+ {
+ int arrival_a = result.template get<1>().arrival[0];
+ int arrival_b = result.template get<1>().arrival[1];
+ bool same_dirs = result.template get<1>().dir_a == 0
+ && result.template get<1>().dir_b == 0;
+
+ if ( same_dirs )
+ {
+ if ( result.template get<0>().count == 2 )
+ {
+ if ( ! result.template get<1>().opposite )
+ {
+ ips[0].p_operation = operation_intersection;
+ ips[0].q_operation = operation_intersection;
+ ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi
+ = equals::equals_point_point(
+ pi, result.template get<0>().intersections[0]);
+ ips[0].is_qi
+ = equals::equals_point_point(
+ qi, result.template get<0>().intersections[0]);
+ ips[1].is_pj = arrival_a != -1;
+ ips[1].is_qj = arrival_b != -1;
+ }
+ else
+ {
+ ips[0].p_operation = operation_intersection;
+ ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+ ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[1].q_operation = operation_intersection;
+
+ ips[0].is_pi = arrival_b != 1;
+ ips[0].is_qj = arrival_b != -1;
+ ips[1].is_pj = arrival_a != -1;
+ ips[1].is_qi = arrival_a != 1;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(result.template get<0>().count == 1);
+ ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi = arrival_a == -1;
+ ips[0].is_qi = arrival_b == -1;
+ ips[0].is_pj = arrival_a == 0;
+ ips[0].is_qj = arrival_b == 0;
+ }
+ }
+ else
+ {
+ ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last);
+ ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi = arrival_a == -1;
+ ips[0].is_qi = arrival_b == -1;
+ ips[0].is_pj = arrival_a == 1;
+ ips[0].is_qj = arrival_b == 1;
+ }
+ }
+
+ struct ip_info
+ {
+ inline ip_info()
+ : p_operation(operation_none), q_operation(operation_none)
+ , is_pi(false), is_pj(false), is_qi(false), is_qj(false)
+ {}
+
+ operation_type p_operation, q_operation;
+ bool is_pi, is_pj, is_qi, is_qj;
+ };
+
+ template <std::size_t I>
+ ip_info const& get() const
+ {
+ BOOST_STATIC_ASSERT(I < 2);
+ return ips[I];
+ }
+
+private:
+
+ // only if collinear (same_dirs)
+ static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last)
+ {
+ if ( arrival == 1 )
+ return operation_blocked;
+ else if ( arrival == -1 )
+ return operation_union;
+ else
+ return is_last ? operation_blocked : operation_union;
+ //return operation_blocked;
+ }
+
+ // only if not collinear (!same_dirs)
+ static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last)
+ {
+ if ( arrival == 1 )
+ //return operation_blocked;
+ return is_last ? operation_blocked : operation_union;
+ else
+ return operation_union;
+ }
+
+ ip_info ips[2];
+};
+
+template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
+struct get_turn_info_for_endpoint
+{
+ BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
+
+ template<typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator
+ >
+ static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ method_type /*method*/,
+ OutputIterator out)
+ {
+ std::size_t ip_count = inters.i_info().count;
+ // no intersection points
+ if ( ip_count == 0 )
+ return false;
+
+ if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
+ return false;
+
+ linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
+
+ bool append0_last
+ = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ intersections.template get<0>(),
+ tp_model, inters, 0, out);
+
+ // NOTE: opposite && ip_count == 1 may be true!
+ bool opposite = inters.d_info().opposite;
+
+ // don't ignore only for collinear opposite
+ bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite );
+
+ if ( intersections.template get<1>().p_operation == operation_none )
+ return result_ignore_ip0;
+
+ bool append1_last
+ = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ intersections.template get<1>(),
+ tp_model, inters, 1, out);
+
+ // don't ignore only for collinear opposite
+ bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/;
+
+ return result_ignore_ip0 || result_ignore_ip1;
+ }
+
+ template <typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator>
+ static inline
+ bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ linear_intersections::ip_info const& ip_info,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ int ip_index,
+ OutputIterator out)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = result.template get<0>().intersections[ip_index];
+ BOOST_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt));
+ BOOST_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt));
+ BOOST_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt));
+ BOOST_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt));
+#endif
+
+ // TODO - calculate first/last only if needed
+ bool is_p_first_ip = is_p_first && ip_info.is_pi;
+ bool is_p_last_ip = is_p_last && ip_info.is_pj;
+ bool is_q_first_ip = is_q_first && ip_info.is_qi;
+ bool is_q_last_ip = is_q_last && ip_info.is_qj;
+ bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip);
+ bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip);
+
+ operation_type p_operation = ip_info.p_operation;
+ operation_type q_operation = ip_info.q_operation;
+
+ if ( append_first || append_last )
+ {
+ bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk,
+ inters.rpi(), inters.rpj(), inters.rpk(),
+ inters.rqi(), inters.rqj(), inters.rqk(),
+ is_p_first_ip, is_p_last_ip,
+ is_q_first_ip, is_q_last_ip,
+ ip_info.is_qi, ip_info.is_qj,
+ tp_model, inters, ip_index,
+ p_operation, q_operation);
+ if ( !handled )
+ {
+ handle_internal<1>(qi, qj, qk, pi, pj, pk,
+ inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk(),
+ is_q_first_ip, is_q_last_ip,
+ is_p_first_ip, is_p_last_ip,
+ ip_info.is_pi, ip_info.is_pj,
+ tp_model, inters, ip_index,
+ q_operation, p_operation);
+ }
+
+ if ( p_operation != operation_none )
+ {
+ method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj,
+ ip_info.is_qi, ip_info.is_qj);
+ turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip);
+ turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip);
+
+ // handle spikes
+
+ // P is spike and should be handled
+ if ( !is_p_last
+ && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
+ && inters.i_info().count == 2
+ && inters.is_spike_p() )
+ {
+ assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
+ assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
+ }
+ // Q is spike and should be handled
+ else if ( !is_q_last
+ && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
+ && inters.i_info().count == 2
+ && inters.is_spike_q() )
+ {
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
+ }
+ // no spikes
+ else
+ {
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out);
+ }
+ }
+ }
+
+ return append_last;
+ }
+
+ // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment
+ // however now it's lazily calculated and then it would be always calculated
+
+ template<std::size_t G1Index,
+ typename Point1,
+ typename Point2,
+ typename RobustPoint1,
+ typename RobustPoint2,
+ typename TurnInfo,
+ typename IntersectionInfo
+ >
+ static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/,
+ Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/,
+ RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/,
+ RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2,
+ bool first1, bool last1, bool first2, bool last2,
+ bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
+ IntersectionInfo const& inters, int ip_index,
+ operation_type & op1, operation_type & op2)
+ {
+ boost::ignore_unused_variable_warning(i2);
+ boost::ignore_unused_variable_warning(j2);
+ boost::ignore_unused_variable_warning(ip_index);
+ boost::ignore_unused_variable_warning(tp_model);
+
+ if ( !first2 && !last2 )
+ {
+ if ( first1 )
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = inters.i_info().intersections[ip_index];
+ BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
+ BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
+#endif
+ if ( ip_i2 )
+ {
+ // don't output this IP - for the first point of other geometry segment
+ op1 = operation_none;
+ op2 = operation_none;
+ return true;
+ }
+ else if ( ip_j2 )
+ {
+ side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
+ side_calc(ri2, ri1, rj1, ri2, rj2, rk2);
+
+ std::pair<operation_type, operation_type>
+ operations = operations_of_equal(side_calc);
+
+// TODO: must the above be calculated?
+// wouldn't it be enough to check if segments are collinear?
+
+ if ( operations_both(operations, operation_continue) )
+ {
+ if ( op1 != operation_union
+ || op2 != operation_union
+ || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
+ {
+ // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
+ bool opposite = inters.d_info().opposite;
+
+ op1 = operation_intersection;
+ op2 = opposite ? operation_union : operation_intersection;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union));
+ //op1 = operation_union;
+ //op2 = operation_union;
+ }
+
+ return true;
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+ else if ( last1 )
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = inters.i_info().intersections[ip_index];
+ BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
+ BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
+#endif
+ if ( ip_i2 )
+ {
+ // don't output this IP - for the first point of other geometry segment
+ op1 = operation_none;
+ op2 = operation_none;
+ return true;
+ }
+ else if ( ip_j2 )
+ {
+ side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
+ side_calc(ri2, rj1, ri1, ri2, rj2, rk2);
+
+ std::pair<operation_type, operation_type>
+ operations = operations_of_equal(side_calc);
+
+// TODO: must the above be calculated?
+// wouldn't it be enough to check if segments are collinear?
+
+ if ( operations_both(operations, operation_continue) )
+ {
+ if ( op1 != operation_blocked
+ || op2 != operation_union
+ || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
+ {
+ // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
+ bool second_going_out = inters.i_info().count > 1;
+
+ op1 = operation_blocked;
+ op2 = second_going_out ? operation_union : operation_intersection;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union));
+ //op1 = operation_blocked;
+ //op2 = operation_union;
+ }
+
+ return true;
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+
+ return false;
+ }
+
+ static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj)
+ {
+ if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) )
+ return method_touch;
+ else
+ return method_touch_interior;
+ }
+
+ static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j)
+ {
+ return is_ip_first_i ? position_front :
+ ( is_ip_last_j ? position_back : position_middle );
+ }
+
+ template <typename Point1,
+ typename Point2,
+ typename IntersectionResult,
+ typename TurnInfo,
+ typename OutputIterator>
+ static inline void assign(Point1 const& pi, Point2 const& qi,
+ IntersectionResult const& result,
+ int ip_index,
+ method_type method,
+ operation_type op0, operation_type op1,
+ turn_position pos0, turn_position pos1,
+ bool is_p_first_ip, bool is_q_first_ip,
+ bool is_p_spike, bool is_q_spike,
+ TurnInfo const& tp_model,
+ OutputIterator out)
+ {
+ TurnInfo tp = tp_model;
+
+ //geometry::convert(ip, tp.point);
+ //tp.method = method;
+ base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index);
+
+ tp.operations[0].operation = op0;
+ tp.operations[1].operation = op1;
+ tp.operations[0].position = pos0;
+ tp.operations[1].position = pos1;
+
+ if ( result.template get<0>().count > 1 )
+ {
+ // NOTE: is_collinear is NOT set for the first endpoint
+ // for which there is no preceding segment
+
+ //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
+ if ( ! is_p_first_ip )
+ {
+ tp.operations[0].is_collinear = op0 != operation_intersection
+ || is_p_spike;
+ }
+
+ if ( ! is_q_first_ip )
+ {
+ tp.operations[1].is_collinear = op1 != operation_intersection
+ || is_q_spike;
+ }
+ }
+ else //if ( result.template get<0>().count == 1 )
+ {
+ if ( op0 == operation_blocked && op1 == operation_intersection )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else if ( op0 == operation_intersection && op1 == operation_blocked )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+
+ AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ *out++ = tp;
+ }
+
+ template <typename SidePolicy>
+ static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side)
+ {
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_p = side.qk_wrt_p1();
+
+ // If pk is collinear with qj-qk, they continue collinearly.
+ // This can be on either side of p1 (== q1), or collinear
+ // The second condition checks if they do not continue
+ // oppositely
+ if ( side_pk_q2 == 0 && side_pk_p == side_qk_p )
+ {
+ return std::make_pair(operation_continue, operation_continue);
+ }
+
+ // If they turn to same side (not opposite sides)
+ if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) )
+ {
+ // If pk is left of q2 or collinear: p: union, q: intersection
+ if ( side_pk_q2 != -1 )
+ {
+ return std::make_pair(operation_union, operation_intersection);
+ }
+ else
+ {
+ return std::make_pair(operation_intersection, operation_union);
+ }
+ }
+ else
+ {
+ // They turn opposite sides. If p turns left (or collinear),
+ // p: union, q: intersection
+ if ( side_pk_p != -1 )
+ {
+ return std::make_pair(operation_union, operation_intersection);
+ }
+ else
+ {
+ return std::make_pair(operation_intersection, operation_union);
+ }
+ }
+ }
+
+ static inline bool operations_both(
+ std::pair<operation_type, operation_type> const& operations,
+ operation_type const op)
+ {
+ return operations.first == op && operations.second == op;
+ }
+
+ static inline bool operations_combination(
+ std::pair<operation_type, operation_type> const& operations,
+ operation_type const op1, operation_type const op2)
+ {
+ return ( operations.first == op1 && operations.second == op2 )
+ || ( operations.first == op2 && operations.second == op1 );
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
new file mode 100644
index 0000000000..eead0d719b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -0,0 +1,329 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_OVERLAY_GET_TURN_INFO_HELPERS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
+
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+enum turn_position { position_middle, position_front, position_back };
+
+template <typename SegmentRatio>
+struct turn_operation_linear
+ : public turn_operation<SegmentRatio>
+{
+ turn_operation_linear()
+ : position(position_middle)
+ , is_collinear(false)
+ {}
+
+ turn_position position;
+ bool is_collinear; // valid only for Linear geometry
+};
+
+template <typename PointP, typename PointQ,
+ typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
+ typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
+>
+struct side_calculator
+{
+ typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
+
+ inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
+ Qi const& qi, Qj const& qj, Qk const& qk)
+ : m_pi(pi), m_pj(pj), m_pk(pk)
+ , m_qi(qi), m_qj(qj), m_qk(qk)
+ {}
+
+ inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
+ inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
+ inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
+ inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
+
+ inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
+ inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
+
+ Pi const& m_pi;
+ Pj const& m_pj;
+ Pk const& m_pk;
+ Qi const& m_qi;
+ Qj const& m_qj;
+ Qk const& m_qk;
+};
+
+template <typename Point1, typename Point2, typename RobustPolicy>
+struct robust_points
+{
+ typedef typename geometry::robust_point_type
+ <
+ Point1, RobustPolicy
+ >::type robust_point1_type;
+ // TODO: define robust_point2_type using Point2?
+ typedef robust_point1_type robust_point2_type;
+
+ inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ {
+ geometry::recalculate(m_rpi, pi, robust_policy);
+ geometry::recalculate(m_rpj, pj, robust_policy);
+ geometry::recalculate(m_rpk, pk, robust_policy);
+ geometry::recalculate(m_rqi, qi, robust_policy);
+ geometry::recalculate(m_rqj, qj, robust_policy);
+ geometry::recalculate(m_rqk, qk, robust_policy);
+ }
+
+ robust_point1_type m_rpi, m_rpj, m_rpk;
+ robust_point2_type m_rqi, m_rqj, m_rqk;
+};
+
+template <typename Point1, typename Point2, typename RobustPolicy>
+class intersection_info_base
+ : private robust_points<Point1, Point2, RobustPolicy>
+{
+ typedef robust_points<Point1, Point2, RobustPolicy> base_t;
+
+public:
+ typedef Point1 point1_type;
+ typedef Point2 point2_type;
+
+ typedef typename base_t::robust_point1_type robust_point1_type;
+ typedef typename base_t::robust_point2_type robust_point2_type;
+
+ typedef side_calculator<robust_point1_type, robust_point2_type> side_calculator_type;
+
+ intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ : base_t(pi, pj, pk, qi, qj, qk, robust_policy)
+ , m_side_calc(base_t::m_rpi, base_t::m_rpj, base_t::m_rpk,
+ base_t::m_rqi, base_t::m_rqj, base_t::m_rqk)
+ , m_pi(pi), m_pj(pj), m_pk(pk)
+ , m_qi(qi), m_qj(qj), m_qk(qk)
+ {}
+
+ inline Point1 const& pi() const { return m_pi; }
+ inline Point1 const& pj() const { return m_pj; }
+ inline Point1 const& pk() const { return m_pk; }
+
+ inline Point2 const& qi() const { return m_qi; }
+ inline Point2 const& qj() const { return m_qj; }
+ inline Point2 const& qk() const { return m_qk; }
+
+ inline robust_point1_type const& rpi() const { return base_t::m_rpi; }
+ inline robust_point1_type const& rpj() const { return base_t::m_rpj; }
+ inline robust_point1_type const& rpk() const { return base_t::m_rpk; }
+
+ inline robust_point2_type const& rqi() const { return base_t::m_rqi; }
+ inline robust_point2_type const& rqj() const { return base_t::m_rqj; }
+ inline robust_point2_type const& rqk() const { return base_t::m_rqk; }
+
+ inline side_calculator_type const& sides() const { return m_side_calc; }
+
+private:
+ side_calculator_type m_side_calc;
+
+ point1_type const& m_pi;
+ point1_type const& m_pj;
+ point1_type const& m_pk;
+ point2_type const& m_qi;
+ point2_type const& m_qj;
+ point2_type const& m_qk;
+};
+
+template <typename Point1, typename Point2>
+class intersection_info_base<Point1, Point2, detail::no_rescale_policy>
+{
+public:
+ typedef Point1 point1_type;
+ typedef Point2 point2_type;
+
+ typedef Point1 robust_point1_type;
+ typedef Point2 robust_point2_type;
+
+ typedef side_calculator<Point1, Point2> side_calculator_type;
+
+ intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ no_rescale_policy const& /*robust_policy*/)
+ : m_side_calc(pi, pj, pk, qi, qj, qk)
+ {}
+
+ inline Point1 const& pi() const { return m_side_calc.m_pi; }
+ inline Point1 const& pj() const { return m_side_calc.m_pj; }
+ inline Point1 const& pk() const { return m_side_calc.m_pk; }
+
+ inline Point2 const& qi() const { return m_side_calc.m_qi; }
+ inline Point2 const& qj() const { return m_side_calc.m_qj; }
+ inline Point2 const& qk() const { return m_side_calc.m_qk; }
+
+ inline Point1 const& rpi() const { return pi(); }
+ inline Point1 const& rpj() const { return pj(); }
+ inline Point1 const& rpk() const { return pk(); }
+
+ inline Point2 const& rqi() const { return qi(); }
+ inline Point2 const& rqj() const { return qj(); }
+ inline Point2 const& rqk() const { return qk(); }
+
+ inline side_calculator_type const& sides() const { return m_side_calc; }
+
+private:
+ side_calculator_type m_side_calc;
+};
+
+
+template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
+class intersection_info
+ : public intersection_info_base<Point1, Point2, RobustPolicy>
+{
+ typedef intersection_info_base<Point1, Point2, RobustPolicy> base_t;
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<TurnPoint>::type,
+ Point1,
+ Point2,
+ TurnPoint,
+ RobustPolicy
+ >::segment_intersection_strategy_type strategy;
+
+public:
+ typedef model::referring_segment<Point1 const> segment_type1;
+ typedef model::referring_segment<Point2 const> segment_type2;
+ typedef typename base_t::side_calculator_type side_calculator_type;
+
+ typedef typename strategy::return_type result_type;
+ typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
+ typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
+
+ intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ : base_t(pi, pj, pk, qi, qj, qk, robust_policy)
+ , m_result(strategy::apply(segment_type1(pi, pj),
+ segment_type2(qi, qj),
+ robust_policy))
+ , m_robust_policy(robust_policy)
+ {}
+
+ inline result_type const& result() const { return m_result; }
+ inline i_info_type const& i_info() const { return m_result.template get<0>(); }
+ inline d_info_type const& d_info() const { return m_result.template get<1>(); }
+
+ // TODO: it's more like is_spike_ip_p
+ inline bool is_spike_p() const
+ {
+ if ( base_t::sides().pk_wrt_p1() == 0 )
+ {
+ if ( ! is_ip_j<0>() )
+ return false;
+
+ int const qk_p1 = base_t::sides().qk_wrt_p1();
+ int const qk_p2 = base_t::sides().qk_wrt_p2();
+
+ if ( qk_p1 == -qk_p2 )
+ {
+ if ( qk_p1 == 0 )
+ {
+ return is_spike_of_collinear(base_t::pi(), base_t::pj(), base_t::pk());
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // TODO: it's more like is_spike_ip_q
+ inline bool is_spike_q() const
+ {
+ if ( base_t::sides().qk_wrt_q1() == 0 )
+ {
+ if ( ! is_ip_j<1>() )
+ return false;
+
+ int const pk_q1 = base_t::sides().pk_wrt_q1();
+ int const pk_q2 = base_t::sides().pk_wrt_q2();
+
+ if ( pk_q1 == -pk_q2 )
+ {
+ if ( pk_q1 == 0 )
+ {
+ return is_spike_of_collinear(base_t::qi(), base_t::qj(), base_t::qk());
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+private:
+ template <typename Point>
+ inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
+ {
+ typedef model::referring_segment<Point const> seg_t;
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
+ typename strategy::return_type result
+ = strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
+
+ return result.template get<0>().count == 2;
+ }
+
+ template <std::size_t OpId>
+ bool is_ip_j() const
+ {
+ int arrival = d_info().arrival[OpId];
+ bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
+
+ if ( same_dirs )
+ {
+ if ( i_info().count == 2 )
+ {
+ return arrival != -1;
+ }
+ else
+ {
+ return arrival == 0;
+ }
+ }
+ else
+ {
+ return arrival == 1;
+ }
+ }
+
+ result_type m_result;
+ RobustPolicy const& m_robust_policy;
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
new file mode 100644
index 0000000000..873567bbf5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
@@ -0,0 +1,805 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_OVERLAY_GET_TURN_INFO_LA_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+
+// TEMP, for spikes detector
+//#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+template<typename AssignPolicy>
+struct get_turn_info_linear_areal
+{
+ static const bool handle_spikes = true;
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
+ {
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
+
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
+
+ char const method = inters.d_info().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_none, out);
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ if ( get_turn_info_for_endpoint<false, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch_interior, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ typedef touch_interior
+ <
+ TurnInfo
+ > policy;
+
+ // If Q (1) arrives (1)
+ if ( inters.d_info().arrival[1] == 1 )
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
+ }
+ else
+ {
+ // Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
+ }
+
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ // this function assumes that 'u' must be set for a spike
+ calculate_spike_operation(tp.operations[0].operation,
+ inters, is_p_last);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ *out++ = tp;
+ }
+ }
+ break;
+ case 'i' :
+ {
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+
+ replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ if ( get_turn_info_for_endpoint<false, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ // workarounds for touch<> not taking spikes into account starts here
+ // those was discovered empirically
+ // touch<> is not symmetrical!
+ // P spikes and Q spikes may produce various operations!
+ // Only P spikes are valid for L/A
+ // TODO: this is not optimal solution - think about rewriting touch<>
+
+ if ( tp.operations[0].operation == operation_blocked )
+ {
+ // a spike on P on the same line with Q1
+ if ( inters.is_spike_p() )
+ {
+ if ( inters.sides().qk_wrt_p1() == 0 )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[0].operation = operation_union;
+ }
+ }
+ }
+ else if ( tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // P spike on the same line with Q2 (opposite)
+ if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
+ && inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_none
+ && tp.operations[1].operation == operation_none )
+ {
+ // spike not handled by touch<>
+ if ( inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_union;
+
+ if ( inters.sides().pk_wrt_q2() == 0 )
+ {
+ tp.operations[0].operation = operation_continue; // will be converted to i
+ tp.operations[0].is_collinear = true;
+ }
+ }
+ }
+
+ // workarounds for touch<> not taking spikes into account ends here
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ bool ignore_spike
+ = calculate_spike_operation(tp.operations[0].operation,
+ inters, is_p_last);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ if ( ! handle_spikes
+ || ignore_spike
+ || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i???
+ tp, inters, is_p_last, is_q_last, out) )
+ {
+ *out++ = tp;
+ }
+ }
+ }
+ break;
+ case 'e':
+ {
+ if ( get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_equal, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ turn_transformer_ec<false> transformer(method_touch);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
+ method_touch, append_equal, out) )
+ {
+ *out++ = tp; // no spikes
+ }
+ }
+ else
+ {
+ equal_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, qi,
+ tp, out, inters.i_info(), inters.d_info());
+ }
+ }
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if ( get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_collinear, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ method_type method_replace = method_touch_interior;
+ append_version_c version = append_collinear;
+
+ if ( inters.d_info().arrival[0] == 0 )
+ {
+ // Collinear, but similar thus handled as equal
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ method_replace = method_touch;
+ version = append_equal;
+ }
+ else
+ {
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ //method_replace = method_touch_interior;
+ //version = append_collinear;
+ }
+
+ turn_transformer_ec<false> transformer(method_replace);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
+ method_replace, version, out) )
+ {
+ // no spikes
+ *out++ = tp;
+ }
+ }
+ else
+ {
+ // Is this always 'm' ?
+ turn_transformer_ec<false> transformer(method_touch_interior);
+
+ // conditionally handle spikes
+ if ( handle_spikes )
+ {
+ append_opposite_spikes<append_collinear_opposite>(
+ tp, inters, is_p_last, is_q_last, out);
+ }
+
+ // TODO: ignore for spikes?
+ // E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
+ // the same with is_q_valid
+
+ collinear_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, inters.i_info(), inters.d_info(),
+ inters.sides(), transformer);
+ }
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert::apply(tp, inters.i_info());
+
+ if ( is_p_first
+ && equals::equals_point_point(pi, tp.point) )
+ {
+ tp.operations[0].position = position_front;
+ }
+ else if ( is_p_last
+ && equals::equals_point_point(pj, tp.point) )
+ {
+ tp.operations[0].position = position_back;
+ }
+ // tp.operations[1].position = position_middle;
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+
+ template <typename Operation,
+ typename IntersectionInfo>
+ static inline bool calculate_spike_operation(Operation & op,
+ IntersectionInfo const& inters,
+ bool is_p_last)
+ {
+ bool is_p_spike = ( op == operation_union || op == operation_intersection )
+ && ! is_p_last
+ && inters.is_spike_p();
+
+ if ( is_p_spike )
+ {
+ bool going_in = false, going_out = false;
+
+ int const pk_q1 = inters.sides().pk_wrt_q1();
+ int const pk_q2 = inters.sides().pk_wrt_q2();
+
+ if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C
+ {
+ going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both
+ going_out = pk_q1 > 0 || pk_q2 > 0; // Pk on the left of one of them
+ }
+ else
+ {
+ going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them
+ going_out = pk_q1 > 0 && pk_q2 > 0; // Pk on the left of both
+ }
+
+ if ( going_in )
+ {
+ op = operation_intersection;
+ return true;
+ }
+ else if ( going_out )
+ {
+ op = operation_union;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ enum append_version_c { append_equal, append_collinear };
+
+ template <typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_collinear_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool /*is_q_last*/,
+ method_type method, append_version_c version,
+ OutIt out)
+ {
+ // method == touch || touch_interior
+ // both position == middle
+
+ bool is_p_spike = ( version == append_equal ?
+ ( tp.operations[0].operation == operation_union
+ || tp.operations[0].operation == operation_intersection ) :
+ tp.operations[0].operation == operation_continue )
+ && ! is_p_last
+ && inters.is_spike_p();
+
+ // TODO: throw an exception for spike in Areal?
+ /*bool is_q_spike = tp.operations[1].operation == spike_op
+ && ! is_q_last
+ && inters.is_spike_q();*/
+
+ if ( is_p_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_union;
+ *out++ = tp;
+ tp.operations[0].operation = operation_continue; // boundary
+ //tp.operations[1].operation = operation_union;
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ enum append_version_o { append_touches, append_collinear_opposite };
+
+ template <append_version_o Version,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_opposite_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool /*is_q_last*/,
+ OutIt out)
+ {
+ bool is_p_spike = ( Version == append_touches ?
+ ( tp.operations[0].operation == operation_continue
+ || tp.operations[0].operation == operation_intersection ) : // i ???
+ true )
+ && ! is_p_last
+ && inters.is_spike_p();
+ // TODO: throw an exception for spike in Areal?
+ /*bool is_q_spike = ( Version == append_touches ?
+ ( tp.operations[1].operation == operation_continue
+ || tp.operations[1].operation == operation_intersection ) :
+ true )
+ && ! is_q_last
+ && inters.is_spike_q();*/
+
+ if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = true;
+ //tp.operations[1].is_collinear = false;
+ tp.method = method_touch;
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ //tp.operations[1].is_collinear = false;
+
+ BOOST_ASSERT(inters.i_info().count > 1);
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_continue; // boundary
+ *out++ = tp;
+ tp.operations[0].operation = operation_continue; // boundary
+ //tp.operations[1].operation = operation_continue; // boundary
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static inline void replace_method_and_operations_tm(method_type & method,
+ operation_type & op0,
+ operation_type & op1)
+ {
+ if ( op0 == operation_blocked && op1 == operation_blocked )
+ {
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ method = (method == method_touch ? method_equal : method_collinear);
+ }
+
+ // Assuming G1 is always Linear
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_continue;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_continue;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ // spikes in 'm'
+ if ( method == method_error )
+ {
+ method = method_touch_interior;
+ op0 = operation_union;
+ op1 = operation_union;
+ }
+ }
+
+ template <bool IsFront>
+ class turn_transformer_ec
+ {
+ public:
+ explicit turn_transformer_ec(method_type method_t_or_m)
+ : m_method(method_t_or_m)
+ {}
+
+ template <typename Turn>
+ void operator()(Turn & turn) const
+ {
+ operation_type & op0 = turn.operations[0].operation;
+ operation_type & op1 = turn.operations[1].operation;
+
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ if ( IsFront
+ || op0 == operation_intersection || op0 == operation_union
+ || op1 == operation_intersection || op1 == operation_union )
+ {
+ turn.method = m_method;
+ }
+
+ turn.operations[0].is_collinear = op0 != operation_blocked;
+
+ // Assuming G1 is always Linear
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_continue;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_continue;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+ }
+
+ private:
+ method_type m_method;
+ };
+
+ static inline void replace_operations_i(operation_type & /*op0*/, operation_type & op1)
+ {
+ // assuming Linear is always the first one
+ op1 = operation_union;
+ }
+
+ // NOTE: Spikes may NOT be handled for Linear endpoints because it's not
+ // possible to define a spike on an endpoint. Areal geometries must
+ // NOT have spikes at all. One thing that could be done is to throw
+ // an exception when spike is detected in Areal geometry.
+
+ template <bool EnableFirst,
+ bool EnableLast,
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator>
+ static inline bool get_turn_info_for_endpoint(
+ Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/,
+ Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/,
+ bool is_p_first, bool is_p_last,
+ bool /*is_q_first*/, bool is_q_last,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ method_type /*method*/,
+ OutputIterator out)
+ {
+ namespace ov = overlay;
+ typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e;
+
+ const std::size_t ip_count = inters.i_info().count;
+ // no intersection points
+ if ( ip_count == 0 )
+ return false;
+
+ if ( !is_p_first && !is_p_last )
+ return false;
+
+// TODO: is_q_last could probably be replaced by false and removed from parameters
+
+ linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
+ linear_intersections::ip_info const& ip0 = intersections.template get<0>();
+ linear_intersections::ip_info const& ip1 = intersections.template get<1>();
+
+ const bool opposite = inters.d_info().opposite;
+
+ // ANALYSE AND ASSIGN FIRST
+
+ // IP on the first point of Linear Geometry
+ if ( EnableFirst && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication
+ {
+ TurnInfo tp = tp_model;
+ tp.operations[0].position = position_front;
+ tp.operations[1].position = position_middle;
+
+ if ( opposite ) // opposite -> collinear
+ {
+ tp.operations[0].operation = operation_continue;
+ tp.operations[1].operation = operation_union;
+ tp.method = ip0.is_qj ? method_touch : method_touch_interior;
+ }
+ else
+ {
+ method_type replaced_method = method_touch_interior;
+
+ if ( ip0.is_qj )
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
+ inters.rqi(), inters.rqj(), inters.rqk());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+
+ replaced_method = method_touch;
+ }
+ else
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
+ inters.rqi(), inters.rpi(), inters.rqj());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+ }
+
+ turn_transformer_ec<true> transformer(replaced_method);
+ transformer(tp);
+ }
+
+ // equals<> or collinear<> will assign the second point,
+ // we'd like to assign the first one
+ base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0);
+
+ // NOTE: is_collinear is not set for the first endpoint of L
+ // for which there is no preceding segment
+ // here is_p_first_ip == true
+ tp.operations[0].is_collinear = false;
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+
+ // ANALYSE AND ASSIGN LAST
+
+ // IP on the last point of Linear Geometry
+ if ( EnableLast
+ && is_p_last
+ && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication
+ {
+ TurnInfo tp = tp_model;
+
+ if ( inters.i_info().count > 1 )
+ {
+ //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].operation = opposite ? operation_continue : operation_union;
+ }
+ else //if ( result.template get<0>().count == 1 )
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpj(), inters.rpi(),
+ inters.rqi(), inters.rqj(), inters.rqk());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+
+ turn_transformer_ec<false> transformer(method_none);
+ transformer(tp);
+
+ tp.operations[0].is_collinear = tp.both(operation_continue);
+ }
+
+ tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[0].position = position_back;
+ tp.operations[1].position = position_middle;
+
+ // equals<> or collinear<> will assign the second point,
+ // we'd like to assign the first one
+ int ip_index = ip_count > 1 ? 1 : 0;
+ base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+
+ return true;
+ }
+
+ // don't ignore anything for now
+ return false;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
new file mode 100644
index 0000000000..4f0384877f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
@@ -0,0 +1,720 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_OVERLAY_GET_TURN_INFO_LL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+template<typename AssignPolicy>
+struct get_turn_info_linear_linear
+{
+ static const bool handle_spikes = true;
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
+ {
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
+
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
+
+ char const method = inters.d_info().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_none, out);
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch_interior, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ typedef touch_interior
+ <
+ TurnInfo
+ > policy;
+
+ // If Q (1) arrives (1)
+ if ( inters.d_info().arrival[1] == 1)
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
+ }
+ else
+ {
+ // Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
+
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
+ }
+
+ if ( tp.operations[0].operation == operation_blocked )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ case 'i' :
+ {
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+
+ replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ // workarounds for touch<> not taking spikes into account starts here
+ // those was discovered empirically
+ // touch<> is not symmetrical!
+ // P spikes and Q spikes may produce various operations!
+ // TODO: this is not optimal solution - think about rewriting touch<>
+
+ if ( tp.operations[0].operation == operation_blocked
+ && tp.operations[1].operation == operation_blocked )
+ {
+ // two touching spikes on the same line
+ if ( inters.is_spike_p() && inters.is_spike_q() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_blocked )
+ {
+ // a spike on P on the same line with Q1
+ if ( inters.is_spike_p() )
+ {
+ if ( inters.sides().qk_wrt_p1() == 0 )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[0].operation = operation_union;
+ }
+ }
+ else
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[1].operation == operation_blocked )
+ {
+ // a spike on Q on the same line with P1
+ if ( inters.is_spike_q() )
+ {
+ if ( inters.sides().pk_wrt_q1() == 0 )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // P spike on the same line with Q2 (opposite)
+ if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
+ && inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_none
+ && tp.operations[1].operation == operation_none )
+ {
+ // spike not handled by touch<>
+ bool const is_p = inters.is_spike_p();
+ bool const is_q = inters.is_spike_q();
+
+ if ( is_p || is_q )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+
+ if ( inters.sides().pk_wrt_q2() == 0 )
+ {
+ tp.operations[0].operation = operation_continue; // will be converted to i
+ if ( is_p )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ }
+
+ if ( inters.sides().qk_wrt_p2() == 0 )
+ {
+ tp.operations[1].operation = operation_continue; // will be converted to i
+ if ( is_q )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ }
+ }
+
+ // workarounds for touch<> not taking spikes into account ends here
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ if ( ! handle_spikes
+ || ! append_opposite_spikes<append_touches>(tp, inters,
+ is_p_last, is_q_last,
+ out) )
+ {
+ *out++ = tp;
+ }
+ }
+ }
+ break;
+ case 'e':
+ {
+ if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_equal, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ // transform turn
+ turn_transformer_ec transformer(method_touch);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters,
+ is_p_last, is_q_last,
+ method_touch, operation_union,
+ out) )
+ {
+ *out++ = tp; // no spikes
+ }
+ }
+ else
+ {
+ // TODO: ignore for spikes or generate something else than opposite?
+
+ equal_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info());
+ }
+ }
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_collinear, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ // NOTE: this is for spikes since those are set in the turn_transformer_ec
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ method_type method_replace = method_touch_interior;
+ operation_type spike_op = operation_continue;
+
+ if ( inters.d_info().arrival[0] == 0 )
+ {
+ // Collinear, but similar thus handled as equal
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ method_replace = method_touch;
+ spike_op = operation_union;
+ }
+ else
+ {
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ //method_replace = method_touch_interior;
+ //spike_op = operation_continue;
+ }
+
+ // transform turn
+ turn_transformer_ec transformer(method_replace);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters,
+ is_p_last, is_q_last,
+ method_replace, spike_op,
+ out) )
+ {
+ // no spikes
+ *out++ = tp;
+ }
+ }
+ else
+ {
+ // If this always 'm' ?
+ turn_transformer_ec transformer(method_touch_interior);
+
+ // conditionally handle spikes
+ if ( handle_spikes )
+ {
+ append_opposite_spikes<append_collinear_opposite>(tp, inters,
+ is_p_last, is_q_last,
+ out);
+ }
+
+ // TODO: ignore for spikes?
+ // E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
+ // the same with is_q_valid
+
+ collinear_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, inters.i_info(), inters.d_info(), inters.sides(),
+ transformer, !is_p_last, !is_q_last);
+ }
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert::apply(tp, inters.i_info());
+
+ // if any, only one of those should be true
+ if ( is_p_first
+ && equals::equals_point_point(pi, tp.point) )
+ {
+ tp.operations[0].position = position_front;
+ }
+ else if ( is_p_last
+ && equals::equals_point_point(pj, tp.point) )
+ {
+ tp.operations[0].position = position_back;
+ }
+ else if ( is_q_first
+ && equals::equals_point_point(qi, tp.point) )
+ {
+ tp.operations[1].position = position_front;
+ }
+ else if ( is_q_last
+ && equals::equals_point_point(qj, tp.point) )
+ {
+ tp.operations[1].position = position_back;
+ }
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+
+ template <typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_collinear_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters_info,
+ bool is_p_last, bool is_q_last,
+ method_type method, operation_type spike_op,
+ OutIt out)
+ {
+ // method == touch || touch_interior
+ // both position == middle
+
+ bool is_p_spike = tp.operations[0].operation == spike_op
+ && ! is_p_last
+ && inters_info.is_spike_p();
+ bool is_q_spike = tp.operations[1].operation == spike_op
+ && ! is_q_last
+ && inters_info.is_spike_q();
+
+ if ( is_p_spike && is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ return true;
+ }
+ else if ( is_p_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_union;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ //tp.operations[1].operation = operation_union;
+ *out++ = tp;
+
+ return true;
+ }
+ else if ( is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ //tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ enum append_version { append_touches, append_collinear_opposite };
+
+ template <append_version Version,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_opposite_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool is_q_last,
+ OutIt out)
+ {
+ bool is_p_spike = ( Version == append_touches ?
+ ( tp.operations[0].operation == operation_continue
+ || tp.operations[0].operation == operation_intersection ) :
+ true )
+ && ! is_p_last
+ && inters.is_spike_p();
+ bool is_q_spike = ( Version == append_touches ?
+ ( tp.operations[1].operation == operation_continue
+ || tp.operations[1].operation == operation_intersection ) :
+ true )
+ && ! is_q_last
+ && inters.is_spike_q();
+
+ bool res = false;
+
+ if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = false;
+ tp.method = method_touch;
+ }
+ else // Version == append_collinear_opposite
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = false;
+
+ BOOST_ASSERT(inters.i_info().count > 1);
+
+ base_turn_handler::assign_point(tp, method_touch_interior,
+ inters.i_info(), 1);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(),
+ inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ //tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ res = true;
+ }
+
+ if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = false;
+ tp.operations[1].is_collinear = true;
+ tp.method = method_touch;
+ }
+ else // Version == append_collinear_opposite
+ {
+ tp.operations[0].is_collinear = false;
+ tp.operations[1].is_collinear = true;
+
+ BOOST_ASSERT(inters.i_info().count > 0);
+
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(),
+ inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ //tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ res = true;
+ }
+
+ return res;
+ }
+
+ static inline void replace_method_and_operations_tm(method_type & method,
+ operation_type & op0,
+ operation_type & op1)
+ {
+ if ( op0 == operation_blocked && op1 == operation_blocked )
+ {
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ method = (method == method_touch ? method_equal : method_collinear);
+ op0 = operation_continue;
+ op1 = operation_continue;
+ }
+ else
+ {
+ if ( op0 == operation_continue || op0 == operation_blocked )
+ {
+ op0 = operation_intersection;
+ }
+ else if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_continue || op1 == operation_blocked )
+ {
+ op1 = operation_intersection;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ // spikes in 'm'
+ if ( method == method_error )
+ {
+ method = method_touch_interior;
+ op0 = operation_union;
+ op1 = operation_union;
+ }
+ }
+ }
+
+ class turn_transformer_ec
+ {
+ public:
+ explicit turn_transformer_ec(method_type method_t_or_m)
+ : m_method(method_t_or_m)
+ {}
+
+ template <typename Turn>
+ void operator()(Turn & turn) const
+ {
+ operation_type & op0 = turn.operations[0].operation;
+ operation_type & op1 = turn.operations[1].operation;
+
+ BOOST_ASSERT(op0 != operation_blocked || op1 != operation_blocked );
+
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_intersection;
+ }
+ else if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_intersection;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ if ( op0 == operation_intersection || op0 == operation_union
+ || op1 == operation_intersection || op1 == operation_union )
+ {
+ turn.method = m_method;
+ }
+
+// TODO: is this correct?
+// it's equivalent to comparing to operation_blocked at the beginning of the function
+ turn.operations[0].is_collinear = op0 != operation_intersection;
+ turn.operations[1].is_collinear = op1 != operation_intersection;
+ }
+
+ private:
+ method_type m_method;
+ };
+
+ static inline void replace_operations_i(operation_type & op0, operation_type & op1)
+ {
+ if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index 26629043cb..a96538c43a 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -1,11 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// 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_OVERLAY_GET_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
@@ -14,19 +20,17 @@
#include <map>
#include <boost/array.hpp>
+#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
-#include <boost/tuple/tuple.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -44,17 +48,22 @@
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
-
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/expand.hpp>
-#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
# include <sstream>
@@ -65,6 +74,12 @@
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace get_turns
@@ -88,9 +103,7 @@ template
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Section1, typename Section2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
class get_turns_in_sections
{
@@ -138,16 +151,21 @@ class get_turns_in_sections
// About first condition: will be optimized by compiler (static)
// It checks if it is areal (box,ring,(multi)polygon
int const n = int(section.range_count);
+
+ boost::ignore_unused_variable_warning(n);
+ boost::ignore_unused_variable_warning(index1);
+ boost::ignore_unused_variable_warning(index2);
+
return boost::is_same
<
typename tag_cast
<
- typename geometry::point_type<Geometry1>::type,
+ typename geometry::tag<Geometry>::type,
areal_tag
- >::type,
+ >::type,
areal_tag
>::value
- && index1 == 0
+ && index1 == 0
&& index2 >= n - 2
;
}
@@ -155,13 +173,27 @@ class get_turns_in_sections
public :
// Returns true if terminated, false if interrupted
+ template <typename Turns, typename RobustPolicy, typename InterruptPolicy>
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
bool skip_larger,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
+ boost::ignore_unused_variable_warning(interrupt_policy);
+
+ if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
+ || (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
+ {
+ // Skip sections containig only duplicates.
+ // They are still important (can indicate non-disjointness)
+ // but they will be found processing adjacent sections.
+ // Do NOT skip if they are the ONLY section
+ return true;
+ }
+
cview_type1 cview1(range_by_section(geometry1, sec1));
cview_type2 cview2(range_by_section(geometry2, sec2));
view_type1 view1(cview1);
@@ -186,7 +218,7 @@ public :
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
- index1, ndi1, dir1, sec2.bounding_box);
+ index1, ndi1, dir1, sec2.bounding_box, robust_policy);
// We need a circular iterator because it might run through the closing point.
// One circle is actually enough but this one is just convenient.
@@ -197,12 +229,12 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
- it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box);
+ it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
begin_range_1, end_range_1, next1, true);
- advance_to_non_duplicate_next(nd_next1, it1, sec1);
+ advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy);
int index2 = sec2.begin_index;
int ndi2 = sec2.non_duplicate_index;
@@ -210,12 +242,12 @@ public :
range2_iterator prev2, it2, end2;
get_start_point_iterator(sec2, view2, prev2, it2, end2,
- index2, ndi2, dir2, sec1.bounding_box);
+ index2, ndi2, dir2, sec1.bounding_box, robust_policy);
ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
next2++;
for (prev2 = it2++, next2++;
- it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box);
+ it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -241,24 +273,28 @@ public :
// Move to the "non duplicate next"
ever_circling_iterator<range2_iterator> nd_next2(
begin_range_2, end_range_2, next2, true);
- advance_to_non_duplicate_next(nd_next2, it2, sec2);
+ advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy);
typedef typename boost::range_value<Turns>::type turn_info;
- typedef typename turn_info::point_type ip;
turn_info ti;
- ti.operations[0].seg_id = segment_identifier(source_id1,
- sec1.ring_id.multi_index, sec1.ring_id.ring_index, index1),
- ti.operations[1].seg_id = segment_identifier(source_id2,
- sec2.ring_id.multi_index, sec2.ring_id.ring_index, index2),
-
- ti.operations[0].other_id = ti.operations[1].seg_id;
- ti.operations[1].other_id = ti.operations[0].seg_id;
+ ti.operations[0].seg_id
+ = segment_identifier(source_id1, sec1.ring_id.multi_index,
+ sec1.ring_id.ring_index, index1);
+ ti.operations[1].seg_id
+ = segment_identifier(source_id2, sec2.ring_id.multi_index,
+ sec2.ring_id.ring_index, index2);
std::size_t const size_before = boost::size(turns);
+ bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index;
+ bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index;
+ bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index;
+ bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index;
+
TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
- ti, std::back_inserter(turns));
+ is_1_first, is_1_last, is_2_first, is_2_last,
+ ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -283,24 +319,34 @@ private :
typedef typename model::referring_segment<point2_type const> segment2_type;
- template <size_t Dim, typename Point, typename Box>
- static inline bool preceding(int dir, Point const& point, Box const& box)
+ template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
+ static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
- return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box))
- || (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box));
+ typename robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dim>(robust_point) < get<min_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(robust_point) > get<max_corner, Dim>(box));
}
- template <size_t Dim, typename Point, typename Box>
- static inline bool exceeding(int dir, Point const& point, Box const& box)
+ template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
+ static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
- return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box))
- || (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box));
+ typename robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dim>(robust_point) > get<max_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(robust_point) < get<min_corner, Dim>(box));
}
- template <typename Iterator, typename RangeIterator, typename Section>
+ template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy>
static inline void advance_to_non_duplicate_next(Iterator& next,
- RangeIterator const& it, Section const& section)
+ RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy)
{
+ typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type;
+ robust_point_type robust_point_from_it;
+ robust_point_type robust_point_from_next;
+ geometry::recalculate(robust_point_from_it, *it, robust_policy);
+ geometry::recalculate(robust_point_from_next, *next, robust_policy);
+
// To see where the next segments bend to, in case of touch/intersections
// on end points, we need (in case of degenerate/duplicate points) an extra
// iterator which moves to the REAL next point, so non duplicate.
@@ -311,10 +357,14 @@ private :
// So advance to the "non duplicate next"
// (the check is defensive, to avoid endless loops)
std::size_t check = 0;
- while(! detail::disjoint::disjoint_point_point(*it, *next)
+ while(! detail::disjoint::disjoint_point_point
+ (
+ robust_point_from_it, robust_point_from_next
+ )
&& check++ < section.range_count)
{
next++;
+ geometry::recalculate(robust_point_from_next, *next, robust_policy);
}
}
@@ -322,14 +372,14 @@ private :
// because of the logistics of "index" (the section-iterator automatically
// skips to the begin-point, we loose the index or have to recalculate it)
// So we mimic it here
- template <typename Range, typename Section, typename Box>
+ template <typename Range, typename Section, typename Box, typename RobustPolicy>
static inline void get_start_point_iterator(Section & section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
typename boost::range_iterator<Range const>::type& end,
int& index, int& ndi,
- int dir, Box const& other_bounding_box)
+ int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
{
it = boost::begin(range) + section.begin_index;
end = boost::begin(range) + section.end_index + 1;
@@ -337,7 +387,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
- for(; it != end && preceding<0>(dir, *it, other_bounding_box);
+ for(; it != end && preceding<0>(dir, *it, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -369,6 +419,7 @@ template
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
+ typename RobustPolicy,
typename InterruptPolicy
>
struct section_visitor
@@ -377,14 +428,17 @@ struct section_visitor
Geometry1 const& m_geometry1;
int m_source_id2;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
section_visitor(int id1, Geometry1 const& g1,
int id2, Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& ip)
: m_source_id1(id1), m_geometry1(g1)
, m_source_id2(id2), m_geometry2(g2)
+ , m_rescale_policy(robust_policy)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -400,13 +454,12 @@ struct section_visitor
Geometry2,
Reverse1, Reverse2,
Section, Section,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>::apply(
m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
false,
+ m_rescale_policy,
m_turns, m_interrupt_policy);
}
return true;
@@ -418,37 +471,45 @@ template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
class get_turns_generic
{
public:
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& geometry1,
int source_id2, Geometry2 const& geometry2,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
{
// First create monotonic sections...
typedef typename boost::range_value<Turns>::type ip_type;
typedef typename ip_type::point_type point_type;
- typedef model::box<point_type> box_type;
+
+ typedef model::box
+ <
+ typename geometry::robust_point_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > box_type;
typedef typename geometry::sections<box_type, 2> sections_type;
sections_type sec1, sec2;
- geometry::sectionalize<Reverse1>(geometry1, sec1, 0);
- geometry::sectionalize<Reverse2>(geometry2, sec2, 1);
+ geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0);
+ geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, sec2, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
<
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy, InterruptPolicy
- > visitor(source_id1, geometry1, source_id2, geometry2, turns, interrupt_policy);
+ Turns, TurnPolicy, RobustPolicy, InterruptPolicy
+ > visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy);
geometry::partition
<
@@ -463,13 +524,10 @@ template
<
typename Range, typename Box,
bool ReverseRange, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_cs
{
- typedef typename boost::range_value<Turns>::type turn_info;
typedef typename geometry::point_type<Range>::type point_type;
typedef typename geometry::point_type<Box>::type box_point_type;
@@ -491,14 +549,16 @@ struct get_turns_cs
>::type iterator_type;
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Range const& range,
int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int multi_index = -1, int ring_index = -1)
{
- if (boost::size(range) <= 1)
+ if ( boost::size(range) <= 1)
{
return;
}
@@ -509,6 +569,8 @@ struct get_turns_cs
cview_type cview(range);
view_type view(cview);
+ typename boost::range_size<view_type>::type segments_count1 = boost::size(view) - 1;
+
iterator_type it = boost::begin(view);
ever_circling_iterator<iterator_type> next(
@@ -557,9 +619,13 @@ struct get_turns_cs
get_turns_with_box(seg_id, source_id2,
*prev, *it, *next,
bp[0], bp[1], bp[2], bp[3],
+ // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes
+ index == 0,
+ unsigned(index) == segments_count1,
+ robust_policy,
turns, interrupt_policy);
- // Future performance enhancement:
- // return if told by the interrupt policy
+ // Future performance enhancement:
+ // return if told by the interrupt policy
}
}
}
@@ -585,6 +651,7 @@ private:
else return 0;
}
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
// Points from a range:
point_type const& rp0,
@@ -595,34 +662,45 @@ private:
box_point_type const& bp1,
box_point_type const& bp2,
box_point_type const& bp3,
+ bool const is_range_first,
+ bool const is_range_last,
+ RobustPolicy const& robust_policy,
// Output
Turns& turns,
InterruptPolicy& interrupt_policy)
{
+ boost::ignore_unused_variable_warning(interrupt_policy);
+
// Depending on code some relations can be left out
typedef typename boost::range_value<Turns>::type turn_info;
turn_info ti;
ti.operations[0].seg_id = seg_id;
- ti.operations[0].other_id = ti.operations[1].seg_id;
- ti.operations[1].other_id = seg_id;
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ true, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, true,
+ ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -638,15 +716,15 @@ template
<
typename Polygon, typename Box,
bool Reverse, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_polygon_cs
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Polygon const& polygon,
int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy,
int multi_index = -1)
{
@@ -656,32 +734,118 @@ struct get_turns_polygon_cs
<
ring_type, Box,
Reverse, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> intersector_type;
intersector_type::apply(
source_id1, geometry::exterior_ring(polygon),
- source_id2, box, turns, interrupt_policy,
+ source_id2, box,
+ robust_policy,
+ turns, interrupt_policy,
multi_index, -1);
int i = 0;
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
- ++it, ++i)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
{
intersector_type::apply(
source_id1, *it,
- source_id2, box, turns, interrupt_policy,
+ source_id2, box,
+ robust_policy,
+ turns, interrupt_policy,
multi_index, i);
}
}
};
+
+template
+<
+ typename Multi, typename Box,
+ bool Reverse, bool ReverseBox,
+ typename TurnPolicy
+>
+struct get_turns_multi_polygon_cs
+{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
+ static inline void apply(
+ int source_id1, Multi const& multi,
+ int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
+ Turns& turns, InterruptPolicy& interrupt_policy)
+ {
+ typedef typename boost::range_iterator
+ <
+ Multi const
+ >::type iterator_type;
+
+ int i = 0;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, ++i)
+ {
+ // Call its single version
+ get_turns_polygon_cs
+ <
+ typename boost::range_value<Multi>::type, Box,
+ Reverse, ReverseBox,
+ TurnPolicy
+ >::apply(source_id1, *it, source_id2, box,
+ robust_policy, turns, interrupt_policy, i);
+ }
+ }
+};
+
+
+// GET_TURN_INFO_TYPE
+
+template <typename Geometry>
+struct topological_tag_base
+{
+ typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type;
+};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy,
+ typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
+ typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
+struct get_turn_info_type
+ : overlay::get_turn_info<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
+struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
+ : overlay::get_turn_info_linear_linear<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
+struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag>
+ : overlay::get_turn_info_linear_areal<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio,
+ typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
+ typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
+struct turn_operation_type
+{
+ typedef overlay::turn_operation<SegmentRatio> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
+struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
+{
+ typedef overlay::turn_operation_linear<SegmentRatio> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
+struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
+{
+ typedef overlay::turn_operation_linear<SegmentRatio> type;
+};
+
}} // namespace detail::get_turns
#endif // DOXYGEN_NO_DETAIL
@@ -697,18 +861,14 @@ template
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
: detail::get_turns::get_turns_generic
<
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
{};
@@ -717,23 +877,19 @@ template
<
typename Polygon, typename Box,
bool ReversePolygon, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
<
polygon_tag, box_tag,
Polygon, Box,
ReversePolygon, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> : detail::get_turns::get_turns_polygon_cs
<
Polygon, Box,
ReversePolygon, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
+ TurnPolicy
>
{};
@@ -742,22 +898,18 @@ template
<
typename Ring, typename Box,
bool ReverseRing, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
<
ring_tag, box_tag,
Ring, Box,
ReverseRing, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> : detail::get_turns::get_turns_cs
<
Ring, Box, ReverseRing, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
+ TurnPolicy
>
{};
@@ -765,28 +917,52 @@ struct get_turns
template
<
+ typename MultiPolygon,
+ typename Box,
+ bool ReverseMultiPolygon, bool ReverseBox,
+ typename TurnPolicy
+>
+struct get_turns
+ <
+ multi_polygon_tag, box_tag,
+ MultiPolygon, Box,
+ ReverseMultiPolygon, ReverseBox,
+ TurnPolicy
+ >
+ : detail::get_turns::get_turns_multi_polygon_cs
+ <
+ MultiPolygon, Box,
+ ReverseMultiPolygon, ReverseBox,
+ TurnPolicy
+ >
+{};
+
+
+template
+<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_reversed
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& g1,
int source_id2, Geometry2 const& g2,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
{
get_turns
<
GeometryTag2, GeometryTag1,
Geometry2, Geometry1,
Reverse2, Reverse1,
- Turns, TurnPolicy,
- InterruptPolicy
- >::apply(source_id2, g2, source_id1, g1, turns, interrupt_policy);
+ TurnPolicy
+ >::apply(source_id2, g2, source_id1, g1, robust_policy,
+ turns, interrupt_policy);
}
};
@@ -804,6 +980,7 @@ struct get_turns_reversed
\tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
+\param robust_policy policy to handle robustness issues
\param turns container which will contain turn points
\param interrupt_policy policy determining if process is stopped
when intersection is found
@@ -814,31 +991,20 @@ template
typename AssignPolicy,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void get_turns(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type,
- typename boost::range_value<Turns>::type,
- AssignPolicy
- > TurnPolicy;
+ typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
+ //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
boost::mpl::if_c
<
@@ -849,8 +1015,7 @@ inline void get_turns(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>,
dispatch::get_turns
<
@@ -858,15 +1023,18 @@ inline void get_turns(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
+ robust_policy,
turns, interrupt_policy);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
index 1e878ca525..085933dd7a 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
@@ -14,7 +14,17 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/robust_type.hpp>
+
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif
+
+#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
@@ -31,6 +41,7 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
@@ -39,10 +50,12 @@ struct sort_in_cluster
inline sort_in_cluster(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
+ , RobustPolicy const& robust_policy
, Strategy const& strategy)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
+ , m_rescale_policy(robust_policy)
, m_strategy(strategy)
{}
@@ -51,49 +64,100 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_rescale_policy;
Strategy const& m_strategy;
typedef typename Indexed::type turn_operation_type;
typedef typename geometry::point_type<Geometry1>::type point_type;
- typedef model::referring_segment<point_type const> segment_type;
+
+ typedef typename geometry::robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // Still necessary in some situations,
+ // for example #case_102_multi, #case_107_multi, #case_recursive_boxes_3
+ inline void get_situation_map(Indexed const& left, Indexed const& right,
+ robust_point_type& pi_rob, robust_point_type& pj_rob,
+ robust_point_type& ri_rob, robust_point_type& rj_rob,
+ robust_point_type& si_rob, robust_point_type& sj_rob) const
+ {
+ point_type pi, pj, ri, rj, si, sj;
+
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject->seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ *left.other_seg_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ *right.other_seg_id,
+ si, sj);
+
+ geometry::recalculate(pi_rob, pi, m_rescale_policy);
+ geometry::recalculate(pj_rob, pj, m_rescale_policy);
+ geometry::recalculate(ri_rob, ri, m_rescale_policy);
+ geometry::recalculate(rj_rob, rj, m_rescale_policy);
+ geometry::recalculate(si_rob, si, m_rescale_policy);
+ geometry::recalculate(sj_rob, sj, m_rescale_policy);
+ }
+
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
+ // This method was still called but did no effect whatsoever on the results,
+ // with or without robustness-rescaling.
+ // Probable cause: we rescale in this file ourselves, ignoring passed policy
+ // TODO: check this more.
+ // Besides this, it currently does not compile for yet unknown reasons
+ // (does not find specialization for segment_ratio_type)
+ // It is currently only called from the Unit Test "multi_intersection.cpp"
// Determine how p/r and p/s are located.
- template <typename P>
- static inline void overlap_info(P const& pi, P const& pj,
- P const& ri, P const& rj,
- P const& si, P const& sj,
- bool& pr_overlap, bool& ps_overlap, bool& rs_overlap)
+ inline void overlap_info(
+ robust_point_type const& pi, robust_point_type const& pj,
+ robust_point_type const& ri, robust_point_type const& rj,
+ robust_point_type const& si, robust_point_type const& sj,
+ bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const
{
// Determine how p/r and p/s are located.
// One of them is coming from opposite direction.
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > intersection_return_type;
+
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
- segment_type,
- segment_type,
- segment_intersection_points<point_type>
+ intersection_return_type
>
> policy;
+ typedef model::referring_segment<robust_point_type const> segment_type;
segment_type p(pi, pj);
segment_type r(ri, rj);
segment_type s(si, sj);
// Get the intersection point (or two points)
- segment_intersection_points<point_type> pr = policy::apply(p, r);
- segment_intersection_points<point_type> ps = policy::apply(p, s);
- segment_intersection_points<point_type> rs = policy::apply(r, s);
+ intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj);
+ intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj);
+ intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj);
// Check on overlap
pr_overlap = pr.count == 2;
ps_overlap = ps.count == 2;
rs_overlap = rs.count == 2;
}
+#endif
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES
inline void debug_consider(int order, Indexed const& left,
Indexed const& right, std::string const& header,
bool skip = true,
@@ -102,19 +166,15 @@ private :
{
if (skip) return;
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ std::cout << "Case: " << header << " for " << left.turn_index << " / " << right.turn_index << std::endl;
+
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
bool prc = false, psc = false, rsc = false;
overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
+#endif
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
@@ -123,8 +183,7 @@ private :
int const side_si_r = m_strategy.apply(ri, rj, si);
int const side_sj_r = m_strategy.apply(ri, rj, sj);
- std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH_MORE
+#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_MORE
std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl;
std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl;
std::cout << " Segment s:" << geometry::wkt(si) << " .. " << geometry::wkt(sj) << std::endl;
@@ -136,13 +195,15 @@ private :
std::cout << header
//<< " order: " << order
- << " ops: " << operation_char(left.subject.operation)
- << "/" << operation_char(right.subject.operation)
+ << " ops: " << operation_char(left.subject->operation)
+ << "/" << operation_char(right.subject->operation)
<< " ri//p: " << side_ri_p
<< " si//p: " << side_si_p
<< " si//r: " << side_si_r
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
<< " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
- //<< " idx: " << left.index << "/" << right.index
+#endif
+ //<< " idx: " << left.turn_index << "/" << right.turn_index
;
if (! extra.empty())
@@ -167,23 +228,23 @@ private :
, std::string const& // header
) const
{
- bool ret = left.index < right.index;
+ bool ret = left.turn_index < right.turn_index;
// In combination of u/x, x/u: take first union, then blocked.
// Solves #88, #61, #56, #80
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_blocked)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_blocked)
{
ret = true;
}
- else if (left.subject.operation == operation_blocked
- && right.subject.operation == operation_union)
+ else if (left.subject->operation == operation_blocked
+ && right.subject->operation == operation_union)
{
ret = false;
}
else
{
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << "ux/ux unhandled" << std::endl;
#endif
}
@@ -201,32 +262,32 @@ private :
{
bool ret = false;
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_union)
{
ret = order == 1;
}
- else if (left.subject.operation == operation_union
- && right.subject.operation == operation_blocked)
+ else if (left.subject->operation == operation_union
+ && right.subject->operation == operation_blocked)
{
ret = true;
}
- else if (right.subject.operation == operation_union
- && left.subject.operation == operation_blocked)
+ else if (right.subject->operation == operation_union
+ && left.subject->operation == operation_blocked)
{
ret = false;
}
- else if (left.subject.operation == operation_union)
+ else if (left.subject->operation == operation_union)
{
ret = true;
}
- else if (right.subject.operation == operation_union)
+ else if (right.subject->operation == operation_union)
{
ret = false;
}
else
{
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
// this still happens in the traverse.cpp test
std::cout << " iu/ux unhandled" << std::endl;
#endif
@@ -245,43 +306,61 @@ private :
{
//debug_consider(order, left, right, header, false, "iu/ix");
- return left.subject.operation == operation_intersection
- && right.subject.operation == operation_intersection ? order == 1
- : left.subject.operation == operation_intersection ? false
- : right.subject.operation == operation_intersection ? true
+ return left.subject->operation == operation_intersection
+ && right.subject->operation == operation_intersection ? order == 1
+ : left.subject->operation == operation_intersection ? false
+ : right.subject->operation == operation_intersection ? true
: order == 1;
}
+ inline bool consider_ix_ix(Indexed const& left, Indexed const& right
+ , std::string const& // header
+ ) const
+ {
+ // Take first intersection, then blocked.
+ if (left.subject->operation == operation_intersection
+ && right.subject->operation == operation_blocked)
+ {
+ return true;
+ }
+ else if (left.subject->operation == operation_blocked
+ && right.subject->operation == operation_intersection)
+ {
+ return false;
+ }
+
+ // Default case, should not occur
+
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+ std::cout << "ix/ix unhandled" << std::endl;
+#endif
+ //debug_consider(0, left, right, header, false, "-> return", ret);
+
+ return left.turn_index < right.turn_index;
+ }
+
inline bool consider_iu_iu(Indexed const& left, Indexed const& right,
- std::string const& header) const
+ std::string const& header, bool redo = false) const
{
//debug_consider(0, left, right, header);
// In general, order it like "union, intersection".
- if (left.subject.operation == operation_intersection
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_intersection
+ && right.subject->operation == operation_union)
{
//debug_consider(0, left, right, header, false, "i,u", false);
return false;
}
- else if (left.subject.operation == operation_union
- && right.subject.operation == operation_intersection)
+ else if (left.subject->operation == operation_union
+ && right.subject->operation == operation_intersection)
{
//debug_consider(0, left, right, header, false, "u,i", true);
return true;
}
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
@@ -291,8 +370,8 @@ private :
if (side_ri_p * side_si_p == 1 && side_si_r != 0)
{
// Take the most left one
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_union)
{
bool ret = side_si_r == 1;
//debug_consider(0, left, right, header, false, "same side", ret);
@@ -311,14 +390,18 @@ private :
debug_consider(0, left, right, header, false, "opp.", ret);
return ret;
}
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << " iu/iu coming from opposite unhandled" << std::endl;
#endif
}
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
// We need EXTRA information here: are p/r/s overlapping?
bool pr_ov = false, ps_ov = false, rs_ov = false;
overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
+#else
+ // std::cout << "Boost.Geometry: skipping overlap_info" << std::endl;
+#endif
// One coming from right (#83,#90)
// One coming from left (#90, #94, #95)
@@ -326,12 +409,14 @@ private :
{
bool ret = false;
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov || ps_ov)
{
int r = side_ri_p != 0 ? side_ri_p : side_si_p;
ret = r * side_si_r == 1;
}
else
+#endif
{
ret = side_si_r == 1;
}
@@ -348,6 +433,7 @@ private :
// Take the one NOT overlapping
bool ret = false;
bool found = false;
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov && ! ps_ov)
{
ret = true;
@@ -358,6 +444,7 @@ private :
ret = false;
found = true;
}
+#endif
debug_consider(0, left, right, header, false, "aligned", ret);
if (found)
@@ -366,11 +453,18 @@ private :
}
}
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << " iu/iu unhandled" << std::endl;
- debug_consider(0, left, right, header, false, "unhandled", left.index < right.index);
+ debug_consider(0, left, right, header, false, "unhandled", left.turn_index < right.turn_index);
#endif
- return left.index < right.index;
+ if (! redo)
+ {
+ // In some cases behaviour is not symmetrical. TODO: fix this properly
+ // OR: alternatively we might consider calling all these functions one-way anyway
+ return ! consider_iu_iu(right, left, header, true);
+ }
+
+ return left.turn_index < right.turn_index;
}
inline bool consider_ii(Indexed const& left, Indexed const& right,
@@ -378,16 +472,8 @@ private :
{
debug_consider(0, left, right, header);
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
@@ -402,84 +488,89 @@ private :
bool const ret = side_si_r != 1;
return ret;
}
- return left.index < right.index;
+ return left.turn_index < right.turn_index;
}
public :
inline bool operator()(Indexed const& left, Indexed const& right) const
{
- bool const default_order = left.index < right.index;
+ bool const default_order = left.turn_index < right.turn_index;
- if ((m_turn_points[left.index].discarded || left.discarded)
- && (m_turn_points[right.index].discarded || right.discarded))
+ if ((m_turn_points[left.turn_index].discarded || left.discarded)
+ && (m_turn_points[right.turn_index].discarded || right.discarded))
{
return default_order;
}
- else if (m_turn_points[left.index].discarded || left.discarded)
+ else if (m_turn_points[left.turn_index].discarded || left.discarded)
{
// Be careful to sort discarded first, then all others
return true;
}
- else if (m_turn_points[right.index].discarded || right.discarded)
+ else if (m_turn_points[right.turn_index].discarded || right.discarded)
{
// See above so return false here such that right (discarded)
// is sorted before left (not discarded)
return false;
}
- else if (m_turn_points[left.index].combination(operation_blocked, operation_union)
- && m_turn_points[right.index].combination(operation_blocked, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_blocked, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_blocked, operation_union))
{
// ux/ux
return consider_ux_ux(left, right, "ux/ux");
}
- else if (m_turn_points[left.index].both(operation_union)
- && m_turn_points[right.index].both(operation_union))
+ else if (m_turn_points[left.turn_index].both(operation_union)
+ && m_turn_points[right.turn_index].both(operation_union))
{
// uu/uu, Order is arbitrary
// Note: uu/uu is discarded now before so this point will
// not be reached.
return default_order;
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
- && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
{
return consider_iu_iu(left, right, "iu/iu");
}
- else if (m_turn_points[left.index].both(operation_intersection)
- && m_turn_points[right.index].both(operation_intersection))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
+ {
+ return consider_ix_ix(left, right, "ix/ix");
+ }
+ else if (m_turn_points[left.turn_index].both(operation_intersection)
+ && m_turn_points[right.turn_index].both(operation_intersection))
{
return consider_ii(left, right, "ii/ii");
}
- else if (m_turn_points[left.index].combination(operation_union, operation_blocked)
- && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_union, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
{
return consider_iu_ux(left, right, -1, "ux/iu");
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
- && m_turn_points[right.index].combination(operation_union, operation_blocked))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_union, operation_blocked))
{
return consider_iu_ux(left, right, 1, "iu/ux");
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_blocked)
- && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
{
return consider_iu_ix(left, right, 1, "ix/iu");
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
- && m_turn_points[right.index].combination(operation_intersection, operation_blocked))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
{
return consider_iu_ix(left, right, -1, "iu/ix");
}
- else if (m_turn_points[left.index].method != method_equal
- && m_turn_points[right.index].method == method_equal
+ else if (m_turn_points[left.turn_index].method != method_equal
+ && m_turn_points[right.turn_index].method == method_equal
)
{
// If one of them was EQUAL or CONTINUES, it should always come first
return false;
}
- else if (m_turn_points[left.index].method == method_equal
- && m_turn_points[right.index].method != method_equal
+ else if (m_turn_points[left.turn_index].method == method_equal
+ && m_turn_points[right.turn_index].method != method_equal
)
{
return true;
@@ -487,13 +578,13 @@ public :
// Now we have no clue how to sort.
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
- std::cout << " Consider: " << operation_char(m_turn_points[left.index].operations[0].operation)
- << operation_char(m_turn_points[left.index].operations[1].operation)
- << "/" << operation_char(m_turn_points[right.index].operations[0].operation)
- << operation_char(m_turn_points[right.index].operations[1].operation)
- << " " << " Take " << left.index << " < " << right.index
- << std::cout;
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+ std::cout << " Consider: " << operation_char(m_turn_points[left.turn_index].operations[0].operation)
+ << operation_char(m_turn_points[left.turn_index].operations[1].operation)
+ << "/" << operation_char(m_turn_points[right.turn_index].operations[0].operation)
+ << operation_char(m_turn_points[right.turn_index].operations[1].operation)
+ << " " << " Take " << left.turn_index << " < " << right.turn_index
+ << std::endl;
#endif
return default_order;
@@ -523,8 +614,8 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
std::map<std::pair<operation_type, operation_type>, int> inspection;
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- operation_type first = turn_points[it->index].operations[0].operation;
- operation_type second = turn_points[it->index].operations[1].operation;
+ operation_type first = turn_points[it->turn_index].operations[0].operation;
+ operation_type second = turn_points[it->turn_index].operations[1].operation;
if (first > second)
{
std::swap(first, second);
@@ -553,7 +644,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
// Because (in case of not discarding iu) correctly ordering of ii/iu appears impossible
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- if (turn_points[it->index].combination(operation_intersection, operation_union))
+ if (turn_points[it->turn_index].combination(operation_intersection, operation_union))
{
it->discarded = true;
}
@@ -569,7 +660,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
if (! it->discarded)
{
nd_count++;
- if (turn_points[it->index].both(operation_continue))
+ if (turn_points[it->turn_index].both(operation_continue))
{
cc_count++;
}
@@ -585,7 +676,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
{
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- if (turn_points[it->index].both(operation_continue))
+ if (turn_points[it->turn_index].both(operation_continue))
{
it->discarded = true;
}
@@ -602,12 +693,14 @@ template
typename TurnPoints,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy& robust_policy,
Strategy const& strategy)
{
// First inspect and (possibly) discard rows
@@ -622,31 +715,31 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints,
IndexType,
Geometry1, Geometry2,
+ RobustPolicy,
Reverse1, Reverse2,
Strategy
- >(turn_points, geometry1, geometry2, strategy));
-
+ >(turn_points, geometry1, geometry2, robust_policy, strategy));
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
typedef typename IndexType::type operations_type;
- operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index];
- std::cout << "Clustered points on equal distance " << op.enriched.distance << std::endl;
- std::cout << "->Indexes ";
+ operations_type const& op = turn_points[begin_cluster->turn_index].operations[begin_cluster->operation_index];
+ std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl;
+ std::cout << "->Indexes ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << it->index;
+ std::cout << " " << it->turn_index;
}
std::cout << std::endl << "->Methods: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << method_char(turn_points[it->index].method);
+ std::cout << " " << method_char(turn_points[it->turn_index].method);
}
std::cout << std::endl << "->Operations: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << operation_char(turn_points[it->index].operations[0].operation)
- << operation_char(turn_points[it->index].operations[1].operation);
+ std::cout << " " << operation_char(turn_points[it->turn_index].operations[0].operation)
+ << operation_char(turn_points[it->turn_index].operations[1].operation);
}
std::cout << std::endl << "->Discarded: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
@@ -656,7 +749,7 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
std::cout << std::endl;
//<< "\tOn segments: " << prev_op.seg_id << " / " << prev_op.other_id
//<< " and " << op.seg_id << " / " << op.other_id
- //<< geometry::distance(turn_points[prev->index].point, turn_points[it->index].point)
+ //<< geometry::distance(turn_points[prev->turn_index].point, turn_points[it->turn_index].point)
#endif
}
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp
new file mode 100644
index 0000000000..dd041b0d7d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp
@@ -0,0 +1,84 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+template <std::size_t Dimension, std::size_t DimensionCount>
+struct intersection_box_box
+{
+ template
+ <
+ typename Box1, typename Box2,
+ typename RobustPolicy,
+ typename BoxOut,
+ typename Strategy
+ >
+ static inline bool apply(Box1 const& box1,
+ Box2 const& box2,
+ RobustPolicy const& robust_policy,
+ BoxOut& box_out,
+ Strategy const& strategy)
+ {
+ typedef typename coordinate_type<BoxOut>::type ct;
+
+ ct min1 = get<min_corner, Dimension>(box1);
+ ct min2 = get<min_corner, Dimension>(box2);
+ ct max1 = get<max_corner, Dimension>(box1);
+ ct max2 = get<max_corner, Dimension>(box2);
+
+ if (max1 < min2 || max2 < min1)
+ {
+ return false;
+ }
+ // Set dimensions of output coordinate
+ set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
+ set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
+
+ return intersection_box_box<Dimension + 1, DimensionCount>
+ ::apply(box1, box2, robust_policy, box_out, strategy);
+ }
+};
+
+template <std::size_t DimensionCount>
+struct intersection_box_box<DimensionCount, DimensionCount>
+{
+ template
+ <
+ typename Box1, typename Box2,
+ typename RobustPolicy,
+ typename BoxOut,
+ typename Strategy
+ >
+ static inline bool apply(Box1 const&, Box2 const&,
+ RobustPolicy const&, BoxOut&, Strategy const&)
+ {
+ return true;
+ }
+};
+
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index 8bca790d74..a13a627456 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// 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.
+
+// Contributed and/or modified by Menelaos Karavelas, 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
@@ -28,8 +33,17 @@
#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/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
#include <boost/geometry/views/segment_view.hpp>
+#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
+
+
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
#include <boost/foreach.hpp>
#endif
@@ -41,31 +55,64 @@ namespace boost { namespace geometry
namespace detail { namespace intersection
{
-template
-<
- typename Segment1, typename Segment2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
+template <typename PointOut>
struct intersection_segment_segment_point
{
+ template
+ <
+ typename Segment1, typename Segment2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(Segment1 const& segment1,
- Segment2 const& segment2, OutputIterator out,
+ Segment2 const& segment2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
+ typedef typename geometry::robust_point_type
+ <
+ typename geometry::point_type<Segment1>::type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // TODO: rescale segment -> robust points
+ robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
+ {
+ // Workaround:
+ point_type pi, pj, qi, qj;
+ assign_point_from_index<0>(segment1, pi);
+ assign_point_from_index<1>(segment1, pj);
+ assign_point_from_index<0>(segment2, qi);
+ assign_point_from_index<1>(segment2, qj);
+ geometry::recalculate(pi_rob, pi, robust_policy);
+ geometry::recalculate(pj_rob, pj, robust_policy);
+ geometry::recalculate(qi_rob, qi, robust_policy);
+ geometry::recalculate(qj_rob, qj, robust_policy);
+ }
+
// Get the intersection point (or two points)
- segment_intersection_points<point_type> is
- = strategy::intersection::relate_cartesian_segments
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > intersection_return_type;
+
+ typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
- Segment1,
- Segment2,
- segment_intersection_points<point_type>
+ intersection_return_type
>
- >::apply(segment1, segment2);
+ > policy;
+
+ intersection_return_type is = policy::apply(segment1, segment2,
+ robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < is.count; i++)
{
@@ -77,24 +124,31 @@ struct intersection_segment_segment_point
}
};
-template
-<
- typename Linestring1, typename Linestring2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
+template <typename PointOut>
struct intersection_linestring_linestring_point
{
+ template
+ <
+ typename Linestring1, typename Linestring2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(Linestring1 const& linestring1,
- Linestring2 const& linestring2, OutputIterator out,
+ Linestring2 const& linestring2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
- typedef detail::overlay::turn_info<point_type> turn_info;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
- geometry::get_intersection_points(linestring1, linestring2, turns);
+ geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns);
for (typename boost::range_iterator<std::deque<turn_info> const>::type
it = boost::begin(turns); it != boost::end(turns); ++it)
@@ -112,25 +166,15 @@ struct intersection_linestring_linestring_point
*/
template
<
- typename LineString, typename Areal,
bool ReverseAreal,
- typename OutputIterator, typename LineStringOut,
- overlay_type OverlayType,
- typename Strategy
+ typename LineStringOut,
+ overlay_type OverlayType
>
struct intersection_of_linestring_with_areal
{
- typedef detail::overlay::follow
- <
- LineStringOut,
- LineString,
- Areal,
- OverlayType
- > follower;
-
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
template <typename Turn, typename Operation>
- static inline void debug_follow(Turn const& turn, Operation op,
+ static inline void debug_follow(Turn const& turn, Operation op,
int index)
{
std::cout << index
@@ -145,7 +189,14 @@ struct intersection_of_linestring_with_areal
}
#endif
+ template
+ <
+ typename LineString, typename Areal,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(LineString const& linestring, Areal const& areal,
+ RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
@@ -154,9 +205,20 @@ struct intersection_of_linestring_with_areal
return out;
}
- typedef typename point_type<LineStringOut>::type point_type;
+ typedef detail::overlay::follow
+ <
+ LineStringOut,
+ LineString,
+ Areal,
+ OverlayType
+ > follower;
- typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef typename point_type<LineStringOut>::type point_type;
+ typedef detail::overlay::traversal_turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
@@ -164,12 +226,12 @@ struct intersection_of_linestring_with_areal
<
false,
(OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal),
- detail::overlay::calculate_distance_policy
- >(linestring, areal, turns, policy);
+ detail::overlay::assign_null_policy
+ >(linestring, areal, robust_policy, turns, policy);
if (turns.empty())
{
- // No intersection points, it is either completely
+ // No intersection points, it is either completely
// inside (interior + borders)
// or completely outside
@@ -181,8 +243,7 @@ struct intersection_of_linestring_with_areal
return out;
}
-
- if (follower::included(border_point, areal))
+ if (follower::included(border_point, areal, robust_policy))
{
LineStringOut copy;
geometry::convert(linestring, copy);
@@ -203,7 +264,7 @@ struct intersection_of_linestring_with_areal
(
linestring, areal,
geometry::detail::overlay::operation_intersection,
- turns, out
+ turns, robust_policy, out
);
}
};
@@ -220,18 +281,22 @@ namespace dispatch
template
<
- // tag dispatching:
- typename TagIn1, typename TagIn2, typename TagOut,
- // orientation
- // metafunction finetuning helpers:
- bool Areal1, bool Areal2, bool ArealOut,
// real types
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ // orientation
+ bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ // tag dispatching:
+ typename TagIn1 = typename geometry::tag<Geometry1>::type,
+ typename TagIn2 = typename geometry::tag<Geometry2>::type,
+ typename TagOut = typename geometry::tag<GeometryOut>::type,
+ // metafunction finetuning helpers:
+ bool Areal1 = geometry::is_areal<Geometry1>::value,
+ bool Areal2 = geometry::is_areal<Geometry2>::value,
+ bool ArealOut = geometry::is_areal<GeometryOut>::value
>
struct intersection_insert
{
@@ -245,124 +310,106 @@ struct intersection_insert
template
<
- typename TagIn1, typename TagIn2, typename TagOut,
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2, typename TagOut
>
struct intersection_insert
<
- TagIn1, TagIn2, TagOut,
- true, true, true,
Geometry1, Geometry2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ TagIn1, TagIn2, TagOut,
+ true, true, true
> : detail::overlay::overlay
- <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+ <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
// Any areal type with box:
template
<
- typename TagIn, typename TagOut,
typename Geometry, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn, typename TagOut
>
struct intersection_insert
<
- TagIn, box_tag, TagOut,
- true, true, true,
Geometry, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ TagIn, box_tag, TagOut,
+ true, true, true
> : detail::overlay::overlay
- <Geometry, Box, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+ <Geometry, Box, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
template
<
typename Segment1, typename Segment2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- segment_tag, segment_tag, point_tag,
- false, false, false,
Segment1, Segment2,
+ GeometryOut,
+ OverlayType,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType, Strategy
- > : detail::intersection::intersection_segment_segment_point
- <
- Segment1, Segment2,
- OutputIterator, GeometryOut,
- Strategy
- >
+ segment_tag, segment_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_segment_segment_point<GeometryOut>
{};
template
<
typename Linestring1, typename Linestring2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, linestring_tag, point_tag,
- false, false, false,
Linestring1, Linestring2,
+ GeometryOut,
+ OverlayType,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType, Strategy
- > : detail::intersection::intersection_linestring_linestring_point
- <
- Linestring1, Linestring2,
- OutputIterator, GeometryOut,
- Strategy
- >
+ linestring_tag, linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_linestring_linestring_point<GeometryOut>
{};
template
<
typename Linestring, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
+ typename GeometryOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, box_tag, linestring_tag,
- false, true, false,
Linestring, Box,
+ GeometryOut,
+ overlay_intersection,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ linestring_tag, box_tag, linestring_tag,
+ false, true, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Linestring const& linestring,
- Box const& box, OutputIterator out, Strategy const& )
+ Box const& box,
+ RobustPolicy const& ,
+ OutputIterator out, Strategy const& )
{
typedef typename point_type<GeometryOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
@@ -375,27 +422,23 @@ struct intersection_insert
template
<
typename Linestring, typename Polygon,
- bool ReverseLinestring, bool ReversePolygon, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool ReverseLinestring, bool ReversePolygon, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, polygon_tag, linestring_tag,
- false, true, false,
Linestring, Polygon,
- ReverseLinestring, ReversePolygon, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ ReverseLinestring, ReversePolygon, ReverseOut,
+ linestring_tag, polygon_tag, linestring_tag,
+ false, true, false
> : detail::intersection::intersection_of_linestring_with_areal
<
- Linestring, Polygon,
ReversePolygon,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ GeometryOut,
+ OverlayType
>
{};
@@ -403,51 +446,48 @@ struct intersection_insert
template
<
typename Linestring, typename Ring,
- bool ReverseLinestring, bool ReverseRing, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool ReverseLinestring, bool ReverseRing, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, ring_tag, linestring_tag,
- false, true, false,
Linestring, Ring,
- ReverseLinestring, ReverseRing, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ ReverseLinestring, ReverseRing, ReverseOut,
+ linestring_tag, ring_tag, linestring_tag,
+ false, true, false
> : detail::intersection::intersection_of_linestring_with_areal
<
- Linestring, Ring,
ReverseRing,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ GeometryOut,
+ OverlayType
>
{};
template
<
typename Segment, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- segment_tag, box_tag, linestring_tag,
- false, true, false,
Segment, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ segment_tag, box_tag, linestring_tag,
+ false, true, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Segment const& segment,
- Box const& box, OutputIterator out, Strategy const& )
+ Box const& box,
+ RobustPolicy const& ,// TODO: propagate to clip_range_with_box
+ OutputIterator out, Strategy const& )
{
geometry::segment_view<Segment> range(segment);
@@ -460,37 +500,42 @@ struct intersection_insert
template
<
- typename Tag1, typename Tag2,
- bool Areal1, bool Areal2,
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename PointOut,
+ typename PointOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename Tag1, typename Tag2,
+ bool Areal1, bool Areal2
>
struct intersection_insert
<
- Tag1, Tag2, point_tag,
- Areal1, Areal2, false,
Geometry1, Geometry2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, PointOut,
+ PointOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ Tag1, Tag2, point_tag,
+ Areal1, Areal2, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out, Strategy const& )
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out, Strategy const& )
{
- typedef detail::overlay::turn_info<PointOut> turn_info;
+ typedef detail::overlay::turn_info
+ <
+ PointOut,
+ typename segment_ratio_type<PointOut, RobustPolicy>::type
+ > turn_info;
std::vector<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
geometry::get_turns
<
false, false, detail::overlay::assign_null_policy
- >(geometry1, geometry2, turns, policy);
+ >(geometry1, geometry2, robust_policy, turns, policy);
for (typename std::vector<turn_info>::const_iterator it
= turns.begin(); it != turns.end(); ++it)
{
@@ -504,35 +549,156 @@ struct intersection_insert
template
<
- typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
- bool Areal1, bool Areal2, bool ArealOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename Geometry1, typename Geometry2, typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert_reversed
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& g1,
- Geometry2 const& g2, OutputIterator out,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
return intersection_insert
<
- GeometryTag2, GeometryTag1, GeometryTag3,
- Areal2, Areal1, ArealOut,
- Geometry2, Geometry1,
- Reverse2, Reverse1, ReverseOut,
- OutputIterator, GeometryOut,
+ Geometry2, Geometry1, GeometryOut,
OverlayType,
- Strategy
- >::apply(g2, g1, out, strategy);
+ Reverse2, Reverse1, ReverseOut
+ >::apply(g2, g1, robust_policy, out, strategy);
}
};
+// dispatch for non-areal geometries
+template
+<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2
+>
+struct intersection_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ TagIn1, TagIn2, linestring_tag,
+ false, false, false
+ > : intersection_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
+ typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
+ linestring_tag,
+ false, false, false
+ >
+{};
+
+
+// dispatch for difference/intersection of linear geometries
+template
+<
+ typename Linear1, typename Linear2, typename LineStringOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linear1, Linear2, LineStringOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ linear_tag, linear_tag, linestring_tag,
+ false, false, false
+ > : detail::overlay::linear_linear_linestring
+ <
+ Linear1, Linear2, LineStringOut, OverlayType
+ >
+{};
+
+
+// dispatch for difference/intersection of point-like geometries
+
+template
+<
+ typename Point1, typename Point2, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Point1, Point2, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ point_tag, point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::point_point_point
+ <
+ Point1, Point2, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint, typename Point, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiPoint, Point, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_point_tag, point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::multipoint_point_point
+ <
+ MultiPoint, Point, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename Point, typename MultiPoint, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Point, MultiPoint, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ point_tag, multi_point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::point_multipoint_point
+ <
+ Point, MultiPoint, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint1, typename MultiPoint2, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_point_tag, multi_point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::multipoint_multipoint_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -548,50 +714,37 @@ template
bool ReverseSecond,
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return boost::mpl::if_c
+ <
+ geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
+ geometry::dispatch::intersection_insert_reversed
<
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- geometry::dispatch::intersection_insert_reversed
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >,
- geometry::dispatch::intersection_insert
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
- >::type::apply(geometry1, geometry2, out, strategy);
+ Geometry1, Geometry2,
+ GeometryOut,
+ OverlayType,
+ overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
+ overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
+ >,
+ geometry::dispatch::intersection_insert
+ <
+ Geometry1, Geometry2,
+ GeometryOut,
+ OverlayType,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value
+ >
+ >::type::apply(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -630,10 +783,14 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ typedef typename Strategy::rescale_policy_type rescale_policy_type;
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
return detail::intersection::insert
<
GeometryOut, false, overlay_intersection
- >(geometry1, geometry2, out, strategy);
+ >(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -667,12 +824,18 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ typedef typename geometry::rescale_policy_type
+ <
+ typename geometry::point_type<Geometry1>::type // TODO from both
+ >::type rescale_policy_type;
+
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ rescale_policy_type
> strategy;
return intersection_insert<GeometryOut>(geometry1, geometry2, out,
diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
new file mode 100644
index 0000000000..3a7a7a7f3e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
@@ -0,0 +1,326 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+
+#include <boost/geometry/algorithms/detail/turns/compare_turns.hpp>
+#include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp>
+#include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename LineStringOut,
+ overlay_type OverlayType,
+ typename Geometry,
+ typename GeometryTag
+>
+struct linear_linear_no_intersections;
+
+
+template <typename LineStringOut, typename LineString>
+struct linear_linear_no_intersections
+ <
+ LineStringOut, overlay_difference, LineString, linestring_tag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(LineString const& linestring,
+ OutputIterator oit)
+ {
+ LineStringOut ls_out;
+ geometry::convert(linestring, ls_out);
+ *oit++ = ls_out;
+ return oit;
+ }
+};
+
+
+template <typename LineStringOut, typename MultiLineString>
+struct linear_linear_no_intersections
+ <
+ LineStringOut,
+ overlay_difference,
+ MultiLineString,
+ multi_linestring_tag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(MultiLineString const& multilinestring,
+ OutputIterator oit)
+ {
+ for (typename boost::range_iterator<MultiLineString const>::type
+ it = boost::begin(multilinestring);
+ it != boost::end(multilinestring); ++it)
+ {
+ LineStringOut ls_out;
+ geometry::convert(*it, ls_out);
+ *oit++ = ls_out;
+ }
+ return oit;
+ }
+};
+
+
+template <typename LineStringOut, typename Geometry, typename GeometryTag>
+struct linear_linear_no_intersections
+ <
+ LineStringOut, overlay_intersection, Geometry, GeometryTag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(Geometry const&,
+ OutputIterator oit)
+ {
+ return oit;
+ }
+};
+
+
+
+
+
+
+
+template
+<
+ typename Linear1,
+ typename Linear2,
+ typename LinestringOut,
+ overlay_type OverlayType,
+ bool EnableFilterContinueTurns = false,
+ bool EnableRemoveDuplicateTurns = false,
+ bool EnableDegenerateTurns = true,
+#ifdef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS
+ bool EnableFollowIsolatedPoints = false
+#else
+ bool EnableFollowIsolatedPoints = true
+#endif
+>
+class linear_linear_linestring
+{
+protected:
+ struct assign_policy
+ {
+ static bool const include_no_turn = false;
+ static bool const include_degenerate = EnableDegenerateTurns;
+ static bool const include_opposite = false;
+
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(Info& , Point1 const& , Point2 const& ,
+ IntersectionInfo const& , DirInfo const& )
+ {
+ }
+ };
+
+
+ template
+ <
+ typename Turns,
+ typename LinearGeometry1,
+ typename LinearGeometry2
+ >
+ static inline void compute_turns(Turns& turns,
+ LinearGeometry1 const& linear1,
+ LinearGeometry2 const& linear2)
+ {
+ turns.clear();
+ geometry::detail::relate::turns::get_turns
+ <
+ LinearGeometry1,
+ LinearGeometry2,
+ detail::get_turns::get_turn_info_type
+ <
+ LinearGeometry1,
+ LinearGeometry2,
+ assign_policy
+ >
+ >::apply(turns, linear1, linear2);
+ }
+
+
+ template
+ <
+ overlay_type OverlayTypeForFollow,
+ bool FollowIsolatedPoints,
+ typename Turns,
+ typename LinearGeometry1,
+ typename LinearGeometry2,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ sort_and_follow_turns(Turns& turns,
+ LinearGeometry1 const& linear1,
+ LinearGeometry2 const& linear2,
+ OutputIterator oit)
+ {
+ // remove turns that have no added value
+ turns::filter_continue_turns
+ <
+ Turns,
+ EnableFilterContinueTurns && OverlayType != overlay_intersection
+ >::apply(turns);
+
+ // sort by seg_id, distance, and operation
+ std::sort(boost::begin(turns), boost::end(turns),
+ detail::turns::less_seg_fraction_other_op<>());
+
+ // remove duplicate turns
+ turns::remove_duplicate_turns
+ <
+ Turns, EnableRemoveDuplicateTurns
+ >::apply(turns);
+
+ return detail::overlay::following::linear::follow
+ <
+ LinestringOut,
+ LinearGeometry1,
+ LinearGeometry2,
+ OverlayTypeForFollow,
+ FollowIsolatedPoints,
+ !EnableFilterContinueTurns || OverlayType == overlay_intersection
+ >::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
+ oit);
+ }
+
+public:
+ template
+ <
+ typename RobustPolicy, typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ RobustPolicy const&,
+ OutputIterator oit,
+ Strategy const& )
+ {
+ typedef typename detail::relate::turns::get_turns
+ <
+ Linear1, Linear2
+ >::turn_info turn_info;
+
+ typedef std::vector<turn_info> turns_container;
+
+ turns_container turns;
+ compute_turns(turns, linear1, linear2);
+
+ if ( turns.empty() )
+ {
+ // the two linear geometries are disjoint
+ return linear_linear_no_intersections
+ <
+ LinestringOut,
+ OverlayType,
+ Linear1,
+ typename tag<Linear1>::type
+ >::apply(linear1, oit);
+ }
+
+ return sort_and_follow_turns
+ <
+ OverlayType,
+ EnableFollowIsolatedPoints
+ && OverlayType == overlay_intersection
+ >(turns, linear1, linear2, oit);
+ }
+};
+
+
+
+
+template
+<
+ typename Linear1,
+ typename Linear2,
+ typename LinestringOut,
+ bool EnableFilterContinueTurns,
+ bool EnableRemoveDuplicateTurns,
+ bool EnableDegenerateTurns,
+ bool EnableFollowIsolatedPoints
+>
+struct linear_linear_linestring
+ <
+ Linear1, Linear2, LinestringOut, overlay_union,
+ EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
+ EnableDegenerateTurns, EnableFollowIsolatedPoints
+ >
+{
+ template
+ <
+ typename RobustPolicy, typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ oit = linear_linear_no_intersections
+ <
+ LinestringOut,
+ overlay_difference,
+ Linear1,
+ typename tag<Linear1>::type
+ >::apply(linear1, oit);
+
+ return linear_linear_linestring
+ <
+ Linear2, Linear1, LinestringOut, overlay_difference,
+ EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
+ EnableDegenerateTurns, EnableFollowIsolatedPoints
+ >::apply(linear2, linear1, robust_policy, oit, strategy);
+ }
+};
+
+
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index 41665e0af1..44b5a0df3c 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
// 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,7 +18,6 @@
#include <boost/mpl/assert.hpp>
-#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -26,6 +26,7 @@
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
@@ -34,12 +35,19 @@
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
# include <boost/geometry/io/dsv/write.hpp>
#endif
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+# include <boost/timer.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -66,19 +74,17 @@ inline void map_turns(Map& map, TurnPoints const& turn_points)
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
- int index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
- ++it, ++index)
+ ++it)
{
if (! skip(*it))
{
- int op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
- ++op_it, ++op_index)
+ ++op_it)
{
ring_identifier ring_id
(
@@ -110,6 +116,12 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
// Union: return either of them
// Intersection: return nothing
// Difference: return first of them
@@ -120,6 +132,11 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
return out;
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+
std::map<ring_identifier, int> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
@@ -134,25 +151,26 @@ template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type Direction,
- typename Strategy
+ typename GeometryOut,
+ overlay_type Direction
>
struct overlay
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
- if (geometry::num_points(geometry1) == 0
- && geometry::num_points(geometry2) == 0)
+ if ( geometry::num_points(geometry1) == 0
+ && geometry::num_points(geometry2) == 0 )
{
return out;
}
- if (geometry::num_points(geometry1) == 0
- || geometry::num_points(geometry2) == 0)
+ if ( geometry::num_points(geometry1) == 0
+ || geometry::num_points(geometry2) == 0 )
{
return return_if_one_input_is_empty
<
@@ -161,7 +179,11 @@ struct overlay
}
typedef typename geometry::point_type<GeometryOut>::type point_type;
- typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef detail::overlay::traversal_turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
typedef std::deque<turn_info> container_type;
typedef std::deque
@@ -182,8 +204,8 @@ std::cout << "get turns" << std::endl;
geometry::get_turns
<
Reverse1, Reverse2,
- detail::overlay::calculate_distance_policy
- >(geometry1, geometry2, turn_points, policy);
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, robust_policy, turn_points, policy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "get_turns: " << timer.elapsed() << std::endl;
@@ -198,6 +220,7 @@ std::cout << "enrich" << std::endl;
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
geometry1, geometry2,
+ robust_policy,
side_strategy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
@@ -218,6 +241,7 @@ std::cout << "traverse" << std::endl;
Direction == overlay_union
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
+ robust_policy,
turn_points, rings
);
@@ -248,8 +272,8 @@ std::cout << "traverse" << std::endl;
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
- it != boost::end(rings);
- ++it)
+ it != boost::end(rings);
+ ++it)
{
selected[id] = properties(*it, true);
selected[id].reversed = ReverseOut;
@@ -273,24 +297,6 @@ std::cout << "traverse" << std::endl;
};
-// Metafunction helper for intersection and union
-template <order_selector Selector, bool Reverse = false>
-struct do_reverse {};
-
-template <>
-struct do_reverse<clockwise, false> : boost::false_type {};
-
-template <>
-struct do_reverse<clockwise, true> : boost::true_type {};
-
-template <>
-struct do_reverse<counterclockwise, false> : boost::true_type {};
-
-template <>
-struct do_reverse<counterclockwise, true> : boost::false_type {};
-
-
-
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
new file mode 100644
index 0000000000..0af062d271
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
@@ -0,0 +1,435 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_POINTLIKE_POINTLIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+// struct for copying points of the pointlike geometries to output
+template
+<
+ typename PointOut,
+ typename GeometryIn,
+ typename TagIn = typename tag<GeometryIn>::type
+>
+struct copy_points
+ : not_implemented<PointOut, GeometryIn>
+{};
+
+template <typename PointOut, typename PointIn>
+struct copy_points<PointOut, PointIn, point_tag>
+{
+ template <typename OutputIterator>
+ static inline void apply(PointIn const& point_in,
+ OutputIterator& oit)
+ {
+ PointOut point_out;
+ geometry::convert(point_in, point_out);
+ *oit++ = point_out;
+ }
+};
+
+
+template <typename PointOut, typename MultiPointIn>
+struct copy_points<PointOut, MultiPointIn, multi_point_tag>
+{
+ template <typename OutputIterator>
+ static inline void apply(MultiPointIn const& multi_point_in,
+ OutputIterator& oit)
+ {
+ for (typename boost::range_iterator<MultiPointIn const>::type
+ it = boost::begin(multi_point_in);
+ it != boost::end(multi_point_in); ++it)
+ {
+ PointOut point_out;
+ geometry::convert(*it, point_out);
+ *oit++ = point_out;
+ }
+ }
+};
+
+
+
+// action struct for difference/intersection
+template <typename PointOut, overlay_type OverlayType>
+struct action_selector_pl_pl
+{};
+
+template <typename PointOut>
+struct action_selector_pl_pl<PointOut, overlay_intersection>
+{
+ template
+ <
+ typename Point,
+ typename OutputIterator
+ >
+ static inline void apply(Point const& point,
+ bool is_common,
+ OutputIterator& oit)
+ {
+ if ( is_common )
+ {
+ copy_points<PointOut, Point>::apply(point, oit);
+ }
+ }
+};
+
+
+
+template <typename PointOut>
+struct action_selector_pl_pl<PointOut, overlay_difference>
+{
+ template
+ <
+ typename Point,
+ typename OutputIterator
+ >
+ static inline void apply(Point const& point,
+ bool is_common,
+ OutputIterator& oit)
+ {
+ if ( !is_common )
+ {
+ copy_points<PointOut, Point>::apply(point, oit);
+ }
+ }
+};
+
+
+//===========================================================================
+
+// difference/intersection of point-point
+template
+<
+ typename Point1,
+ typename Point2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct point_point_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Point1 const& point1,
+ Point2 const& point2,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(point1,
+ detail::equals::equals_point_point(point1, point2),
+ oit);
+
+ return oit;
+ }
+};
+
+
+
+// difference of multipoint-point
+//
+// the apply method in the following struct is called only for
+// difference; for intersection the reversal will
+// always call the point-multipoint version
+template
+<
+ typename MultiPoint,
+ typename Point,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct multipoint_point_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(MultiPoint const& multipoint,
+ Point const& point,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ BOOST_ASSERT( OverlayType == overlay_difference );
+
+ for (typename boost::range_iterator<MultiPoint const>::type
+ it = boost::begin(multipoint);
+ it != boost::end(multipoint); ++it)
+ {
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(*it,
+ detail::equals::equals_point_point(*it, point),
+ oit);
+ }
+
+ return oit;
+ }
+};
+
+
+// difference/intersection of point-multipoint
+template
+<
+ typename Point,
+ typename MultiPoint,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct point_multipoint_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Point const& point,
+ MultiPoint const& multipoint,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ typedef action_selector_pl_pl<PointOut, OverlayType> action;
+
+ for (typename boost::range_iterator<MultiPoint const>::type
+ it = boost::begin(multipoint);
+ it != boost::end(multipoint); ++it)
+ {
+ if ( detail::equals::equals_point_point(*it, point) )
+ {
+ action::apply(point, true, oit);
+ return oit;
+ }
+ }
+
+ action::apply(point, false, oit);
+ return oit;
+ }
+};
+
+
+
+// difference/intersection of multipoint-multipoint
+template
+<
+ typename MultiPoint1,
+ typename MultiPoint2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct multipoint_multipoint_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ if ( OverlayType != overlay_difference
+ && boost::size(multipoint1) > boost::size(multipoint2) )
+ {
+ return multipoint_multipoint_point
+ <
+ MultiPoint2, MultiPoint1, PointOut, OverlayType
+ >::apply(multipoint2, multipoint1, robust_policy, oit, strategy);
+ }
+
+ std::vector<typename point_type<MultiPoint2>::type>
+ points2(boost::begin(multipoint2), boost::end(multipoint2));
+
+ std::sort(points2.begin(), points2.end(), detail::relate::less());
+
+ for (typename boost::range_iterator<MultiPoint1 const>::type
+ it1 = boost::begin(multipoint1);
+ it1 != boost::end(multipoint1); ++it1)
+ {
+ bool found = std::binary_search(points2.begin(), points2.end(),
+ *it1, detail::relate::less());
+
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(*it1, found, oit);
+ }
+ return oit;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+//===========================================================================
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace overlay
+{
+
+// dispatch struct for pointlike-pointlike difference/intersection
+// computation
+template
+<
+ typename PointLike1,
+ typename PointLike2,
+ typename PointOut,
+ overlay_type OverlayType,
+ typename Tag1,
+ typename Tag2
+>
+struct pointlike_pointlike_point
+ : not_implemented<PointLike1, PointLike2, PointOut>
+{};
+
+
+template
+<
+ typename Point1,
+ typename Point2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ Point1, Point2, PointOut, OverlayType,
+ point_tag, point_tag
+ > : detail::overlay::point_point_point
+ <
+ Point1, Point2, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename Point,
+ typename MultiPoint,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ Point, MultiPoint, PointOut, OverlayType,
+ point_tag, multi_point_tag
+ > : detail::overlay::point_multipoint_point
+ <
+ Point, MultiPoint, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint,
+ typename Point,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ MultiPoint, Point, PointOut, OverlayType,
+ multi_point_tag, point_tag
+ > : detail::overlay::multipoint_point_point
+ <
+ MultiPoint, Point, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint1,
+ typename MultiPoint2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType,
+ multi_point_tag, multi_point_tag
+ > : detail::overlay::multipoint_multipoint_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType
+ >
+{};
+
+
+}} // namespace detail_dispatch::overlay
+#endif // DOXYGEN_NO_DISPATCH
+
+
+//===========================================================================
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+// generic pointlike-pointlike union implementation
+template
+<
+ typename PointLike1,
+ typename PointLike2,
+ typename PointOut
+>
+struct union_pointlike_pointlike_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(PointLike1 const& pointlike1,
+ PointLike2 const& pointlike2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ copy_points<PointOut, PointLike1>::apply(pointlike1, oit);
+
+ return detail_dispatch::overlay::pointlike_pointlike_point
+ <
+ PointLike2, PointLike1, PointOut, overlay_difference,
+ typename tag<PointLike2>::type,
+ typename tag<PointLike1>::type
+ >::apply(pointlike2, pointlike1, robust_policy, oit, strategy);
+ }
+
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
index 007113ffba..516ec349e8 100644
--- a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
+++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
@@ -14,19 +14,19 @@
# define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
#endif
+#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
+#include <iostream>
+#endif
-#include <vector>
-
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/algorithms/detail/signed_index_type.hpp>
namespace boost { namespace geometry
{
+
// Internal struct to uniquely identify a segment
// on a linestring,ring
// or polygon (needs ring_index)
@@ -40,7 +40,10 @@ struct segment_identifier
, segment_index(-1)
{}
- inline segment_identifier(int src, int mul, int rin, int seg)
+ inline segment_identifier(signed_index_type src,
+ signed_index_type mul,
+ signed_index_type rin,
+ signed_index_type seg)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
@@ -68,20 +71,20 @@ struct segment_identifier
#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id)
{
- std::cout
+ os
<< "s:" << seg_id.source_index
- << ", v:" << seg_id.segment_index // ~vertex
+ << ", v:" << seg_id.segment_index // v:vertex because s is used for source
;
- if (seg_id.ring_index >= 0) std::cout << ", r:" << seg_id.ring_index;
- if (seg_id.multi_index >= 0) std::cout << ", m:" << seg_id.multi_index;
+ if (seg_id.ring_index >= 0) os << ", r:" << seg_id.ring_index;
+ if (seg_id.multi_index >= 0) os << ", m:" << seg_id.multi_index;
return os;
}
#endif
- int source_index;
- int multi_index;
- int ring_index;
- int segment_index;
+ signed_index_type source_index;
+ signed_index_type multi_index;
+ signed_index_type ring_index;
+ signed_index_type segment_index;
};
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index f664b19514..385658a190 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -1,6 +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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -9,11 +10,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
+
#include <map>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
@@ -40,14 +46,14 @@ namespace dispatch
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename Map>
- static inline void apply(Box const& box, Geometry const& ,
+ static inline void apply(Box const& box, Geometry const& ,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
}
template <typename Map>
- static inline void apply(Box const& box,
+ static inline void apply(Box const& box,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
@@ -68,7 +74,7 @@ namespace dispatch
}
template <typename Map>
- static inline void apply(Ring const& ring,
+ static inline void apply(Ring const& ring,
ring_identifier const& id, Map& map, bool midpoint)
{
if (boost::size(ring) > 0)
@@ -91,9 +97,10 @@ namespace dispatch
per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, map, midpoint);
@@ -109,16 +116,42 @@ namespace dispatch
per_ring::apply(exterior_ring(polygon), id, map, midpoint);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, map, midpoint);
}
}
};
-}
+
+ template <typename Multi>
+ struct select_rings<multi_polygon_tag, Multi>
+ {
+ template <typename Geometry, typename Map>
+ static inline void apply(Multi const& multi, Geometry const& geometry,
+ ring_identifier id, Map& map, bool midpoint)
+ {
+ typedef typename boost::range_iterator
+ <
+ Multi const
+ >::type iterator_type;
+
+ typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon;
+
+ id.multi_index = 0;
+ for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ id.ring_index = -1;
+ per_polygon::apply(*it, geometry, id, map, midpoint);
+ id.multi_index++;
+ }
+ }
+ };
+
+} // namespace dispatch
template<overlay_type OverlayType>
@@ -213,7 +246,7 @@ inline void update_selection_map(Geometry1 const& geometry1,
typename SelectionMap::mapped_type properties = it->second; // Copy by value
// Calculate the "within code" (previously this was done earlier but is
- // must efficienter here - it can be even more efficient doing it all at once,
+ // much efficienter here - it can be even more efficient doing it all at once,
// using partition, TODO)
// So though this is less elegant than before, it avoids many unused point-in-poly calculations
switch(id.source_index)
@@ -248,7 +281,7 @@ template
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
- IntersectionMap const& intersection_map,
+ IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry1>::type tag1;
@@ -271,16 +304,16 @@ template
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry const& geometry,
- IntersectionMap const& intersection_map,
+ IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry>::type tag;
SelectionMap map_with_all;
- dispatch::select_rings<tag, Geometry>::apply(geometry,
+ dispatch::select_rings<tag, Geometry>::apply(geometry,
ring_identifier(0, -1, -1), map_with_all, midpoint);
- update_selection_map<OverlayType>(geometry, geometry, intersection_map,
+ update_selection_map<OverlayType>(geometry, geometry, intersection_map,
map_with_all, selection_map);
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 9c4c99394e..8dffeae283 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -9,16 +9,18 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
+
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -55,17 +57,21 @@ template
typename Geometry,
typename Turns,
typename TurnPolicy,
+ typename RobustPolicy,
typename InterruptPolicy
>
struct self_section_visitor
{
Geometry const& m_geometry;
+ RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
inline self_section_visitor(Geometry const& g,
+ RobustPolicy const& rp,
Turns& turns, InterruptPolicy& ip)
: m_geometry(g)
+ , m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -82,12 +88,12 @@ struct self_section_visitor
Geometry, Geometry,
false, false,
Section, Section,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>::apply(
0, m_geometry, sec1,
0, m_geometry, sec2,
false,
+ m_rescale_policy,
m_turns, m_interrupt_policy);
}
if (m_interrupt_policy.has_intersections)
@@ -103,17 +109,13 @@ struct self_section_visitor
-template
-<
- typename Geometry,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
->
+template<typename TurnPolicy>
struct get_turns
{
+ template <typename Geometry, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Geometry const& geometry,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
@@ -127,20 +129,20 @@ struct get_turns
> sections_type;
sections_type sec;
- geometry::sectionalize<false>(geometry, sec);
+ geometry::sectionalize<false>(geometry, robust_policy, false, sec);
self_section_visitor
<
Geometry,
- Turns, TurnPolicy, InterruptPolicy
- > visitor(geometry, turns, interrupt_policy);
+ Turns, TurnPolicy, RobustPolicy, InterruptPolicy
+ > visitor(geometry, robust_policy, turns, interrupt_policy);
try
{
geometry::partition
<
- box_type,
- detail::get_turns::get_section_box,
+ box_type,
+ detail::get_turns::get_section_box,
detail::get_turns::ovelaps_section_box
>::apply(sec, visitor);
}
@@ -166,9 +168,7 @@ template
<
typename GeometryTag,
typename Geometry,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
{
@@ -178,44 +178,32 @@ struct self_get_turn_points
template
<
typename Ring,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
ring_tag, Ring,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
- : detail::self_get_turn_points::get_turns
- <
- Ring,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
{};
template
<
typename Box,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
box_tag, Box,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Box const& ,
+ RobustPolicy const& ,
Turns& ,
InterruptPolicy& )
{
@@ -227,24 +215,28 @@ struct self_get_turn_points
template
<
typename Polygon,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
polygon_tag, Polygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
+ >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
+{};
+
+
+template
+<
+ typename MultiPolygon,
+ typename TurnPolicy
+>
+struct self_get_turn_points
+ <
+ multi_polygon_tag, MultiPolygon,
+ TurnPolicy
>
- : detail::self_get_turn_points::get_turns
- <
- Polygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
{};
@@ -259,6 +251,7 @@ struct self_get_turn_points
\tparam Turns type of intersection container
(e.g. vector of "intersection/turn point"'s)
\param geometry geometry
+ \param robust_policy policy to handle robustness issues
\param turns container which will contain intersection points
\param interrupt_policy policy determining if process is stopped
when intersection is found
@@ -267,38 +260,24 @@ template
<
typename AssignPolicy,
typename Geometry,
+ typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy)
{
concept::check<Geometry const>();
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry>::type,
- Geometry,
- Geometry,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type strategy_type;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- typename boost::range_value<Turns>::type,
- detail::overlay::assign_null_policy
- > TurnPolicy;
+ typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
dispatch::self_get_turn_points
<
typename tag<Geometry>::type,
Geometry,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >::apply(geometry, turns, interrupt_policy);
+ turn_policy
+ >::apply(geometry, robust_policy, turns, interrupt_policy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
index eebe381944..51fd1b3dca 100644
--- a/boost/geometry/algorithms/detail/overlay/stream_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
@@ -35,7 +35,6 @@ namespace detail { namespace overlay
template <typename P>
std::ostream& operator<<(std::ostream &os, turn_info<P> const& info)
{
- typename geometry::coordinate_type<P>::type d = info.distance;
os << "\t"
<< " src " << info.seg_id.source_index
<< " seg " << info.seg_id.segment_index
@@ -54,7 +53,7 @@ namespace detail { namespace overlay
<< " nxt seg " << info.travels_to_vertex_index
<< " , ip " << info.travels_to_ip_index
<< " , or " << info.next_ip_index
- << " dst " << double(d)
+ << " frac " << info.fraction
<< info.visit_state;
if (info.flagged)
{
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
index 810a27af04..6ee32c17c0 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
@@ -24,15 +24,21 @@ namespace detail { namespace overlay
{
-template <typename P>
-struct traversal_turn_operation : public turn_operation
+template <typename Point, typename SegmentRatio>
+struct traversal_turn_operation : public turn_operation<SegmentRatio>
{
- enrichment_info<P> enriched;
+ enrichment_info<Point> enriched;
visit_info visited;
};
-template <typename P>
-struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> >
+template <typename Point, typename SegmentRatio>
+struct traversal_turn_info
+ : public turn_info
+ <
+ Point,
+ SegmentRatio,
+ traversal_turn_operation<Point, SegmentRatio>
+ >
{};
diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp
index 12daafa0cf..59d2ba703e 100644
--- a/boost/geometry/algorithms/detail/overlay/traverse.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp
@@ -13,11 +13,12 @@
#include <boost/range.hpp>
-#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -38,7 +39,7 @@ namespace detail { namespace overlay
template <typename Turn, typename Operation>
#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
-inline void debug_traverse(Turn const& turn, Operation op,
+inline void debug_traverse(Turn const& turn, Operation op,
std::string const& header)
{
std::cout << header
@@ -57,7 +58,7 @@ inline void debug_traverse(Turn const& turn, Operation op,
}
}
#else
-inline void debug_traverse(Turn const& , Operation, std::string const& )
+inline void debug_traverse(Turn const& , Operation, const char*)
{
}
#endif
@@ -92,14 +93,16 @@ template
typename G1,
typename G2,
typename Turns,
- typename IntersectionInfo
+ typename IntersectionInfo,
+ typename RobustPolicy
>
inline bool assign_next_ip(G1 const& g1, G2 const& g2,
Turns& turns,
typename boost::range_iterator<Turns>::type& ip,
GeometryOut& current_output,
IntersectionInfo& info,
- segment_identifier& seg_id)
+ segment_identifier& seg_id,
+ RobustPolicy const& robust_policy)
{
info.visited.set_visited();
set_visited_for_continue(*ip, info);
@@ -107,7 +110,7 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
// If there is no next IP on this segment
if (info.enriched.next_ip_index < 0)
{
- if (info.enriched.travels_to_vertex_index < 0
+ if (info.enriched.travels_to_vertex_index < 0
|| info.enriched.travels_to_ip_index < 0)
{
return false;
@@ -120,12 +123,14 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
{
geometry::copy_segments<Reverse1>(g1, info.seg_id,
info.enriched.travels_to_vertex_index,
+ robust_policy,
current_output);
}
else
{
geometry::copy_segments<Reverse2>(g2, info.seg_id,
info.enriched.travels_to_vertex_index,
+ robust_policy,
current_output);
}
seg_id = info.seg_id;
@@ -137,12 +142,16 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
seg_id = info.seg_id;
}
- detail::overlay::append_no_duplicates(current_output, ip->point);
+ detail::overlay::append_no_dups_or_spikes(current_output, ip->point,
+ robust_policy);
+
return true;
}
-inline bool select_source(operation_type operation, int source1, int source2)
+inline bool select_source(operation_type operation,
+ signed_index_type source1,
+ signed_index_type source2)
{
return (operation == operation_intersection && source1 != source2)
|| (operation == operation_union && source1 == source2)
@@ -227,12 +236,14 @@ template
class traverse
{
public :
- template <typename Turns, typename Rings>
+ template <typename RobustPolicy, typename Turns, typename Rings>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
detail::overlay::operation_type operation,
+ RobustPolicy const& robust_policy,
Turns& turns, Rings& rings)
{
+ typedef typename boost::range_value<Rings>::type ring_type;
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename boost::range_iterator
@@ -240,6 +251,12 @@ public :
typename turn_type::container_type
>::type turn_operation_iterator_type;
+ std::size_t const min_num_points
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<ring_type>::value
+ >::value;
+
std::size_t size_at_start = boost::size(rings);
typename Backtrack::state_type state;
@@ -253,7 +270,7 @@ public :
++it)
{
// Skip discarded ones
- if (! (it->is_discarded() || it->blocked()))
+ if (! (it->discarded || ! it->selectable_start || it->blocked()))
{
for (turn_operation_iterator_type iit = boost::begin(it->operations);
state.good() && iit != boost::end(it->operations);
@@ -267,9 +284,9 @@ public :
{
set_visited_for_continue(*it, *iit);
- typename boost::range_value<Rings>::type current_output;
- detail::overlay::append_no_duplicates(current_output,
- it->point, true);
+ ring_type current_output;
+ detail::overlay::append_no_dups_or_spikes(current_output,
+ it->point, robust_policy);
turn_iterator current = it;
turn_operation_iterator_type current_iit = iit;
@@ -279,13 +296,14 @@ public :
geometry1, geometry2,
turns,
current, current_output,
- *iit, current_seg_id))
+ *iit, current_seg_id,
+ robust_policy))
{
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *current_iit,
"No next IP",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
if (! detail::overlay::select_next_ip(
@@ -295,10 +313,10 @@ public :
current_iit))
{
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Dead end at start",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
else
{
@@ -308,7 +326,7 @@ public :
detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
- unsigned int i = 0;
+ typename boost::range_size<Turns>::type i = 0;
while (current_iit != iit && state.good())
{
@@ -317,10 +335,10 @@ public :
// It visits a visited node again, without passing the start node.
// This makes it suspicious for endless loops
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Visit again",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
else
{
@@ -339,7 +357,8 @@ public :
detail::overlay::assign_next_ip<Reverse1, Reverse2>(
geometry1, geometry2,
turns, current, current_output,
- *current_iit, current_seg_id);
+ *current_iit, current_seg_id,
+ robust_policy);
if (! detail::overlay::select_next_ip(
operation,
@@ -351,12 +370,15 @@ public :
// Should not occur in self-intersecting polygons without spikes
// Might occur in polygons with spikes
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Dead end",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
+ }
+ else
+ {
+ detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
}
- detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
if (i++ > 2 + 2 * turns.size())
{
@@ -364,10 +386,10 @@ public :
// than turn points.
// Turn points marked as "ii" can be visited twice.
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Endless loop",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
}
}
@@ -376,7 +398,11 @@ public :
{
iit->visited.set_finished();
detail::overlay::debug_traverse(*current, *iit, "->Finished");
- rings.push_back(current_output);
+ if (geometry::num_points(current_output) >= min_num_points)
+ {
+ clean_closing_dups_and_spikes(current_output, robust_policy);
+ rings.push_back(current_output);
+ }
}
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
index 89a60b21ab..26669a4b1f 100644
--- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -54,11 +54,12 @@ enum method_type
The class is to be included in the turn_info class, either direct
or a derived or similar class with more (e.g. enrichment) information.
*/
+template <typename SegmentRatio>
struct turn_operation
{
operation_type operation;
segment_identifier seg_id;
- segment_identifier other_id;
+ SegmentRatio fraction;
inline turn_operation()
: operation(operation_none)
@@ -78,7 +79,8 @@ struct turn_operation
template
<
typename Point,
- typename Operation = turn_operation,
+ typename SegmentRatio,
+ typename Operation = turn_operation<SegmentRatio>,
typename Container = boost::array<Operation, 2>
>
struct turn_info
@@ -90,6 +92,7 @@ struct turn_info
Point point;
method_type method;
bool discarded;
+ bool selectable_start; // Can be used as starting-turn in traverse
Container operations;
@@ -97,13 +100,14 @@ struct turn_info
inline turn_info()
: method(method_none)
, discarded(false)
+ , selectable_start(true)
{}
inline bool both(operation_type type) const
{
return has12(type, type);
}
-
+
inline bool has(operation_type type) const
{
return this->operations[0].operation == type
@@ -115,8 +119,6 @@ struct turn_info
return has12(type1, type2) || has12(type2, type1);
}
-
- inline bool is_discarded() const { return discarded; }
inline bool blocked() const
{
return both(operation_blocked);
diff --git a/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
index 6be63f42b4..4284a801a1 100644
--- a/boost/geometry/algorithms/detail/overlay/visit_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
@@ -10,11 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
-#ifdef BOOST_GEOMETRY_USE_MSM
-# include <boost/geometry/algorithms/detail/overlay/msm_state.hpp>
-#endif
-
-
namespace boost { namespace geometry
{
@@ -22,9 +17,6 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
-
-#if ! defined(BOOST_GEOMETRY_USE_MSM)
-
class visit_info
{
private :
@@ -66,8 +58,6 @@ public:
}
}
-
-
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
{
@@ -82,50 +72,6 @@ public:
};
-#else
-
-
-class visit_info
-{
-
-private :
-
-#ifndef USE_MSM_MINI
- mutable
-#endif
- traverse_state state;
-
-public :
- inline visit_info()
- {
- state.start();
- }
-
- inline void set_none() { state.process_event(none()); } // Not Yet Implemented!
- inline void set_visited() { state.process_event(visit()); }
- inline void set_started() { state.process_event(starting()); }
- inline void set_finished() { state.process_event(finish()); }
-
-#ifdef USE_MSM_MINI
- inline bool none() const { return state.flag_none(); }
- inline bool visited() const { return state.flag_visited(); }
- inline bool started() const { return state.flag_started(); }
-#else
- inline bool none() const { return state.is_flag_active<is_init>(); }
- inline bool visited() const { return state.is_flag_active<is_visited>(); }
- inline bool started() const { return state.is_flag_active<is_started>(); }
-#endif
-
-#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
- friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
- {
- return os;
- }
-#endif
-};
-#endif
-
-
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp
index 45ff52ccb1..a44d5637bc 100644
--- a/boost/geometry/algorithms/detail/partition.hpp
+++ b/boost/geometry/algorithms/detail/partition.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2011-2014 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
@@ -10,6 +10,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
#include <vector>
+#include <boost/assert.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
@@ -23,7 +24,7 @@ namespace detail { namespace partition
typedef std::vector<std::size_t> index_vector_type;
template <int Dimension, typename Box>
-inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
+void divide_box(Box const& box, Box& lower_box, Box& upper_box)
{
typedef typename coordinate_type<Box>::type ctype;
@@ -39,10 +40,10 @@ inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
}
// Divide collection into three subsets: lower, upper and oversized
-// (not-fitting)
+// (not-fitting)
// (lower == left or bottom, upper == right or top)
template <typename OverlapsPolicy, typename InputCollection, typename Box>
-static inline void divide_into_subsets(Box const& lower_box,
+inline void divide_into_subsets(Box const& lower_box,
Box const& upper_box,
InputCollection const& collection,
index_vector_type const& input,
@@ -79,14 +80,14 @@ static inline void divide_into_subsets(Box const& lower_box,
else
{
// Is nowhere! Should not occur!
- BOOST_ASSERT(true);
+ BOOST_ASSERT(false);
}
}
}
// Match collection with itself
template <typename InputCollection, typename Policy>
-static inline void handle_one(InputCollection const& collection,
+inline void handle_one(InputCollection const& collection,
index_vector_type const& input,
Policy& policy)
{
@@ -106,10 +107,15 @@ static inline void handle_one(InputCollection const& collection,
}
// Match collection 1 with collection 2
-template <typename InputCollection, typename Policy>
-static inline void handle_two(
- InputCollection const& collection1, index_vector_type const& input1,
- InputCollection const& collection2, index_vector_type const& input2,
+template
+<
+ typename InputCollection1,
+ typename InputCollection2,
+ typename Policy
+>
+inline void handle_two(
+ InputCollection1 const& collection1, index_vector_type const& input1,
+ InputCollection2 const& collection2, index_vector_type const& input2,
Policy& policy)
{
typedef boost::range_iterator
@@ -209,7 +215,8 @@ template
<
int Dimension,
typename Box,
- typename OverlapsPolicy,
+ typename OverlapsPolicy1,
+ typename OverlapsPolicy2,
typename VisitBoxPolicy
>
class partition_two_collections
@@ -220,15 +227,21 @@ class partition_two_collections
<
1 - Dimension,
Box,
- OverlapsPolicy,
+ OverlapsPolicy1,
+ OverlapsPolicy2,
VisitBoxPolicy
> sub_divide;
- template <typename InputCollection, typename Policy>
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2,
+ typename Policy
+ >
static inline void next_level(Box const& box,
- InputCollection const& collection1,
+ InputCollection1 const& collection1,
index_vector_type const& input1,
- InputCollection const& collection2,
+ InputCollection2 const& collection2,
index_vector_type const& input2,
int level, std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
@@ -252,10 +265,15 @@ class partition_two_collections
}
public :
- template <typename InputCollection, typename Policy>
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2,
+ typename Policy
+ >
static inline void apply(Box const& box,
- InputCollection const& collection1, index_vector_type const& input1,
- InputCollection const& collection2, index_vector_type const& input2,
+ InputCollection1 const& collection1, index_vector_type const& input1,
+ InputCollection2 const& collection2, index_vector_type const& input2,
int level,
std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
@@ -267,9 +285,9 @@ public :
index_vector_type lower1, upper1, exceeding1;
index_vector_type lower2, upper2, exceeding2;
- divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection1,
+ divide_into_subsets<OverlapsPolicy1>(lower_box, upper_box, collection1,
input1, lower1, upper1, exceeding1);
- divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection2,
+ divide_into_subsets<OverlapsPolicy2>(lower_box, upper_box, collection2,
input2, lower2, upper2, exceeding2);
if (boost::size(exceeding1) > 0)
@@ -308,15 +326,17 @@ struct visit_no_policy
template
<
typename Box,
- typename ExpandPolicy,
- typename OverlapsPolicy,
+ typename ExpandPolicy1,
+ typename OverlapsPolicy1,
+ typename ExpandPolicy2 = ExpandPolicy1,
+ typename OverlapsPolicy2 = OverlapsPolicy1,
typename VisitBoxPolicy = visit_no_policy
>
class partition
{
typedef std::vector<std::size_t> index_vector_type;
- template <typename InputCollection>
+ template <typename ExpandPolicy, typename InputCollection>
static inline void expand_to_collection(InputCollection const& collection,
Box& total, index_vector_type& index_vector)
{
@@ -344,12 +364,12 @@ public :
index_vector_type index_vector;
Box total;
assign_inverse(total);
- expand_to_collection(collection, total, index_vector);
+ expand_to_collection<ExpandPolicy1>(collection, total, index_vector);
detail::partition::partition_one_collection
<
0, Box,
- OverlapsPolicy,
+ OverlapsPolicy1,
VisitBoxPolicy
>::apply(total, collection, index_vector, 0, min_elements,
visitor, box_visitor);
@@ -373,9 +393,14 @@ public :
}
}
- template <typename InputCollection, typename VisitPolicy>
- static inline void apply(InputCollection const& collection1,
- InputCollection const& collection2,
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2,
+ typename VisitPolicy
+ >
+ static inline void apply(InputCollection1 const& collection1,
+ InputCollection2 const& collection2,
VisitPolicy& visitor,
std::size_t min_elements = 16,
VisitBoxPolicy box_visitor = visit_no_policy()
@@ -387,12 +412,12 @@ public :
index_vector_type index_vector1, index_vector2;
Box total;
assign_inverse(total);
- expand_to_collection(collection1, total, index_vector1);
- expand_to_collection(collection2, total, index_vector2);
+ expand_to_collection<ExpandPolicy1>(collection1, total, index_vector1);
+ expand_to_collection<ExpandPolicy2>(collection2, total, index_vector2);
detail::partition::partition_two_collections
<
- 0, Box, OverlapsPolicy, VisitBoxPolicy
+ 0, Box, OverlapsPolicy1, OverlapsPolicy2, VisitBoxPolicy
>::apply(total,
collection1, index_vector1,
collection2, index_vector2,
@@ -402,13 +427,17 @@ public :
{
typedef typename boost::range_iterator
<
- InputCollection const
- >::type iterator_type;
- for(iterator_type it1 = boost::begin(collection1);
+ InputCollection1 const
+ >::type iterator_type1;
+ typedef typename boost::range_iterator
+ <
+ InputCollection2 const
+ >::type iterator_type2;
+ for(iterator_type1 it1 = boost::begin(collection1);
it1 != boost::end(collection1);
++it1)
{
- for(iterator_type it2 = boost::begin(collection2);
+ for(iterator_type2 it2 = boost::begin(collection2);
it2 != boost::end(collection2);
++it2)
{
@@ -417,9 +446,9 @@ public :
}
}
}
-
};
+
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
new file mode 100644
index 0000000000..cd3acb5ba4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
@@ -0,0 +1,126 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// 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_POINT_IS_EQUAL_OR_SPIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+// Checks if a point ("last_point") causes a spike w.r.t.
+// the specified two other points (segment_a, segment_b)
+//
+// x-------x------x
+// a lp b
+//
+// Above, lp generates a spike w.r.t. segment(a,b)
+// So specify last point first, then (a,b) (this is unordered, so unintuitive)
+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)
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point1>::type
+ >::type side_strategy;
+
+ typedef Point1 vector_type;
+
+ int const side = side_strategy::apply(last_point, segment_a, segment_b);
+ if (side == 0)
+ {
+ // Last point is collinear w.r.t previous segment.
+ // Check if it is equal
+ vector_type diff1;
+ conversion::convert_point_to_point(last_point, diff1);
+ geometry::subtract_point(diff1, segment_b);
+ int const sgn_x1 = math::sign(geometry::get<0>(diff1));
+ int const sgn_y1 = math::sign(geometry::get<1>(diff1));
+ if (sgn_x1 == 0 && sgn_y1 == 0)
+ {
+ return true;
+ }
+
+ // Check if it moves forward
+ vector_type diff2;
+ conversion::convert_point_to_point(segment_b, diff2);
+ geometry::subtract_point(diff2, segment_a);
+ int const sgn_x2 = math::sign(geometry::get<0>(diff2));
+ int const sgn_y2 = math::sign(geometry::get<1>(diff2));
+
+ return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
+ }
+ return false;
+}
+
+template
+<
+ typename Point1,
+ typename Point2,
+ typename Point3,
+ typename RobustPolicy
+>
+static inline bool point_is_spike_or_equal(Point1 const& last_point,
+ Point2 const& segment_a,
+ Point3 const& segment_b,
+ RobustPolicy const& robust_policy)
+{
+ if (point_is_spike_or_equal(last_point, segment_a, segment_b))
+ {
+ return true;
+ }
+
+ if (! RobustPolicy::enabled)
+ {
+ return false;
+ }
+
+ // Try using specified robust policy
+ typedef typename geometry::robust_point_type
+ <
+ Point1,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type last_point_rob, segment_a_rob, segment_b_rob;
+ geometry::recalculate(last_point_rob, last_point, robust_policy);
+ geometry::recalculate(segment_a_rob, segment_a, robust_policy);
+ geometry::recalculate(segment_b_rob, segment_b, robust_policy);
+
+ return point_is_spike_or_equal
+ (
+ last_point_rob,
+ segment_a_rob,
+ segment_b_rob
+ );
+}
+
+
+} // namespace detail
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP
diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp
index b7e15ba3f9..24b88a8d19 100644
--- a/boost/geometry/algorithms/detail/point_on_border.hpp
+++ b/boost/geometry/algorithms/detail/point_on_border.hpp
@@ -19,6 +19,7 @@
#include <boost/range.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
@@ -26,7 +27,7 @@
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
namespace boost { namespace geometry
@@ -153,6 +154,35 @@ struct point_on_box
};
+template
+<
+ typename Point,
+ typename MultiGeometry,
+ typename Policy
+>
+struct point_on_multi
+{
+ static inline bool apply(Point& point, MultiGeometry const& multi, bool midpoint)
+ {
+ // Take a point on the first multi-geometry
+ // (i.e. the first that is not empty)
+ for (typename boost::range_iterator
+ <
+ MultiGeometry const
+ >::type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ if (Policy::apply(point, *it, midpoint))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+
}} // namespace detail::point_on_border
#endif // DOXYGEN_NO_DETAIL
@@ -203,6 +233,36 @@ struct point_on_border<box_tag, Point, Box>
{};
+template<typename Point, typename Multi>
+struct point_on_border<multi_polygon_tag, Point, Multi>
+ : detail::point_on_border::point_on_multi
+ <
+ Point,
+ Multi,
+ detail::point_on_border::point_on_polygon
+ <
+ Point,
+ typename boost::range_value<Multi>::type
+ >
+ >
+{};
+
+
+template<typename Point, typename Multi>
+struct point_on_border<multi_linestring_tag, Point, Multi>
+ : detail::point_on_border::point_on_multi
+ <
+ Point,
+ Multi,
+ detail::point_on_border::point_on_range
+ <
+ Point,
+ typename boost::range_value<Multi>::type
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -229,8 +289,6 @@ inline bool point_on_border(Point& point,
concept::check<Point>();
concept::check<Geometry const>();
- typedef typename point_type<Geometry>::type point_type;
-
return dispatch::point_on_border
<
typename tag<Geometry>::type,
diff --git a/boost/geometry/algorithms/detail/recalculate.hpp b/boost/geometry/algorithms/detail/recalculate.hpp
new file mode 100644
index 0000000000..2c3ea7413b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/recalculate.hpp
@@ -0,0 +1,231 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// 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_RECALCULATE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP
+
+
+#include <cstddef>
+
+#include <boost/concept/requires.hpp>
+#include <boost/concept_check.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/numeric/conversion/bounds.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/type_traits.hpp>
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace recalculate
+{
+
+template <std::size_t Dimension>
+struct recalculate_point
+{
+ template <typename Point1, typename Point2, typename Strategy>
+ static inline void apply(Point1& point1, Point2 const& point2, Strategy const& strategy)
+ {
+ std::size_t const dim = Dimension - 1;
+ geometry::set<dim>(point1, strategy.template apply<dim>(geometry::get<dim>(point2)));
+ recalculate_point<dim>::apply(point1, point2, strategy);
+ }
+};
+
+template <>
+struct recalculate_point<0>
+{
+ template <typename Point1, typename Point2, typename Strategy>
+ static inline void apply(Point1&, Point2 const&, Strategy const&)
+ {
+ }
+};
+
+
+template <std::size_t Dimension>
+struct recalculate_indexed
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // Do it for both indices in one dimension
+ static std::size_t const dim = Dimension - 1;
+ geometry::set<0, dim>(geometry1, strategy.template apply<dim>(geometry::get<0, dim>(geometry2)));
+ geometry::set<1, dim>(geometry1, strategy.template apply<dim>(geometry::get<1, dim>(geometry2)));
+ recalculate_indexed<dim>::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <>
+struct recalculate_indexed<0>
+{
+
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline void apply(Geometry1& , Geometry2 const& , Strategy const& )
+ {
+ }
+};
+
+struct range_to_range
+{
+ template
+ <
+ typename Range1,
+ typename Range2,
+ typename Strategy
+ >
+ static inline void apply(Range1& destination, Range2 const& source,
+ Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Range2>::type point_type;
+ typedef recalculate_point<geometry::dimension<point_type>::value> per_point;
+ geometry::clear(destination);
+
+ for (typename boost::range_iterator<Range2 const>::type it
+ = boost::begin(source);
+ it != boost::end(source);
+ ++it)
+ {
+ point_type p;
+ per_point::apply(p, *it, strategy);
+ geometry::append(destination, p);
+ }
+ }
+};
+
+struct polygon_to_polygon
+{
+private:
+ template
+ <
+ typename IteratorIn,
+ typename IteratorOut,
+ typename Strategy
+ >
+ static inline void iterate(IteratorIn begin, IteratorIn end,
+ IteratorOut it_out,
+ Strategy const& strategy)
+ {
+ for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out)
+ {
+ range_to_range::apply(*it_out, *it_in, strategy);
+ }
+ }
+
+ template
+ <
+ typename InteriorRingsOut,
+ typename InteriorRingsIn,
+ typename Strategy
+ >
+ static inline void apply_interior_rings(
+ InteriorRingsOut& interior_rings_out,
+ InteriorRingsIn const& interior_rings_in,
+ Strategy const& strategy)
+ {
+ traits::resize<InteriorRingsOut>::apply(interior_rings_out,
+ boost::size(interior_rings_in));
+
+ iterate(
+ boost::begin(interior_rings_in), boost::end(interior_rings_in),
+ boost::begin(interior_rings_out),
+ strategy);
+ }
+
+public:
+ template
+ <
+ typename Polygon1,
+ typename Polygon2,
+ typename Strategy
+ >
+ static inline void apply(Polygon1& destination, Polygon2 const& source,
+ Strategy const& strategy)
+ {
+ range_to_range::apply(geometry::exterior_ring(destination),
+ geometry::exterior_ring(source), strategy);
+
+ apply_interior_rings(geometry::interior_rings(destination),
+ geometry::interior_rings(source), strategy);
+ }
+};
+
+}} // namespace detail::recalculate
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type
+>
+struct recalculate : not_implemented<Tag1, Tag2>
+{};
+
+template <typename Point1, typename Point2>
+struct recalculate<Point1, Point2, point_tag, point_tag>
+ : detail::recalculate::recalculate_point<geometry::dimension<Point1>::value>
+{};
+
+template <typename Box1, typename Box2>
+struct recalculate<Box1, Box2, box_tag, box_tag>
+ : detail::recalculate::recalculate_indexed<geometry::dimension<Box1>::value>
+{};
+
+template <typename Segment1, typename Segment2>
+struct recalculate<Segment1, Segment2, segment_tag, segment_tag>
+ : detail::recalculate::recalculate_indexed<geometry::dimension<Segment1>::value>
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct recalculate<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : detail::recalculate::polygon_to_polygon
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline void recalculate(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+{
+ concept::check<Geometry1>();
+ concept::check<Geometry2 const>();
+
+ // static assert dimensions (/types) are the same
+
+ dispatch::recalculate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP
diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp
new file mode 100644
index 0000000000..31d206ac99
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp
@@ -0,0 +1,823 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_AREAL_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
+
+#include <boost/geometry/core/topological_dimension.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/single_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
+#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// WARNING!
+// TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM)
+// Use the rtree in this case!
+
+// may be used to set EI and EB for an Areal geometry for which no turns were generated
+template <typename OtherAreal, typename Result, bool TransposeResult>
+class no_turns_aa_pred
+{
+public:
+ no_turns_aa_pred(OtherAreal const& other_areal, Result & res)
+ : m_result(res)
+ , m_other_areal(other_areal)
+ , m_flags(0)
+ {
+ // check which relations must be analysed
+
+ if ( ! may_update<interior, interior, '2', TransposeResult>(m_result)
+ && ! may_update<boundary, interior, '1', TransposeResult>(m_result)
+ && ! may_update<exterior, interior, '2', TransposeResult>(m_result) )
+ {
+ m_flags |= 1;
+ }
+
+ if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result)
+ && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
+ {
+ m_flags |= 2;
+ }
+ }
+
+ template <typename Areal>
+ bool operator()(Areal const& areal)
+ {
+ // if those flags are set nothing will change
+ if ( m_flags == 3 )
+ {
+ return false;
+ }
+
+ typedef typename geometry::point_type<Areal>::type point_type;
+ point_type pt;
+ bool const ok = boost::geometry::point_on_border(pt, areal);
+
+ // TODO: for now ignore, later throw an exception?
+ if ( !ok )
+ {
+ return true;
+ }
+
+ // check if the areal is inside the other_areal
+ // TODO: This is O(N)
+ // Run in a loop O(NM) - optimize!
+ int const pig = detail::within::point_in_geometry(pt, m_other_areal);
+ //BOOST_ASSERT( pig != 0 );
+
+ // inside
+ if ( pig > 0 )
+ {
+ update<interior, interior, '2', TransposeResult>(m_result);
+ update<boundary, interior, '1', TransposeResult>(m_result);
+ update<exterior, interior, '2', TransposeResult>(m_result);
+ m_flags |= 1;
+
+ // TODO: OPTIMIZE!
+ // Only the interior rings of other ONE single geometry must be checked
+ // NOT all geometries
+
+ // Check if any interior ring is outside
+ ring_identifier ring_id(0, -1, 0);
+ int const irings_count = boost::numeric_cast<int>(
+ geometry::num_interior_rings(areal) );
+ for ( ; ring_id.ring_index < irings_count ; ++ring_id.ring_index )
+ {
+ typename detail::sub_range_return_type<Areal const>::type
+ range_ref = detail::sub_range(areal, ring_id);
+
+ if ( boost::empty(range_ref) )
+ {
+ // TODO: throw exception?
+ continue; // ignore
+ }
+
+ // TODO: O(N)
+ // Optimize!
+ int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal);
+
+ // hole outside
+ if ( hpig < 0 )
+ {
+ update<interior, exterior, '2', TransposeResult>(m_result);
+ update<boundary, exterior, '1', TransposeResult>(m_result);
+ m_flags |= 2;
+ break;
+ }
+ }
+ }
+ // outside
+ else
+ {
+ update<interior, exterior, '2', TransposeResult>(m_result);
+ update<boundary, exterior, '1', TransposeResult>(m_result);
+ m_flags |= 2;
+
+ // Check if any interior ring is inside
+ ring_identifier ring_id(0, -1, 0);
+ int const irings_count = boost::numeric_cast<int>(
+ geometry::num_interior_rings(areal) );
+ for ( ; ring_id.ring_index < irings_count ; ++ring_id.ring_index )
+ {
+ typename detail::sub_range_return_type<Areal const>::type
+ range_ref = detail::sub_range(areal, ring_id);
+
+ if ( boost::empty(range_ref) )
+ {
+ // TODO: throw exception?
+ continue; // ignore
+ }
+
+ // TODO: O(N)
+ // Optimize!
+ int const hpig = detail::within::point_in_geometry(range::front(range_ref), m_other_areal);
+
+ // hole inside
+ if ( hpig > 0 )
+ {
+ update<interior, interior, '2', TransposeResult>(m_result);
+ update<boundary, interior, '1', TransposeResult>(m_result);
+ update<exterior, interior, '2', TransposeResult>(m_result);
+ m_flags |= 1;
+ break;
+ }
+ }
+ }
+
+ return m_flags != 3 && !m_result.interrupt;
+ }
+
+private:
+ Result & m_result;
+ OtherAreal const& m_other_areal;
+ int m_flags;
+};
+
+// The implementation of an algorithm calculating relate() for A/A
+template <typename Geometry1, typename Geometry2>
+struct areal_areal
+{
+ // check Linear / Areal
+ BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2
+ && topological_dimension<Geometry2>::value == 2);
+
+ static const bool interruption_enabled = true;
+
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+// TODO: If Areal geometry may have infinite size, change the following line:
+
+ // The result should be FFFFFFFFF
+ relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
+
+ if ( result.interrupt )
+ return;
+
+ // get and analyse turns
+ typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ std::vector<turn_type> turns;
+
+ interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
+
+ turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
+ if ( result.interrupt )
+ return;
+
+ no_turns_aa_pred<Geometry2, Result, false> pred1(geometry2, result);
+ for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
+ if ( result.interrupt )
+ return;
+
+ no_turns_aa_pred<Geometry1, Result, true> pred2(geometry1, result);
+ for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
+ if ( result.interrupt )
+ return;
+
+ if ( turns.empty() )
+ return;
+
+ if ( may_update<interior, interior, '2'>(result)
+ || may_update<interior, exterior, '2'>(result)
+ || may_update<boundary, interior, '1'>(result)
+ || may_update<boundary, exterior, '1'>(result)
+ || may_update<exterior, interior, '2'>(result) )
+ {
+ // sort turns
+ typedef turns::less<0, turns::less_op_areal_areal<0> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ /*if ( may_update<interior, exterior, '2'>(result)
+ || may_update<boundary, exterior, '1'>(result)
+ || may_update<boundary, interior, '1'>(result)
+ || may_update<exterior, interior, '2'>(result) )*/
+ {
+ // analyse sorted turns
+ turns_analyser<turn_type, 0> analyser;
+ analyse_each_turn(result, analyser, turns.begin(), turns.end());
+
+ if ( result.interrupt )
+ return;
+ }
+
+ if ( may_update<interior, interior, '2'>(result)
+ || may_update<interior, exterior, '2'>(result)
+ || may_update<boundary, interior, '1'>(result)
+ || may_update<boundary, exterior, '1'>(result)
+ || may_update<exterior, interior, '2'>(result) )
+ {
+ // analyse rings for which turns were not generated
+ // or only i/i or u/u was generated
+ uncertain_rings_analyser<0, Result, Geometry1, Geometry2> rings_analyser(result, geometry1, geometry2);
+ analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
+
+ if ( result.interrupt )
+ return;
+ }
+ }
+
+ if ( may_update<interior, interior, '2', true>(result)
+ || may_update<interior, exterior, '2', true>(result)
+ || may_update<boundary, interior, '1', true>(result)
+ || may_update<boundary, exterior, '1', true>(result)
+ || may_update<exterior, interior, '2', true>(result) )
+ {
+ // sort turns
+ typedef turns::less<1, turns::less_op_areal_areal<1> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ /*if ( may_update<interior, exterior, '2', true>(result)
+ || may_update<boundary, exterior, '1', true>(result)
+ || may_update<boundary, interior, '1', true>(result)
+ || may_update<exterior, interior, '2', true>(result) )*/
+ {
+ // analyse sorted turns
+ turns_analyser<turn_type, 1> analyser;
+ analyse_each_turn(result, analyser, turns.begin(), turns.end());
+
+ if ( result.interrupt )
+ return;
+ }
+
+ if ( may_update<interior, interior, '2', true>(result)
+ || may_update<interior, exterior, '2', true>(result)
+ || may_update<boundary, interior, '1', true>(result)
+ || may_update<boundary, exterior, '1', true>(result)
+ || may_update<exterior, interior, '2', true>(result) )
+ {
+ // analyse rings for which turns were not generated
+ // or only i/i or u/u was generated
+ uncertain_rings_analyser<1, Result, Geometry2, Geometry1> rings_analyser(result, geometry2, geometry1);
+ analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end());
+
+ //if ( result.interrupt )
+ // return;
+ }
+ }
+ }
+
+ // interrupt policy which may be passed to get_turns to interrupt the analysis
+ // based on the info in the passed result/mask
+ template <typename Result>
+ class interrupt_policy_areal_areal
+ {
+ public:
+ static bool const enabled = true;
+
+ interrupt_policy_areal_areal(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Result & result)
+ : m_result(result)
+ , m_geometry1(geometry1)
+ , m_geometry2(geometry2)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& turns)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ {
+ per_turn<0>(*it);
+ per_turn<1>(*it);
+ }
+
+ return m_result.interrupt;
+ }
+
+ private:
+ template <std::size_t OpId, typename Turn>
+ inline void per_turn(Turn const& turn)
+ {
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static const bool transpose_result = OpId != 0;
+
+ overlay::operation_type const op = turn.operations[OpId].operation;
+
+ if ( op == overlay::operation_union )
+ {
+ // ignore u/u
+ /*if ( turn.operations[other_op_id].operation != overlay::operation_union )
+ {
+ update<interior, exterior, '2', transpose_result>(m_result);
+ update<boundary, exterior, '1', transpose_result>(m_result);
+ }*/
+
+ update<boundary, boundary, '0', transpose_result>(m_result);
+ }
+ else if ( op == overlay::operation_intersection )
+ {
+ // ignore i/i
+ if ( turn.operations[other_op_id].operation != overlay::operation_intersection )
+ {
+ update<interior, interior, '2', transpose_result>(m_result);
+ //update<boundary, interior, '1', transpose_result>(m_result);
+ }
+
+ update<boundary, boundary, '0', transpose_result>(m_result);
+ }
+ else if ( op == overlay::operation_continue )
+ {
+ update<boundary, boundary, '1', transpose_result>(m_result);
+ update<interior, interior, '2', transpose_result>(m_result);
+ }
+ else if ( op == overlay::operation_blocked )
+ {
+ update<boundary, boundary, '1', transpose_result>(m_result);
+ update<interior, exterior, '2', transpose_result>(m_result);
+ }
+ }
+
+ Result & m_result;
+ Geometry1 const& m_geometry1;
+ Geometry2 const& m_geometry2;
+ };
+
+ // This analyser should be used like Input or SinglePass Iterator
+ // IMPORTANT! It should be called also for the end iterator - last
+ template <typename TurnInfo, std::size_t OpId>
+ class turns_analyser
+ {
+ typedef typename TurnInfo::point_type turn_point_type;
+
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static const bool transpose_result = OpId != 0;
+
+ public:
+ turns_analyser()
+ : m_previous_turn_ptr(0)
+ , m_previous_operation(overlay::operation_none)
+ , m_enter_detected(false)
+ , m_exit_detected(false)
+ {}
+
+ template <typename Result,
+ typename TurnIt>
+ void apply(Result & result, TurnIt it)
+ {
+ //BOOST_ASSERT( it != last );
+
+ overlay::operation_type const op = it->operations[op_id].operation;
+
+ if ( op != overlay::operation_union
+ && op != overlay::operation_intersection
+ && op != overlay::operation_blocked
+ && op != overlay::operation_continue )
+ {
+ return;
+ }
+
+ segment_identifier const& seg_id = it->operations[op_id].seg_id;
+ //segment_identifier const& other_id = it->operations[other_op_id].seg_id;
+
+ const bool first_in_range = m_seg_watcher.update(seg_id);
+
+ if ( m_previous_turn_ptr )
+ {
+ if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
+ {
+ // real exit point - may be multiple
+ if ( first_in_range
+ || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ {
+ update_exit(result);
+ m_exit_detected = false;
+ }
+ // fake exit point, reset state
+ else if ( op != overlay::operation_union )
+ {
+ m_exit_detected = false;
+ }
+ }
+ /*else*/
+ if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
+ {
+ // real entry point
+ if ( first_in_range
+ || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ {
+ update_enter(result);
+ m_enter_detected = false;
+ }
+ // fake entry point, reset state
+ else if ( op != overlay::operation_intersection )
+ {
+ m_enter_detected = false;
+ }
+ }
+ }
+
+ if ( op == overlay::operation_union )
+ {
+ // already set in interrupt policy
+ //update<boundary, boundary, '0', transpose_result>(m_result);
+
+ // ignore u/u
+ //if ( it->operations[other_op_id].operation != overlay::operation_union )
+ {
+ m_exit_detected = true;
+ }
+ }
+ else if ( op == overlay::operation_intersection )
+ {
+ // ignore i/i
+ if ( it->operations[other_op_id].operation != overlay::operation_intersection )
+ {
+ // already set in interrupt policy
+ //update<interior, interior, '2', transpose_result>(result);
+ //update<boundary, boundary, '0', transpose_result>(result);
+ m_enter_detected = true;
+ }
+ }
+ else if ( op == overlay::operation_blocked )
+ {
+ // already set in interrupt policy
+ }
+ else // if ( op == overlay::operation_continue )
+ {
+ // already set in interrupt policy
+ }
+
+ // store ref to previously analysed (valid) turn
+ m_previous_turn_ptr = boost::addressof(*it);
+ // and previously analysed (valid) operation
+ m_previous_operation = op;
+ }
+
+ // it == last
+ template <typename Result>
+ void apply(Result & result)
+ {
+ //BOOST_ASSERT( first != last );
+
+ if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
+ {
+ update_exit(result);
+ m_exit_detected = false;
+ }
+
+ if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
+ {
+ update_enter(result);
+ m_enter_detected = false;
+ }
+ }
+
+ template <typename Result>
+ static inline void update_exit(Result & result)
+ {
+ update<interior, exterior, '2', transpose_result>(result);
+ update<boundary, exterior, '1', transpose_result>(result);
+ }
+
+ template <typename Result>
+ static inline void update_enter(Result & result)
+ {
+ update<boundary, interior, '1', transpose_result>(result);
+ update<exterior, interior, '2', transpose_result>(result);
+ }
+
+ private:
+ segment_watcher<same_ring> m_seg_watcher;
+ TurnInfo * m_previous_turn_ptr;
+ overlay::operation_type m_previous_operation;
+ bool m_enter_detected;
+ bool m_exit_detected;
+ };
+
+ // call analyser.apply() for each turn in range
+ // IMPORTANT! The analyser is also called for the end iterator - last
+ template <typename Result,
+ typename Analyser,
+ typename TurnIt>
+ static inline void analyse_each_turn(Result & res,
+ Analyser & analyser,
+ TurnIt first, TurnIt last)
+ {
+ if ( first == last )
+ return;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ analyser.apply(res, it);
+
+ if ( res.interrupt )
+ return;
+ }
+
+ analyser.apply(res);
+ }
+
+ template <std::size_t OpId, typename Result, typename Geometry, typename OtherGeometry>
+ class uncertain_rings_analyser
+ {
+ static const bool transpose_result = OpId != 0;
+ static const int other_id = (OpId + 1) % 2;
+
+ public:
+ inline uncertain_rings_analyser(Result & result,
+ Geometry const& geom,
+ OtherGeometry const& other_geom)
+ : geometry(geom), other_geometry(other_geom)
+ , interrupt(result.interrupt) // just in case, could be false as well
+ , m_result(result)
+ , m_flags(0)
+ {
+ // check which relations must be analysed
+
+ if ( ! may_update<interior, interior, '2', transpose_result>(m_result)
+ && ! may_update<boundary, interior, '1', transpose_result>(m_result) )
+ {
+ m_flags |= 1;
+ }
+
+ if ( ! may_update<interior, exterior, '2', transpose_result>(m_result)
+ && ! may_update<boundary, exterior, '1', transpose_result>(m_result) )
+ {
+ m_flags |= 2;
+ }
+
+ if ( ! may_update<boundary, interior, '1', transpose_result>(m_result)
+ && ! may_update<exterior, interior, '2', transpose_result>(m_result) )
+ {
+ m_flags |= 4;
+ }
+ }
+
+ inline void no_turns(segment_identifier const& seg_id)
+ {
+ // if those flags are set nothing will change
+ if ( (m_flags & 3) == 3 )
+ {
+ return;
+ }
+
+ typename detail::sub_range_return_type<Geometry const>::type
+ range_ref = detail::sub_range(geometry, seg_id);
+
+ if ( boost::empty(range_ref) )
+ {
+ // TODO: throw an exception?
+ return; // ignore
+ }
+
+ // TODO: possible optimization
+ // if the range is an interior ring we may use other IPs generated for this single geometry
+ // to know which other single geometries should be checked
+
+ // TODO: optimize! e.g. use spatial index
+ // O(N) - running it in a loop would gives O(NM)
+ int const pig = detail::within::point_in_geometry(range::front(range_ref), other_geometry);
+
+ //BOOST_ASSERT(pig != 0);
+ if ( pig > 0 )
+ {
+ update<boundary, interior, '1', transpose_result>(m_result);
+ update<interior, interior, '2', transpose_result>(m_result);
+ m_flags |= 1;
+ }
+ else
+ {
+ update<boundary, exterior, '1', transpose_result>(m_result);
+ update<interior, exterior, '2', transpose_result>(m_result);
+ m_flags |= 2;
+ }
+
+// TODO: break if all things are set
+// also some of them could be checked outside, before the analysis
+// In this case we shouldn't relay just on dummy flags
+// Flags should be initialized with proper values
+// or the result should be checked directly
+// THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A
+
+ interrupt = m_flags == 7 || m_result.interrupt;
+ }
+
+ template <typename TurnIt>
+ inline void turns(TurnIt first, TurnIt last)
+ {
+ // if those flags are set nothing will change
+ if ( (m_flags & 6) == 6 )
+ {
+ return;
+ }
+
+ bool found_ii = false;
+ bool found_uu = false;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ if ( it->operations[0].operation == overlay::operation_intersection
+ && it->operations[1].operation == overlay::operation_intersection )
+ {
+ // ignore exterior ring
+ if ( it->operations[OpId].seg_id.ring_index >= 0 )
+ {
+ found_ii = true;
+ }
+ }
+ else if ( it->operations[0].operation == overlay::operation_union
+ && it->operations[1].operation == overlay::operation_union )
+ {
+ // ignore if u/u is for holes
+ //if ( it->operations[OpId].seg_id.ring_index >= 0
+ // && it->operations[other_id].seg_id.ring_index >= 0 )
+ {
+ found_uu = true;
+ }
+ }
+ else // ignore
+ {
+ return; // don't interrupt
+ }
+ }
+
+ // only i/i was generated for this ring
+ if ( found_ii )
+ {
+ //update<interior, interior, '0', transpose_result>(m_result);
+ //update<boundary, boundary, '0', transpose_result>(m_result);
+ update<boundary, interior, '1', transpose_result>(m_result);
+ update<exterior, interior, '2', transpose_result>(m_result);
+ m_flags |= 4;
+ }
+
+ // only u/u was generated for this ring
+ if ( found_uu )
+ {
+ update<boundary, exterior, '1', transpose_result>(m_result);
+ update<interior, exterior, '2', transpose_result>(m_result);
+ m_flags |= 2;
+
+ // not necessary since this will be checked in the next iteration
+ // but increases the pruning strength
+ // WARNING: this is not reflected in flags
+ update<exterior, boundary, '1', transpose_result>(m_result);
+ update<exterior, interior, '2', transpose_result>(m_result);
+ }
+
+ interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future
+ }
+
+ Geometry const& geometry;
+ OtherGeometry const& other_geometry;
+ bool interrupt;
+
+ private:
+ Result & m_result;
+ int m_flags;
+ };
+
+ template <std::size_t OpId>
+ class analyse_uncertain_rings
+ {
+ public:
+ template <typename Analyser, typename TurnIt>
+ static inline void apply(Analyser & analyser, TurnIt first, TurnIt last)
+ {
+ if ( first == last )
+ return;
+
+ for_preceding_rings(analyser, *first);
+ //analyser.per_turn(*first);
+
+ TurnIt prev = first;
+ for ( ++first ; first != last ; ++first, ++prev )
+ {
+ // same multi
+ if ( prev->operations[OpId].seg_id.multi_index
+ == first->operations[OpId].seg_id.multi_index )
+ {
+ // same ring
+ if ( prev->operations[OpId].seg_id.ring_index
+ == first->operations[OpId].seg_id.ring_index )
+ {
+ //analyser.per_turn(*first);
+ }
+ // same multi, next ring
+ else
+ {
+ //analyser.end_ring(*prev);
+ analyser.turns(prev, first);
+
+ //if ( prev->operations[OpId].seg_id.ring_index + 1
+ // < first->operations[OpId].seg_id.ring_index)
+ {
+ for_no_turns_rings(analyser,
+ *first,
+ prev->operations[OpId].seg_id.ring_index + 1,
+ first->operations[OpId].seg_id.ring_index);
+ }
+
+ //analyser.per_turn(*first);
+ }
+ }
+ // next multi
+ else
+ {
+ //analyser.end_ring(*prev);
+ analyser.turns(prev, first);
+ for_following_rings(analyser, *prev);
+ for_preceding_rings(analyser, *first);
+ //analyser.per_turn(*first);
+ }
+
+ if ( analyser.interrupt )
+ {
+ return;
+ }
+ }
+
+ //analyser.end_ring(*prev);
+ analyser.turns(prev, first); // first == last
+ for_following_rings(analyser, *prev);
+ }
+
+ private:
+ template <typename Analyser, typename Turn>
+ static inline void for_preceding_rings(Analyser & analyser, Turn const& turn)
+ {
+ segment_identifier const& seg_id = turn.operations[OpId].seg_id;
+
+ for_no_turns_rings(analyser, turn, -1, seg_id.ring_index);
+ }
+
+ template <typename Analyser, typename Turn>
+ static inline void for_following_rings(Analyser & analyser, Turn const& turn)
+ {
+ segment_identifier const& seg_id = turn.operations[OpId].seg_id;
+
+ int count = boost::numeric_cast<int>(
+ geometry::num_interior_rings(
+ detail::single_geometry(analyser.geometry, seg_id)));
+
+ for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count);
+ }
+
+ template <typename Analyser, typename Turn>
+ static inline void for_no_turns_rings(Analyser & analyser, Turn const& turn, int first, int last)
+ {
+ segment_identifier seg_id = turn.operations[OpId].seg_id;
+
+ for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index )
+ {
+ analyser.no_turns(seg_id);
+ }
+ }
+ };
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp
new file mode 100644
index 0000000000..f98c3e9b82
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/boundary_checker.hpp
@@ -0,0 +1,134 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Oracle and/or its affiliates.
+
+// 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_BOUNDARY_CHECKER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
+
+#include <boost/geometry/util/range.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+enum boundary_query { boundary_front, boundary_back, boundary_any };
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+class boundary_checker {};
+
+template <typename Geometry>
+class boundary_checker<Geometry, linestring_tag>
+{
+ typedef typename point_type<Geometry>::type point_type;
+
+public:
+ boundary_checker(Geometry const& g)
+ : has_boundary( boost::size(g) >= 2
+ && !detail::equals::equals_point_point(range::front(g), range::back(g)) )
+ , geometry(g)
+ {}
+
+ template <boundary_query BoundaryQuery>
+ bool is_endpoint_boundary(point_type const& pt) const
+ {
+ boost::ignore_unused_variable_warning(pt);
+#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
+ // may give false positives for INT
+ BOOST_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
+ && detail::equals::equals_point_point(pt, range::front(geometry))
+ || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
+ && detail::equals::equals_point_point(pt, range::back(geometry)) );
+#endif
+ return has_boundary;
+ }
+
+private:
+ bool has_boundary;
+ Geometry const& geometry;
+};
+
+template <typename Geometry>
+class boundary_checker<Geometry, multi_linestring_tag>
+{
+ typedef typename point_type<Geometry>::type point_type;
+
+public:
+ boundary_checker(Geometry const& g)
+ : is_filled(false), geometry(g)
+ {}
+
+ // First call O(NlogN)
+ // Each next call O(logN)
+ template <boundary_query BoundaryQuery>
+ bool is_endpoint_boundary(point_type const& pt) const
+ {
+ typedef typename boost::range_size<Geometry>::type size_type;
+ size_type multi_count = boost::size(geometry);
+
+ if ( multi_count < 1 )
+ return false;
+
+ if ( ! is_filled )
+ {
+ //boundary_points.clear();
+ boundary_points.reserve(multi_count * 2);
+
+ typedef typename boost::range_iterator<Geometry const>::type multi_iterator;
+ for ( multi_iterator it = boost::begin(geometry) ;
+ it != boost::end(geometry) ; ++ it )
+ {
+ // empty or point - no boundary
+ if ( boost::size(*it) < 2 )
+ continue;
+
+ // linear ring or point - no boundary
+ if ( equals::equals_point_point(range::front(*it), range::back(*it)) )
+ continue;
+
+ boundary_points.push_back(range::front(*it));
+ boundary_points.push_back(range::back(*it));
+ }
+
+ std::sort(boundary_points.begin(), boundary_points.end(), geometry::less<point_type>());
+
+ is_filled = true;
+ }
+
+ std::size_t equal_points_count
+ = boost::size(
+ std::equal_range(boundary_points.begin(),
+ boundary_points.end(),
+ pt,
+ geometry::less<point_type>())
+ );
+
+ return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
+ }
+
+private:
+ mutable bool is_filled;
+ // TODO: store references/pointers instead of points?
+ mutable std::vector<point_type> boundary_points;
+
+ Geometry const& geometry;
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
new file mode 100644
index 0000000000..78fa03798d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
@@ -0,0 +1,401 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_FOLLOW_HELPERS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
+
+#include <boost/geometry/util/range.hpp>
+//#include <boost/geometry/algorithms/detail/sub_range.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// NOTE: This iterates through single geometries for which turns were not generated.
+// It doesn't mean that the geometry is disjoint, only that no turns were detected.
+
+template <std::size_t OpId,
+ typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type,
+ bool IsMulti = boost::is_base_of<multi_tag, Tag>::value
+>
+struct for_each_disjoint_geometry_if
+ : public not_implemented<Tag>
+{};
+
+template <std::size_t OpId, typename Geometry, typename Tag>
+struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false>
+{
+ template <typename TurnIt, typename Pred>
+ static inline bool apply(TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ Pred & pred)
+ {
+ if ( first != last )
+ return false;
+ pred(geometry);
+ return true;
+ }
+};
+
+template <std::size_t OpId, typename Geometry, typename Tag>
+struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
+{
+ template <typename TurnIt, typename Pred>
+ static inline bool apply(TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ Pred & pred)
+ {
+ if ( first != last )
+ return for_turns(first, last, geometry, pred);
+ else
+ return for_empty(geometry, pred);
+ }
+
+ template <typename Pred>
+ static inline bool for_empty(Geometry const& geometry,
+ Pred & pred)
+ {
+ typedef typename boost::range_iterator<Geometry const>::type iterator;
+
+ // O(N)
+ // check predicate for each contained geometry without generated turn
+ for ( iterator it = boost::begin(geometry) ;
+ it != boost::end(geometry) ; ++it )
+ {
+ bool cont = pred(*it);
+ if ( !cont )
+ break;
+ }
+
+ return !boost::empty(geometry);
+ }
+
+ template <typename TurnIt, typename Pred>
+ static inline bool for_turns(TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ Pred & pred)
+ {
+ BOOST_ASSERT(first != last);
+
+ const std::size_t count = boost::size(geometry);
+ boost::ignore_unused_variable_warning(count);
+
+ // O(I)
+ // gather info about turns generated for contained geometries
+ std::vector<bool> detected_intersections(count, false);
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ int multi_index = it->operations[OpId].seg_id.multi_index;
+ BOOST_ASSERT(multi_index >= 0);
+ std::size_t index = static_cast<std::size_t>(multi_index);
+ BOOST_ASSERT(index < count);
+ detected_intersections[index] = true;
+ }
+
+ bool found = false;
+
+ // O(N)
+ // check predicate for each contained geometry without generated turn
+ for ( std::vector<bool>::iterator it = detected_intersections.begin() ;
+ it != detected_intersections.end() ; ++it )
+ {
+ // if there were no intersections for this multi_index
+ if ( *it == false )
+ {
+ found = true;
+ bool cont = pred(range::at(geometry,
+ std::distance(detected_intersections.begin(), it)));
+ if ( !cont )
+ break;
+ }
+ }
+
+ return found;
+ }
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+template <typename Point>
+class point_info
+{
+public:
+ point_info() : sid_ptr(NULL), pt_ptr(NULL) {}
+ point_info(Point const& pt, segment_identifier const& sid)
+ : sid_ptr(boost::addressof(sid))
+ , pt_ptr(boost::addressof(pt))
+ {}
+ segment_identifier const& seg_id() const
+ {
+ BOOST_ASSERT(sid_ptr);
+ return *sid_ptr;
+ }
+ Point const& point() const
+ {
+ BOOST_ASSERT(pt_ptr);
+ return *pt_ptr;
+ }
+
+ //friend bool operator==(point_identifier const& l, point_identifier const& r)
+ //{
+ // return l.seg_id() == r.seg_id()
+ // && detail::equals::equals_point_point(l.point(), r.point());
+ //}
+
+private:
+ const segment_identifier * sid_ptr;
+ const Point * pt_ptr;
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+class same_single
+{
+public:
+ same_single(segment_identifier const& sid)
+ : sid_ptr(boost::addressof(sid))
+ {}
+
+ bool operator()(segment_identifier const& sid) const
+ {
+ return sid.multi_index == sid_ptr->multi_index;
+ }
+
+ template <typename Point>
+ bool operator()(point_info<Point> const& pid) const
+ {
+ return operator()(pid.seg_id());
+ }
+
+private:
+ const segment_identifier * sid_ptr;
+};
+
+class same_ring
+{
+public:
+ same_ring(segment_identifier const& sid)
+ : sid_ptr(boost::addressof(sid))
+ {}
+
+ bool operator()(segment_identifier const& sid) const
+ {
+ return sid.multi_index == sid_ptr->multi_index
+ && sid.ring_index == sid_ptr->ring_index;
+ }
+
+private:
+ const segment_identifier * sid_ptr;
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+template <typename SameRange = same_single>
+class segment_watcher
+{
+public:
+ segment_watcher()
+ : m_seg_id_ptr(NULL)
+ {}
+
+ bool update(segment_identifier const& seg_id)
+ {
+ bool result = m_seg_id_ptr == 0 || !SameRange(*m_seg_id_ptr)(seg_id);
+ m_seg_id_ptr = boost::addressof(seg_id);
+ return result;
+ }
+
+private:
+ const segment_identifier * m_seg_id_ptr;
+};
+
+// WARNING! This class stores pointers!
+// Passing a reference to local variable will result in undefined behavior!
+template <typename TurnInfo, std::size_t OpId>
+class exit_watcher
+{
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+
+ typedef typename TurnInfo::point_type point_type;
+ typedef detail::relate::point_info<point_type> point_info;
+
+public:
+ exit_watcher()
+ : m_exit_operation(overlay::operation_none)
+ , m_exit_turn_ptr(NULL)
+ {}
+
+ void enter(TurnInfo const& turn)
+ {
+ m_other_entry_points.push_back(
+ point_info(turn.point, turn.operations[other_op_id].seg_id) );
+ }
+
+ // TODO: exit_per_geometry parameter looks not very safe
+ // wrong value may be easily passed
+
+ void exit(TurnInfo const& turn, bool exit_per_geometry = true)
+ {
+ //segment_identifier const& seg_id = turn.operations[op_id].seg_id;
+ segment_identifier const& other_id = turn.operations[other_op_id].seg_id;
+ overlay::operation_type exit_op = turn.operations[op_id].operation;
+
+ typedef typename std::vector<point_info>::iterator point_iterator;
+ // search for the entry point in the same range of other geometry
+ point_iterator entry_it = std::find_if(m_other_entry_points.begin(),
+ m_other_entry_points.end(),
+ same_single(other_id));
+
+ // this end point has corresponding entry point
+ if ( entry_it != m_other_entry_points.end() )
+ {
+ // erase the corresponding entry point
+ m_other_entry_points.erase(entry_it);
+
+ if ( exit_per_geometry || m_other_entry_points.empty() )
+ {
+ // here we know that we possibly left LS
+ // we must still check if we didn't get back on the same point
+ m_exit_operation = exit_op;
+ m_exit_turn_ptr = boost::addressof(turn);
+ }
+ }
+ }
+
+ bool is_outside() const
+ {
+ // if we didn't entered anything in the past, we're outside
+ return m_other_entry_points.empty();
+ }
+
+ bool is_outside(TurnInfo const& turn) const
+ {
+ return m_other_entry_points.empty()
+ || std::find_if(m_other_entry_points.begin(),
+ m_other_entry_points.end(),
+ same_single(
+ turn.operations[other_op_id].seg_id))
+ == m_other_entry_points.end();
+ }
+
+ overlay::operation_type get_exit_operation() const
+ {
+ return m_exit_operation;
+ }
+
+ point_type const& get_exit_point() const
+ {
+ BOOST_ASSERT(m_exit_operation != overlay::operation_none);
+ BOOST_ASSERT(m_exit_turn_ptr);
+ return m_exit_turn_ptr->point;
+ }
+
+ TurnInfo const& get_exit_turn() const
+ {
+ BOOST_ASSERT(m_exit_operation != overlay::operation_none);
+ BOOST_ASSERT(m_exit_turn_ptr);
+ return *m_exit_turn_ptr;
+ }
+
+ void reset_detected_exit()
+ {
+ m_exit_operation = overlay::operation_none;
+ }
+
+ void reset()
+ {
+ m_exit_operation = overlay::operation_none;
+ m_other_entry_points.clear();
+ }
+
+private:
+ overlay::operation_type m_exit_operation;
+ const TurnInfo * m_exit_turn_ptr;
+ std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector?
+};
+
+template <std::size_t OpId, typename Turn>
+inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn)
+{
+ segment_identifier const& prev_seg_id = prev_turn.operations[OpId].seg_id;
+ segment_identifier const& curr_seg_id = curr_turn.operations[OpId].seg_id;
+
+ if ( prev_seg_id.multi_index != curr_seg_id.multi_index
+ || prev_seg_id.ring_index != curr_seg_id.ring_index )
+ {
+ return false;
+ }
+
+ // TODO: will this work if between segments there will be some number of degenerated ones?
+
+ if ( prev_seg_id.segment_index != curr_seg_id.segment_index
+ && ( ! curr_turn.operations[OpId].fraction.is_zero()
+ || prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) )
+ {
+ return false;
+ }
+
+ return detail::equals::equals_point_point(prev_turn.point, curr_turn.point);
+}
+
+template <boundary_query BoundaryQuery,
+ typename Point,
+ typename BoundaryChecker>
+static inline bool is_endpoint_on_boundary(Point const& pt,
+ BoundaryChecker & boundary_checker)
+{
+ return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt);
+}
+
+template <boundary_query BoundaryQuery,
+ typename IntersectionPoint,
+ typename OperationInfo,
+ typename BoundaryChecker>
+static inline bool is_ip_on_boundary(IntersectionPoint const& ip,
+ OperationInfo const& operation_info,
+ BoundaryChecker & boundary_checker,
+ segment_identifier const& seg_id)
+{
+ boost::ignore_unused_variable_warning(seg_id);
+
+ bool res = false;
+
+ // IP on the last point of the linestring
+ if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
+ && operation_info.position == overlay::position_back )
+ {
+ // check if this point is a boundary
+ res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
+ }
+ // IP on the last point of the linestring
+ else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
+ && operation_info.position == overlay::position_front )
+ {
+ // check if this point is a boundary
+ res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip);
+ }
+
+ return res;
+}
+
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
diff --git a/boost/geometry/algorithms/detail/relate/less.hpp b/boost/geometry/algorithms/detail/relate/less.hpp
new file mode 100644
index 0000000000..3f11d4e87d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/less.hpp
@@ -0,0 +1,79 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// 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.
+
+// 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_LESS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace relate {
+
+// TODO: Integrate it with geometry::less?
+
+template <typename Point1,
+ typename Point2,
+ std::size_t I = 0,
+ std::size_t D = geometry::dimension<Point1>::value>
+struct less
+{
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ typename geometry::coordinate_type<Point1>::type
+ cleft = geometry::get<I>(left);
+ typename geometry::coordinate_type<Point2>::type
+ cright = geometry::get<I>(right);
+
+ if ( geometry::math::equals(cleft, cright) )
+ {
+ return less<Point1, Point2, I + 1, D>::apply(left, right);
+ }
+ else
+ {
+ return cleft < cright;
+ }
+ }
+};
+
+template <typename Point1, typename Point2, std::size_t D>
+struct less<Point1, Point2, D, D>
+{
+ static inline bool apply(Point1 const&, Point2 const&)
+ {
+ return false;
+ }
+};
+
+}} // namespace detail_dispatch::relate
+
+#endif
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+struct less
+{
+ template <typename Point1, typename Point2>
+ inline bool operator()(Point1 const& point1, Point2 const& point2) const
+ {
+ return detail_dispatch::relate::less<Point1, Point2>::apply(point1, point2);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
new file mode 100644
index 0000000000..3159ab329d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
@@ -0,0 +1,1115 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_LINEAR_AREAL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/core/topological_dimension.hpp>
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/single_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
+#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+
+#include <boost/geometry/views/detail/normalized_view.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// WARNING!
+// TODO: In the worst case calling this Pred in a loop for MultiLinestring/MultiPolygon may take O(NM)
+// Use the rtree in this case!
+
+// may be used to set IE and BE for a Linear geometry for which no turns were generated
+template <typename Geometry2, typename Result, typename BoundaryChecker, bool TransposeResult>
+class no_turns_la_linestring_pred
+{
+public:
+ no_turns_la_linestring_pred(Geometry2 const& geometry2,
+ Result & res,
+ BoundaryChecker const& boundary_checker)
+ : m_geometry2(geometry2)
+ , m_result(res)
+ , m_boundary_checker(boundary_checker)
+ , m_interrupt_flags(0)
+ {
+ if ( ! may_update<interior, interior, '1', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 1;
+ }
+
+ if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 2;
+ }
+
+ if ( ! may_update<boundary, interior, '0', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 4;
+ }
+
+ if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
+ {
+ m_interrupt_flags |= 8;
+ }
+ }
+
+ template <typename Linestring>
+ bool operator()(Linestring const& linestring)
+ {
+ std::size_t const count = boost::size(linestring);
+
+ // invalid input
+ if ( count < 2 )
+ {
+ // ignore
+ // TODO: throw an exception?
+ return true;
+ }
+
+ // if those flags are set nothing will change
+ if ( m_interrupt_flags == 0xF )
+ {
+ return false;
+ }
+
+ int const pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2);
+ //BOOST_ASSERT_MSG(pig != 0, "There should be no IPs");
+
+ if ( pig > 0 )
+ {
+ update<interior, interior, '1', TransposeResult>(m_result);
+ m_interrupt_flags |= 1;
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(m_result);
+ m_interrupt_flags |= 2;
+ }
+
+ // check if there is a boundary
+ if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set
+ && ( m_boundary_checker.template
+ is_endpoint_boundary<boundary_front>(range::front(linestring))
+ || m_boundary_checker.template
+ is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
+ {
+ if ( pig > 0 )
+ {
+ update<boundary, interior, '0', TransposeResult>(m_result);
+ m_interrupt_flags |= 4;
+ }
+ else
+ {
+ update<boundary, exterior, '0', TransposeResult>(m_result);
+ m_interrupt_flags |= 8;
+ }
+ }
+
+ return m_interrupt_flags != 0xF
+ && ! m_result.interrupt;
+ }
+
+private:
+ Geometry2 const& m_geometry2;
+ Result & m_result;
+ BoundaryChecker const& m_boundary_checker;
+ unsigned m_interrupt_flags;
+};
+
+// may be used to set EI and EB for an Areal geometry for which no turns were generated
+template <typename Result, bool TransposeResult>
+class no_turns_la_areal_pred
+{
+public:
+ no_turns_la_areal_pred(Result & res)
+ : m_result(res)
+ , interrupt(! may_update<interior, exterior, '2', TransposeResult>(m_result)
+ && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
+ {}
+
+ template <typename Areal>
+ bool operator()(Areal const& areal)
+ {
+ if ( interrupt )
+ {
+ return false;
+ }
+
+ // TODO:
+ // handle empty/invalid geometries in a different way than below?
+
+ typedef typename geometry::point_type<Areal>::type point_type;
+ point_type dummy;
+ bool const ok = boost::geometry::point_on_border(dummy, areal);
+
+ // TODO: for now ignore, later throw an exception?
+ if ( !ok )
+ {
+ return true;
+ }
+
+ update<interior, exterior, '2', TransposeResult>(m_result);
+ update<boundary, exterior, '1', TransposeResult>(m_result);
+
+ return false;
+ }
+
+private:
+ Result & m_result;
+ bool const interrupt;
+};
+
+// The implementation of an algorithm calculating relate() for L/A
+template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
+struct linear_areal
+{
+ // check Linear / Areal
+ BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 1
+ && topological_dimension<Geometry2>::value == 2);
+
+ static const bool interruption_enabled = true;
+
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+// TODO: If Areal geometry may have infinite size, change the following line:
+
+ // The result should be FFFFFFFFF
+ relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
+
+ if ( result.interrupt )
+ return;
+
+ // get and analyse turns
+ typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ std::vector<turn_type> turns;
+
+ interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
+
+ turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
+ if ( result.interrupt )
+ return;
+
+ boundary_checker<Geometry1> boundary_checker1(geometry1);
+ no_turns_la_linestring_pred
+ <
+ Geometry2,
+ Result,
+ boundary_checker<Geometry1>,
+ TransposeResult
+ > pred1(geometry2, result, boundary_checker1);
+ for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
+ if ( result.interrupt )
+ return;
+
+ no_turns_la_areal_pred<Result, !TransposeResult> pred2(result);
+ for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
+ if ( result.interrupt )
+ return;
+
+ if ( turns.empty() )
+ return;
+
+ // This is set here because in the case if empty Areal geometry were passed
+ // those shouldn't be set
+ relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
+ if ( result.interrupt )
+ return;
+
+ {
+ // for different multi or same ring id: x, u, i, c
+ // for same multi and different ring id: c, i, u, x
+ typedef turns::less<0, turns::less_op_linear_areal<0> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ turns_analyser<turn_type> analyser;
+ analyse_each_turn(result, analyser,
+ turns.begin(), turns.end(),
+ geometry1, geometry2,
+ boundary_checker1);
+
+ if ( result.interrupt )
+ return;
+ }
+
+ // If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings
+ if ( !interrupt_policy.is_boundary_found )
+ {
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ }
+ // Don't calculate it if it's required
+ else if ( may_update<exterior, boundary, '1', TransposeResult>(result) )
+ {
+// TODO: REVISE THIS CODE AND PROBABLY REWRITE SOME PARTS TO BE MORE HUMAN-READABLE
+// IN GENERAL IT ANALYSES THE RINGS OF AREAL GEOMETRY AND DETECTS THE ONES THAT
+// MAY OVERLAP THE INTERIOR OF LINEAR GEOMETRY (NO IPs OR NON-FAKE 'u' OPERATION)
+// NOTE: For one case std::sort may be called again to sort data by operations for data already sorted by ring index
+// In the worst case scenario the complexity will be O( NlogN + R*(N/R)log(N/R) )
+// So always should remain O(NlogN) -> for R==1 <-> 1(N/1)log(N/1), for R==N <-> N(N/N)log(N/N)
+// Some benchmarking should probably be done to check if only one std::sort should be used
+
+ // sort by multi_index and rind_index
+ std::sort(turns.begin(), turns.end(), less_ring());
+
+ typedef typename std::vector<turn_type>::iterator turn_iterator;
+
+ turn_iterator it = turns.begin();
+ segment_identifier * prev_seg_id_ptr = NULL;
+ // for each ring
+ for ( ; it != turns.end() ; )
+ {
+ // it's the next single geometry
+ if ( prev_seg_id_ptr == NULL
+ || prev_seg_id_ptr->multi_index != it->operations[1].seg_id.multi_index )
+ {
+ // if the first ring has no IPs
+ if ( it->operations[1].seg_id.ring_index > -1 )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ // if there was some previous ring
+ if ( prev_seg_id_ptr != NULL )
+ {
+ int const next_ring_index = prev_seg_id_ptr->ring_index + 1;
+ BOOST_ASSERT(next_ring_index >= 0);
+
+ // if one of the last rings of previous single geometry was ommited
+ if ( static_cast<std::size_t>(next_ring_index)
+ < geometry::num_interior_rings(
+ single_geometry(geometry2, *prev_seg_id_ptr)) )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ }
+ }
+ // if it's the same single geometry
+ else /*if ( previous_multi_index == it->operations[1].seg_id.multi_index )*/
+ {
+ // and we jumped over one of the rings
+ if ( prev_seg_id_ptr != NULL // just in case
+ && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ }
+
+ prev_seg_id_ptr = boost::addressof(it->operations[1].seg_id);
+
+ // find the next ring first iterator and check if the analysis should be performed
+ has_boundary_intersection has_boundary_inters;
+ turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters);
+
+ // if there is no 1d overlap with the boundary
+ if ( !has_boundary_inters.result )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ // else there is 1d overlap with the boundary so we must analyse the boundary
+ else
+ {
+ // u, c
+ typedef turns::less<1, turns::less_op_areal_linear<1> > less;
+ std::sort(it, next, less());
+
+ // analyse
+ areal_boundary_analyser<turn_type> analyser;
+ for ( turn_iterator rit = it ; rit != next ; ++rit )
+ {
+ // if the analyser requests, break the search
+ if ( !analyser.apply(it, rit, next) )
+ break;
+ }
+
+ // if the boundary of Areal goes out of the Linear
+ if ( analyser.is_union_detected )
+ {
+ // we can be sure that the boundary of Areal overlaps the exterior of Linear
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ break;
+ }
+ }
+
+ it = next;
+ }
+
+ // if there was some previous ring
+ if ( prev_seg_id_ptr != NULL )
+ {
+ int const next_ring_index = prev_seg_id_ptr->ring_index + 1;
+ BOOST_ASSERT(next_ring_index >= 0);
+
+ // if one of the last rings of previous single geometry was ommited
+ if ( static_cast<std::size_t>(next_ring_index)
+ < geometry::num_interior_rings(
+ single_geometry(geometry2, *prev_seg_id_ptr)) )
+ {
+ // we can be sure that the exterior overlaps the boundary
+ relate::set<exterior, boundary, '1', TransposeResult>(result);
+ }
+ }
+ }
+ }
+
+ // interrupt policy which may be passed to get_turns to interrupt the analysis
+ // based on the info in the passed result/mask
+ template <typename Areal, typename Result>
+ class interrupt_policy_linear_areal
+ {
+ public:
+ static bool const enabled = true;
+
+ interrupt_policy_linear_areal(Areal const& areal, Result & result)
+ : m_result(result), m_areal(areal)
+ , is_boundary_found(false)
+ {}
+
+// TODO: since we update result for some operations here, we may not do it in the analyser!
+
+ template <typename Range>
+ inline bool apply(Range const& turns)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ {
+ if ( it->operations[0].operation == overlay::operation_intersection )
+ {
+ bool const no_interior_rings
+ = geometry::num_interior_rings(
+ single_geometry(m_areal, it->operations[1].seg_id)) == 0;
+
+ // WARNING! THIS IS TRUE ONLY IF THE POLYGON IS SIMPLE!
+ // OR WITHOUT INTERIOR RINGS (AND OF COURSE VALID)
+ if ( no_interior_rings )
+ update<interior, interior, '1', TransposeResult>(m_result);
+ }
+ else if ( it->operations[0].operation == overlay::operation_continue )
+ {
+ update<interior, boundary, '1', TransposeResult>(m_result);
+ is_boundary_found = true;
+ }
+ else if ( ( it->operations[0].operation == overlay::operation_union
+ || it->operations[0].operation == overlay::operation_blocked )
+ && it->operations[0].position == overlay::position_middle )
+ {
+// TODO: here we could also check the boundaries and set BB at this point
+ update<interior, boundary, '0', TransposeResult>(m_result);
+ }
+ }
+
+ return m_result.interrupt;
+ }
+
+ private:
+ Result & m_result;
+ Areal const& m_areal;
+
+ public:
+ bool is_boundary_found;
+ };
+
+ // This analyser should be used like Input or SinglePass Iterator
+ // IMPORTANT! It should be called also for the end iterator - last
+ template <typename TurnInfo>
+ class turns_analyser
+ {
+ typedef typename TurnInfo::point_type turn_point_type;
+
+ static const std::size_t op_id = 0;
+ static const std::size_t other_op_id = 1;
+
+ public:
+ turns_analyser()
+ : m_previous_turn_ptr(NULL)
+ , m_previous_operation(overlay::operation_none)
+ , m_boundary_counter(0)
+ , m_interior_detected(false)
+ , m_first_interior_other_id_ptr(NULL)
+ {}
+
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker>
+ void apply(Result & res, TurnIt it,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker)
+ {
+ overlay::operation_type op = it->operations[op_id].operation;
+
+ if ( op != overlay::operation_union
+ && op != overlay::operation_intersection
+ && op != overlay::operation_blocked
+ && op != overlay::operation_continue ) // operation_boundary / operation_boundary_intersection
+ {
+ return;
+ }
+
+ segment_identifier const& seg_id = it->operations[op_id].seg_id;
+ segment_identifier const& other_id = it->operations[other_op_id].seg_id;
+
+ const bool first_in_range = m_seg_watcher.update(seg_id);
+
+ // handle possible exit
+ bool fake_enter_detected = false;
+ if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
+ {
+ // real exit point - may be multiple
+ // we know that we entered and now we exit
+ if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ m_exit_watcher.reset_detected_exit();
+
+ // not the last IP
+ update<interior, exterior, '1', TransposeResult>(res);
+ }
+ // fake exit point, reset state
+ else if ( op == overlay::operation_intersection
+ || op == overlay::operation_continue ) // operation_boundary
+ {
+ m_exit_watcher.reset_detected_exit();
+ fake_enter_detected = true;
+ }
+ }
+ else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
+ {
+ // ignore multiple BLOCKs
+ if ( op == overlay::operation_blocked )
+ return;
+
+ if ( ( op == overlay::operation_intersection
+ || op == overlay::operation_continue )
+ && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ fake_enter_detected = true;
+ }
+
+ m_exit_watcher.reset_detected_exit();
+ }
+
+// NOTE: THE WHOLE m_interior_detected HANDLING IS HERE BECAUSE WE CAN'T EFFICIENTLY SORT TURNS (CORRECTLY)
+// BECAUSE THE SAME IP MAY BE REPRESENTED BY TWO SEGMENTS WITH DIFFERENT DISTANCES
+// IT WOULD REQUIRE THE CALCULATION OF MAX DISTANCE
+// TODO: WE COULD GET RID OF THE TEST IF THE DISTANCES WERE NORMALIZED
+
+// TODO: THIS IS POTENTIALLY ERROREOUS!
+// THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS
+// IT WOULD GIVE WRONG RESULTS E.G.
+// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u'
+
+ // handle the interior overlap
+ if ( m_interior_detected )
+ {
+ // real interior overlap
+ if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ {
+ update<interior, interior, '1', TransposeResult>(res);
+ m_interior_detected = false;
+ }
+ // fake interior overlap
+ else if ( op == overlay::operation_continue )
+ {
+ m_interior_detected = false;
+ }
+ else if ( op == overlay::operation_union )
+ {
+// TODO: this probably is not a good way of handling the interiors/enters
+// the solution similar to exit_watcher would be more robust
+// all enters should be kept and handled.
+// maybe integrate it with the exit_watcher -> enter_exit_watcher
+ if ( m_first_interior_other_id_ptr
+ && m_first_interior_other_id_ptr->multi_index == other_id.multi_index )
+ {
+ m_interior_detected = false;
+ }
+ }
+ }
+
+ // i/u, c/u
+ if ( op == overlay::operation_intersection
+ || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection
+ {
+ bool no_enters_detected = m_exit_watcher.is_outside();
+ m_exit_watcher.enter(*it);
+
+ if ( op == overlay::operation_intersection )
+ {
+ if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
+ --m_boundary_counter;
+
+ if ( m_boundary_counter == 0 )
+ {
+ // interiors overlaps
+ //update<interior, interior, '1', TransposeResult>(res);
+
+// TODO: think about the implementation of the more robust version
+// this way only the first enter will be handled
+ if ( !m_interior_detected )
+ {
+ // don't update now
+ // we might enter a boundary of some other ring on the same IP
+ m_interior_detected = true;
+ m_first_interior_other_id_ptr = boost::addressof(other_id);
+ }
+ }
+ }
+ else // operation_boundary
+ {
+ // don't add to the count for all met boundaries
+ // only if this is the "new" boundary
+ if ( first_in_range || !it->operations[op_id].is_collinear )
+ ++m_boundary_counter;
+
+ update<interior, boundary, '1', TransposeResult>(res);
+ }
+
+ bool const this_b
+ = is_ip_on_boundary<boundary_front>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+ // going inside on boundary point
+ if ( this_b )
+ {
+ update<boundary, boundary, '0', TransposeResult>(res);
+ }
+ // going inside on non-boundary point
+ else
+ {
+ update<interior, boundary, '0', TransposeResult>(res);
+
+ // if we didn't enter in the past, we were outside
+ if ( no_enters_detected
+ && ! fake_enter_detected
+ && it->operations[op_id].position != overlay::position_front )
+ {
+// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
+ bool const from_inside = first_in_range
+ && calculate_from_inside(geometry,
+ other_geometry,
+ *it);
+
+ if ( from_inside )
+ update<interior, interior, '1', TransposeResult>(res);
+ else
+ update<interior, exterior, '1', TransposeResult>(res);
+
+ // if it's the first IP then the first point is outside
+ if ( first_in_range )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ if ( from_inside )
+ update<boundary, interior, '0', TransposeResult>(res);
+ else
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
+ }
+ }
+ }
+ // u/u, x/u
+ else if ( op == overlay::operation_union || op == overlay::operation_blocked )
+ {
+ bool const op_blocked = op == overlay::operation_blocked;
+ bool const no_enters_detected = m_exit_watcher.is_outside()
+// TODO: is this condition ok?
+// TODO: move it into the exit_watcher?
+ && m_exit_watcher.get_exit_operation() == overlay::operation_none;
+
+ if ( op == overlay::operation_union )
+ {
+ if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
+ --m_boundary_counter;
+ }
+ else // overlay::operation_blocked
+ {
+ m_boundary_counter = 0;
+ }
+
+ // we're inside, possibly going out right now
+ if ( ! no_enters_detected )
+ {
+ if ( op_blocked
+ && it->operations[op_id].position == overlay::position_back ) // ignore spikes!
+ {
+ // check if this is indeed the boundary point
+ // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
+ if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
+ {
+ update<boundary, boundary, '0', TransposeResult>(res);
+ }
+ }
+ // union, inside, but no exit -> collinear on self-intersection point
+ // not needed since we're already inside the boundary
+ /*else if ( !exit_detected )
+ {
+ update<interior, boundary, '0', TransposeResult>(res);
+ }*/
+ }
+ // we're outside or inside and this is the first turn
+ else
+ {
+ bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+ // if current IP is on boundary of the geometry
+ if ( this_b )
+ {
+ update<boundary, boundary, '0', TransposeResult>(res);
+ }
+ // if current IP is not on boundary of the geometry
+ else
+ {
+ update<interior, boundary, '0', TransposeResult>(res);
+ }
+
+ // TODO: very similar code is used in the handling of intersection
+ if ( it->operations[op_id].position != overlay::position_front )
+ {
+// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
+ bool const first_from_inside = first_in_range
+ && calculate_from_inside(geometry,
+ other_geometry,
+ *it);
+ if ( first_from_inside )
+ {
+ update<interior, interior, '1', TransposeResult>(res);
+
+ // notify the exit_watcher that we started inside
+ m_exit_watcher.enter(*it);
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(res);
+ }
+
+ // first IP on the last segment point - this means that the first point is outside or inside
+ if ( first_in_range && ( !this_b || op_blocked ) )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ if ( first_from_inside )
+ update<boundary, interior, '0', TransposeResult>(res);
+ else
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
+ }
+ }
+
+ // if we're going along a boundary, we exit only if the linestring was collinear
+ if ( m_boundary_counter == 0
+ || it->operations[op_id].is_collinear )
+ {
+ // notify the exit watcher about the possible exit
+ m_exit_watcher.exit(*it);
+ }
+ }
+
+ // store ref to previously analysed (valid) turn
+ m_previous_turn_ptr = boost::addressof(*it);
+ // and previously analysed (valid) operation
+ m_previous_operation = op;
+ }
+
+ // it == last
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker>
+ void apply(Result & res,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& /*other_geometry*/,
+ BoundaryChecker const& boundary_checker)
+ {
+ boost::ignore_unused(first, last);
+ //BOOST_ASSERT( first != last );
+
+ // here, the possible exit is the real one
+ // we know that we entered and now we exit
+ if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
+ ||*/ m_previous_operation == overlay::operation_union
+ && !m_interior_detected )
+ {
+ // for sure
+ update<interior, exterior, '1', TransposeResult>(res);
+
+ BOOST_ASSERT(first != last);
+ BOOST_ASSERT(m_previous_turn_ptr);
+
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
+ // we might enter some Areal and didn't go out,
+ else if ( m_previous_operation == overlay::operation_intersection
+ || m_interior_detected )
+ {
+ // just in case
+ update<interior, interior, '1', TransposeResult>(res);
+ m_interior_detected = false;
+
+ BOOST_ASSERT(first != last);
+ BOOST_ASSERT(m_previous_turn_ptr);
+
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, interior, '0', TransposeResult>(res);
+ }
+ }
+
+ BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue,
+ "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)");
+
+ // Reset exit watcher before the analysis of the next Linestring
+ m_exit_watcher.reset();
+ m_boundary_counter = 0;
+ }
+
+ // check if the passed turn's segment of Linear geometry arrived
+ // from the inside or the outside of the Areal geometry
+ template <typename Turn>
+ static inline bool calculate_from_inside(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Turn const& turn)
+ {
+ if ( turn.operations[op_id].position == overlay::position_front )
+ return false;
+
+ typename sub_range_return_type<Geometry1 const>::type
+ range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
+
+ typedef detail::normalized_view<Geometry2 const> const range2_type;
+ typedef typename boost::range_iterator<range2_type>::type range2_iterator;
+ range2_type range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
+
+ BOOST_ASSERT(boost::size(range1));
+ std::size_t const s2 = boost::size(range2);
+ BOOST_ASSERT(s2 > 2);
+ std::size_t const seg_count2 = s2 - 1;
+
+ std::size_t const p_seg_ij = turn.operations[op_id].seg_id.segment_index;
+ std::size_t const q_seg_ij = turn.operations[other_op_id].seg_id.segment_index;
+
+ BOOST_ASSERT(p_seg_ij + 1 < boost::size(range1));
+ BOOST_ASSERT(q_seg_ij + 1 < s2);
+
+ point1_type const& pi = range::at(range1, p_seg_ij);
+ point2_type const& qi = range::at(range2, q_seg_ij);
+ point2_type const& qj = range::at(range2, q_seg_ij + 1);
+ point1_type qi_conv;
+ geometry::convert(qi, qi_conv);
+ bool const is_ip_qj = equals::equals_point_point(turn.point, qj);
+// TODO: test this!
+// BOOST_ASSERT(!equals::equals_point_point(turn.point, pi));
+// BOOST_ASSERT(!equals::equals_point_point(turn.point, qi));
+ point1_type new_pj;
+ geometry::convert(turn.point, new_pj);
+
+ if ( is_ip_qj )
+ {
+ std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
+// TODO: the following function should return immediately, however the worst case complexity is O(N)
+// It would be good to replace it with some O(1) mechanism
+ range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
+ boost::begin(range2) + q_seg_jk,
+ boost::end(range2));
+
+ // Will this sequence of points be always correct?
+ overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it);
+
+ return calculate_from_inside_sides(side_calc);
+ }
+ else
+ {
+ point1_type new_qj;
+ geometry::convert(turn.point, new_qj);
+
+ overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj);
+
+ return calculate_from_inside_sides(side_calc);
+ }
+ }
+
+ template <typename It>
+ static inline It find_next_non_duplicated(It first, It current, It last)
+ {
+ BOOST_ASSERT( current != last );
+
+ It it = current;
+
+ for ( ++it ; it != last ; ++it )
+ {
+ if ( !equals::equals_point_point(*current, *it) )
+ return it;
+ }
+
+ // if not found start from the beginning
+ for ( it = first ; it != current ; ++it )
+ {
+ if ( !equals::equals_point_point(*current, *it) )
+ return it;
+ }
+
+ return current;
+ }
+
+ // calculate inside or outside based on side_calc
+ // this is simplified version of a check from equal<>
+ template <typename SideCalc>
+ static inline bool calculate_from_inside_sides(SideCalc const& side_calc)
+ {
+ int const side_pk_p = side_calc.pk_wrt_p1();
+ int const side_qk_p = side_calc.qk_wrt_p1();
+ // If they turn to same side (not opposite sides)
+ if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
+ {
+ int const side_pk_q2 = side_calc.pk_wrt_q2();
+ return side_pk_q2 == -1;
+ }
+ else
+ {
+ return side_pk_p == -1;
+ }
+ }
+
+ private:
+ exit_watcher<TurnInfo, op_id> m_exit_watcher;
+ segment_watcher<same_single> m_seg_watcher;
+ TurnInfo * m_previous_turn_ptr;
+ overlay::operation_type m_previous_operation;
+ unsigned m_boundary_counter;
+ bool m_interior_detected;
+ const segment_identifier * m_first_interior_other_id_ptr;
+ };
+
+ // call analyser.apply() for each turn in range
+ // IMPORTANT! The analyser is also called for the end iterator - last
+ template <typename Result,
+ typename TurnIt,
+ typename Analyser,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker>
+ static inline void analyse_each_turn(Result & res,
+ Analyser & analyser,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker)
+ {
+ if ( first == last )
+ return;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ analyser.apply(res, it,
+ geometry, other_geometry,
+ boundary_checker);
+
+ if ( res.interrupt )
+ return;
+ }
+
+ analyser.apply(res, first, last,
+ geometry, other_geometry,
+ boundary_checker);
+ }
+
+ // less comparator comparing multi_index then ring_index
+ // may be used to sort turns by ring
+ struct less_ring
+ {
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ return left.operations[1].seg_id.multi_index < right.operations[1].seg_id.multi_index
+ || ( left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index
+ && left.operations[1].seg_id.ring_index < right.operations[1].seg_id.ring_index );
+ }
+ };
+
+ // policy/functor checking if a turn's operation is operation_continue
+ struct has_boundary_intersection
+ {
+ has_boundary_intersection()
+ : result(false) {}
+
+ template <typename Turn>
+ inline void operator()(Turn const& turn)
+ {
+ if ( turn.operations[1].operation == overlay::operation_continue )
+ result = true;
+ }
+
+ bool result;
+ };
+
+ // iterate through the range and search for the different multi_index or ring_index
+ // also call fun for each turn in the current range
+ template <typename It, typename Fun>
+ static inline It find_next_ring(It first, It last, Fun & fun)
+ {
+ if ( first == last )
+ return last;
+
+ int const multi_index = first->operations[1].seg_id.multi_index;
+ int const ring_index = first->operations[1].seg_id.ring_index;
+
+ fun(*first);
+ ++first;
+
+ for ( ; first != last ; ++first )
+ {
+ if ( multi_index != first->operations[1].seg_id.multi_index
+ || ring_index != first->operations[1].seg_id.ring_index )
+ {
+ return first;
+ }
+
+ fun(*first);
+ }
+
+ return last;
+ }
+
+ // analyser which called for turns sorted by seg/distance/operation
+ // checks if the boundary of Areal geometry really got out
+ // into the exterior of Linear geometry
+ template <typename TurnInfo>
+ class areal_boundary_analyser
+ {
+ public:
+ areal_boundary_analyser()
+ : is_union_detected(false)
+ , m_previous_turn_ptr(NULL)
+ {}
+
+ template <typename TurnIt>
+ bool apply(TurnIt /*first*/, TurnIt it, TurnIt last)
+ {
+ overlay::operation_type op = it->operations[1].operation;
+
+ if ( it != last )
+ {
+ if ( op != overlay::operation_union
+ && op != overlay::operation_continue )
+ {
+ return true;
+ }
+
+ if ( is_union_detected )
+ {
+ BOOST_ASSERT(m_previous_turn_ptr != NULL);
+ if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point) )
+ {
+ // break
+ return false;
+ }
+ else if ( op == overlay::operation_continue ) // operation_boundary
+ {
+ is_union_detected = false;
+ }
+ }
+
+ if ( op == overlay::operation_union )
+ {
+ is_union_detected = true;
+ m_previous_turn_ptr = boost::addressof(*it);
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ bool is_union_detected;
+
+ private:
+ const TurnInfo * m_previous_turn_ptr;
+ };
+};
+
+template <typename Geometry1, typename Geometry2>
+struct areal_linear
+{
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+ linear_areal<Geometry2, Geometry1, true>::apply(geometry2, geometry1, result);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp
new file mode 100644
index 0000000000..263c82de56
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp
@@ -0,0 +1,768 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/single_geometry.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
+#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+template <typename Result, typename BoundaryChecker, bool TransposeResult>
+class disjoint_linestring_pred
+{
+public:
+ disjoint_linestring_pred(Result & res,
+ BoundaryChecker const& boundary_checker)
+ : m_result(res)
+ , m_boundary_checker(boundary_checker)
+ , m_flags(0)
+ {
+ if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
+ {
+ m_flags |= 1;
+ }
+ if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
+ {
+ m_flags |= 2;
+ }
+ }
+
+ template <typename Linestring>
+ bool operator()(Linestring const& linestring)
+ {
+ if ( m_flags == 3 )
+ {
+ return false;
+ }
+
+ std::size_t const count = boost::size(linestring);
+
+ // invalid input
+ if ( count < 2 )
+ {
+ // ignore
+ // TODO: throw an exception?
+ return true;
+ }
+
+ // point-like linestring
+ if ( count == 2
+ && equals::equals_point_point(range::front(linestring),
+ range::back(linestring)) )
+ {
+ update<interior, exterior, '0', TransposeResult>(m_result);
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(m_result);
+ m_flags |= 1;
+
+ // check if there is a boundary
+ if ( m_flags < 2
+ && ( m_boundary_checker.template
+ is_endpoint_boundary<boundary_front>(range::front(linestring))
+ || m_boundary_checker.template
+ is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
+ {
+ update<boundary, exterior, '0', TransposeResult>(m_result);
+ m_flags |= 2;
+ }
+ }
+
+ return m_flags != 3
+ && ! m_result.interrupt;
+ }
+
+private:
+ Result & m_result;
+ BoundaryChecker const& m_boundary_checker;
+ unsigned m_flags;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct linear_linear
+{
+ static const bool interruption_enabled = true;
+
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Result>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
+ {
+ // The result should be FFFFFFFFF
+ relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
+ if ( result.interrupt )
+ return;
+
+ // get and analyse turns
+ typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ std::vector<turn_type> turns;
+
+ interrupt_policy_linear_linear<Result> interrupt_policy(result);
+
+ turns::get_turns
+ <
+ Geometry1,
+ Geometry2,
+ detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
+ >::apply(turns, geometry1, geometry2, interrupt_policy);
+
+ if ( result.interrupt )
+ return;
+
+ boundary_checker<Geometry1> boundary_checker1(geometry1);
+ disjoint_linestring_pred<Result, boundary_checker<Geometry1>, false> pred1(result, boundary_checker1);
+ for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
+ if ( result.interrupt )
+ return;
+
+ boundary_checker<Geometry2> boundary_checker2(geometry2);
+ disjoint_linestring_pred<Result, boundary_checker<Geometry2>, true> pred2(result, boundary_checker2);
+ for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
+ if ( result.interrupt )
+ return;
+
+ if ( turns.empty() )
+ return;
+
+ // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point
+ // for linear geometries union operation must be detected which I guess would be quite often
+
+ if ( may_update<interior, interior, '1'>(result)
+ || may_update<interior, boundary, '0'>(result)
+ || may_update<interior, exterior, '1'>(result)
+ || may_update<boundary, interior, '0'>(result)
+ || may_update<boundary, boundary, '0'>(result)
+ || may_update<boundary, exterior, '0'>(result) )
+ {
+ typedef turns::less<0, turns::less_op_linear_linear<0> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ turns_analyser<turn_type, 0> analyser;
+ analyse_each_turn(result, analyser,
+ turns.begin(), turns.end(),
+ geometry1, geometry2,
+ boundary_checker1, boundary_checker2);
+ }
+
+ if ( result.interrupt )
+ return;
+
+ if ( may_update<interior, interior, '1', true>(result)
+ || may_update<interior, boundary, '0', true>(result)
+ || may_update<interior, exterior, '1', true>(result)
+ || may_update<boundary, interior, '0', true>(result)
+ || may_update<boundary, boundary, '0', true>(result)
+ || may_update<boundary, exterior, '0', true>(result) )
+ {
+ typedef turns::less<1, turns::less_op_linear_linear<1> > less;
+ std::sort(turns.begin(), turns.end(), less());
+
+ turns_analyser<turn_type, 1> analyser;
+ analyse_each_turn(result, analyser,
+ turns.begin(), turns.end(),
+ geometry2, geometry1,
+ boundary_checker2, boundary_checker1);
+ }
+ }
+
+ template <typename Result>
+ class interrupt_policy_linear_linear
+ {
+ public:
+ static bool const enabled = true;
+
+ explicit interrupt_policy_linear_linear(Result & result)
+ : m_result(result)
+ {}
+
+// TODO: since we update result for some operations here, we may not do it in the analyser!
+
+ template <typename Range>
+ inline bool apply(Range const& turns)
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ {
+ if ( it->operations[0].operation == overlay::operation_intersection
+ || it->operations[1].operation == overlay::operation_intersection )
+ {
+ update<interior, interior, '1'>(m_result);
+ }
+ else if ( ( it->operations[0].operation == overlay::operation_union
+ || it->operations[0].operation == overlay::operation_blocked
+ || it->operations[1].operation == overlay::operation_union
+ || it->operations[1].operation == overlay::operation_blocked )
+ && it->operations[0].position == overlay::position_middle
+ && it->operations[1].position == overlay::position_middle )
+ {
+// TODO: here we could also check the boundaries and set IB,BI,BB at this point
+ update<interior, interior, '0'>(m_result);
+ }
+ }
+
+ return m_result.interrupt;
+ }
+
+ private:
+ Result & m_result;
+ };
+
+ // This analyser should be used like Input or SinglePass Iterator
+ template <typename TurnInfo, std::size_t OpId>
+ class turns_analyser
+ {
+ typedef typename TurnInfo::point_type turn_point_type;
+
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static const bool transpose_result = OpId != 0;
+
+ public:
+ turns_analyser()
+ : m_previous_turn_ptr(NULL)
+ , m_previous_operation(overlay::operation_none)
+ , m_degenerated_turn_ptr(NULL)
+ {}
+
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ void apply(Result & res, TurnIt it,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& other_boundary_checker)
+ {
+ overlay::operation_type const op = it->operations[op_id].operation;
+
+ segment_identifier const& seg_id = it->operations[op_id].seg_id;
+ segment_identifier const& other_id = it->operations[other_op_id].seg_id;
+
+ bool const first_in_range = m_seg_watcher.update(seg_id);
+
+ if ( op != overlay::operation_union
+ && op != overlay::operation_intersection
+ && op != overlay::operation_blocked )
+ {
+ // degenerated turn
+ if ( op == overlay::operation_continue
+ && it->method == overlay::method_none
+ && m_exit_watcher.is_outside(*it)
+ /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none
+ || ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ )
+ {
+ // TODO: rewrite the above condition
+
+ // WARNING! For spikes the above condition may be TRUE
+ // When degenerated turns are be marked in a different way than c,c/c
+ // different condition will be checked
+
+ handle_degenerated(res, *it,
+ geometry, other_geometry,
+ boundary_checker, other_boundary_checker,
+ first_in_range);
+
+ // TODO: not elegant solution! should be rewritten.
+ if ( it->operations[op_id].position == overlay::position_back )
+ {
+ m_previous_operation = overlay::operation_blocked;
+ m_exit_watcher.reset_detected_exit();
+ }
+ }
+
+ return;
+ }
+
+ // reset
+ m_degenerated_turn_ptr = NULL;
+
+ // handle possible exit
+ bool fake_enter_detected = false;
+ if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
+ {
+ // real exit point - may be multiple
+ // we know that we entered and now we exit
+ if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ m_exit_watcher.reset_detected_exit();
+
+ // not the last IP
+ update<interior, exterior, '1', transpose_result>(res);
+ }
+ // fake exit point, reset state
+ else if ( op == overlay::operation_intersection )
+ {
+ m_exit_watcher.reset_detected_exit();
+ fake_enter_detected = true;
+ }
+ }
+ else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
+ {
+ // ignore multiple BLOCKs
+ if ( op == overlay::operation_blocked )
+ return;
+
+ if ( op == overlay::operation_intersection
+ && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
+ {
+ fake_enter_detected = true;
+ }
+
+ m_exit_watcher.reset_detected_exit();
+ }
+
+ // i/i, i/x, i/u
+ if ( op == overlay::operation_intersection )
+ {
+ bool const was_outside = m_exit_watcher.is_outside();
+ m_exit_watcher.enter(*it);
+
+ // interiors overlaps
+ update<interior, interior, '1', transpose_result>(res);
+
+ bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes!
+ && is_ip_on_boundary<boundary_front>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+
+ // going inside on boundary point
+ // may be front only
+ if ( this_b )
+ {
+ // may be front and back
+ bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[other_op_id],
+ other_boundary_checker,
+ other_id);
+
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<boundary, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ }
+ // going inside on non-boundary point
+ else
+ {
+ // if we didn't enter in the past, we were outside
+ if ( was_outside
+ && ! fake_enter_detected
+ && it->operations[op_id].position != overlay::position_front )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ // if it's the first IP then the first point is outside
+ if ( first_in_range )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+ }
+ }
+ // u/i, u/u, u/x, x/i, x/u, x/x
+ else if ( op == overlay::operation_union || op == overlay::operation_blocked )
+ {
+ // TODO: is exit watcher still needed?
+ // couldn't is_collinear and some going inside counter be used instead?
+
+ bool const is_collinear = it->operations[op_id].is_collinear;
+ bool const was_outside = m_exit_watcher.is_outside()
+ && m_exit_watcher.get_exit_operation() == overlay::operation_none;
+// TODO: move the above condition into the exit_watcher?
+
+ // to exit we must be currently inside and the current segment must be collinear
+ if ( !was_outside && is_collinear )
+ {
+ m_exit_watcher.exit(*it, false);
+ }
+
+ bool const op_blocked = op == overlay::operation_blocked;
+
+ // we're inside and going out from inside
+ // possibly going out right now
+ if ( ! was_outside && is_collinear )
+ {
+ if ( op_blocked
+ && it->operations[op_id].position == overlay::position_back ) // ignore spikes!
+ {
+ // check if this is indeed the boundary point
+ // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
+ if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
+ {
+ // may be front and back
+ bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[other_op_id],
+ other_boundary_checker,
+ other_id);
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<boundary, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ }
+ }
+ }
+ // we're outside or intersects some segment from the outside
+ else
+ {
+ // if we are truly outside
+ if ( was_outside
+ && it->operations[op_id].position != overlay::position_front
+ /*&& !is_collinear*/ )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+ }
+
+ // boundaries don't overlap - just an optimization
+ if ( it->method == overlay::method_crosses )
+ {
+ // the L1 is going from one side of the L2 to the other through the point
+ update<interior, interior, '0', transpose_result>(res);
+
+ // it's the first point in range
+ if ( first_in_range )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+ // method other than crosses, check more conditions
+ else
+ {
+ bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[op_id],
+ boundary_checker,
+ seg_id);
+
+ bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
+ it->operations[other_op_id],
+ other_boundary_checker,
+ other_id);
+
+ // if current IP is on boundary of the geometry
+ if ( this_b )
+ {
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<boundary, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ }
+ // if current IP is not on boundary of the geometry
+ else
+ {
+ // it's also the boundary of the other geometry
+ if ( other_b )
+ {
+ update<interior, boundary, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<interior, interior, '0', transpose_result>(res);
+ }
+ }
+
+ // first IP on the last segment point - this means that the first point is outside
+ if ( first_in_range
+ && ( !this_b || op_blocked )
+ && was_outside
+ && it->operations[op_id].position != overlay::position_front
+ /*&& !is_collinear*/ )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(sub_range(geometry, seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the first point
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+
+ }
+ }
+ }
+
+ // store ref to previously analysed (valid) turn
+ m_previous_turn_ptr = boost::addressof(*it);
+ // and previously analysed (valid) operation
+ m_previous_operation = op;
+ }
+
+ // Called for last
+ template <typename Result,
+ typename TurnIt,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ void apply(Result & res,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& /*other_geometry*/,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& /*other_boundary_checker*/)
+ {
+ boost::ignore_unused(first, last);
+ //BOOST_ASSERT( first != last );
+
+ // here, the possible exit is the real one
+ // we know that we entered and now we exit
+ if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
+ ||*/ m_previous_operation == overlay::operation_union
+ || m_degenerated_turn_ptr )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ BOOST_ASSERT(first != last);
+
+ const TurnInfo * turn_ptr = NULL;
+ if ( m_degenerated_turn_ptr )
+ turn_ptr = m_degenerated_turn_ptr;
+ else if ( m_previous_turn_ptr )
+ turn_ptr = m_previous_turn_ptr;
+
+ if ( turn_ptr )
+ {
+ segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id;
+
+ //BOOST_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id)));
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+
+ // Just in case,
+ // reset exit watcher before the analysis of the next Linestring
+ // note that if there are some enters stored there may be some error above
+ m_exit_watcher.reset();
+
+ m_previous_turn_ptr = NULL;
+ m_previous_operation = overlay::operation_none;
+ m_degenerated_turn_ptr = NULL;
+ }
+
+ template <typename Result,
+ typename Turn,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ void handle_degenerated(Result & res,
+ Turn const& turn,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& /*other_boundary_checker*/,
+ bool first_in_range)
+ {
+ typename detail::single_geometry_return_type<Geometry const>::type
+ ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id);
+ typename detail::single_geometry_return_type<OtherGeometry const>::type
+ ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id);
+
+ // only one of those should be true:
+
+ if ( turn.operations[op_id].position == overlay::position_front )
+ {
+ // valid, point-sized
+ if ( boost::size(ls2_ref) == 2 )
+ {
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker);
+
+ if ( front_b )
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<interior, interior, '0', transpose_result>(res);
+ }
+
+ // operation 'c' should be last for the same IP so we know that the next point won't be the same
+ update<interior, exterior, '1', transpose_result>(res);
+
+ m_degenerated_turn_ptr = boost::addressof(turn);
+ }
+ }
+ else if ( turn.operations[op_id].position == overlay::position_back )
+ {
+ // valid, point-sized
+ if ( boost::size(ls2_ref) == 2 )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker);
+
+ if ( back_b )
+ {
+ update<boundary, interior, '0', transpose_result>(res);
+ }
+ else
+ {
+ update<interior, interior, '0', transpose_result>(res);
+ }
+
+ if ( first_in_range )
+ {
+ //BOOST_ASSERT(!boost::empty(ls1_ref));
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(ls1_ref), boundary_checker);
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+ }
+ }
+ else if ( turn.operations[op_id].position == overlay::position_middle
+ && turn.operations[other_op_id].position == overlay::position_middle )
+ {
+ update<interior, interior, '0', transpose_result>(res);
+
+ // here we don't know which one is degenerated
+
+ bool const is_point1 = boost::size(ls1_ref) == 2
+ && equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref));
+ bool const is_point2 = boost::size(ls2_ref) == 2
+ && equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref));
+
+ // if the second one is degenerated
+ if ( !is_point1 && is_point2 )
+ {
+ update<interior, exterior, '1', transpose_result>(res);
+
+ if ( first_in_range )
+ {
+ //BOOST_ASSERT(!boost::empty(ls1_ref));
+ bool const front_b = is_endpoint_on_boundary<boundary_front>(
+ range::front(ls1_ref), boundary_checker);
+ if ( front_b )
+ {
+ update<boundary, exterior, '0', transpose_result>(res);
+ }
+ }
+
+ m_degenerated_turn_ptr = boost::addressof(turn);
+ }
+ }
+
+ // NOTE: other.position == front and other.position == back
+ // will be handled later, for the other geometry
+ }
+
+ private:
+ exit_watcher<TurnInfo, OpId> m_exit_watcher;
+ segment_watcher<same_single> m_seg_watcher;
+ const TurnInfo * m_previous_turn_ptr;
+ overlay::operation_type m_previous_operation;
+ const TurnInfo * m_degenerated_turn_ptr;
+ };
+
+ template <typename Result,
+ typename TurnIt,
+ typename Analyser,
+ typename Geometry,
+ typename OtherGeometry,
+ typename BoundaryChecker,
+ typename OtherBoundaryChecker>
+ static inline void analyse_each_turn(Result & res,
+ Analyser & analyser,
+ TurnIt first, TurnIt last,
+ Geometry const& geometry,
+ OtherGeometry const& other_geometry,
+ BoundaryChecker const& boundary_checker,
+ OtherBoundaryChecker const& other_boundary_checker)
+ {
+ if ( first == last )
+ return;
+
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ analyser.apply(res, it,
+ geometry, other_geometry,
+ boundary_checker, other_boundary_checker);
+
+ if ( res.interrupt )
+ return;
+ }
+
+ analyser.apply(res, first, last,
+ geometry, other_geometry,
+ boundary_checker, other_boundary_checker);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
new file mode 100644
index 0000000000..86c236d357
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
@@ -0,0 +1,205 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
+// 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_POINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
+
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+//#include <boost/geometry/algorithms/within.hpp>
+//#include <boost/geometry/algorithms/covered_by.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// non-point geometry
+template <typename Point, typename Geometry, bool Transpose = false>
+struct point_geometry
+{
+ // TODO: interrupt only if the topology check is complex
+
+ static const bool interruption_enabled = true;
+
+ template <typename Result>
+ static inline void apply(Point const& point, Geometry const& geometry, Result & result)
+ {
+ int pig = detail::within::point_in_geometry(point, geometry);
+
+ if ( pig > 0 ) // within
+ {
+ set<interior, interior, '0', Transpose>(result);
+ }
+ else if ( pig == 0 )
+ {
+ set<interior, boundary, '0', Transpose>(result);
+ }
+ else // pig < 0 - not within
+ {
+ set<interior, exterior, '0', Transpose>(result);
+ }
+
+ set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
+
+ if ( result.interrupt )
+ return;
+
+ // 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
+
+ // check if there are other boundaries outside
+ typedef detail::relate::topology_check<Geometry> tc_t;
+ //tc_t tc(geometry, point);
+ //if ( tc.has_interior )
+ set<exterior, interior, tc_t::interior, Transpose>(result);
+ //if ( tc.has_boundary )
+ 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 )
+ set<exterior, interior, tc_t::interior, Transpose>(result);
+ if ( tc.has_boundary )
+ set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ }
+};
+
+// transposed result of point_geometry
+template <typename Geometry, typename Point>
+struct geometry_point
+{
+ // TODO: interrupt only if the topology check is complex
+
+ static const bool interruption_enabled = true;
+
+ template <typename Result>
+ static inline void apply(Geometry const& geometry, Point const& point, Result & result)
+ {
+ point_geometry<Point, Geometry, true>::apply(point, geometry, result);
+ }
+};
+
+// TODO: rewrite the folowing:
+
+//// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box)
+//// There is no EPS used in those functions, values are compared using < or <=
+//// so comparing MIN and MAX in the same way should be fine
+//
+//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
+//struct box_has_interior
+//{
+// static inline bool apply(Box const& box)
+// {
+// return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box)
+// && box_has_interior<Box, I + 1, D>::apply(box);
+// }
+//};
+//
+//template <typename Box, std::size_t D>
+//struct box_has_interior<Box, D, D>
+//{
+// static inline bool apply(Box const&) { return true; }
+//};
+//
+//// NOTE: especially important here (see the NOTE above).
+//
+//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
+//struct box_has_equal_min_max
+//{
+// static inline bool apply(Box const& box)
+// {
+// return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box)
+// && box_has_equal_min_max<Box, I + 1, D>::apply(box);
+// }
+//};
+//
+//template <typename Box, std::size_t D>
+//struct box_has_equal_min_max<Box, D, D>
+//{
+// static inline bool apply(Box const&) { return true; }
+//};
+//
+//template <typename Point, typename Box>
+//struct point_box
+//{
+// static inline result apply(Point const& point, Box const& box)
+// {
+// result res;
+//
+// if ( geometry::within(point, box) ) // this also means that the box has interior
+// {
+// return result("0FFFFFTTT");
+// }
+// else if ( geometry::covered_by(point, box) ) // point is on the boundary
+// {
+// //if ( box_has_interior<Box>::apply(box) )
+// //{
+// // return result("F0FFFFTTT");
+// //}
+// //else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point
+// //{
+// // return result("F0FFFFFFT");
+// //}
+// //else // no interior outside point
+// //{
+// // return result("F0FFFFFTT");
+// //}
+// return result("F0FFFF**T");
+// }
+// else
+// {
+// /*if ( box_has_interior<Box>::apply(box) )
+// {
+// return result("FF0FFFTTT");
+// }
+// else
+// {
+// return result("FF0FFFFTT");
+// }*/
+// return result("FF0FFF*TT");
+// }
+//
+// return res;
+// }
+//};
+//
+//template <typename Box, typename Point>
+//struct box_point
+//{
+// static inline result apply(Box const& box, Point const& point)
+// {
+// if ( geometry::within(point, box) )
+// return result("0FTFFTFFT");
+// else if ( geometry::covered_by(point, box) )
+// return result("FF*0F*FFT");
+// else
+// return result("FF*FFT0FT");
+// }
+//};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp
new file mode 100644
index 0000000000..e623868b92
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/point_point.hpp
@@ -0,0 +1,242 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
+// 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_POINT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+template <typename Point1, typename Point2>
+struct point_point
+{
+ static const bool interruption_enabled = false;
+
+ template <typename Result>
+ static inline void apply(Point1 const& point1, Point2 const& point2, Result & result)
+ {
+ bool equal = detail::equals::equals_point_point(point1, point2);
+ if ( equal )
+ {
+ set<interior, interior, '0'>(result);
+ }
+ else
+ {
+ set<interior, exterior, '0'>(result);
+ set<exterior, interior, '0'>(result);
+ }
+
+ set<exterior, exterior, result_dimension<Point1>::value>(result);
+ }
+};
+
+template <typename Point, typename MultiPoint>
+std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point)
+{
+ bool found_inside = false;
+ bool found_outside = false;
+
+ // point_in_geometry could be used here but why iterate over MultiPoint twice?
+ // we must search for a point in the exterior because all points in MultiPoint can be equal
+
+ typedef typename boost::range_iterator<MultiPoint const>::type iterator;
+ iterator it = boost::begin(multi_point);
+ iterator last = boost::end(multi_point);
+ for ( ; it != last ; ++it )
+ {
+ bool ii = detail::equals::equals_point_point(point, *it);
+
+ if ( ii )
+ found_inside = true;
+ else
+ found_outside = true;
+
+ if ( found_inside && found_outside )
+ break;
+ }
+
+ return std::make_pair(found_inside, found_outside);
+}
+
+template <typename Point, typename MultiPoint, bool Transpose = false>
+struct point_multipoint
+{
+ static const bool interruption_enabled = false;
+
+ template <typename Result>
+ static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result)
+ {
+ if ( boost::empty(multi_point) )
+ {
+ // TODO: throw on empty input?
+ set<interior, exterior, '0', Transpose>(result);
+ return;
+ }
+
+ std::pair<bool, bool> rel = point_multipoint_check(point, multi_point);
+
+ if ( rel.first ) // some point of MP is equal to P
+ {
+ set<interior, interior, '0', Transpose>(result);
+
+ if ( rel.second ) // a point of MP was found outside P
+ {
+ set<exterior, interior, '0', Transpose>(result);
+ }
+ }
+ else
+ {
+ set<interior, exterior, '0', Transpose>(result);
+ set<exterior, interior, '0', Transpose>(result);
+ }
+
+ set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
+ }
+};
+
+template <typename MultiPoint, typename Point>
+struct multipoint_point
+{
+ static const bool interruption_enabled = false;
+
+ template <typename Result>
+ static inline void apply(MultiPoint const& multi_point, Point const& point, Result & result)
+ {
+ point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result);
+ }
+};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct multipoint_multipoint
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result>
+ static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result)
+ {
+ {
+ // TODO: throw on empty input?
+ bool empty1 = boost::empty(multi_point1);
+ bool empty2 = boost::empty(multi_point2);
+ if ( empty1 && empty2 )
+ {
+ return;
+ }
+ else if ( empty1 )
+ {
+ set<exterior, interior, '0'>(result);
+ return;
+ }
+ else if ( empty2 )
+ {
+ set<interior, exterior, '0'>(result);
+ return;
+ }
+ }
+
+// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
+
+// 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
+
+// TODO: Also, the geometry with the smaller number of points may be analysed first
+ //if ( boost::size(multi_point1) < boost::size(multi_point2) )
+
+ // NlogN + MlogN
+ bool all_handled = search<false>(multi_point1, multi_point2, result);
+
+ if ( all_handled || result.interrupt )
+ return;
+
+ // MlogM + NlogM
+ search<true>(multi_point2, multi_point1, result);
+ }
+
+ template <bool Transpose,
+ typename SortedMultiPoint,
+ typename IteratedMultiPoint,
+ typename Result>
+ static inline bool search(SortedMultiPoint const& sorted_mpt,
+ IteratedMultiPoint const& iterated_mpt,
+ Result & result)
+ {
+ // sort points from the 1 MPt
+ typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
+ std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
+ std::sort(points.begin(), points.end(), less());
+
+ bool found_inside = false;
+ bool found_outside = false;
+
+ // for each point in the second MPt
+ typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator;
+ for ( iterator it = boost::begin(iterated_mpt) ;
+ it != boost::end(iterated_mpt) ; ++it )
+ {
+ bool ii =
+ std::binary_search(points.begin(), points.end(), *it, less());
+ if ( ii )
+ found_inside = true;
+ else
+ found_outside = true;
+
+ if ( found_inside && found_outside )
+ 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
+// so if e.g. only I/I must be analysed we musn't check the other MPt
+
+ set<interior, interior, '0', Transpose>(result);
+
+ if ( found_outside ) // some point of MP2 was found outside of MP1
+ {
+ set<exterior, interior, '0', Transpose>(result);
+ }
+ }
+ else
+ {
+ set<interior, exterior, '0', Transpose>(result);
+ 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;
+ }
+
+ set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result);
+
+ return all_handled;
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/relate/relate.hpp b/boost/geometry/algorithms/detail/relate/relate.hpp
new file mode 100644
index 0000000000..946653452a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/relate.hpp
@@ -0,0 +1,339 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_RELATE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP
+
+#include <cstddef>
+
+#include <boost/concept_check.hpp>
+#include <boost/range.hpp>
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/type_traits/is_base_of.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/relate/result.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/point_point.hpp>
+#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/areal_areal.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// Those are used only to allow dispatch::relate to produce compile-time error
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct is_supported_by_generic
+{
+ static const bool value
+ = boost::is_same<Tag, linestring_tag>::value
+ || boost::is_same<Tag, multi_linestring_tag>::value
+ || boost::is_same<Tag, ring_tag>::value
+ || boost::is_same<Tag, polygon_tag>::value
+ || boost::is_same<Tag, multi_polygon_tag>::value;
+};
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type>
+struct is_generic
+{
+ static const bool value = is_supported_by_generic<Geometry1>::value
+ && is_supported_by_generic<Geometry2>::value;
+};
+
+
+template <typename Point, typename Geometry, typename Tag>
+struct is_generic<Point, Geometry, point_tag, Tag>
+{
+ static const bool value = is_supported_by_generic<Geometry>::value;
+};
+
+template <typename Geometry, typename Point, typename Tag>
+struct is_generic<Geometry, Point, Tag, point_tag>
+{
+ static const bool value = is_supported_by_generic<Geometry>::value;
+};
+
+template <typename Point1, typename Point2>
+struct is_generic<Point1, Point2, point_tag, point_tag>
+{
+ static const bool value = false;
+};
+
+
+}} // namespace detail::relate
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace relate {
+
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ int TopDim1 = geometry::topological_dimension<Geometry1>::value,
+ int TopDim2 = geometry::topological_dimension<Geometry2>::value,
+ bool IsGeneric = detail::relate::is_generic<Geometry1, Geometry2>::value
+>
+struct relate : not_implemented<Tag1, Tag2>
+{};
+
+
+template <typename Point1, typename Point2>
+struct relate<Point1, Point2, point_tag, point_tag, 0, 0, false>
+ : detail::relate::point_point<Point1, Point2>
+{};
+
+template <typename Point, typename MultiPoint>
+struct relate<Point, MultiPoint, point_tag, multi_point_tag, 0, 0, false>
+ : detail::relate::point_multipoint<Point, MultiPoint>
+{};
+
+template <typename MultiPoint, typename Point>
+struct relate<MultiPoint, Point, multi_point_tag, point_tag, 0, 0, false>
+ : detail::relate::multipoint_point<MultiPoint, Point>
+{};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, 0, 0, false>
+ : detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2>
+{};
+
+//template <typename Point, typename Box, int TopDim2>
+//struct relate<Point, Box, point_tag, box_tag, 0, TopDim2, false>
+// : detail::relate::point_box<Point, Box>
+//{};
+//
+//template <typename Box, typename Point, int TopDim1>
+//struct relate<Box, Point, box_tag, point_tag, TopDim1, 0, false>
+// : detail::relate::box_point<Box, Point>
+//{};
+
+
+template <typename Point, typename Geometry, typename Tag2, int TopDim2>
+struct relate<Point, Geometry, point_tag, Tag2, 0, TopDim2, true>
+ : detail::relate::point_geometry<Point, Geometry>
+{};
+
+template <typename Geometry, typename Point, typename Tag1, int TopDim1>
+struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true>
+ : detail::relate::geometry_point<Geometry, Point>
+{};
+
+
+template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
+struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true>
+ : detail::relate::linear_linear<Linear1, Linear2>
+{};
+
+
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct relate<Linear, Areal, Tag1, Tag2, 1, 2, true>
+ : detail::relate::linear_areal<Linear, Areal>
+{};
+
+template <typename Areal, typename Linear, typename Tag1, typename Tag2>
+struct relate<Areal, Linear, Tag1, Tag2, 2, 1, true>
+ : detail::relate::areal_linear<Areal, Linear>
+{};
+
+
+template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
+struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true>
+ : detail::relate::areal_areal<Areal1, Areal2>
+{};
+
+
+}} // namespace detail_dispatch::relate
+#endif // DOXYGEN_NO_DISPATCH
+
+namespace detail { namespace relate {
+
+template <typename Geometry1, typename Geometry2>
+struct interruption_enabled
+{
+ static const bool value =
+ detail_dispatch::relate::relate<Geometry1, Geometry2>::interruption_enabled;
+};
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Result,
+ bool IsSequence = boost::mpl::is_sequence<Result>::value>
+struct result_handler_type
+ : not_implemented<Result>
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct result_handler_type<Geometry1, Geometry2, matrix9, false>
+{
+ typedef matrix_handler<matrix9> type;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct result_handler_type<Geometry1, Geometry2, mask9, false>
+{
+ typedef mask_handler
+ <
+ mask9,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename Geometry1, typename Geometry2, typename Head, typename Tail>
+struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail>, false>
+{
+ typedef mask_handler
+ <
+ boost::tuples::cons<Head, Tail>,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename Geometry1, typename Geometry2,
+ char II, char IB, char IE,
+ char BI, char BB, char BE,
+ char EI, char EB, char EE>
+struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>, false>
+{
+ typedef static_mask_handler
+ <
+ static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename Geometry1, typename Geometry2, typename StaticSequence>
+struct result_handler_type<Geometry1, Geometry2, StaticSequence, true>
+{
+ typedef static_mask_handler
+ <
+ StaticSequence,
+ interruption_enabled
+ <
+ Geometry1,
+ Geometry2
+ >::value
+ > type;
+};
+
+template <typename MatrixOrMask, typename Geometry1, typename Geometry2>
+inline
+typename result_handler_type
+ <
+ Geometry1,
+ Geometry2,
+ MatrixOrMask
+ >::type::result_type
+relate(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ MatrixOrMask const& matrix_or_mask = MatrixOrMask())
+{
+ typedef typename result_handler_type
+ <
+ Geometry1,
+ Geometry2,
+ MatrixOrMask
+ >::type handler_type;
+
+ handler_type handler(matrix_or_mask);
+ detail_dispatch::relate::relate<Geometry1, Geometry2>::apply(geometry1, geometry2, handler);
+ return handler.result();
+}
+
+struct implemented_tag {};
+
+template <template <typename, typename> class StaticMaskTrait,
+ typename Geometry1,
+ typename Geometry2>
+struct relate_base
+ : boost::mpl::if_
+ <
+ boost::mpl::or_
+ <
+ boost::is_base_of
+ <
+ nyi::not_implemented_tag,
+ StaticMaskTrait<Geometry1, Geometry2>
+ >,
+ boost::is_base_of
+ <
+ nyi::not_implemented_tag,
+ detail_dispatch::relate::relate<Geometry1, Geometry2>
+ >
+ >,
+ not_implemented
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type
+ >,
+ implemented_tag
+ >::type
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ typedef typename StaticMaskTrait<Geometry1, Geometry2>::type static_mask;
+ return detail::relate::relate<static_mask>(g1, g2);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_HPP
diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp
new file mode 100644
index 0000000000..1bcb5275d2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/result.hpp
@@ -0,0 +1,1390 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+
+// 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_RESULT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
+
+#include <boost/tuple/tuple.hpp>
+
+#include <boost/mpl/is_sequence.hpp>
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/next.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/vector_c.hpp>
+
+#include <boost/geometry/core/topological_dimension.hpp>
+
+// TEMP - move this header to geometry/detail
+#include <boost/geometry/index/detail/tuples.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+enum field { interior = 0, boundary = 1, exterior = 2 };
+
+// TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES
+// THE VALUE ALREADY STORED MUSN'T BE CHECKED
+// update() calls chould be replaced with set() in those cases
+// but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that
+// so some additional function could be added, e.g. set_dim()
+
+// matrix
+
+// TODO add height?
+
+template <std::size_t Width>
+class matrix
+{
+ BOOST_STATIC_ASSERT(Width == 2 || Width == 3);
+
+public:
+
+ static const std::size_t size = Width * Width;
+
+ inline matrix()
+ {
+ ::memset(m_array, 'F', size);
+ }
+
+ template <field F1, field F2>
+ inline char get() const
+ {
+ static const bool in_bounds = F1 * Width + F2 < size;
+ return get_dispatch<F1, F2>(integral_constant<bool, in_bounds>());
+ }
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ static const bool in_bounds = F1 * Width + F2 < size;
+ set_dispatch<F1, F2, V>(integral_constant<bool, in_bounds>());
+ }
+
+ template <field F1, field F2, char D>
+ inline void update()
+ {
+ static const bool in_bounds = F1 * Width + F2 < size;
+ update_dispatch<F1, F2, D>(integral_constant<bool, in_bounds>());
+ }
+
+ inline const char * data() const
+ {
+ return m_array;
+ }
+
+private:
+ template <field F1, field F2>
+ inline char get_dispatch(integral_constant<bool, true>) const
+ {
+ return m_array[F1 * Width + F2];
+ }
+ template <field F1, field F2>
+ inline char get_dispatch(integral_constant<bool, false>) const
+ {
+ return 'F';
+ }
+
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<bool, true>)
+ {
+ BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F');
+ m_array[F1 * Width + F2] = V;
+ }
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<bool, false>)
+ {}
+
+ template <field F1, field F2, char D>
+ inline void update_dispatch(integral_constant<bool, true>)
+ {
+ BOOST_STATIC_ASSERT('0' <= D && D <= '9');
+ char c = m_array[F1 * Width + F2];
+ if ( D > c || c > '9')
+ m_array[F1 * Width + F2] = D;
+ }
+ template <field F1, field F2, char D>
+ inline void update_dispatch(integral_constant<bool, false>)
+ {}
+
+ char m_array[size];
+};
+
+// TODO add EnableDimensions parameter?
+
+struct matrix9 {};
+//struct matrix4 {};
+
+// matrix_width
+
+template <typename MatrixOrMask>
+struct matrix_width
+ : not_implemented<MatrixOrMask>
+{};
+
+template <>
+struct matrix_width<matrix9>
+{
+ static const std::size_t value = 3;
+};
+
+// matrix_handler
+
+template <typename Matrix>
+class matrix_handler
+ : private matrix<matrix_width<Matrix>::value>
+{
+ typedef matrix<matrix_width<Matrix>::value> base_t;
+
+public:
+ typedef std::string result_type;
+
+ static const bool interrupt = false;
+
+ matrix_handler(Matrix const&)
+ {}
+
+ result_type result() const
+ {
+ return std::string(this->data(),
+ this->data() + base_t::size);
+ }
+
+ template <field F1, field F2, char D>
+ inline bool may_update() const
+ {
+ BOOST_STATIC_ASSERT('0' <= D && D <= '9');
+
+ char const c = static_cast<base_t const&>(*this).template get<F1, F2>();
+ return D > c || c > '9';
+ }
+
+ //template <field F1, field F2>
+ //inline char get() const
+ //{
+ // return static_cast<base_t const&>(*this).template get<F1, F2>();
+ //}
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ static_cast<base_t&>(*this).template set<F1, F2, V>();
+ }
+
+ template <field F1, field F2, char D>
+ inline void update()
+ {
+ static_cast<base_t&>(*this).template update<F1, F2, D>();
+ }
+};
+
+// RUN-TIME MASKS
+
+// mask9
+
+class mask9
+{
+public:
+ static const std::size_t width = 3; // TEMP
+
+ inline mask9(std::string const& de9im_mask)
+ {
+ // TODO: throw an exception here?
+ BOOST_ASSERT(de9im_mask.size() == 9);
+ ::memcpy(m_mask, de9im_mask.c_str(), 9);
+ }
+
+ template <field F1, field F2>
+ inline char get() const
+ {
+ return m_mask[F1 * 3 + F2];
+ }
+
+private:
+ char m_mask[9];
+};
+
+// interrupt()
+
+template <typename Mask, bool InterruptEnabled>
+struct interrupt_dispatch
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Mask const&)
+ {
+ return false;
+ }
+};
+
+template <typename Mask>
+struct interrupt_dispatch<Mask, true>
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Mask const& mask)
+ {
+ char m = mask.template get<F1, F2>();
+ return check<V>(m);
+ }
+
+ template <char V>
+ static inline bool check(char m)
+ {
+ if ( V >= '0' && V <= '9' )
+ {
+ return m == 'F' || ( m < V && m >= '0' && m <= '9' );
+ }
+ else if ( V == 'T' )
+ {
+ return m == 'F';
+ }
+ return false;
+ }
+};
+
+template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
+struct interrupt_dispatch_tuple
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Masks const& masks)
+ {
+ typedef typename boost::tuples::element<I, Masks>::type mask_type;
+ mask_type const& mask = boost::get<I>(masks);
+ return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask)
+ && interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks);
+ }
+};
+
+template <typename Masks, int N>
+struct interrupt_dispatch_tuple<Masks, N, N>
+{
+ template <field F1, field F2, char V>
+ static inline bool apply(Masks const& )
+ {
+ return true;
+ }
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct interrupt_dispatch<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, true>
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
+
+ template <field F1, field F2, char V>
+ static inline bool apply(mask_type const& mask)
+ {
+ return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
+ }
+};
+
+template <typename Head, typename Tail>
+struct interrupt_dispatch<boost::tuples::cons<Head, Tail>, true>
+{
+ typedef boost::tuples::cons<Head, Tail> mask_type;
+
+ template <field F1, field F2, char V>
+ static inline bool apply(mask_type const& mask)
+ {
+ return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
+ }
+};
+
+template <field F1, field F2, char V, bool InterruptEnabled, typename Mask>
+inline bool interrupt(Mask const& mask)
+{
+ return interrupt_dispatch<Mask, InterruptEnabled>
+ ::template apply<F1, F2, V>(mask);
+}
+
+// may_update()
+
+template <typename Mask>
+struct may_update_dispatch
+{
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(Mask const& mask, Matrix const& matrix)
+ {
+ BOOST_STATIC_ASSERT('0' <= D && D <= '9');
+
+ char const m = mask.template get<F1, F2>();
+
+ if ( m == 'F' )
+ {
+ return true;
+ }
+ else if ( m == 'T' )
+ {
+ char const c = matrix.template get<F1, F2>();
+ return c == 'F'; // if it's T or between 0 and 9, the result will be the same
+ }
+ else if ( m >= '0' && m <= '9' )
+ {
+ char const c = matrix.template get<F1, F2>();
+ return D > c || c > '9';
+ }
+
+ return false;
+ }
+};
+
+template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
+struct may_update_dispatch_tuple
+{
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(Masks const& masks, Matrix const& matrix)
+ {
+ typedef typename boost::tuples::element<I, Masks>::type mask_type;
+ mask_type const& mask = boost::get<I>(masks);
+ return may_update_dispatch<mask_type>::template apply<F1, F2, D>(mask, matrix)
+ || may_update_dispatch_tuple<Masks, I+1>::template apply<F1, F2, D>(masks, matrix);
+ }
+};
+
+template <typename Masks, int N>
+struct may_update_dispatch_tuple<Masks, N, N>
+{
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(Masks const& , Matrix const& )
+ {
+ return false;
+ }
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct may_update_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
+
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix);
+ }
+};
+
+template <typename Head, typename Tail>
+struct may_update_dispatch< boost::tuples::cons<Head, Tail> >
+{
+ typedef boost::tuples::cons<Head, Tail> mask_type;
+
+ template <field F1, field F2, char D, typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix);
+ }
+};
+
+template <field F1, field F2, char D, typename Mask, typename Matrix>
+inline bool may_update(Mask const& mask, Matrix const& matrix)
+{
+ return may_update_dispatch<Mask>
+ ::template apply<F1, F2, D>(mask, matrix);
+}
+
+// check()
+
+template <typename Mask>
+struct check_dispatch
+{
+ template <typename Matrix>
+ static inline bool apply(Mask const& mask, Matrix const& matrix)
+ {
+ return per_one<interior, interior>(mask, matrix)
+ && per_one<interior, boundary>(mask, matrix)
+ && per_one<interior, exterior>(mask, matrix)
+ && per_one<boundary, interior>(mask, matrix)
+ && per_one<boundary, boundary>(mask, matrix)
+ && per_one<boundary, exterior>(mask, matrix)
+ && per_one<exterior, interior>(mask, matrix)
+ && per_one<exterior, boundary>(mask, matrix)
+ && per_one<exterior, exterior>(mask, matrix);
+ }
+
+ template <field F1, field F2, typename Matrix>
+ static inline bool per_one(Mask const& mask, Matrix const& matrix)
+ {
+ const char mask_el = mask.template get<F1, F2>();
+ const char el = matrix.template get<F1, F2>();
+
+ if ( mask_el == 'F' )
+ {
+ return el == 'F';
+ }
+ else if ( mask_el == 'T' )
+ {
+ return el == 'T' || ( el >= '0' && el <= '9' );
+ }
+ else if ( mask_el >= '0' && mask_el <= '9' )
+ {
+ return el == mask_el;
+ }
+
+ return true;
+ }
+};
+
+template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
+struct check_dispatch_tuple
+{
+ template <typename Matrix>
+ static inline bool apply(Masks const& masks, Matrix const& matrix)
+ {
+ typedef typename boost::tuples::element<I, Masks>::type mask_type;
+ mask_type const& mask = boost::get<I>(masks);
+ return check_dispatch<mask_type>::apply(mask, matrix)
+ || check_dispatch_tuple<Masks, I+1>::apply(masks, matrix);
+ }
+};
+
+template <typename Masks, int N>
+struct check_dispatch_tuple<Masks, N, N>
+{
+ template <typename Matrix>
+ static inline bool apply(Masks const&, Matrix const&)
+ {
+ return false;
+ }
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8, typename T9>
+struct check_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
+{
+ typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
+
+ template <typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return check_dispatch_tuple<mask_type>::apply(mask, matrix);
+ }
+};
+
+template <typename Head, typename Tail>
+struct check_dispatch< boost::tuples::cons<Head, Tail> >
+{
+ typedef boost::tuples::cons<Head, Tail> mask_type;
+
+ template <typename Matrix>
+ static inline bool apply(mask_type const& mask, Matrix const& matrix)
+ {
+ return check_dispatch_tuple<mask_type>::apply(mask, matrix);
+ }
+};
+
+template <typename Mask, typename Matrix>
+inline bool check(Mask const& mask, Matrix const& matrix)
+{
+ return check_dispatch<Mask>::apply(mask, matrix);
+}
+
+// matrix_width
+
+template <>
+struct matrix_width<mask9>
+{
+ static const std::size_t value = 3;
+};
+
+template <typename Tuple,
+ int I = 0,
+ int N = boost::tuples::length<Tuple>::value>
+struct matrix_width_tuple
+{
+ static const std::size_t
+ current = matrix_width<typename boost::tuples::element<I, Tuple>::type>::value;
+ static const std::size_t
+ next = matrix_width_tuple<Tuple, I+1>::value;
+
+ static const std::size_t
+ value = current > next ? current : next;
+};
+
+template <typename Tuple, int N>
+struct matrix_width_tuple<Tuple, N, N>
+{
+ static const std::size_t value = 0;
+};
+
+template <typename Head, typename Tail>
+struct matrix_width< boost::tuples::cons<Head, Tail> >
+{
+ static const std::size_t
+ value = matrix_width_tuple< boost::tuples::cons<Head, Tail> >::value;
+};
+
+// matrix_handler
+
+template <typename Mask, bool Interrupt>
+class mask_handler
+ : private matrix<matrix_width<Mask>::value>
+{
+ typedef matrix<matrix_width<Mask>::value> base_t;
+
+public:
+ typedef bool result_type;
+
+ bool interrupt;
+
+ inline mask_handler(Mask const& m)
+ : interrupt(false)
+ , m_mask(m)
+ {}
+
+ result_type result() const
+ {
+ return !interrupt
+ && check(m_mask, static_cast<base_t const&>(*this));
+ }
+
+ template <field F1, field F2, char D>
+ inline bool may_update() const
+ {
+ return detail::relate::may_update<F1, F2, D>(
+ m_mask, static_cast<base_t const&>(*this)
+ );
+ }
+
+ //template <field F1, field F2>
+ //inline char get() const
+ //{
+ // return static_cast<base_t const&>(*this).template get<F1, F2>();
+ //}
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
+ {
+ interrupt = true;
+ }
+ else
+ {
+ base_t::template set<F1, F2, V>();
+ }
+ }
+
+ template <field F1, field F2, char V>
+ inline void update()
+ {
+ if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
+ {
+ interrupt = true;
+ }
+ else
+ {
+ base_t::template update<F1, F2, V>();
+ }
+ }
+
+private:
+ Mask const& m_mask;
+};
+
+// STATIC MASKS
+
+// static_mask
+
+template <char II, char IB, char IE,
+ char BI, char BB, char BE,
+ char EI, char EB, char EE>
+class static_mask
+{
+ typedef boost::mpl::vector_c
+ <
+ char, II, IB, IE, BI, BB, BE, EI, EB, EE
+ > vector_type;
+
+public:
+ template <field F1, field F2>
+ struct get
+ {
+ BOOST_STATIC_ASSERT(F1 * 3 + F2 < boost::mpl::size<vector_type>::value);
+
+ static const char value
+ = boost::mpl::at_c<vector_type, F1 * 3 + F2>::type::value;
+ };
+};
+
+// static_should_handle_element
+
+template <typename StaticMask, field F1, field F2, bool IsSequence>
+struct static_should_handle_element_dispatch
+{
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+ static const bool value = mask_el == 'F'
+ || mask_el == 'T'
+ || ( mask_el >= '0' && mask_el <= '9' );
+};
+
+template <typename First, typename Last, field F1, field F2>
+struct static_should_handle_element_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ static const bool value
+ = static_should_handle_element_dispatch
+ <
+ StaticMask,
+ F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value
+ || static_should_handle_element_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last,
+ F1, F2
+ >::value;
+};
+
+template <typename Last, field F1, field F2>
+struct static_should_handle_element_sequence<Last, Last, F1, F2>
+{
+ static const bool value = false;
+};
+
+template <typename StaticMask, field F1, field F2>
+struct static_should_handle_element_dispatch<StaticMask, F1, F2, true>
+{
+ static const bool value
+ = static_should_handle_element_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type,
+ F1, F2
+ >::value;
+};
+
+template <typename StaticMask, field F1, field F2>
+struct static_should_handle_element
+{
+ static const bool value
+ = static_should_handle_element_dispatch
+ <
+ StaticMask,
+ F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value;
+};
+
+// static_interrupt
+
+template <typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsSequence>
+struct static_interrupt_dispatch
+{
+ static const bool value = false;
+};
+
+template <typename StaticMask, char V, field F1, field F2, bool IsSequence>
+struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence>
+{
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+
+ static const bool value
+ = ( V >= '0' && V <= '9' ) ?
+ ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) :
+ ( ( V == 'T' ) ? mask_el == 'F' : false );
+};
+
+template <typename First, typename Last, char V, field F1, field F2>
+struct static_interrupt_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ static const bool value
+ = static_interrupt_dispatch
+ <
+ StaticMask,
+ V, F1, F2,
+ true,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value
+ && static_interrupt_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last,
+ V, F1, F2
+ >::value;
+};
+
+template <typename Last, char V, field F1, field F2>
+struct static_interrupt_sequence<Last, Last, V, F1, F2>
+{
+ static const bool value = true;
+};
+
+template <typename StaticMask, char V, field F1, field F2>
+struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, true>
+{
+ static const bool value
+ = static_interrupt_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type,
+ V, F1, F2
+ >::value;
+};
+
+template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt>
+struct static_interrupt
+{
+ static const bool value
+ = static_interrupt_dispatch
+ <
+ StaticMask,
+ V, F1, F2,
+ EnableInterrupt,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::value;
+};
+
+// static_may_update
+
+template <typename StaticMask, char D, field F1, field F2, bool IsSequence>
+struct static_may_update_dispatch
+{
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+ static const int version
+ = mask_el == 'F' ? 0
+ : mask_el == 'T' ? 1
+ : mask_el >= '0' && mask_el <= '9' ? 2
+ : 3;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return apply_dispatch(matrix, integral_constant<int, version>());
+ }
+
+ // mask_el == 'F'
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const& , integral_constant<int, 0>)
+ {
+ return true;
+ }
+ // mask_el == 'T'
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 1>)
+ {
+ char const c = matrix.template get<F1, F2>();
+ return c == 'F'; // if it's T or between 0 and 9, the result will be the same
+ }
+ // mask_el >= '0' && mask_el <= '9'
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 2>)
+ {
+ char const c = matrix.template get<F1, F2>();
+ return D > c || c > '9';
+ }
+ // else
+ template <typename Matrix>
+ static inline bool apply_dispatch(Matrix const&, integral_constant<int, 3>)
+ {
+ return false;
+ }
+};
+
+template <typename First, typename Last, char D, field F1, field F2>
+struct static_may_update_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_may_update_dispatch
+ <
+ StaticMask,
+ D, F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix)
+ || static_may_update_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last,
+ D, F1, F2
+ >::apply(matrix);
+ }
+};
+
+template <typename Last, char D, field F1, field F2>
+struct static_may_update_sequence<Last, Last, D, F1, F2>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& /*matrix*/)
+ {
+ return false;
+ }
+};
+
+template <typename StaticMask, char D, field F1, field F2>
+struct static_may_update_dispatch<StaticMask, D, F1, F2, true>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_may_update_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type,
+ D, F1, F2
+ >::apply(matrix);
+ }
+};
+
+template <typename StaticMask, char D, field F1, field F2>
+struct static_may_update
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_may_update_dispatch
+ <
+ StaticMask,
+ D, F1, F2,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix);
+ }
+};
+
+// static_check
+
+template <typename StaticMask, bool IsSequence>
+struct static_check_dispatch
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return per_one<interior, interior>::apply(matrix)
+ && per_one<interior, boundary>::apply(matrix)
+ && per_one<interior, exterior>::apply(matrix)
+ && per_one<boundary, interior>::apply(matrix)
+ && per_one<boundary, boundary>::apply(matrix)
+ && per_one<boundary, exterior>::apply(matrix)
+ && per_one<exterior, interior>::apply(matrix)
+ && per_one<exterior, boundary>::apply(matrix)
+ && per_one<exterior, exterior>::apply(matrix);
+ }
+
+ template <field F1, field F2>
+ struct per_one
+ {
+ static const char mask_el = StaticMask::template get<F1, F2>::value;
+ static const int version
+ = mask_el == 'F' ? 0
+ : mask_el == 'T' ? 1
+ : mask_el >= '0' && mask_el <= '9' ? 2
+ : 3;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ const char el = matrix.template get<F1, F2>();
+ return apply_dispatch(el, integral_constant<int, version>());
+ }
+
+ // mask_el == 'F'
+ static inline bool apply_dispatch(char el, integral_constant<int, 0>)
+ {
+ return el == 'F';
+ }
+ // mask_el == 'T'
+ static inline bool apply_dispatch(char el, integral_constant<int, 1>)
+ {
+ return el == 'T' || ( el >= '0' && el <= '9' );
+ }
+ // mask_el >= '0' && mask_el <= '9'
+ static inline bool apply_dispatch(char el, integral_constant<int, 2>)
+ {
+ return el == mask_el;
+ }
+ // else
+ static inline bool apply_dispatch(char /*el*/, integral_constant<int, 3>)
+ {
+ return true;
+ }
+ };
+};
+
+template <typename First, typename Last>
+struct static_check_sequence
+{
+ typedef typename boost::mpl::deref<First>::type StaticMask;
+
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_check_dispatch
+ <
+ StaticMask,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix)
+ || static_check_sequence
+ <
+ typename boost::mpl::next<First>::type,
+ Last
+ >::apply(matrix);
+ }
+};
+
+template <typename Last>
+struct static_check_sequence<Last, Last>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& /*matrix*/)
+ {
+ return false;
+ }
+};
+
+template <typename StaticMask>
+struct static_check_dispatch<StaticMask, true>
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_check_sequence
+ <
+ typename boost::mpl::begin<StaticMask>::type,
+ typename boost::mpl::end<StaticMask>::type
+ >::apply(matrix);
+ }
+};
+
+template <typename StaticMask>
+struct static_check
+{
+ template <typename Matrix>
+ static inline bool apply(Matrix const& matrix)
+ {
+ return static_check_dispatch
+ <
+ StaticMask,
+ boost::mpl::is_sequence<StaticMask>::value
+ >::apply(matrix);
+ }
+};
+
+// static_mask_handler
+
+template <typename StaticMask, bool Interrupt>
+class static_mask_handler
+ : private matrix<3>
+{
+ typedef matrix<3> base_t;
+
+public:
+ typedef bool result_type;
+
+ bool interrupt;
+
+ inline static_mask_handler(StaticMask const& /*dummy*/)
+ : interrupt(false)
+ {}
+
+ result_type result() const
+ {
+ return (!Interrupt || !interrupt)
+ && static_check<StaticMask>::
+ apply(static_cast<base_t const&>(*this));
+ }
+
+ template <field F1, field F2, char D>
+ inline bool may_update() const
+ {
+ return static_may_update<StaticMask, D, F1, F2>::
+ apply(static_cast<base_t const&>(*this));
+ }
+
+ template <field F1, field F2>
+ static inline bool expects()
+ {
+ return static_should_handle_element<StaticMask, F1, F2>::value;
+ }
+
+ //template <field F1, field F2>
+ //inline char get() const
+ //{
+ // return base_t::template get<F1, F2>();
+ //}
+
+ template <field F1, field F2, char V>
+ inline void set()
+ {
+ static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
+ static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
+ static const int version = interrupt_c ? 0
+ : should_handle ? 1
+ : 2;
+
+ set_dispatch<F1, F2, V>(integral_constant<int, version>());
+ }
+
+ template <field F1, field F2, char V>
+ inline void update()
+ {
+ static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
+ static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
+ static const int version = interrupt_c ? 0
+ : should_handle ? 1
+ : 2;
+
+ update_dispatch<F1, F2, V>(integral_constant<int, version>());
+ }
+
+private:
+ // Interrupt && interrupt
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<int, 0>)
+ {
+ interrupt = true;
+ }
+ // else should_handle
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<int, 1>)
+ {
+ base_t::template set<F1, F2, V>();
+ }
+ // else
+ template <field F1, field F2, char V>
+ inline void set_dispatch(integral_constant<int, 2>)
+ {}
+
+ // Interrupt && interrupt
+ template <field F1, field F2, char V>
+ inline void update_dispatch(integral_constant<int, 0>)
+ {
+ interrupt = true;
+ }
+ // else should_handle
+ template <field F1, field F2, char V>
+ inline void update_dispatch(integral_constant<int, 1>)
+ {
+ base_t::template update<F1, F2, V>();
+ }
+ // else
+ template <field F1, field F2, char V>
+ inline void update_dispatch(integral_constant<int, 2>)
+ {}
+};
+
+// OPERATORS
+
+template <typename Mask1, typename Mask2> inline
+boost::tuples::cons<
+ Mask1,
+ boost::tuples::cons<Mask2, boost::tuples::null_type>
+>
+operator||(Mask1 const& m1, Mask2 const& m2)
+{
+ namespace bt = boost::tuples;
+
+ return
+ bt::cons< Mask1, bt::cons<Mask2, bt::null_type> >
+ ( m1, bt::cons<Mask2, bt::null_type>(m2, bt::null_type()) );
+}
+
+template <typename Head, typename Tail, typename Mask> inline
+typename index::detail::tuples::push_back<
+ boost::tuples::cons<Head, Tail>, Mask
+>::type
+operator||(boost::tuples::cons<Head, Tail> const& t, Mask const& m)
+{
+ namespace bt = boost::tuples;
+
+ return
+ index::detail::tuples::push_back<
+ bt::cons<Head, Tail>, Mask
+ >::apply(t, m);
+}
+
+// PREDEFINED MASKS
+
+// TODO:
+// 1. specialize for simplified masks if available
+// e.g. for TOUCHES use 1 mask for A/A
+// 2. Think about dimensions > 2 e.g. should TOUCHES be true
+// if the interior of the Areal overlaps the boundary of the Volumetric
+// like it's true for Linear/Areal
+
+// EQUALS
+template <typename Geometry1, typename Geometry2>
+struct static_mask_equals_type
+{
+ typedef static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> type; // wikipedia
+ //typedef static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> type; // OGC
+};
+
+// DISJOINT
+typedef static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> static_mask_disjoint;
+
+// TOUCHES - NOT P/P
+template <typename Geometry1,
+ typename Geometry2,
+ std::size_t Dim1 = topological_dimension<Geometry1>::value,
+ std::size_t Dim2 = topological_dimension<Geometry2>::value>
+struct static_mask_touches_impl
+{
+ typedef boost::mpl::vector<
+ static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>,
+ static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>,
+ static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'>
+ > type;
+};
+// According to OGC, doesn't apply to P/P
+// Using the above mask the result would be always false
+template <typename Geometry1, typename Geometry2>
+struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0>
+ : not_implemented<typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type>
+{};
+
+template <typename Geometry1, typename Geometry2>
+struct static_mask_touches_type
+ : static_mask_touches_impl<Geometry1, Geometry2>
+{};
+
+// WITHIN
+typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within;
+
+// COVERED_BY (non OGC)
+typedef boost::mpl::vector<
+ static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>,
+ static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>,
+ static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>,
+ static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'>
+ > static_mask_covered_by;
+
+// CROSSES
+// dim(G1) < dim(G2) - P/L P/A L/A
+template <typename Geometry1,
+ typename Geometry2,
+ std::size_t Dim1 = topological_dimension<Geometry1>::value,
+ std::size_t Dim2 = topological_dimension<Geometry2>::value,
+ bool D1LessD2 = (Dim1 < Dim2)
+>
+struct static_mask_crosses_impl
+{
+ typedef static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type;
+};
+// TODO: I'm not sure if this one below should be available!
+// dim(G1) > dim(G2) - L/P A/P A/L
+template <typename Geometry1, typename Geometry2,
+ std::size_t Dim1, std::size_t Dim2
+>
+struct static_mask_crosses_impl<Geometry1, Geometry2, Dim1, Dim2, false>
+{
+ typedef static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type;
+};
+// dim(G1) == dim(G2) - P/P A/A
+template <typename Geometry1, typename Geometry2,
+ std::size_t Dim
+>
+struct static_mask_crosses_impl<Geometry1, Geometry2, Dim, Dim, false>
+ : not_implemented<typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type>
+{};
+// dim(G1) == 1 && dim(G2) == 1 - L/L
+template <typename Geometry1, typename Geometry2>
+struct static_mask_crosses_impl<Geometry1, Geometry2, 1, 1, false>
+{
+ typedef static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct static_mask_crosses_type
+ : static_mask_crosses_impl<Geometry1, Geometry2>
+{};
+
+// OVERLAPS
+
+// dim(G1) != dim(G2) - NOT P/P, L/L, A/A
+template <typename Geometry1,
+ typename Geometry2,
+ std::size_t Dim1 = topological_dimension<Geometry1>::value,
+ std::size_t Dim2 = topological_dimension<Geometry2>::value
+>
+struct static_mask_overlaps_impl
+ : not_implemented<typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type>
+{};
+// dim(G1) == D && dim(G2) == D - P/P A/A
+template <typename Geometry1, typename Geometry2, std::size_t Dim>
+struct static_mask_overlaps_impl<Geometry1, Geometry2, Dim, Dim>
+{
+ typedef static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
+};
+// dim(G1) == 1 && dim(G2) == 1 - L/L
+template <typename Geometry1, typename Geometry2>
+struct static_mask_overlaps_impl<Geometry1, Geometry2, 1, 1>
+{
+ typedef static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
+};
+
+template <typename Geometry1, typename Geometry2>
+struct static_mask_overlaps_type
+ : static_mask_overlaps_impl<Geometry1, Geometry2>
+{};
+
+// RESULTS/HANDLERS UTILS
+
+template <field F1, field F2, char V, typename Result>
+inline void set(Result & res)
+{
+ res.template set<F1, F2, V>();
+}
+
+template <field F1, field F2, char V, bool Transpose>
+struct set_dispatch
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ res.template set<F1, F2, V>();
+ }
+};
+
+template <field F1, field F2, char V>
+struct set_dispatch<F1, F2, V, true>
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ res.template set<F2, F1, V>();
+ }
+};
+
+template <field F1, field F2, char V, bool Transpose, typename Result>
+inline void set(Result & res)
+{
+ set_dispatch<F1, F2, V, Transpose>::apply(res);
+}
+
+template <char V, typename Result>
+inline void set(Result & res)
+{
+ res.template set<interior, interior, V>();
+ res.template set<interior, boundary, V>();
+ res.template set<interior, exterior, V>();
+ res.template set<boundary, interior, V>();
+ res.template set<boundary, boundary, V>();
+ res.template set<boundary, exterior, V>();
+ res.template set<exterior, interior, V>();
+ res.template set<exterior, boundary, V>();
+ res.template set<exterior, exterior, V>();
+}
+
+template <char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE, typename Result>
+inline void set(Result & res)
+{
+ res.template set<interior, interior, II>();
+ res.template set<interior, boundary, IB>();
+ res.template set<interior, exterior, IE>();
+ res.template set<boundary, interior, BI>();
+ res.template set<boundary, boundary, BB>();
+ res.template set<boundary, exterior, BE>();
+ res.template set<exterior, interior, EI>();
+ res.template set<exterior, boundary, EB>();
+ res.template set<exterior, exterior, EE>();
+}
+
+template <field F1, field F2, char D, typename Result>
+inline void update(Result & res)
+{
+ res.template update<F1, F2, D>();
+}
+
+template <field F1, field F2, char D, bool Transpose>
+struct update_result_dispatch
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ update<F1, F2, D>(res);
+ }
+};
+
+template <field F1, field F2, char D>
+struct update_result_dispatch<F1, F2, D, true>
+{
+ template <typename Result>
+ static inline void apply(Result & res)
+ {
+ update<F2, F1, D>(res);
+ }
+};
+
+template <field F1, field F2, char D, bool Transpose, typename Result>
+inline void update(Result & res)
+{
+ update_result_dispatch<F1, F2, D, Transpose>::apply(res);
+}
+
+template <field F1, field F2, char D, typename Result>
+inline bool may_update(Result const& res)
+{
+ return res.template may_update<F1, F2, D>();
+}
+
+template <field F1, field F2, char D, bool Transpose>
+struct may_update_result_dispatch
+{
+ template <typename Result>
+ static inline bool apply(Result const& res)
+ {
+ return may_update<F1, F2, D>(res);
+ }
+};
+
+template <field F1, field F2, char D>
+struct may_update_result_dispatch<F1, F2, D, true>
+{
+ template <typename Result>
+ static inline bool apply(Result const& res)
+ {
+ return may_update<F2, F1, D>(res);
+ }
+};
+
+template <field F1, field F2, char D, bool Transpose, typename Result>
+inline bool may_update(Result const& res)
+{
+ return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res);
+}
+
+template <typename Result, char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE>
+inline Result return_result()
+{
+ Result res;
+ set<II, IB, IE, BI, BB, BE, EI, EB, EE>(res);
+ return res;
+}
+
+template <typename Geometry>
+struct result_dimension
+{
+ BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0);
+ static const char value
+ = ( geometry::dimension<Geometry>::value <= 9 ) ?
+ ( '0' + geometry::dimension<Geometry>::value ) :
+ 'T';
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp
new file mode 100644
index 0000000000..98b857a488
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp
@@ -0,0 +1,241 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate {
+
+// TODO: change the name for e.g. something with the word "exterior"
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct topology_check
+ : not_implemented<Tag>
+{};
+
+//template <typename Point>
+//struct topology_check<Point, point_tag>
+//{
+// static const char interior = '0';
+// static const char boundary = 'F';
+//
+// static const bool has_interior = true;
+// static const bool has_boundary = false;
+//
+// topology_check(Point const&) {}
+// template <typename IgnoreBoundaryPoint>
+// topology_check(Point const&, IgnoreBoundaryPoint const&) {}
+//};
+
+template <typename Linestring>
+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)
+ {
+ init(ls, 0); /*dummy param*/
+ }
+
+ template <typename IgnoreBoundaryPoint>
+ topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp)
+ {
+ init(ls, ibp); /*dummy param, won't be used*/
+ }
+
+ // 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&)
+ {
+ std::size_t count = boost::size(ls);
+ 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));
+ }
+};
+
+template <typename MultiLinestring>
+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)
+ {
+ init(mls, not_ignoring_counter());
+ }
+
+ template <typename IgnoreBoundaryPoint>
+ topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp)
+ {
+ init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp));
+ }
+
+ template <typename OddCounter>
+ void init(MultiLinestring const& mls, OddCounter const& odd_counter)
+ {
+ typedef typename geometry::point_type<MultiLinestring>::type point_type;
+ std::vector<point_type> endpoints;
+ endpoints.reserve(boost::size(mls) * 2);
+
+ typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
+ for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it )
+ {
+ std::size_t count = boost::size(*it);
+
+ if ( count > 0 )
+ {
+ has_interior = true;
+ }
+
+ if ( count > 1 )
+ {
+ // don't store boundaries of linear rings, this doesn't change anything
+ if ( ! equals::equals_point_point(range::front(*it), range::back(*it)) )
+ {
+ endpoints.push_back(range::front(*it));
+ endpoints.push_back(range::back(*it));
+ }
+ }
+ }
+
+ has_boundary = false;
+
+ if ( !endpoints.empty() )
+ {
+ std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>());
+ has_boundary = odd_counter(endpoints.begin(), endpoints.end());
+ }
+ }
+
+ struct not_ignoring_counter
+ {
+ template <typename It>
+ bool operator()(It first, It last) const
+ {
+ return find_odd_count(first, last);
+ }
+ };
+
+ template <typename Point>
+ struct ignoring_counter
+ {
+ ignoring_counter(Point const& pt) : m_pt(pt) {}
+
+ template <typename It>
+ bool operator()(It first, It last) 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);
+ }
+
+ Point const& m_pt;
+ };
+
+ template <typename It>
+ static inline bool find_odd_count(It first, It last)
+ {
+ if ( first == last )
+ return false;
+
+ std::size_t count = 1;
+ It prev = first;
+ ++first;
+ for ( ; first != last ; ++first, ++prev )
+ {
+ // the end of the equal points subrange
+ if ( ! equals::equals_point_point(*first, *prev) )
+ {
+ if ( count % 2 != 0 )
+ return true;
+
+ count = 1;
+ }
+ else
+ {
+ ++count;
+ }
+ }
+
+ return count % 2 != 0;
+ }
+};
+
+template <typename Ring>
+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&) {}
+};
+
+template <typename Polygon>
+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&) {}
+};
+
+template <typename MultiPolygon>
+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&) {}
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp
new file mode 100644
index 0000000000..a2e56a8882
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/turns.hpp
@@ -0,0 +1,253 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
+
+#include <boost/geometry/strategies/distance.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+
+#include <boost/type_traits/is_base_of.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate { namespace turns {
+
+template <bool IncludeDegenerate = false>
+struct assign_policy
+ : overlay::assign_null_policy
+{
+ static bool const include_degenerate = IncludeDegenerate;
+};
+
+// GET_TURNS
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename GetTurnPolicy
+ = detail::get_turns::get_turn_info_type<Geometry1, Geometry2, assign_policy<> > >
+struct get_turns
+{
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+
+ typedef overlay::turn_info
+ <
+ point1_type,
+ typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type,
+ typename detail::get_turns::turn_operation_type
+ <
+ Geometry1, Geometry2,
+ typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type
+ >::type
+ > turn_info;
+
+ template <typename Turns>
+ static inline void apply(Turns & turns,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ detail::get_turns::no_interrupt_policy interrupt_policy;
+
+ apply(turns, geometry1, geometry2, interrupt_policy);
+ }
+
+ template <typename Turns, typename InterruptPolicy>
+ static inline void apply(Turns & turns,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ InterruptPolicy & interrupt_policy)
+ {
+ static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value;
+ static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value;
+
+ dispatch::get_turns
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type,
+ Geometry1,
+ Geometry2,
+ reverse1,
+ reverse2,
+ GetTurnPolicy
+ >::apply(0, geometry1, 1, geometry2,
+ detail::no_rescale_policy(), turns, interrupt_policy);
+ }
+};
+
+// TURNS SORTING AND SEARCHING
+
+template <int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0>
+struct op_to_int
+{
+ template <typename SegmentRatio>
+ inline int operator()(detail::overlay::turn_operation<SegmentRatio> const& op) const
+ {
+ switch(op.operation)
+ {
+ case detail::overlay::operation_none : return N;
+ case detail::overlay::operation_union : return U;
+ case detail::overlay::operation_intersection : return I;
+ case detail::overlay::operation_blocked : return B;
+ case detail::overlay::operation_continue : return C;
+ case detail::overlay::operation_opposite : return O;
+ }
+ return -1;
+ }
+};
+
+template <std::size_t OpId, typename OpToInt>
+struct less_op_xxx_linear
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ static OpToInt op_to_int;
+ return op_to_int(left.operations[OpId]) < op_to_int(right.operations[OpId]);
+ }
+};
+
+template <std::size_t OpId>
+struct less_op_linear_linear
+ : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> >
+{};
+
+template <std::size_t OpId>
+struct less_op_linear_areal
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
+ static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc;
+
+ segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
+ segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
+
+ if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
+ {
+ typedef typename Turn::turn_operation_type operation_type;
+ operation_type const& left_operation = left.operations[OpId];
+ operation_type const& right_operation = right.operations[OpId];
+
+ if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
+ {
+ return op_to_int_xuic(left_operation)
+ < op_to_int_xuic(right_operation);
+ }
+ else
+ {
+ return op_to_int_xiuc(left_operation)
+ < op_to_int_xiuc(right_operation);
+ }
+ }
+ else
+ {
+ //return op_to_int_xuic(left.operations[OpId]) < op_to_int_xuic(right.operations[OpId]);
+ return left_other_seg_id.multi_index < right_other_seg_id.multi_index;
+ }
+ }
+};
+
+template <std::size_t OpId>
+struct less_op_areal_linear
+ : less_op_xxx_linear< OpId, op_to_int<0,1,0,0,2,0> >
+{};
+
+template <std::size_t OpId>
+struct less_op_areal_areal
+{
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+ static op_to_int<0, 1, 2, 3, 4, 0> op_to_int_uixc;
+ static op_to_int<0, 2, 1, 3, 4, 0> op_to_int_iuxc;
+
+ segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
+ segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
+
+ typedef typename Turn::turn_operation_type operation_type;
+ operation_type const& left_operation = left.operations[OpId];
+ operation_type const& right_operation = right.operations[OpId];
+
+ if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
+ {
+ if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
+ {
+ return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
+ }
+ else
+ {
+ if ( left_other_seg_id.ring_index == -1 )
+ {
+ if ( left_operation.operation == overlay::operation_union )
+ return false;
+ else if ( left_operation.operation == overlay::operation_intersection )
+ return true;
+ }
+ else if ( right_other_seg_id.ring_index == -1 )
+ {
+ if ( right_operation.operation == overlay::operation_union )
+ return true;
+ else if ( right_operation.operation == overlay::operation_intersection )
+ return false;
+ }
+
+ return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation);
+ }
+ }
+ else
+ {
+ return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
+ }
+ }
+};
+
+// sort turns by G1 - source_index == 0 by:
+// seg_id -> distance -> operation
+template <std::size_t OpId = 0,
+ typename LessOp = less_op_xxx_linear< OpId, op_to_int<> > >
+struct less
+{
+ BOOST_STATIC_ASSERT(OpId < 2);
+
+ template <typename Turn>
+ static inline bool use_fraction(Turn const& left, Turn const& right)
+ {
+ static LessOp less_op;
+
+ return left.operations[OpId].fraction < right.operations[OpId].fraction
+ || ( left.operations[OpId].fraction == right.operations[OpId].fraction
+ && less_op(left, right) );
+ }
+
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.operations[OpId].seg_id;
+ segment_identifier const& sr = right.operations[OpId].seg_id;
+
+ return sl < sr || ( sl == sr && use_fraction(left, right) );
+ }
+};
+
+}}} // namespace detail::relate::turns
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/ring_identifier.hpp b/boost/geometry/algorithms/detail/ring_identifier.hpp
index 9209ee0304..bc3fe1fef3 100644
--- a/boost/geometry/algorithms/detail/ring_identifier.hpp
+++ b/boost/geometry/algorithms/detail/ring_identifier.hpp
@@ -10,6 +10,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
+#if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
+#include <iostream>
+#endif
+
+
+#include <boost/geometry/algorithms/detail/signed_index_type.hpp>
+
+
namespace boost { namespace geometry
{
@@ -24,7 +32,9 @@ struct ring_identifier
, ring_index(-1)
{}
- inline ring_identifier(int src, int mul, int rin)
+ inline ring_identifier(signed_index_type src,
+ signed_index_type mul,
+ signed_index_type rin)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
@@ -58,9 +68,9 @@ struct ring_identifier
#endif
- int source_index;
- int multi_index;
- int ring_index;
+ signed_index_type source_index;
+ signed_index_type multi_index;
+ signed_index_type ring_index;
};
diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
index ad62f232bd..63feb12a71 100644
--- a/boost/geometry/algorithms/detail/sections/range_by_section.hpp
+++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
@@ -7,14 +7,19 @@
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
// 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_SECTIONS_RANGE_BY_SECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
-
+#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
@@ -22,7 +27,10 @@
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
-
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -50,7 +58,29 @@ struct full_section_polygon
{
return section.ring_id.ring_index < 0
? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[section.ring_id.ring_index];
+ : range::at(geometry::interior_rings(polygon), section.ring_id.ring_index);
+ }
+};
+
+
+template
+<
+ typename MultiGeometry,
+ typename Section,
+ typename Policy
+>
+struct full_section_multi
+{
+ static inline typename ring_return_type<MultiGeometry const>::type apply(
+ MultiGeometry const& multi, Section const& section)
+ {
+ BOOST_ASSERT
+ (
+ section.ring_id.multi_index >= 0
+ && section.ring_id.multi_index < int(boost::size(multi))
+ );
+
+ return Policy::apply(range::at(multi, section.ring_id.multi_index), section);
}
};
@@ -98,6 +128,35 @@ struct range_by_section<polygon_tag, Polygon, Section>
{};
+template <typename MultiPolygon, typename Section>
+struct range_by_section<multi_polygon_tag, MultiPolygon, Section>
+ : detail::section::full_section_multi
+ <
+ MultiPolygon,
+ Section,
+ detail::section::full_section_polygon
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ Section
+ >
+ >
+{};
+
+template <typename MultiLinestring, typename Section>
+struct range_by_section<multi_linestring_tag, MultiLinestring, Section>
+ : detail::section::full_section_multi
+ <
+ MultiLinestring,
+ Section,
+ detail::section::full_section_range
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ Section
+ >
+ >
+{};
+
+
} // namespace dispatch
#endif
diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
index a6e6837fe4..250577c0c2 100644
--- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp
+++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
@@ -3,6 +3,10 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,33 +15,39 @@
// 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_SECTIONS_SECTIONALIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
#include <cstddef>
#include <vector>
+#include <boost/concept/requires.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/geometries/segment.hpp>
-
namespace boost { namespace geometry
{
@@ -71,6 +81,9 @@ struct section
bool duplicate;
int non_duplicate_index;
+ bool is_non_duplicate_first;
+ bool is_non_duplicate_last;
+
inline section()
: id(-1)
, begin_index(-1)
@@ -79,9 +92,11 @@ struct section
, range_count(0)
, duplicate(false)
, non_duplicate_index(-1)
+ , is_non_duplicate_first(false)
+ , is_non_duplicate_last(false)
{
assign_inverse(bounding_box);
- for (register std::size_t i = 0; i < DimensionCount; i++)
+ for (std::size_t i = 0; i < DimensionCount; i++)
{
directions[i] = 0;
}
@@ -107,14 +122,14 @@ struct sections : std::vector<section<Box, DimensionCount> >
namespace detail { namespace sectionalize
{
-template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
+template <std::size_t Dimension, std::size_t DimensionCount>
struct get_direction_loop
{
- typedef typename coordinate_type<Segment>::type coordinate_type;
-
+ template <typename Segment>
static inline void apply(Segment const& seg,
int directions[DimensionCount])
{
+ typedef typename coordinate_type<Segment>::type coordinate_type;
coordinate_type const diff =
geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
@@ -123,14 +138,15 @@ struct get_direction_loop
get_direction_loop
<
- Segment, Dimension + 1, DimensionCount
+ Dimension + 1, DimensionCount
>::apply(seg, directions);
}
};
-template <typename Segment, std::size_t DimensionCount>
-struct get_direction_loop<Segment, DimensionCount, DimensionCount>
+template <std::size_t DimensionCount>
+struct get_direction_loop<DimensionCount, DimensionCount>
{
+ template <typename Segment>
static inline void apply(Segment const&, int [DimensionCount])
{}
};
@@ -182,16 +198,15 @@ struct compare_loop<T, DimensionCount, DimensionCount>
};
-template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
+template <std::size_t Dimension, std::size_t DimensionCount>
struct check_duplicate_loop
{
- typedef typename coordinate_type<Segment>::type coordinate_type;
-
+ template <typename Segment>
static inline bool apply(Segment const& seg)
{
if (! geometry::math::equals
(
- geometry::get<0, Dimension>(seg),
+ geometry::get<0, Dimension>(seg),
geometry::get<1, Dimension>(seg)
)
)
@@ -201,14 +216,15 @@ struct check_duplicate_loop
return check_duplicate_loop
<
- Segment, Dimension + 1, DimensionCount
+ Dimension + 1, DimensionCount
>::apply(seg);
}
};
-template <typename Segment, std::size_t DimensionCount>
-struct check_duplicate_loop<Segment, DimensionCount, DimensionCount>
+template <std::size_t DimensionCount>
+struct check_duplicate_loop<DimensionCount, DimensionCount>
{
+ template <typename Segment>
static inline bool apply(Segment const&)
{
return true;
@@ -236,48 +252,62 @@ struct assign_loop<T, DimensionCount, DimensionCount>
/// @brief Helper class to create sections of a part of a range, on the fly
template
<
- typename Range, // Can be closeable_view
typename Point,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_part
{
- typedef model::referring_segment<Point const> segment_type;
- typedef typename boost::range_value<Sections>::type section_type;
+ template
+ <
+ typename Range, // Can be closeable_view
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Sections& sections,
+ Range const& range,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ ring_identifier ring_id,
+ std::size_t max_count)
+ {
+ boost::ignore_unused_variable_warning(robust_policy);
+ boost::ignore_unused_variable_warning(make_rescaled_boxes);
- typedef typename boost::range_iterator<Range const>::type iterator_type;
+ typedef model::referring_segment<Point const> segment_type;
+ typedef typename boost::range_value<Sections>::type section_type;
+ typedef model::segment
+ <
+ typename robust_point_type<Point, RobustPolicy>::type
+ > robust_segment_type;
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
- static inline void apply(Sections& sections, section_type& section,
- int& index, int& ndi,
- Range const& range,
- ring_identifier ring_id)
- {
- if (int(boost::size(range)) <= index)
+ if ( boost::empty(range) )
{
return;
}
- if (index == 0)
- {
- ndi = 0;
- }
+ int index = 0;
+ int ndi = 0; // non duplicate index
+ section_type section;
- iterator_type it = boost::begin(range);
- it += index;
+ bool mark_first_non_duplicated = true;
+ std::size_t last_non_duplicate_index = sections.size();
+ iterator_type it = boost::begin(range);
+
for(iterator_type previous = it++;
it != boost::end(range);
++previous, ++it, index++)
{
segment_type segment(*previous, *it);
+ robust_segment_type robust_segment;
+ geometry::recalculate(robust_segment, segment, robust_policy);
int direction_classes[DimensionCount] = {0};
get_direction_loop
<
- segment_type, 0, DimensionCount
- >::apply(segment, direction_classes);
+ 0, DimensionCount
+ >::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
// Those sections might be omitted, if wished, lateron
@@ -290,8 +320,8 @@ struct sectionalize_part
// (DimensionCount might be < dimension<P>::value)
if (check_duplicate_loop
<
- segment_type, 0, geometry::dimension<Point>::type::value
- >::apply(segment)
+ 0, geometry::dimension<Point>::type::value
+ >::apply(robust_segment)
)
{
duplicate = true;
@@ -312,10 +342,15 @@ struct sectionalize_part
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions)
- || section.count > MaxCount
+ || section.count > max_count
)
)
{
+ if ( !section.duplicate )
+ {
+ last_non_duplicate_index = sections.size();
+ }
+
sections.push_back(section);
section = section_type();
}
@@ -328,14 +363,21 @@ struct sectionalize_part
section.non_duplicate_index = ndi;
section.range_count = boost::size(range);
+ if ( mark_first_non_duplicated && !duplicate )
+ {
+ section.is_non_duplicate_first = true;
+ mark_first_non_duplicated = false;
+ }
+
copy_loop
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions);
- geometry::expand(section.bounding_box, *previous);
+
+ expand_box(*previous, robust_policy, section);
}
- geometry::expand(section.bounding_box, *it);
+ expand_box(*it, robust_policy, section);
section.end_index = index + 1;
section.count++;
if (! duplicate)
@@ -343,20 +385,58 @@ struct sectionalize_part
ndi++;
}
}
+
+ // Add last section if applicable
+ if (section.count > 0)
+ {
+ if ( !section.duplicate )
+ {
+ last_non_duplicate_index = sections.size();
+ }
+
+ sections.push_back(section);
+ }
+
+ if ( last_non_duplicate_index < sections.size()
+ && !sections[last_non_duplicate_index].duplicate )
+ {
+ sections[last_non_duplicate_index].is_non_duplicate_last = true;
+ }
+ }
+
+ template <typename InputPoint, typename RobustPolicy, typename Section>
+ static inline void expand_box(InputPoint const& point,
+ RobustPolicy const& robust_policy,
+ Section& section)
+ {
+ typename geometry::point_type<typename Section::box_type>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ geometry::expand(section.bounding_box, robust_point);
}
};
template
<
- typename Range, closure_selector Closure, bool Reverse,
+ closure_selector Closure, bool Reverse,
typename Point,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_range
{
+ template
+ <
+ typename Range,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Range const& range,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections,
+ ring_identifier ring_id,
+ std::size_t max_count)
+ {
typedef typename closeable_view<Range const, Closure>::type cview_type;
typedef typename reversible_view
<
@@ -364,11 +444,6 @@ struct sectionalize_range
Reverse ? iterate_reverse : iterate_forward
>::type view_type;
- static inline void apply(Range const& range, Sections& sections,
- ring_identifier ring_id)
- {
- typedef model::referring_segment<Point const> segment_type;
-
cview_type cview(range);
view_type view(cview);
@@ -385,72 +460,69 @@ struct sectionalize_range
return;
}
- int index = 0;
- int ndi = 0; // non duplicate index
-
- typedef typename boost::range_value<Sections>::type section_type;
- section_type section;
-
- sectionalize_part
- <
- view_type, Point, Sections,
- DimensionCount, MaxCount
- >::apply(sections, section, index, ndi,
- view, ring_id);
-
- // Add last section if applicable
- if (section.count > 0)
- {
- sections.push_back(section);
- }
+ sectionalize_part<Point, DimensionCount>
+ ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count);
}
};
template
<
- typename Polygon,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_polygon
{
- static inline void apply(Polygon const& poly, Sections& sections,
- ring_identifier ring_id)
+ template
+ <
+ typename Polygon,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Polygon const& poly,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections,
+ ring_identifier ring_id, std::size_t max_count)
{
typedef typename point_type<Polygon>::type point_type;
- typedef typename ring_type<Polygon>::type ring_type;
+ //typedef typename ring_type<Polygon>::type ring_type;
typedef sectionalize_range
<
- ring_type, closure<Polygon>::value, Reverse,
- point_type, Sections, DimensionCount, MaxCount
- > sectionalizer_type;
+ closure<Polygon>::value, Reverse,
+ point_type, DimensionCount
+ > per_range;
ring_id.ring_index = -1;
- sectionalizer_type::apply(exterior_ring(poly), sections, ring_id);//-1, multi_index);
+ per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
ring_id.ring_index++;
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
- ++it, ++ring_id.ring_index)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
{
- sectionalizer_type::apply(*it, sections, ring_id);
+ per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
}
}
};
template
<
- typename Box,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize_box
{
- static inline void apply(Box const& box, Sections& sections, ring_identifier const& ring_id)
+ template
+ <
+ typename Box,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(Box const& box,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections,
+ ring_identifier const& ring_id, std::size_t max_count)
{
typedef typename point_type<Box>::type point_type;
@@ -462,7 +534,7 @@ struct sectionalize_box
// (or polygon would be a helper-type).
// Therefore we mimic a linestring/std::vector of 5 points
- // TODO: might be replaced by assign_box_corners_oriented
+ // TODO: might be replaced by assign_box_corners_oriented
// or just "convert"
point_type ll, lr, ul, ur;
geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
@@ -476,12 +548,36 @@ struct sectionalize_box
sectionalize_range
<
- std::vector<point_type>, closed, false,
+ closed, false,
point_type,
- Sections,
- DimensionCount,
- MaxCount
- >::apply(points, sections, ring_id);
+ DimensionCount
+ >::apply(points, robust_policy, make_rescaled_boxes, sections,
+ ring_id, max_count);
+ }
+};
+
+template <std::size_t DimensionCount, typename Policy>
+struct sectionalize_multi
+{
+ template
+ <
+ typename MultiGeometry,
+ typename RobustPolicy,
+ typename Sections
+ >
+ static inline void apply(MultiGeometry const& multi,
+ RobustPolicy const& robust_policy,
+ bool make_rescaled_boxes,
+ Sections& sections, ring_identifier ring_id, std::size_t max_count)
+ {
+ ring_id.multi_index = 0;
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, ++ring_id.multi_index)
+ {
+ Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
+ }
}
};
@@ -498,6 +594,29 @@ inline void set_section_unique_ids(Sections& sections)
}
}
+template <typename Sections>
+inline void enlarge_sections(Sections& sections)
+{
+ // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
+ // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1")
+ // Drawback: not really, range is now completely inside the section. Section is a tiny bit too large,
+ // which might cause (a small number) of more comparisons
+ // TODO: make dimension-agnostic
+ for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
+ it != boost::end(sections);
+ ++it)
+ {
+ typedef typename boost::range_value<Sections>::type section_type;
+ typedef typename section_type::box_type box_type;
+ typedef typename geometry::coordinate_type<box_type>::type coordinate_type;
+ coordinate_type const reps = math::relaxed_epsilon(10.0);
+ geometry::set<0, 0>(it->bounding_box, geometry::get<0, 0>(it->bounding_box) - reps);
+ geometry::set<0, 1>(it->bounding_box, geometry::get<0, 1>(it->bounding_box) - reps);
+ geometry::set<1, 0>(it->bounding_box, geometry::get<1, 0>(it->bounding_box) + reps);
+ geometry::set<1, 1>(it->bounding_box, geometry::get<1, 1>(it->bounding_box) + reps);
+ }
+}
+
}} // namespace detail::sectionalize
#endif // DOXYGEN_NO_DETAIL
@@ -512,9 +631,7 @@ template
typename Tag,
typename Geometry,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize
{
@@ -529,43 +646,29 @@ template
<
typename Box,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
-struct sectionalize<box_tag, Box, Reverse, Sections, DimensionCount, MaxCount>
- : detail::sectionalize::sectionalize_box
- <
- Box,
- Sections,
- DimensionCount,
- MaxCount
- >
+struct sectionalize<box_tag, Box, Reverse, DimensionCount>
+ : detail::sectionalize::sectionalize_box<DimensionCount>
{};
template
<
typename LineString,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
struct sectionalize
<
linestring_tag,
LineString,
false,
- Sections,
- DimensionCount,
- MaxCount
+ DimensionCount
>
: detail::sectionalize::sectionalize_range
<
- LineString, closed, false,
+ closed, false,
typename point_type<LineString>::type,
- Sections,
- DimensionCount,
- MaxCount
+ DimensionCount
>
{};
@@ -573,18 +676,14 @@ template
<
typename Ring,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
-struct sectionalize<ring_tag, Ring, Reverse, Sections, DimensionCount, MaxCount>
+struct sectionalize<ring_tag, Ring, Reverse, DimensionCount>
: detail::sectionalize::sectionalize_range
<
- Ring, geometry::closure<Ring>::value, Reverse,
+ geometry::closure<Ring>::value, Reverse,
typename point_type<Ring>::type,
- Sections,
- DimensionCount,
- MaxCount
+ DimensionCount
>
{};
@@ -592,17 +691,54 @@ template
<
typename Polygon,
bool Reverse,
- typename Sections,
- std::size_t DimensionCount,
- std::size_t MaxCount
+ std::size_t DimensionCount
>
-struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, MaxCount>
+struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount>
: detail::sectionalize::sectionalize_polygon
<
- Polygon, Reverse, Sections, DimensionCount, MaxCount
+ Reverse, DimensionCount
>
{};
+template
+<
+ typename MultiPolygon,
+ bool Reverse,
+ std::size_t DimensionCount
+>
+struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount>
+ : detail::sectionalize::sectionalize_multi
+ <
+ DimensionCount,
+ detail::sectionalize::sectionalize_polygon
+ <
+ Reverse,
+ DimensionCount
+ >
+ >
+
+{};
+
+template
+<
+ typename MultiLinestring,
+ bool Reverse,
+ std::size_t DimensionCount
+>
+struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount>
+ : detail::sectionalize::sectionalize_multi
+ <
+ DimensionCount,
+ detail::sectionalize::sectionalize_range
+ <
+ closed, false,
+ typename point_type<MultiLinestring>::type,
+ DimensionCount
+ >
+ >
+
+{};
+
} // namespace dispatch
#endif
@@ -613,33 +749,55 @@ struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, Max
\tparam Geometry type of geometry to check
\tparam Sections type of sections to create
\param geometry geometry to create sections from
+ \param robust_policy policy to handle robustness issues
+ \param enlarge_secion_boxes if true, boxes are enlarged a tiny bit to be sure
+ they really contain all geometries (w.r.t. robustness)
\param sections structure with sections
\param source_index index to assign to the ring_identifiers
*/
-template<bool Reverse, typename Geometry, typename Sections>
-inline void sectionalize(Geometry const& geometry, Sections& sections, int source_index = 0)
+template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy>
+inline void sectionalize(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
+ bool enlarge_secion_boxes,
+ Sections& sections,
+ int source_index = 0)
{
concept::check<Geometry const>();
- // TODO: review use of this constant (see below) as causing problems with GCC 4.6 --mloskot
+ sections.clear();
+
+ ring_identifier ring_id;
+ ring_id.source_index = source_index;
+
// A maximum of 10 segments per section seems to give the fastest results
- //static std::size_t const max_segments_per_section = 10;
- typedef dispatch::sectionalize
+ dispatch::sectionalize
<
typename tag<Geometry>::type,
Geometry,
Reverse,
- Sections,
- Sections::value,
- 10 // TODO: max_segments_per_section
- > sectionalizer_type;
+ Sections::value
+ >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10);
- sections.clear();
- ring_identifier ring_id;
- ring_id.source_index = source_index;
- sectionalizer_type::apply(geometry, sections, ring_id);
detail::sectionalize::set_section_unique_ids(sections);
+ if (! enlarge_secion_boxes)
+ {
+ detail::sectionalize::enlarge_sections(sections);
+ }
+}
+
+
+#if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE)
+// Backwards compatibility
+template<bool Reverse, typename Geometry, typename Sections>
+inline void sectionalize(Geometry const& geometry,
+ Sections& sections,
+ int source_index = 0)
+{
+ return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
+ false, sections,
+ source_index);
}
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/signed_index_type.hpp b/boost/geometry/algorithms/detail/signed_index_type.hpp
new file mode 100644
index 0000000000..36dcf4de4c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/signed_index_type.hpp
@@ -0,0 +1,29 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, 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_SIGNED_INDEX_TYPE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP
+
+
+#include <cstddef>
+#include <boost/type_traits/make_signed.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+typedef boost::make_signed<std::size_t>::type signed_index_type;
+//typedef std::ptrdiff_t signed_index_type;
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_INDEX_TYPE_HPP
diff --git a/boost/geometry/algorithms/detail/single_geometry.hpp b/boost/geometry/algorithms/detail/single_geometry.hpp
new file mode 100644
index 0000000000..c65ff8bf84
--- /dev/null
+++ b/boost/geometry/algorithms/detail/single_geometry.hpp
@@ -0,0 +1,95 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// 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_SINGLE_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP
+
+#include <boost/type_traits/is_base_of.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/util/range.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch {
+
+// Returns single geometry by Id
+// for single geometries returns the geometry itself
+template <typename Geometry,
+ bool IsMulti = boost::is_base_of
+ <
+ multi_tag,
+ typename geometry::tag<Geometry>::type
+ >::value
+>
+struct single_geometry
+{
+ typedef Geometry & return_type;
+
+ template <typename Id>
+ static inline return_type apply(Geometry & g, Id const& ) { return g; }
+};
+
+// for multi geometries returns one of the stored single geometries
+template <typename Geometry>
+struct single_geometry<Geometry, true>
+{
+ typedef typename boost::mpl::if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::range_value<Geometry>::type const&,
+ typename boost::range_value<Geometry>::type
+ >::type return_type;
+
+ template <typename Id>
+ static inline return_type apply(Geometry & g, Id const& id)
+ {
+ BOOST_ASSERT(id.multi_index >= 0);
+ return range::at(g, id.multi_index);
+ }
+};
+
+} // namespace detail_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail {
+
+template <typename Geometry>
+struct single_geometry_return_type
+{
+ typedef typename detail_dispatch::single_geometry<Geometry>::return_type type;
+};
+
+template <typename Geometry, typename Id>
+inline
+typename single_geometry_return_type<Geometry>::type
+single_geometry(Geometry & geometry, Id const& id)
+{
+ return detail_dispatch::single_geometry<Geometry>::apply(geometry, id);
+}
+
+template <typename Geometry, typename Id>
+inline
+typename single_geometry_return_type<Geometry const>::type
+single_geometry(Geometry const& geometry, Id const& id)
+{
+ return detail_dispatch::single_geometry<Geometry const>::apply(geometry, id);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/sub_range.hpp b/boost/geometry/algorithms/detail/sub_range.hpp
new file mode 100644
index 0000000000..a68f31362a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/sub_range.hpp
@@ -0,0 +1,113 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// 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_SUB_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP
+
+#include <boost/geometry/util/range.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch {
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type,
+ bool IsMulti = boost::is_base_of<multi_tag, Tag>::value>
+struct sub_range : not_implemented<Tag>
+{};
+
+template <typename Geometry, typename Tag>
+struct sub_range<Geometry, Tag, false>
+{
+ typedef Geometry & return_type;
+
+ template <typename Id> static inline
+ return_type apply(Geometry & geometry, Id const&)
+ {
+ return geometry;
+ }
+};
+
+template <typename Geometry>
+struct sub_range<Geometry, polygon_tag, false>
+{
+ typedef typename geometry::ring_type<Geometry>::type & return_type;
+
+ template <typename Id> static inline
+ return_type apply(Geometry & geometry, Id const& id)
+ {
+ if ( id.ring_index < 0 )
+ {
+ return geometry::exterior_ring(geometry);
+ }
+ else
+ {
+ std::size_t ri = static_cast<std::size_t>(id.ring_index);
+ return range::at(geometry::interior_rings(geometry), ri);
+ }
+ }
+};
+
+template <typename Geometry, typename Tag>
+struct sub_range<Geometry, Tag, true>
+{
+ typedef typename boost::range_value<Geometry>::type value_type;
+ typedef typename boost::mpl::if_c
+ <
+ boost::is_const<Geometry>::value,
+ typename boost::add_const<value_type>::type,
+ value_type
+ >::type sub_type;
+
+ typedef detail_dispatch::sub_range<sub_type> sub_sub_range;
+
+ // TODO: shouldn't it be return_type?
+ typedef typename sub_sub_range::return_type return_type;
+
+ template <typename Id> static inline
+ return_type apply(Geometry & geometry, Id const& id)
+ {
+ BOOST_ASSERT(0 <= id.multi_index);
+ return sub_sub_range::apply(range::at(geometry, id.multi_index), id);
+ }
+};
+
+} // namespace detail_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+namespace detail {
+
+template <typename Geometry>
+struct sub_range_return_type
+{
+ typedef typename detail_dispatch::sub_range<Geometry>::return_type type;
+};
+
+// This function also works for geometry::segment_identifier
+
+template <typename Geometry, typename Id> inline
+typename sub_range_return_type<Geometry>::type
+sub_range(Geometry & geometry, Id const& id)
+{
+ return detail_dispatch::sub_range<Geometry>::apply(geometry, id);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
index 62328a0d87..21f5fe40b7 100644
--- a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
+++ b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
@@ -16,7 +16,7 @@
// BSG 2012-02-06: we use this currently only for distance.
// For other scalar results area,length,perimeter it is commented on purpose.
-// Reason is that for distance there is no other choice. distance of two
+// Reason is that for distance there is no other choice. distance of two
// empty geometries (or one empty) should NOT return any value.
// But for area it is no problem to be 0.
// Suppose: area(intersection(a,b)). We (probably) don't want a throw there...
@@ -24,6 +24,10 @@
// So decided that at least for Boost 1.49 this is commented for
// scalar results, except distance.
+#if defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW)
+#include <boost/core/ignore_unused.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -39,6 +43,8 @@ inline void throw_on_empty_input(Geometry const& geometry)
{
throw empty_input_exception();
}
+#else
+ boost::ignore_unused(geometry);
#endif
}
diff --git a/boost/geometry/algorithms/detail/turns/compare_turns.hpp b/boost/geometry/algorithms/detail/turns/compare_turns.hpp
new file mode 100644
index 0000000000..c29d5863b7
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/compare_turns.hpp
@@ -0,0 +1,113 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_TURNS_COMPARE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP
+
+#include <cstddef>
+#include <functional>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+// TURNS SORTING AND SEARCHING
+
+// sort turns by G1 - source_index == 0 by:
+// seg_id -> fraction -> other_id -> operation
+template
+<
+ typename IdLess = std::less<signed_index_type>,
+ int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0,
+ std::size_t OpId = 0
+>
+struct less_seg_fraction_other_op
+{
+ BOOST_STATIC_ASSERT(OpId < 2);
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+
+ template <typename Op>
+ static inline int order_op(Op const& op)
+ {
+ switch (op.operation)
+ {
+ case detail::overlay::operation_none : return N;
+ case detail::overlay::operation_union : return U;
+ case detail::overlay::operation_intersection : return I;
+ case detail::overlay::operation_blocked : return B;
+ case detail::overlay::operation_continue : return C;
+ case detail::overlay::operation_opposite : return O;
+ }
+ return -1;
+ }
+
+ template <typename Op>
+ static inline bool use_operation(Op const& left, Op const& right)
+ {
+ return order_op(left) < order_op(right);
+ }
+
+ template <typename Turn>
+ static inline bool use_other_id(Turn const& left, Turn const& right)
+ {
+ segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
+ segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
+
+ if ( left_other_seg_id.multi_index != right_other_seg_id.multi_index )
+ {
+ return left_other_seg_id.multi_index < right_other_seg_id.multi_index;
+ }
+ if ( left_other_seg_id.ring_index != right_other_seg_id.ring_index )
+ {
+ return left_other_seg_id.ring_index != right_other_seg_id.ring_index;
+ }
+ if ( left_other_seg_id.segment_index != right_other_seg_id.segment_index )
+ {
+ return IdLess()(left_other_seg_id.segment_index,
+ right_other_seg_id.segment_index);
+ }
+ return use_operation(left.operations[OpId], right.operations[OpId]);
+ }
+
+ template <typename Turn>
+ static inline bool use_fraction(Turn const& left, Turn const& right)
+ {
+ return left.operations[OpId].fraction < right.operations[OpId].fraction
+ || ( geometry::math::equals(left.operations[OpId].fraction, right.operations[OpId].fraction)
+ && use_other_id(left, right)
+ );
+ }
+
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.operations[OpId].seg_id;
+ segment_identifier const& sr = right.operations[OpId].seg_id;
+
+ return sl < sr || ( sl == sr && use_fraction(left, right) );
+ }
+};
+
+
+
+
+
+}} // namespace detail::turns
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/turns/debug_turn.hpp b/boost/geometry/algorithms/detail/turns/debug_turn.hpp
new file mode 100644
index 0000000000..5c4f03277a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/debug_turn.hpp
@@ -0,0 +1,65 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_TURNS_DEBUG_TURN_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP
+
+#ifdef BOOST_GEOMETRY_DEBUG_TURNS
+#include <iostream>
+#include <string>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <boost/geometry/io/wkt/write.hpp>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif // BOOST_GEOMETRY_DEBUG_TURNS
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace turns
+{
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_TURNS
+template <typename Turn, typename Operation>
+inline void debug_turn(Turn const& turn, Operation op,
+ std::string const& header)
+{
+ std::cout << header
+ << " at " << op.seg_id
+ << " meth: " << method_char(turn.method)
+ << " op: " << operation_char(op.operation)
+ << " of: " << operation_char(turn.operations[0].operation)
+ << operation_char(turn.operations[1].operation)
+ << " " << geometry::wkt(turn.point)
+ << std::endl;
+
+ if (boost::contains(header, "Finished"))
+ {
+ std::cout << std::endl;
+ }
+}
+#else
+template <typename Turn, typename Operation>
+inline void debug_turn(Turn const& , Operation, const char*)
+{
+}
+#endif // BOOST_GEOMETRY_DEBUG_TURNS
+
+
+}} // namespace detail::turns
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost:geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP
diff --git a/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp b/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp
new file mode 100644
index 0000000000..17fbd65ddc
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_TURNS_FILTER_CONTINUE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP
+
+#include <algorithm>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+
+template <typename Turns, bool Enable>
+struct filter_continue_turns
+{
+ static inline void apply(Turns&) {}
+};
+
+
+template <typename Turns>
+class filter_continue_turns<Turns, true>
+{
+private:
+ class IsContinueTurn
+ {
+ private:
+ template <typename Operation>
+ inline bool is_continue_or_opposite(Operation const& operation) const
+ {
+ return operation == detail::overlay::operation_continue
+ || operation == detail::overlay::operation_opposite;
+ }
+
+ public:
+ template <typename Turn>
+ bool operator()(Turn const& turn) const
+ {
+ if ( turn.method != detail::overlay::method_collinear
+ && turn.method != detail::overlay::method_equal )
+ {
+ return false;
+ }
+
+ return is_continue_or_opposite(turn.operations[0].operation)
+ && is_continue_or_opposite(turn.operations[1].operation);
+ }
+ };
+
+
+public:
+ static inline void apply(Turns& turns)
+ {
+ turns.erase( std::remove_if(turns.begin(), turns.end(),
+ IsContinueTurn()),
+ turns.end()
+ );
+ }
+};
+
+
+}} // namespace detail::turns
+
+}} // namespect boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/turns/print_turns.hpp b/boost/geometry/algorithms/detail/turns/print_turns.hpp
new file mode 100644
index 0000000000..b339e11c94
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/print_turns.hpp
@@ -0,0 +1,96 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_TURNS_PRINT_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
+
+#include <iostream>
+
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#include <boost/geometry/io/wkt/write.hpp>
+#include <boost/geometry/io/dsv/write.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+
+
+template <typename Geometry1, typename Geometry2, typename Turns>
+static inline void print_turns(Geometry1 const& g1,
+ Geometry2 const& g2,
+ Turns const& turns)
+{
+ typedef typename boost::range_value<Turns>::type turn_info;
+
+ std::cout << geometry::wkt(g1) << std::endl;
+ std::cout << geometry::wkt(g2) << std::endl;
+ int index = 0;
+ BOOST_FOREACH(turn_info const& turn, turns)
+ {
+ std::ostream& out = std::cout;
+ out << index
+ << ": " << geometry::method_char(turn.method);
+
+ if ( turn.discarded )
+ out << " (discarded)\n";
+ else if ( turn.blocked() )
+ out << " (blocked)\n";
+ else
+ out << '\n';
+
+ double fraction[2];
+
+ fraction[0] = turn.operations[0].fraction.numerator()
+ / turn.operations[0].fraction.denominator();
+
+ out << geometry::operation_char(turn.operations[0].operation)
+ <<": seg: " << turn.operations[0].seg_id.source_index
+ << ", m: " << turn.operations[0].seg_id.multi_index
+ << ", r: " << turn.operations[0].seg_id.ring_index
+ << ", s: " << turn.operations[0].seg_id.segment_index << ", ";
+ out << ", fr: " << fraction[0];
+ out << ", col?: " << turn.operations[0].is_collinear;
+ out << ' ' << geometry::dsv(turn.point) << ' ';
+
+ out << '\n';
+
+ fraction[1] = turn.operations[1].fraction.numerator()
+ / turn.operations[1].fraction.denominator();
+
+ out << geometry::operation_char(turn.operations[1].operation)
+ << ": seg: " << turn.operations[1].seg_id.source_index
+ << ", m: " << turn.operations[1].seg_id.multi_index
+ << ", r: " << turn.operations[1].seg_id.ring_index
+ << ", s: " << turn.operations[1].seg_id.segment_index << ", ";
+ out << ", fr: " << fraction[1];
+ out << ", col?: " << turn.operations[1].is_collinear;
+ out << ' ' << geometry::dsv(turn.point) << ' ';
+
+ ++index;
+ std::cout << std::endl;
+ }
+}
+
+
+
+
+}} // namespace detail::turns
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp
new file mode 100644
index 0000000000..ccb19efb73
--- /dev/null
+++ b/boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp
@@ -0,0 +1,62 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_TURNS_REMOVE_DUPLICATE_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP
+
+#include <algorithm>
+#include <boost/geometry/algorithms/equals.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace turns
+{
+
+template <typename Turns, bool Enable>
+struct remove_duplicate_turns
+{
+ static inline void apply(Turns&) {}
+};
+
+
+
+template <typename Turns>
+class remove_duplicate_turns<Turns, true>
+{
+private:
+ struct TurnEqualsTo
+ {
+ template <typename Turn>
+ bool operator()(Turn const& t1, Turn const& t2) const
+ {
+ return geometry::equals(t1.point, t2.point)
+ && t1.operations[0].seg_id == t2.operations[0].seg_id
+ && t1.operations[1].seg_id == t2.operations[1].seg_id;
+ }
+ };
+
+public:
+ static inline void apply(Turns& turns)
+ {
+ turns.erase( std::unique(turns.begin(), turns.end(),
+ TurnEqualsTo()),
+ turns.end()
+ );
+ }
+};
+
+
+
+}} // namespace detail::turns
+
+}} // namespect boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
new file mode 100644
index 0000000000..6f1c1816cb
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
@@ -0,0 +1,463 @@
+// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
+
+#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.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/strategies/covered_by.hpp>
+
+#include <boost/geometry/views/detail/normalized_view.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+// TODO: is this needed?
+inline int check_result_type(int result)
+{
+ return result;
+}
+
+template <typename T>
+inline T check_result_type(T result)
+{
+ BOOST_ASSERT(false);
+ return result;
+}
+
+template <typename Point, typename Range, typename Strategy> inline
+int point_in_range(Point const& point, Range const& range, Strategy const& strategy)
+{
+ boost::ignore_unused_variable_warning(strategy);
+
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
+ typename Strategy::state_type state;
+ iterator_type it = boost::begin(range);
+ iterator_type end = boost::end(range);
+
+ for ( iterator_type previous = it++ ; it != end ; ++previous, ++it )
+ {
+ if ( ! strategy.apply(point, *previous, *it, state) )
+ {
+ break;
+ }
+ }
+
+ return check_result_type(strategy.result(state));
+}
+
+template <typename Geometry, typename Point, typename Range>
+inline int point_in_range(Point const& point, Range const& range)
+{
+ typedef typename point_type<Point>::type point_type1;
+ typedef typename point_type<Geometry>::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type2;
+
+ static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
+ BOOST_MPL_ASSERT_MSG((same_strategies),
+ DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
+ (strategy_type, strategy_type2));
+
+ return point_in_range(point, range, strategy_type());
+}
+
+}} // namespace detail::within
+
+namespace detail_dispatch { namespace within {
+
+// checks the relation between a point P and geometry G
+// returns 1 if P is in the interior of G
+// returns 0 if P is on the boundry of G
+// returns -1 if P is in the exterior of G
+
+template <typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type>
+struct point_in_geometry
+ : not_implemented<Tag>
+{};
+
+template <typename Point2>
+struct point_in_geometry<Point2, point_tag>
+{
+ template <typename Point1, typename Strategy> static inline
+ int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
+ {
+ boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(point1, point2) ? 1 : -1;
+ }
+};
+
+template <typename Segment>
+struct point_in_geometry<Segment, segment_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Segment const& segment, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Segment>::type point_type;
+ point_type p0, p1;
+// TODO: don't copy points
+ detail::assign_point_from_index<0>(segment, p0);
+ detail::assign_point_from_index<1>(segment, p1);
+
+ typename Strategy::state_type state;
+ strategy.apply(point, p0, p1, state);
+ int r = detail::within::check_result_type(strategy.result(state));
+
+ if ( r != 0 )
+ return -1; // exterior
+
+ // if the point is equal to the one of the terminal points
+ if ( detail::equals::equals_point_point(point, p0)
+ || detail::equals::equals_point_point(point, p1) )
+ return 0; // boundary
+ else
+ return 1; // interior
+ }
+};
+
+
+template <typename Linestring>
+struct point_in_geometry<Linestring, linestring_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Linestring const& linestring, Strategy const& strategy)
+ {
+ std::size_t count = boost::size(linestring);
+ if ( count > 1 )
+ {
+ if ( detail::within::point_in_range(point, linestring, strategy) != 0 )
+ return -1; // exterior
+
+ // if the linestring doesn't have a boundary
+ if ( detail::equals::equals_point_point(*boost::begin(linestring), *(--boost::end(linestring))) )
+ return 1; // interior
+ // else if the point is equal to the one of the terminal points
+ else if ( detail::equals::equals_point_point(point, *boost::begin(linestring))
+ || detail::equals::equals_point_point(point, *(--boost::end(linestring))) )
+ return 0; // boundary
+ else
+ return 1; // interior
+ }
+// TODO: for now degenerated linestrings are ignored
+// throw an exception here?
+ /*else if ( count == 1 )
+ {
+ if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) )
+ return 1;
+ }*/
+
+ return -1; // exterior
+ }
+};
+
+template <typename Ring>
+struct point_in_geometry<Ring, ring_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Ring const& ring, Strategy const& strategy)
+ {
+ if ( boost::size(ring) < core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Ring>::value
+ >::value )
+ {
+ return -1;
+ }
+
+ detail::normalized_view<Ring const> view(ring);
+ return detail::within::point_in_range(point, view, strategy);
+ }
+};
+
+// Polygon: in exterior ring, and if so, not within interior ring(s)
+template <typename Polygon>
+struct point_in_geometry<Polygon, polygon_tag>
+{
+ template <typename Point, typename Strategy>
+ static inline int apply(Point const& point, Polygon const& polygon,
+ Strategy const& strategy)
+ {
+ int const code = point_in_geometry
+ <
+ typename ring_type<Polygon>::type
+ >::apply(point, exterior_ring(polygon), strategy);
+
+ if (code == 1)
+ {
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings);
+ it != boost::end(rings);
+ ++it)
+ {
+ int const interior_code = point_in_geometry
+ <
+ typename ring_type<Polygon>::type
+ >::apply(point, *it, strategy);
+
+ if (interior_code != -1)
+ {
+ // If 0, return 0 (touch)
+ // If 1 (inside hole) return -1 (outside polygon)
+ // If -1 (outside hole) check other holes if any
+ return -interior_code;
+ }
+ }
+ }
+ return code;
+ }
+};
+
+template <typename Geometry>
+struct point_in_geometry<Geometry, multi_point_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ typedef typename boost::range_value<Geometry>::type point_type;
+ typedef typename boost::range_const_iterator<Geometry>::type iterator;
+ for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
+ {
+ int pip = point_in_geometry<point_type>::apply(point, *it, strategy);
+
+ //BOOST_ASSERT(pip != 0);
+ if ( pip > 0 ) // inside
+ return 1;
+ }
+
+ return -1; // outside
+ }
+};
+
+template <typename Geometry>
+struct point_in_geometry<Geometry, multi_linestring_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ int pip = -1; // outside
+
+ typedef typename boost::range_value<Geometry>::type linestring_type;
+ typedef typename boost::range_value<linestring_type>::type point_type;
+ typedef typename boost::range_iterator<Geometry const>::type iterator;
+ iterator it = boost::begin(geometry);
+ for ( ; it != boost::end(geometry) ; ++it )
+ {
+ pip = point_in_geometry<linestring_type>::apply(point, *it, strategy);
+
+ // inside or on the boundary
+ if ( pip >= 0 )
+ {
+ ++it;
+ break;
+ }
+ }
+
+ // outside
+ if ( pip < 0 )
+ return -1;
+
+ // TODO: the following isn't needed for covered_by()
+
+ unsigned boundaries = pip == 0 ? 1 : 0;
+
+ for ( ; it != boost::end(geometry) ; ++it )
+ {
+ if ( boost::size(*it) < 2 )
+ continue;
+
+ point_type const& front = *boost::begin(*it);
+ point_type const& back = *(--boost::end(*it));
+
+ // is closed_ring - no boundary
+ if ( detail::equals::equals_point_point(front, back) )
+ continue;
+
+ // is point on boundary
+ if ( detail::equals::equals_point_point(point, front)
+ || detail::equals::equals_point_point(point, back) )
+ {
+ ++boundaries;
+ }
+ }
+
+ // if the number of boundaries is odd, the point is on the boundary
+ return boundaries % 2 ? 0 : 1;
+ }
+};
+
+template <typename Geometry>
+struct point_in_geometry<Geometry, multi_polygon_tag>
+{
+ template <typename Point, typename Strategy> static inline
+ int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ // For invalid multipolygons
+ //int res = -1; // outside
+
+ typedef typename boost::range_value<Geometry>::type polygon_type;
+ typedef typename boost::range_const_iterator<Geometry>::type iterator;
+ for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
+ {
+ int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy);
+
+ // inside or on the boundary
+ if ( pip >= 0 )
+ return pip;
+
+ // For invalid multi-polygons
+ //if ( 1 == pip ) // inside polygon
+ // return 1;
+ //else if ( res < pip ) // point must be inside at least one polygon
+ // res = pip;
+ }
+
+ return -1; // for valid multipolygons
+ //return res; // for invalid multipolygons
+ }
+};
+
+}} // namespace detail_dispatch::within
+
+namespace detail { namespace within {
+
+// 1 - in the interior
+// 0 - in the boundry
+// -1 - in the exterior
+template <typename Point, typename Geometry, typename Strategy>
+inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy)
+{
+ concept::within::check
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ Strategy
+ >();
+
+ return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy);
+}
+
+template <typename Point, typename Geometry>
+inline int point_in_geometry(Point const& point, Geometry const& geometry)
+{
+ typedef typename point_type<Point>::type point_type1;
+ typedef typename point_type<Geometry>::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ typename tag<Point>::type,
+ typename tag<Geometry>::type,
+ typename tag<Point>::type,
+ typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Point,
+ Geometry
+ >::type strategy_type2;
+
+ static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
+ BOOST_MPL_ASSERT_MSG((same_strategies),
+ DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
+ (strategy_type, strategy_type2));
+
+ return point_in_geometry(point, geometry, strategy_type());
+}
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/within/within_no_turns.hpp b/boost/geometry/algorithms/detail/within/within_no_turns.hpp
new file mode 100644
index 0000000000..8da05e58fd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/within_no_turns.hpp
@@ -0,0 +1,221 @@
+// 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.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
+// 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_WITHIN_NO_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
+
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail_dispatch { namespace within {
+
+// returns true if G1 is within G2
+// this function should be called only if there are no intersection points
+// otherwise it may return invalid result
+// e.g. when non-first point of G1 is outside G2 or when some rings of G1 are the same as rings of G2
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type>
+struct within_no_turns
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, geometry1) )
+ return false;
+
+ return detail::within::point_in_geometry(p, geometry2, strategy) >= 0;
+ }
+};
+
+template <typename Geometry1, typename Geometry2>
+struct within_no_turns<Geometry1, Geometry2, ring_tag, polygon_tag>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, geometry1) )
+ return false;
+ // check if one of ring points is outside the polygon
+ if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 )
+ return false;
+ // Now check if holes of G2 aren't inside G1
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type<Geometry2>::type
+ >::type iterator;
+ for ( iterator it = boost::begin(geometry::interior_rings(geometry2)) ;
+ it != boost::end(geometry::interior_rings(geometry2)) ;
+ ++it )
+ {
+ point2_type p;
+ if ( !geometry::point_on_border(p, *it) )
+ return false;
+ if ( detail::within::point_in_geometry(p, geometry1, strategy) > 0 )
+ return false;
+ }
+ return true;
+ }
+};
+
+template <typename Geometry1, typename Geometry2>
+struct within_no_turns<Geometry1, Geometry2, polygon_tag, polygon_tag>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, geometry1) )
+ return false;
+ // check if one of ring points is outside the polygon
+ if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 )
+ return false;
+ // Now check if holes of G2 aren't inside G1
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type<Geometry2>::type
+ >::type iterator2;
+ for ( iterator2 it = boost::begin(geometry::interior_rings(geometry2)) ;
+ it != boost::end(geometry::interior_rings(geometry2)) ;
+ ++it )
+ {
+ point2_type p2;
+ if ( !geometry::point_on_border(p2, *it) )
+ return false;
+ // if the hole of G2 is inside G1
+ if ( detail::within::point_in_geometry(p2, geometry1, strategy) > 0 )
+ {
+ // if it's also inside one of the G1 holes, it's ok
+ bool ok = false;
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type<Geometry1>::type
+ >::type iterator1;
+ for ( iterator1 it1 = boost::begin(geometry::interior_rings(geometry1)) ;
+ it1 != boost::end(geometry::interior_rings(geometry1)) ;
+ ++it1 )
+ {
+ if ( detail::within::point_in_geometry(p2, *it1, strategy) < 0 )
+ {
+ ok = true;
+ break;
+ }
+ }
+ if ( !ok )
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+template <typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ bool IsMulti1 = boost::is_base_of<geometry::multi_tag, Tag1>::value,
+ bool IsMulti2 = boost::is_base_of<geometry::multi_tag, Tag2>::value>
+struct within_no_turns_multi
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return within_no_turns<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, false>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // All values of G1 must be inside G2
+ typedef typename boost::range_value<Geometry1>::type subgeometry1;
+ typedef typename boost::range_const_iterator<Geometry1>::type iterator;
+ for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it )
+ {
+ if ( !within_no_turns<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) )
+ return false;
+ }
+ return true;
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, false, true>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // G1 must be within at least one value of G2
+ typedef typename boost::range_value<Geometry2>::type subgeometry2;
+ typedef typename boost::range_const_iterator<Geometry2>::type iterator;
+ for ( iterator it = boost::begin(geometry2) ; it != boost::end(geometry2) ; ++it )
+ {
+ if ( within_no_turns<Geometry1, subgeometry2>::apply(geometry1, *it, strategy) )
+ return true;
+ }
+ return false;
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, true>
+{
+ template <typename Strategy> static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ // each value of G1 must be inside at least one value of G2
+ typedef typename boost::range_value<Geometry1>::type subgeometry1;
+ typedef typename boost::range_const_iterator<Geometry1>::type iterator;
+ for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it )
+ {
+ if ( !within_no_turns_multi<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) )
+ return false;
+ }
+ return true;
+ }
+};
+
+}} // namespace detail_dispatch::within
+
+namespace detail { namespace within {
+
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool within_no_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+{
+ return detail_dispatch::within::within_no_turns_multi<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+}
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
diff --git a/boost/geometry/algorithms/difference.hpp b/boost/geometry/algorithms/difference.hpp
index 480dd928de..780436f015 100644
--- a/boost/geometry/algorithms/difference.hpp
+++ b/boost/geometry/algorithms/difference.hpp
@@ -12,6 +12,7 @@
#include <algorithm>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
namespace boost { namespace geometry
{
@@ -43,33 +44,28 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
-
+
return geometry::dispatch::intersection_insert
<
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
+ GeometryOut,
overlay_difference,
- Strategy
- >::apply(geometry1, geometry2, out, strategy);
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
+ >::apply(geometry1, geometry2, robust_policy, out, strategy);
}
/*!
@@ -93,10 +89,13 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out)
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
@@ -107,11 +106,12 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ RobustPolicy
> strategy;
return difference_insert<GeometryOut>(geometry1, geometry2,
- out, strategy());
+ robust_policy, out, strategy());
}
@@ -148,8 +148,17 @@ inline void difference(Geometry1 const& geometry1,
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
detail::difference::difference_insert<geometry_out>(
- geometry1, geometry2,
+ geometry1, geometry2, robust_policy,
std::back_inserter(output_collection));
}
diff --git a/boost/geometry/algorithms/disjoint.hpp b/boost/geometry/algorithms/disjoint.hpp
index f986cc24af..f997487c71 100644
--- a/boost/geometry/algorithms/disjoint.hpp
+++ b/boost/geometry/algorithms/disjoint.hpp
@@ -1,8 +1,15 @@
// 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.
+// 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.
+// 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.
+
+// 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.
@@ -14,288 +21,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
-#include <cstddef>
-#include <deque>
-
-#include <boost/mpl/if.hpp>
-#include <boost/range.hpp>
-
-#include <boost/static_assert.hpp>
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
-#include <boost/geometry/algorithms/detail/for_each_range.hpp>
-#include <boost/geometry/algorithms/detail/point_on_border.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
-#include <boost/geometry/algorithms/within.hpp>
-
-#include <boost/geometry/geometries/concepts/check.hpp>
-
-#include <boost/geometry/util/math.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace disjoint
-{
-
-template<typename Geometry>
-struct check_each_ring_for_within
-{
- bool has_within;
- Geometry const& m_geometry;
-
- inline check_each_ring_for_within(Geometry const& g)
- : has_within(false)
- , m_geometry(g)
- {}
-
- template <typename Range>
- inline void apply(Range const& range)
- {
- typename geometry::point_type<Range>::type p;
- geometry::point_on_border(p, range);
- if (geometry::within(p, m_geometry))
- {
- has_within = true;
- }
- }
-};
-
-template <typename FirstGeometry, typename SecondGeometry>
-inline bool rings_containing(FirstGeometry const& geometry1,
- SecondGeometry const& geometry2)
-{
- check_each_ring_for_within<FirstGeometry> checker(geometry1);
- geometry::detail::for_each_range(geometry2, checker);
- return checker.has_within;
-}
-
-
-struct assign_disjoint_policy
-{
- // We want to include all points:
- static bool const include_no_turn = true;
- static bool const include_degenerate = true;
- static bool const include_opposite = true;
-
- // We don't assign extra info:
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
- static inline void apply(Info& , Point1 const& , Point2 const&,
- IntersectionInfo const&, DirInfo const&)
- {}
-};
-
-
-template <typename Geometry1, typename Geometry2>
-struct disjoint_linear
-{
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
- {
- typedef typename geometry::point_type<Geometry1>::type point_type;
-
- typedef overlay::turn_info<point_type> turn_info;
- std::deque<turn_info> turns;
-
- // Specify two policies:
- // 1) Stop at any intersection
- // 2) In assignment, include also degenerate points (which are normally skipped)
- disjoint_interrupt_policy policy;
- geometry::get_turns
- <
- false, false,
- assign_disjoint_policy
- >(geometry1, geometry2, turns, policy);
- if (policy.has_intersections)
- {
- return false;
- }
-
- return true;
- }
-};
-
-template <typename Segment1, typename Segment2>
-struct disjoint_segment
-{
- static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
- {
- typedef typename point_type<Segment1>::type point_type;
-
- segment_intersection_points<point_type> is
- = strategy::intersection::relate_cartesian_segments
- <
- policies::relate::segments_intersection_points
- <
- Segment1,
- Segment2,
- segment_intersection_points<point_type>
- >
- >::apply(segment1, segment2);
-
- return is.count == 0;
- }
-};
-
-template <typename Geometry1, typename Geometry2>
-struct general_areal
-{
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
- {
- if (! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2))
- {
- return false;
- }
-
- // If there is no intersection of segments, they might located
- // inside each other
- if (rings_containing(geometry1, geometry2)
- || rings_containing(geometry2, geometry1))
- {
- return false;
- }
-
- return true;
- }
-};
-
-
-}} // namespace detail::disjoint
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename GeometryTag1, typename GeometryTag2,
- typename Geometry1, typename Geometry2,
- std::size_t DimensionCount
->
-struct disjoint
- : detail::disjoint::general_areal<Geometry1, Geometry2>
-{};
-
-
-template <typename Point1, typename Point2, std::size_t DimensionCount>
-struct disjoint<point_tag, point_tag, Point1, Point2, DimensionCount>
- : detail::disjoint::point_point<Point1, Point2, 0, DimensionCount>
-{};
-
-
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct disjoint<box_tag, box_tag, Box1, Box2, DimensionCount>
- : detail::disjoint::box_box<Box1, Box2, 0, DimensionCount>
-{};
-
-
-template <typename Point, typename Box, std::size_t DimensionCount>
-struct disjoint<point_tag, box_tag, Point, Box, DimensionCount>
- : detail::disjoint::point_box<Point, Box, 0, DimensionCount>
-{};
-
-template <typename Linestring1, typename Linestring2>
-struct disjoint<linestring_tag, linestring_tag, Linestring1, Linestring2, 2>
- : detail::disjoint::disjoint_linear<Linestring1, Linestring2>
-{};
-
-template <typename Linestring1, typename Linestring2>
-struct disjoint<segment_tag, segment_tag, Linestring1, Linestring2, 2>
- : detail::disjoint::disjoint_segment<Linestring1, Linestring2>
-{};
-
-template <typename Linestring, typename Segment>
-struct disjoint<linestring_tag, segment_tag, Linestring, Segment, 2>
- : detail::disjoint::disjoint_linear<Linestring, Segment>
-{};
-
-
-template
-<
- typename GeometryTag1, typename GeometryTag2,
- typename Geometry1, typename Geometry2,
- std::size_t DimensionCount
->
-struct disjoint_reversed
-{
- static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
- {
- return disjoint
- <
- GeometryTag2, GeometryTag1,
- Geometry2, Geometry1,
- DimensionCount
- >::apply(g2, g1);
- }
-};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-
-/*!
-\brief \brief_check2{are disjoint}
-\ingroup disjoint
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_check2{are disjoint}
-
-\qbk{[include reference/algorithms/disjoint.qbk]}
-*/
-template <typename Geometry1, typename Geometry2>
-inline bool disjoint(Geometry1 const& geometry1,
- Geometry2 const& geometry2)
-{
- concept::check_concepts_and_equal_dimensions
- <
- Geometry1 const,
- Geometry2 const
- >();
-
- return boost::mpl::if_c
- <
- reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::disjoint_reversed
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >,
- dispatch::disjoint
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >
- >::type::apply(geometry1, geometry2);
-}
-
-
-}} // namespace boost::geometry
-
+#include <boost/geometry/algorithms/detail/disjoint/interface.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/dispatch/disjoint.hpp b/boost/geometry/algorithms/dispatch/disjoint.hpp
new file mode 100644
index 0000000000..627bcff83c
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/disjoint.hpp
@@ -0,0 +1,70 @@
+// 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.
+// 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.
+
+// 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_DISPATCH_DISJOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP
+
+#include <cstddef>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ std::size_t DimensionCount = dimension<Geometry1>::type::value,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type,
+ segment_tag, box_tag, linear_tag, areal_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type,
+ segment_tag, box_tag, linear_tag, areal_tag
+ >::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct disjoint
+ : not_implemented<Geometry1, Geometry2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/dispatch/distance.hpp b/boost/geometry/algorithms/dispatch/distance.hpp
new file mode 100644
index 0000000000..cae3ebd0c9
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/distance.hpp
@@ -0,0 +1,82 @@
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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_DISPATCH_DISTANCE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_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/strategies/distance.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Strategy = typename detail::distance::default_strategy
+ <
+ Geometry1, Geometry2
+ >::type,
+ typename Tag1 = typename tag_cast
+ <
+ typename tag<Geometry1>::type,
+ segment_tag,
+ box_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ typename Tag2 = typename tag_cast
+ <
+ typename tag<Geometry2>::type,
+ segment_tag,
+ box_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ typename StrategyTag = typename strategy::distance::services::tag
+ <
+ Strategy
+ >::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct distance: not_implemented<Tag1, Tag2>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP
diff --git a/boost/geometry/algorithms/dispatch/is_simple.hpp b/boost/geometry/algorithms/dispatch/is_simple.hpp
new file mode 100644
index 0000000000..2ac92256b3
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/is_simple.hpp
@@ -0,0 +1,38 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
+
+#include <boost/geometry/core/tag.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct is_simple
+ : not_implemented<Geometry>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
diff --git a/boost/geometry/algorithms/dispatch/is_valid.hpp b/boost/geometry/algorithms/dispatch/is_valid.hpp
new file mode 100644
index 0000000000..266bab9181
--- /dev/null
+++ b/boost/geometry/algorithms/dispatch/is_valid.hpp
@@ -0,0 +1,46 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
+
+#include <boost/geometry/core/tag.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type,
+ // for linear geometries: determines if spikes are allowed
+ bool AllowSpikes = true,
+ // for areal geometries: determines if duplicate points are allowed
+ bool AllowDuplicates = true
+>
+struct is_valid
+ : not_implemented<Geometry>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
diff --git a/boost/geometry/algorithms/distance.hpp b/boost/geometry/algorithms/distance.hpp
index 11c2bc929b..dcfe597cd0 100644
--- a/boost/geometry/algorithms/distance.hpp
+++ b/boost/geometry/algorithms/distance.hpp
@@ -1,8 +1,14 @@
// 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.
+// 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.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -14,578 +20,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
-
-#include <boost/mpl/if.hpp>
-#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-#include <boost/geometry/core/tag_cast.hpp>
-
-#include <boost/geometry/algorithms/not_implemented.hpp>
-#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
-
-#include <boost/geometry/geometries/segment.hpp>
-#include <boost/geometry/geometries/concepts/check.hpp>
-
-#include <boost/geometry/strategies/distance.hpp>
-#include <boost/geometry/strategies/default_distance_result.hpp>
-#include <boost/geometry/algorithms/assign.hpp>
-#include <boost/geometry/algorithms/within.hpp>
-
-#include <boost/geometry/views/closeable_view.hpp>
-#include <boost/geometry/util/math.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace distance
-{
-
-// To avoid spurious namespaces here:
-using strategy::distance::services::return_type;
-
-template <typename P1, typename P2, typename Strategy>
-struct point_to_point
-{
- static inline typename return_type<Strategy>::type apply(P1 const& p1,
- P2 const& p2, Strategy const& strategy)
- {
- return strategy.apply(p1, p2);
- }
-};
-
-
-template<typename Point, typename Segment, typename Strategy>
-struct point_to_segment
-{
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Segment const& segment, Strategy const& )
- {
- typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Segment>::type,
- typename cs_tag<Point>::type,
- typename cs_tag<typename point_type<Segment>::type>::type,
- Strategy
- >::type segment_strategy;
-
- typename point_type<Segment>::type p[2];
- geometry::detail::assign_point_from_index<0>(segment, p[0]);
- geometry::detail::assign_point_from_index<1>(segment, p[1]);
- return segment_strategy.apply(point, p[0], p[1]);
- }
-};
-
-
-template
-<
- typename Point,
- typename Range,
- closure_selector Closure,
- typename PPStrategy,
- typename PSStrategy
->
-struct point_to_range
-{
- typedef typename return_type<PSStrategy>::type return_type;
-
- static inline return_type apply(Point const& point, Range const& range,
- PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
- {
- return_type const zero = return_type(0);
-
- if (boost::size(range) == 0)
- {
- return zero;
- }
-
- typedef typename closeable_view<Range const, Closure>::type view_type;
-
- view_type view(range);
-
- // line of one point: return point distance
- typedef typename boost::range_iterator<view_type const>::type iterator_type;
- iterator_type it = boost::begin(view);
- iterator_type prev = it++;
- if (it == boost::end(view))
- {
- return pp_strategy.apply(point, *boost::begin(view));
- }
-
- // Create comparable (more efficient) strategy
- typedef typename strategy::distance::services::comparable_type<PSStrategy>::type eps_strategy_type;
- eps_strategy_type eps_strategy = strategy::distance::services::get_comparable<PSStrategy>::apply(ps_strategy);
-
- // start with first segment distance
- return_type d = eps_strategy.apply(point, *prev, *it);
- return_type rd = ps_strategy.apply(point, *prev, *it);
-
- // check if other segments are closer
- for (++prev, ++it; it != boost::end(view); ++prev, ++it)
- {
- return_type const ds = eps_strategy.apply(point, *prev, *it);
- if (geometry::math::equals(ds, zero))
- {
- return ds;
- }
- else if (ds < d)
- {
- d = ds;
- rd = ps_strategy.apply(point, *prev, *it);
- }
- }
-
- return rd;
- }
-};
-
-
-template
-<
- typename Point,
- typename Ring,
- closure_selector Closure,
- typename PPStrategy,
- typename PSStrategy
->
-struct point_to_ring
-{
- typedef std::pair
- <
- typename return_type<PPStrategy>::type, bool
- > distance_containment;
-
- static inline distance_containment apply(Point const& point,
- Ring const& ring,
- PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
- {
- return distance_containment
- (
- point_to_range
- <
- Point,
- Ring,
- Closure,
- PPStrategy,
- PSStrategy
- >::apply(point, ring, pp_strategy, ps_strategy),
- geometry::within(point, ring)
- );
- }
-};
-
-
-
-template
-<
- typename Point,
- typename Polygon,
- closure_selector Closure,
- typename PPStrategy,
- typename PSStrategy
->
-struct point_to_polygon
-{
- typedef typename return_type<PPStrategy>::type return_type;
- typedef std::pair<return_type, bool> distance_containment;
-
- static inline distance_containment apply(Point const& point,
- Polygon const& polygon,
- PPStrategy const& pp_strategy, PSStrategy const& ps_strategy)
- {
- // Check distance to all rings
- typedef point_to_ring
- <
- Point,
- typename ring_type<Polygon>::type,
- Closure,
- PPStrategy,
- PSStrategy
- > per_ring;
-
- distance_containment dc = per_ring::apply(point,
- exterior_ring(polygon), pp_strategy, ps_strategy);
-
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
- {
- distance_containment dcr = per_ring::apply(point,
- *it, pp_strategy, ps_strategy);
- if (dcr.first < dc.first)
- {
- dc.first = dcr.first;
- }
- // If it was inside, and also inside inner ring,
- // turn off the inside-flag, it is outside the polygon
- if (dc.second && dcr.second)
- {
- dc.second = false;
- }
- }
- return dc;
- }
-};
-
-
-// Helper metafunction for default strategy retrieval
-template <typename Geometry1, typename Geometry2>
-struct default_strategy
- : strategy::distance::services::default_strategy
- <
- point_tag,
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type
- >
-{};
-
-
-}} // namespace detail::distance
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-using strategy::distance::services::return_type;
-
-
-template
-<
- typename Geometry1, typename Geometry2,
- typename Strategy = typename detail::distance::default_strategy<Geometry1, Geometry2>::type,
- typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
- typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
- typename StrategyTag = typename strategy::distance::services::tag<Strategy>::type,
- bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
->
-struct distance: not_implemented<Tag1, Tag2>
-{};
-
-
-// If reversal is needed, perform it
-template
-<
- typename Geometry1, typename Geometry2, typename Strategy,
- typename Tag1, typename Tag2, typename StrategyTag
->
-struct distance
-<
- Geometry1, Geometry2, Strategy,
- Tag1, Tag2, StrategyTag,
- true
->
- : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
-{
- static inline typename return_type<Strategy>::type apply(
- Geometry1 const& g1,
- Geometry2 const& g2,
- Strategy const& strategy)
- {
- return distance
- <
- Geometry2, Geometry1, Strategy,
- Tag2, Tag1, StrategyTag,
- false
- >::apply(g2, g1, strategy);
- }
-};
-
-// If reversal is needed and we got the strategy by default, invert it before
-// proceeding to the reversal.
-template
-<
- typename Geometry1, typename Geometry2,
- typename Tag1, typename Tag2, typename StrategyTag
->
-struct distance
-<
- Geometry1, Geometry2,
- typename detail::distance::default_strategy<Geometry1, Geometry2>::type,
- Tag1, Tag2, StrategyTag,
- true
->
- : distance
- <
- Geometry2, Geometry1,
- typename detail::distance::default_strategy<Geometry2, Geometry1>::type,
- Tag2, Tag1, StrategyTag,
- false
- >
-{
- typedef typename detail::distance::default_strategy<Geometry2, Geometry1>::type reversed_strategy;
-
- static inline typename strategy::distance::services::return_type<reversed_strategy>::type apply(
- Geometry1 const& g1,
- Geometry2 const& g2,
- typename detail::distance::default_strategy<Geometry1, Geometry2>::type const&)
- {
- return distance
- <
- Geometry2, Geometry1, reversed_strategy,
- Tag2, Tag1, StrategyTag,
- false
- >::apply(g2, g1, reversed_strategy());
- }
-};
-
-
-// Point-point
-template <typename P1, typename P2, typename Strategy>
-struct distance
- <
- P1, P2, Strategy,
- point_tag, point_tag, strategy_tag_distance_point_point,
- false
- >
- : detail::distance::point_to_point<P1, P2, Strategy>
-{};
-
-
-// Point-line version 1, where point-point strategy is specified
-template <typename Point, typename Linestring, typename Strategy>
-struct distance
-<
- Point, Linestring, Strategy,
- point_tag, linestring_tag, strategy_tag_distance_point_point,
- false
->
-{
-
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Linestring const& linestring,
- Strategy const& strategy)
- {
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Linestring>::type
- >::type ps_strategy_type;
-
- return detail::distance::point_to_range
- <
- Point, Linestring, closed, Strategy, ps_strategy_type
- >::apply(point, linestring, strategy, ps_strategy_type());
- }
-};
-
-
-// Point-line version 2, where point-segment strategy is specified
-template <typename Point, typename Linestring, typename Strategy>
-struct distance
-<
- Point, Linestring, Strategy,
- point_tag, linestring_tag, strategy_tag_distance_point_segment,
- false
->
-{
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Linestring const& linestring,
- Strategy const& strategy)
- {
- typedef typename Strategy::point_strategy_type pp_strategy_type;
- return detail::distance::point_to_range
- <
- Point, Linestring, closed, pp_strategy_type, Strategy
- >::apply(point, linestring, pp_strategy_type(), strategy);
- }
-};
-
-// Point-ring , where point-segment strategy is specified
-template <typename Point, typename Ring, typename Strategy>
-struct distance
-<
- Point, Ring, Strategy,
- point_tag, ring_tag, strategy_tag_distance_point_point,
- false
->
-{
- typedef typename return_type<Strategy>::type return_type;
-
- static inline return_type apply(Point const& point,
- Ring const& ring,
- Strategy const& strategy)
- {
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Ring>::type
- >::type ps_strategy_type;
-
- std::pair<return_type, bool>
- dc = detail::distance::point_to_ring
- <
- Point, Ring,
- geometry::closure<Ring>::value,
- Strategy, ps_strategy_type
- >::apply(point, ring, strategy, ps_strategy_type());
-
- return dc.second ? return_type(0) : dc.first;
- }
-};
-
-
-// Point-polygon , where point-segment strategy is specified
-template <typename Point, typename Polygon, typename Strategy>
-struct distance
-<
- Point, Polygon, Strategy,
- point_tag, polygon_tag, strategy_tag_distance_point_point,
- false
->
-{
- typedef typename return_type<Strategy>::type return_type;
-
- static inline return_type apply(Point const& point,
- Polygon const& polygon,
- Strategy const& strategy)
- {
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag,
- Point,
- typename point_type<Polygon>::type
- >::type ps_strategy_type;
-
- std::pair<return_type, bool>
- dc = detail::distance::point_to_polygon
- <
- Point, Polygon,
- geometry::closure<Polygon>::value,
- Strategy, ps_strategy_type
- >::apply(point, polygon, strategy, ps_strategy_type());
-
- return dc.second ? return_type(0) : dc.first;
- }
-};
-
-
-
-// Point-segment version 1, with point-point strategy
-template <typename Point, typename Segment, typename Strategy>
-struct distance
-<
- Point, Segment, Strategy,
- point_tag, segment_tag, strategy_tag_distance_point_point,
- false
-> : detail::distance::point_to_segment<Point, Segment, Strategy>
-{};
-
-// Point-segment version 2, with point-segment strategy
-template <typename Point, typename Segment, typename Strategy>
-struct distance
-<
- Point, Segment, Strategy,
- point_tag, segment_tag, strategy_tag_distance_point_segment,
- false
->
-{
- static inline typename return_type<Strategy>::type apply(Point const& point,
- Segment const& segment, Strategy const& strategy)
- {
-
- typename point_type<Segment>::type p[2];
- geometry::detail::assign_point_from_index<0>(segment, p[0]);
- geometry::detail::assign_point_from_index<1>(segment, p[1]);
- return strategy.apply(point, p[0], p[1]);
- }
-};
-
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-/*!
-\brief \brief_calc2{distance} \brief_strategy
-\ingroup distance
-\details
-\details \details_calc{area}. \brief_strategy. \details_strategy_reasons
-
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam Strategy \tparam_strategy{Distance}
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param strategy \param_strategy{distance}
-\return \return_calc{distance}
-\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
- it may also be a point-segment strategy.
-
-\qbk{distinguish,with strategy}
-
-\qbk{
-[heading Available Strategies]
-\* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
-\* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
-\* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
-\* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
-\* more (currently extensions): Vincenty\, Andoyer (geographic)
-}
- */
-
-/*
-Note, in case of a Compilation Error:
-if you get:
- - "Failed to specialize function template ..."
- - "error: no matching function for call to ..."
-for distance, it is probably so that there is no specialization
-for return_type<...> for your strategy.
-*/
-template <typename Geometry1, typename Geometry2, typename Strategy>
-inline typename strategy::distance::services::return_type<Strategy>::type distance(
- Geometry1 const& geometry1, Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- detail::throw_on_empty_input(geometry1);
- detail::throw_on_empty_input(geometry2);
-
- return dispatch::distance
- <
- Geometry1,
- Geometry2,
- Strategy
- >::apply(geometry1, geometry2, strategy);
-}
-
-
-/*!
-\brief \brief_calc2{distance}
-\ingroup distance
-\details The default strategy is used, corresponding to the coordinate system of the geometries
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_calc{distance}
-
-\qbk{[include reference/algorithms/distance.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline typename default_distance_result<Geometry1, Geometry2>::type distance(
- Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- return distance(geometry1, geometry2,
- typename detail::distance::default_strategy<Geometry1, Geometry2>::type());
-}
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/distance/interface.hpp>
+#include <boost/geometry/algorithms/detail/distance/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP
diff --git a/boost/geometry/algorithms/envelope.hpp b/boost/geometry/algorithms/envelope.hpp
index da34f6a783..e06ed71e81 100644
--- a/boost/geometry/algorithms/envelope.hpp
+++ b/boost/geometry/algorithms/envelope.hpp
@@ -14,15 +14,22 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP
-#include <boost/mpl/assert.hpp>
-#include <boost/range.hpp>
+#include <vector>
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -35,9 +42,9 @@ namespace detail { namespace envelope
/// Calculate envelope of an 2D or 3D segment
-template<typename Geometry, typename Box>
struct envelope_expand_one
{
+ template<typename Geometry, typename Box>
static inline void apply(Geometry const& geometry, Box& mbr)
{
assign_inverse(mbr);
@@ -63,10 +70,10 @@ inline void envelope_range_additional(Range const& range, Box& mbr)
/// Generic range dispatching struct
-template <typename Range, typename Box>
struct envelope_range
{
/// Calculate envelope of range using a strategy
+ template <typename Range, typename Box>
static inline void apply(Range const& range, Box& mbr)
{
assign_inverse(mbr);
@@ -74,6 +81,42 @@ struct envelope_range
}
};
+
+struct envelope_multi_linestring
+{
+ template<typename MultiLinestring, typename Box>
+ static inline void apply(MultiLinestring const& mp, Box& mbr)
+ {
+ assign_inverse(mbr);
+ for (typename boost::range_iterator<MultiLinestring const>::type
+ it = mp.begin();
+ it != mp.end();
+ ++it)
+ {
+ envelope_range_additional(*it, mbr);
+ }
+ }
+};
+
+
+// version for multi_polygon: outer ring's of all polygons
+struct envelope_multi_polygon
+{
+ template<typename MultiPolygon, typename Box>
+ static inline void apply(MultiPolygon const& mp, Box& mbr)
+ {
+ assign_inverse(mbr);
+ for (typename boost::range_const_iterator<MultiPolygon>::type
+ it = mp.begin();
+ it != mp.end();
+ ++it)
+ {
+ envelope_range_additional(exterior_ring(*it), mbr);
+ }
+ }
+};
+
+
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
@@ -82,131 +125,125 @@ namespace dispatch
{
-// Note, the strategy is for future use (less/greater -> compare spherical
-// using other methods), defaults are OK for now.
-// However, they are already in the template methods
-
template
<
- typename Tag1, typename Tag2,
- typename Geometry, typename Box,
- typename StrategyLess, typename StrategyGreater
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
>
-struct envelope
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+struct envelope: not_implemented<Tag>
+{};
-template
-<
- typename Point, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- point_tag, box_tag,
- Point, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_expand_one<Point, Box>
+template <typename Point>
+struct envelope<Point, point_tag>
+ : detail::envelope::envelope_expand_one
{};
-template
-<
- typename BoxIn, typename BoxOut,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- box_tag, box_tag,
- BoxIn, BoxOut,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_expand_one<BoxIn, BoxOut>
+template <typename Box>
+struct envelope<Box, box_tag>
+ : detail::envelope::envelope_expand_one
{};
-template
-<
- typename Segment, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- segment_tag, box_tag,
- Segment, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_expand_one<Segment, Box>
+template <typename Segment>
+struct envelope<Segment, segment_tag>
+ : detail::envelope::envelope_expand_one
{};
-template
-<
- typename Linestring, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- linestring_tag, box_tag,
- Linestring, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_range<Linestring, Box>
+template <typename Linestring>
+struct envelope<Linestring, linestring_tag>
+ : detail::envelope::envelope_range
{};
-template
-<
- typename Ring, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- ring_tag, box_tag,
- Ring, Box,
- StrategyLess, StrategyGreater
- >
- : detail::envelope::envelope_range<Ring, Box>
+template <typename Ring>
+struct envelope<Ring, ring_tag>
+ : detail::envelope::envelope_range
{};
-template
-<
- typename Polygon, typename Box,
- typename StrategyLess, typename StrategyGreater
->
-struct envelope
- <
- polygon_tag, box_tag,
- Polygon, Box,
- StrategyLess, StrategyGreater
- >
+template <typename Polygon>
+struct envelope<Polygon, polygon_tag>
+ : detail::envelope::envelope_range
{
+ template <typename Box>
static inline void apply(Polygon const& poly, Box& mbr)
{
// For polygon, inspecting outer ring is sufficient
-
- detail::envelope::envelope_range
- <
- typename ring_type<Polygon>::type,
- Box
- >::apply(exterior_ring(poly), mbr);
+ detail::envelope::envelope_range::apply(exterior_ring(poly), mbr);
}
};
+template <typename Multi>
+struct envelope<Multi, multi_point_tag>
+ : detail::envelope::envelope_range
+{};
+
+
+template <typename Multi>
+struct envelope<Multi, multi_linestring_tag>
+ : detail::envelope::envelope_multi_linestring
+{};
+
+
+template <typename Multi>
+struct envelope<Multi, multi_polygon_tag>
+ : detail::envelope::envelope_multi_polygon
+{};
+
+
} // namespace dispatch
#endif
+namespace resolve_variant {
+
+template <typename Geometry>
+struct envelope
+{
+ template <typename Box>
+ static inline void apply(Geometry const& geometry, Box& box)
+ {
+ concept::check<Geometry const>();
+ concept::check<Box>();
+
+ dispatch::envelope<Geometry>::apply(geometry, box);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Box>
+ struct visitor: boost::static_visitor<void>
+ {
+ Box& m_box;
+
+ visitor(Box& box): m_box(box) {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ envelope<Geometry>::apply(geometry, m_box);
+ }
+ };
+
+ template <typename Box>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Box& box)
+ {
+ boost::apply_visitor(visitor<Box>(box), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{envelope}
\ingroup envelope
@@ -225,15 +262,7 @@ struct envelope
template<typename Geometry, typename Box>
inline void envelope(Geometry const& geometry, Box& mbr)
{
- concept::check<Geometry const>();
- concept::check<Box>();
-
- dispatch::envelope
- <
- typename tag<Geometry>::type, typename tag<Box>::type,
- Geometry, Box,
- void, void
- >::apply(geometry, mbr);
+ resolve_variant::envelope<Geometry>::apply(geometry, mbr);
}
@@ -255,16 +284,8 @@ inline void envelope(Geometry const& geometry, Box& mbr)
template<typename Box, typename Geometry>
inline Box return_envelope(Geometry const& geometry)
{
- concept::check<Geometry const>();
- concept::check<Box>();
-
Box mbr;
- dispatch::envelope
- <
- typename tag<Geometry>::type, typename tag<Box>::type,
- Geometry, Box,
- void, void
- >::apply(geometry, mbr);
+ resolve_variant::envelope<Geometry>::apply(geometry, mbr);
return mbr;
}
diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp
index 6b094f76d0..c6b718da1b 100644
--- a/boost/geometry/algorithms/equals.hpp
+++ b/boost/geometry/algorithms/equals.hpp
@@ -3,6 +3,12 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 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,18 +24,19 @@
#include <cstddef>
#include <vector>
-#include <boost/mpl/if.hpp>
-#include <boost/static_assert.hpp>
#include <boost/range.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/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/not.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
// For trivial checks
#include <boost/geometry/algorithms/area.hpp>
@@ -39,7 +46,12 @@
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
+#include <boost/geometry/views/detail/indexed_point_view.hpp>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
namespace boost { namespace geometry
{
@@ -51,13 +63,12 @@ namespace detail { namespace equals
template
<
- typename Box1,
- typename Box2,
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box
{
+ template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
@@ -65,13 +76,14 @@ struct box_box
{
return false;
}
- return box_box<Box1, Box2, Dimension + 1, DimensionCount>::apply(box1, box2);
+ return box_box<Dimension + 1, DimensionCount>::apply(box1, box2);
}
};
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct box_box<Box1, Box2, DimensionCount, DimensionCount>
+template <std::size_t DimensionCount>
+struct box_box<DimensionCount, DimensionCount>
{
+ template <typename Box1, typename Box2>
static inline bool apply(Box1 const& , Box2 const& )
{
return true;
@@ -79,6 +91,28 @@ struct box_box<Box1, Box2, DimensionCount, DimensionCount>
};
+struct segment_segment
+{
+ template <typename Segment1, typename Segment2>
+ static inline bool apply(Segment1 const& segment1, Segment2 const& segment2)
+ {
+ 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>
@@ -103,9 +137,10 @@ struct length_check
};
-template <typename Geometry1, typename Geometry2, typename TrivialCheck>
+template <typename TrivialCheck>
struct equals_by_collection
{
+ template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
if (! TrivialCheck::apply(geometry1, geometry2))
@@ -141,6 +176,15 @@ struct equals_by_collection
}
};
+template<typename Geometry1, typename Geometry2>
+struct equals_by_relate
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_equals_type,
+ Geometry1,
+ Geometry2
+ >
+{};
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
@@ -152,17 +196,42 @@ namespace dispatch
template
<
- typename Tag1, typename Tag2,
typename Geometry1,
typename Geometry2,
- std::size_t DimensionCount
+ 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
+struct equals: not_implemented<Tag1, Tag2>
{};
-template <typename P1, typename P2, std::size_t DimensionCount>
-struct equals<point_tag, point_tag, P1, P2, DimensionCount>
+// 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>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ return equals
+ <
+ Geometry2, Geometry1,
+ Tag2, Tag1,
+ DimensionCount,
+ false
+ >::apply(g2, g1);
+ }
+};
+
+
+template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
+struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
: geometry::detail::not_
<
P1,
@@ -172,104 +241,208 @@ struct equals<point_tag, point_tag, P1, P2, DimensionCount>
{};
-template <typename Box1, typename Box2, std::size_t DimensionCount>
-struct equals<box_tag, box_tag, Box1, Box2, DimensionCount>
- : detail::equals::box_box<Box1, Box2, 0, DimensionCount>
+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>
-struct equals<ring_tag, ring_tag, Ring1, Ring2, 2>
- : detail::equals::equals_by_collection
- <
- Ring1, Ring2,
- detail::equals::area_check
- >
+template <typename Ring1, typename Ring2, bool Reverse>
+struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
-template <typename Polygon1, typename Polygon2>
-struct equals<polygon_tag, polygon_tag, Polygon1, Polygon2, 2>
- : detail::equals::equals_by_collection
- <
- Polygon1, Polygon2,
- 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<detail::equals::area_check>
{};
-template <typename LineString1, typename LineString2>
-struct equals<linestring_tag, linestring_tag, LineString1, LineString2, 2>
- : detail::equals::equals_by_collection
- <
- LineString1, LineString2,
- detail::equals::length_check
- >
+template <typename Polygon, typename Ring, bool Reverse>
+struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
{};
-template <typename Polygon, typename Ring>
-struct equals<polygon_tag, ring_tag, Polygon, Ring, 2>
- : detail::equals::equals_by_collection
- <
- Polygon, Ring,
- 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 Ring, typename Box>
-struct equals<ring_tag, box_tag, Ring, Box, 2>
- : detail::equals::equals_by_collection
- <
- Ring, Box,
- 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 Polygon, typename Box>
-struct equals<polygon_tag, box_tag, Polygon, Box, 2>
- : detail::equals::equals_by_collection
- <
- Polygon, Box,
- detail::equals::area_check
- >
+template <typename LineString1, typename LineString2, bool Reverse>
+struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
+ //: detail::equals::equals_by_collection<detail::equals::length_check>
+ : 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 Tag1, typename Tag2,
- typename Geometry1,
- typename Geometry2,
- std::size_t DimensionCount
->
-struct equals_reversed
+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<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<detail::equals::area_check>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct equals
{
- static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
{
- return equals
- <
- Tag2, Tag1,
- Geometry2, Geometry1,
- DimensionCount
- >::apply(g2, g1);
+ concept::check_concepts_and_equal_dimensions
+ <
+ Geometry1 const,
+ Geometry2 const
+ >();
+
+ return dispatch::equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
}
};
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2)
+ : m_geometry2(geometry2)
+ {}
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+ template <typename Geometry1>
+ inline bool operator()(Geometry1 const& geometry1) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2);
+ }
+
+ };
+
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2
+ )
+ {
+ return apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1)
+ : m_geometry1(geometry1)
+ {}
+
+ template <typename Geometry2>
+ inline bool operator()(Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2);
+ }
+
+ };
+
+ static inline bool apply(
+ Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2
+ )
+ {
+ return apply_visitor(visitor(geometry1), 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)>
+>
+{
+ struct visitor: static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ inline bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
+ }
+
+ };
+
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2
+ )
+ {
+ return apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
/*!
\brief \brief_check{are spatially equal}
-\details \details_check12{equals, is spatially equal}. Spatially equal means
+\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 theoretically, not all combinations
- are implemented yet.
+ 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
@@ -283,32 +456,8 @@ struct equals_reversed
template <typename Geometry1, typename Geometry2>
inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check_concepts_and_equal_dimensions
- <
- Geometry1 const,
- Geometry2 const
- >();
-
- return boost::mpl::if_c
- <
- reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::equals_reversed
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >,
- dispatch::equals
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- Geometry1,
- Geometry2,
- dimension<Geometry1>::type::value
- >
- >::type::apply(geometry1, geometry2);
+ return resolve_variant::equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
}
diff --git a/boost/geometry/algorithms/expand.hpp b/boost/geometry/algorithms/expand.hpp
index da7442b593..19e40aa2d0 100644
--- a/boost/geometry/algorithms/expand.hpp
+++ b/boost/geometry/algorithms/expand.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -19,6 +20,7 @@
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -27,6 +29,9 @@
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/policies/compare.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+
namespace boost { namespace geometry
{
@@ -38,26 +43,26 @@ namespace detail { namespace expand
template
<
- typename Box, typename Point,
typename StrategyLess, typename StrategyGreater,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_loop
{
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyLess, 1, Point, Dimension
- >::type less_type;
+ template <typename Box, typename Point>
+ static inline void apply(Box& box, Point const& source)
+ {
+ typedef typename strategy::compare::detail::select_strategy
+ <
+ StrategyLess, 1, Point, Dimension
+ >::type less_type;
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyGreater, -1, Point, Dimension
- >::type greater_type;
+ typedef typename strategy::compare::detail::select_strategy
+ <
+ StrategyGreater, -1, Point, Dimension
+ >::type greater_type;
- typedef typename select_coordinate_type<Point, Box>::type coordinate_type;
+ typedef typename select_coordinate_type<Point, Box>::type coordinate_type;
- static inline void apply(Box& box, Point const& source)
- {
less_type less;
greater_type greater;
@@ -75,7 +80,6 @@ struct point_loop
point_loop
<
- Box, Point,
StrategyLess, StrategyGreater,
Dimension + 1, DimensionCount
>::apply(box, source);
@@ -85,49 +89,47 @@ struct point_loop
template
<
- typename Box, typename Point,
typename StrategyLess, typename StrategyGreater,
std::size_t DimensionCount
>
struct point_loop
<
- Box, Point,
StrategyLess, StrategyGreater,
DimensionCount, DimensionCount
>
{
+ template <typename Box, typename Point>
static inline void apply(Box&, Point const&) {}
};
template
<
- typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct indexed_loop
{
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyLess, 1, Box, Dimension
- >::type less_type;
-
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyGreater, -1, Box, Dimension
- >::type greater_type;
+ template <typename Box, typename Geometry>
+ static inline void apply(Box& box, Geometry const& source)
+ {
+ typedef typename strategy::compare::detail::select_strategy
+ <
+ StrategyLess, 1, Box, Dimension
+ >::type less_type;
- typedef typename select_coordinate_type
+ typedef typename strategy::compare::detail::select_strategy
<
- Box,
- Geometry
- >::type coordinate_type;
+ StrategyGreater, -1, Box, Dimension
+ >::type greater_type;
+ typedef typename select_coordinate_type
+ <
+ Box,
+ Geometry
+ >::type coordinate_type;
- static inline void apply(Box& box, Geometry const& source)
- {
less_type less;
greater_type greater;
@@ -145,7 +147,6 @@ struct indexed_loop
indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
Index, Dimension + 1, DimensionCount
>::apply(box, source);
@@ -155,17 +156,16 @@ struct indexed_loop
template
<
- typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater,
std::size_t Index, std::size_t DimensionCount
>
struct indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
Index, DimensionCount, DimensionCount
>
{
+ template <typename Box, typename Geometry>
static inline void apply(Box&, Geometry const&) {}
};
@@ -174,23 +174,21 @@ struct indexed_loop
// Changes a box such that the other box is also contained by the box
template
<
- typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater
>
struct expand_indexed
{
+ template <typename Box, typename Geometry>
static inline void apply(Box& box, Geometry const& geometry)
{
indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
0, 0, dimension<Geometry>::type::value
>::apply(box, geometry);
indexed_loop
<
- Box, Geometry,
StrategyLess, StrategyGreater,
1, 0, dimension<Geometry>::type::value
>::apply(box, geometry);
@@ -206,11 +204,13 @@ namespace dispatch
template
<
- typename Tag,
- typename BoxOut, typename Geometry,
- typename StrategyLess, typename StrategyGreater
+ typename GeometryOut, typename Geometry,
+ typename StrategyLess = strategy::compare::default_strategy,
+ typename StrategyGreater = strategy::compare::default_strategy,
+ typename TagOut = typename tag<GeometryOut>::type,
+ typename Tag = typename tag<Geometry>::type
>
-struct expand
+struct expand: not_implemented<TagOut, Tag>
{};
@@ -220,10 +220,9 @@ template
typename BoxOut, typename Point,
typename StrategyLess, typename StrategyGreater
>
-struct expand<point_tag, BoxOut, Point, StrategyLess, StrategyGreater>
+struct expand<BoxOut, Point, StrategyLess, StrategyGreater, box_tag, point_tag>
: detail::expand::point_loop
<
- BoxOut, Point,
StrategyLess, StrategyGreater,
0, dimension<Point>::type::value
>
@@ -236,9 +235,8 @@ template
typename BoxOut, typename BoxIn,
typename StrategyLess, typename StrategyGreater
>
-struct expand<box_tag, BoxOut, BoxIn, StrategyLess, StrategyGreater>
- : detail::expand::expand_indexed
- <BoxOut, BoxIn, StrategyLess, StrategyGreater>
+struct expand<BoxOut, BoxIn, StrategyLess, StrategyGreater, box_tag, box_tag>
+ : detail::expand::expand_indexed<StrategyLess, StrategyGreater>
{};
template
@@ -246,9 +244,8 @@ template
typename Box, typename Segment,
typename StrategyLess, typename StrategyGreater
>
-struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater>
- : detail::expand::expand_indexed
- <Box, Segment, StrategyLess, StrategyGreater>
+struct expand<Box, Segment, StrategyLess, StrategyGreater, box_tag, segment_tag>
+ : detail::expand::expand_indexed<StrategyLess, StrategyGreater>
{};
@@ -256,6 +253,51 @@ struct expand<segment_tag, Box, Segment, StrategyLess, StrategyGreater>
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct expand
+{
+ template <typename Box>
+ static inline void apply(Box& box, Geometry const& geometry)
+ {
+ concept::check<Box>();
+ concept::check<Geometry const>();
+ concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
+
+ dispatch::expand<Box, Geometry>::apply(box, geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Box>
+ struct visitor: boost::static_visitor<void>
+ {
+ Box& m_box;
+
+ visitor(Box& box) : m_box(box) {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ return expand<Geometry>::apply(m_box, geometry);
+ }
+ };
+
+ template <class Box>
+ static inline void
+ apply(Box& box,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor<Box>(box), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/***
*!
\brief Expands a box using the extend (envelope) of another geometry (box, point)
@@ -279,13 +321,7 @@ inline void expand(Box& box, Geometry const& geometry,
{
concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
- dispatch::expand
- <
- typename tag<Geometry>::type,
- Box,
- Geometry,
- StrategyLess, StrategyGreater
- >::apply(box, geometry);
+ dispatch::expand<Box, Geometry>::apply(box, geometry);
}
***/
@@ -303,15 +339,7 @@ inline void expand(Box& box, Geometry const& geometry,
template <typename Box, typename Geometry>
inline void expand(Box& box, Geometry const& geometry)
{
- concept::check_concepts_and_equal_dimensions<Box, Geometry const>();
-
- dispatch::expand
- <
- typename tag<Geometry>::type,
- Box, Geometry,
- strategy::compare::default_strategy,
- strategy::compare::default_strategy
- >::apply(box, geometry);
+ resolve_variant::expand<Geometry>::apply(box, geometry);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/for_each.hpp b/boost/geometry/algorithms/for_each.hpp
index 671f26a70d..c5c099b1ad 100644
--- a/boost/geometry/algorithms/for_each.hpp
+++ b/boost/geometry/algorithms/for_each.hpp
@@ -1,8 +1,14 @@
// 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.
+// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -18,17 +24,24 @@
#include <algorithm>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/is_const.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/util/add_const_if_c.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -39,127 +52,162 @@ namespace detail { namespace for_each
{
-template <typename Point, typename Functor, bool IsConst>
struct fe_point_per_point
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Point>::type& point, Functor f)
+ template <typename Point, typename Functor>
+ static inline void apply(Point& point, Functor& f)
{
f(point);
- return f;
}
};
-template <typename Point, typename Functor, bool IsConst>
struct fe_point_per_segment
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Point>::type& , Functor f)
+ template <typename Point, typename Functor>
+ static inline void apply(Point& , Functor& /*f*/)
{
// TODO: if non-const, we should extract the points from the segment
// and call the functor on those two points
- return f;
}
};
-template <typename Range, typename Functor, bool IsConst>
struct fe_range_per_point
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Range>::type& range,
- Functor f)
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
{
- return (std::for_each(boost::begin(range), boost::end(range), f));
+ // The previous implementation called the std library:
+ // return (std::for_each(boost::begin(range), boost::end(range), f));
+ // But that is not accepted for capturing lambda's.
+ // It needs to do it like that to return the state of Functor f (f is passed by value in std::for_each).
+
+ // So we now loop manually.
+
+ for (typename boost::range_iterator<Range>::type
+ it = boost::begin(range); it != boost::end(range); ++it)
+ {
+ f(*it);
+ }
}
};
-template <typename Range, typename Functor, bool IsConst>
-struct fe_range_per_segment
+template <closure_selector Closure>
+struct fe_range_per_segment_with_closure
{
- static inline Functor apply(
- typename add_const_if_c<IsConst, Range>::type& range,
- Functor f)
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
{
typedef typename add_const_if_c
<
- IsConst,
+ is_const<Range>::value,
typename point_type<Range>::type
>::type point_type;
- BOOST_AUTO_TPL(it, boost::begin(range));
- BOOST_AUTO_TPL(previous, it++);
+ typedef typename boost::range_iterator<Range>::type iterator_type;
+
+ iterator_type it = boost::begin(range);
+ iterator_type previous = it++;
while(it != boost::end(range))
{
model::referring_segment<point_type> s(*previous, *it);
f(s);
previous = it++;
}
+ }
+};
+
- return f;
+template <>
+struct fe_range_per_segment_with_closure<open>
+{
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
+ {
+ fe_range_per_segment_with_closure<closed>::apply(range, f);
+
+ model::referring_segment
+ <
+ typename add_const_if_c
+ <
+ is_const<Range>::value,
+ typename point_type<Range>::type
+ >::type
+ > s(range::back(range), range::front(range));
+
+ f(s);
}
};
-template <typename Polygon, typename Functor, bool IsConst>
-struct fe_polygon_per_point
+struct fe_range_per_segment
{
- typedef typename add_const_if_c<IsConst, Polygon>::type poly_type;
+ template <typename Range, typename Functor>
+ static inline void apply(Range& range, Functor& f)
+ {
+ fe_range_per_segment_with_closure
+ <
+ closure<Range>::value
+ >::apply(range, f);
+ }
+};
+
- static inline Functor apply(poly_type& poly, Functor f)
+struct fe_polygon_per_point
+{
+ template <typename Polygon, typename Functor>
+ static inline void apply(Polygon& poly, Functor& f)
{
- typedef fe_range_per_point
- <
- typename ring_type<Polygon>::type,
- Functor,
- IsConst
- > per_ring;
+ fe_range_per_point::apply(exterior_ring(poly), f);
- f = per_ring::apply(exterior_ring(poly), f);
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
- typename interior_return_type<poly_type>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- f = per_ring::apply(*it, f);
+ fe_range_per_point::apply(*it, f);
}
-
- return f;
}
};
-
-template <typename Polygon, typename Functor, bool IsConst>
struct fe_polygon_per_segment
{
- typedef typename add_const_if_c<IsConst, Polygon>::type poly_type;
-
- static inline Functor apply(poly_type& poly, Functor f)
+ template <typename Polygon, typename Functor>
+ static inline void apply(Polygon& poly, Functor& f)
{
- typedef fe_range_per_segment
- <
- typename ring_type<Polygon>::type,
- Functor,
- IsConst
- > per_ring;
+ fe_range_per_segment::apply(exterior_ring(poly), f);
- f = per_ring::apply(exterior_ring(poly), f);
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
- typename interior_return_type<poly_type>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- f = per_ring::apply(*it, f);
+ fe_range_per_segment::apply(*it, f);
}
-
- return f;
}
};
+// Implementation of multi, for both point and segment,
+// just calling the single version.
+template <typename Policy>
+struct for_each_multi
+{
+ template <typename MultiGeometry, typename Functor>
+ static inline void apply(MultiGeometry& multi, Functor& f)
+ {
+ for (typename boost::range_iterator<MultiGeometry>::type
+ it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ Policy::apply(*it, f);
+ }
+ }
+};
}} // namespace detail::for_each
#endif // DOXYGEN_NO_DETAIL
@@ -171,102 +219,105 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename Functor,
- bool IsConst
+ typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
-struct for_each_point {};
+struct for_each_point: not_implemented<Tag>
+{};
-template <typename Point, typename Functor, bool IsConst>
-struct for_each_point<point_tag, Point, Functor, IsConst>
- : detail::for_each::fe_point_per_point<Point, Functor, IsConst>
+template <typename Point>
+struct for_each_point<Point, point_tag>
+ : detail::for_each::fe_point_per_point
{};
-template <typename Linestring, typename Functor, bool IsConst>
-struct for_each_point<linestring_tag, Linestring, Functor, IsConst>
- : detail::for_each::fe_range_per_point<Linestring, Functor, IsConst>
+template <typename Linestring>
+struct for_each_point<Linestring, linestring_tag>
+ : detail::for_each::fe_range_per_point
{};
-template <typename Ring, typename Functor, bool IsConst>
-struct for_each_point<ring_tag, Ring, Functor, IsConst>
- : detail::for_each::fe_range_per_point<Ring, Functor, IsConst>
+template <typename Ring>
+struct for_each_point<Ring, ring_tag>
+ : detail::for_each::fe_range_per_point
{};
-template <typename Polygon, typename Functor, bool IsConst>
-struct for_each_point<polygon_tag, Polygon, Functor, IsConst>
- : detail::for_each::fe_polygon_per_point<Polygon, Functor, IsConst>
+template <typename Polygon>
+struct for_each_point<Polygon, polygon_tag>
+ : detail::for_each::fe_polygon_per_point
{};
template
<
- typename Tag,
typename Geometry,
- typename Functor,
- bool IsConst
+ typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
-struct for_each_segment {};
+struct for_each_segment: not_implemented<Tag>
+{};
-template <typename Point, typename Functor, bool IsConst>
-struct for_each_segment<point_tag, Point, Functor, IsConst>
- : detail::for_each::fe_point_per_segment<Point, Functor, IsConst>
+template <typename Point>
+struct for_each_segment<Point, point_tag>
+ : detail::for_each::fe_point_per_segment
{};
-template <typename Linestring, typename Functor, bool IsConst>
-struct for_each_segment<linestring_tag, Linestring, Functor, IsConst>
- : detail::for_each::fe_range_per_segment<Linestring, Functor, IsConst>
+template <typename Linestring>
+struct for_each_segment<Linestring, linestring_tag>
+ : detail::for_each::fe_range_per_segment
{};
-template <typename Ring, typename Functor, bool IsConst>
-struct for_each_segment<ring_tag, Ring, Functor, IsConst>
- : detail::for_each::fe_range_per_segment<Ring, Functor, IsConst>
+template <typename Ring>
+struct for_each_segment<Ring, ring_tag>
+ : detail::for_each::fe_range_per_segment
{};
-template <typename Polygon, typename Functor, bool IsConst>
-struct for_each_segment<polygon_tag, Polygon, Functor, IsConst>
- : detail::for_each::fe_polygon_per_segment<Polygon, Functor, IsConst>
+template <typename Polygon>
+struct for_each_segment<Polygon, polygon_tag>
+ : detail::for_each::fe_polygon_per_segment
{};
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+template <typename MultiGeometry>
+struct for_each_point<MultiGeometry, multi_tag>
+ : detail::for_each::for_each_multi
+ <
+ // Specify the dispatch of the single-version as policy
+ for_each_point
+ <
+ typename add_const_if_c
+ <
+ is_const<MultiGeometry>::value,
+ typename boost::range_value<MultiGeometry>::type
+ >::type
+ >
+ >
+{};
-/*!
-\brief \brf_for_each{point}
-\details \det_for_each{point}
-\ingroup for_each
-\param geometry \param_geometry
-\param f \par_for_each_f{const point}
-\tparam Geometry \tparam_geometry
-\tparam Functor \tparam_functor
+template <typename MultiGeometry>
+struct for_each_segment<MultiGeometry, multi_tag>
+ : detail::for_each::for_each_multi
+ <
+ // Specify the dispatch of the single-version as policy
+ for_each_segment
+ <
+ typename add_const_if_c
+ <
+ is_const<MultiGeometry>::value,
+ typename boost::range_value<MultiGeometry>::type
+ >::type
+ >
+ >
+{};
-\qbk{distinguish,const version}
-\qbk{[include reference/algorithms/for_each_point.qbk]}
-\qbk{[heading Example]}
-\qbk{[for_each_point_const] [for_each_point_const_output]}
-*/
-template<typename Geometry, typename Functor>
-inline Functor for_each_point(Geometry const& geometry, Functor f)
-{
- concept::check<Geometry const>();
- return dispatch::for_each_point
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- true
- >::apply(geometry, f);
-}
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
/*!
@@ -281,19 +332,15 @@ inline Functor for_each_point(Geometry const& geometry, Functor f)
\qbk{[include reference/algorithms/for_each_point.qbk]}
\qbk{[heading Example]}
\qbk{[for_each_point] [for_each_point_output]}
+\qbk{[for_each_point_const] [for_each_point_const_output]}
*/
template<typename Geometry, typename Functor>
inline Functor for_each_point(Geometry& geometry, Functor f)
{
concept::check<Geometry>();
- return dispatch::for_each_point
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- false
- >::apply(geometry, f);
+ dispatch::for_each_point<Geometry>::apply(geometry, f);
+ return f;
}
@@ -302,53 +349,21 @@ inline Functor for_each_point(Geometry& geometry, Functor f)
\details \det_for_each{segment}
\ingroup for_each
\param geometry \param_geometry
-\param f \par_for_each_f{const segment}
+\param f \par_for_each_f{segment}
\tparam Geometry \tparam_geometry
\tparam Functor \tparam_functor
-\qbk{distinguish,const version}
\qbk{[include reference/algorithms/for_each_segment.qbk]}
\qbk{[heading Example]}
\qbk{[for_each_segment_const] [for_each_segment_const_output]}
*/
template<typename Geometry, typename Functor>
-inline Functor for_each_segment(Geometry const& geometry, Functor f)
-{
- concept::check<Geometry const>();
-
- return dispatch::for_each_segment
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- true
- >::apply(geometry, f);
-}
-
-
-/*!
-\brief \brf_for_each{segment}
-\details \det_for_each{segment}
-\ingroup for_each
-\param geometry \param_geometry
-\param f \par_for_each_f{segment}
-\tparam Geometry \tparam_geometry
-\tparam Functor \tparam_functor
-
-\qbk{[include reference/algorithms/for_each_segment.qbk]}
-*/
-template<typename Geometry, typename Functor>
inline Functor for_each_segment(Geometry& geometry, Functor f)
{
concept::check<Geometry>();
- return dispatch::for_each_segment
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry,
- Functor,
- false
- >::apply(geometry, f);
+ dispatch::for_each_segment<Geometry>::apply(geometry, f);
+ return f;
}
diff --git a/boost/geometry/algorithms/intersection.hpp b/boost/geometry/algorithms/intersection.hpp
index 8d3dd68b3a..0169f12db1 100644
--- a/boost/geometry/algorithms/intersection.hpp
+++ b/boost/geometry/algorithms/intersection.hpp
@@ -2,6 +2,11 @@
// 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.
+
+// 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,228 +15,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
-#include <boost/geometry/algorithms/intersects.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace intersection
-{
-
-template
-<
- typename Box1, typename Box2,
- typename BoxOut,
- typename Strategy,
- std::size_t Dimension, std::size_t DimensionCount
->
-struct intersection_box_box
-{
- static inline bool apply(Box1 const& box1,
- Box2 const& box2, BoxOut& box_out,
- Strategy const& strategy)
- {
- typedef typename coordinate_type<BoxOut>::type ct;
-
- ct min1 = get<min_corner, Dimension>(box1);
- ct min2 = get<min_corner, Dimension>(box2);
- ct max1 = get<max_corner, Dimension>(box1);
- ct max2 = get<max_corner, Dimension>(box2);
-
- if (max1 < min2 || max2 < min1)
- {
- return false;
- }
- // Set dimensions of output coordinate
- set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
- set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
-
- return intersection_box_box
- <
- Box1, Box2, BoxOut, Strategy,
- Dimension + 1, DimensionCount
- >::apply(box1, box2, box_out, strategy);
- }
-};
-
-template
-<
- typename Box1, typename Box2,
- typename BoxOut,
- typename Strategy,
- std::size_t DimensionCount
->
-struct intersection_box_box<Box1, Box2, BoxOut, Strategy, DimensionCount, DimensionCount>
-{
- static inline bool apply(Box1 const&, Box2 const&, BoxOut&, Strategy const&)
- {
- return true;
- }
-};
-
-
-}} // namespace detail::intersection
-#endif // DOXYGEN_NO_DETAIL
-
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-// By default, all is forwarded to the intersection_insert-dispatcher
-template
-<
- typename Tag1, typename Tag2, typename TagOut,
- typename Geometry1, typename Geometry2,
- typename GeometryOut,
- typename Strategy
->
-struct intersection
-{
- typedef std::back_insert_iterator<GeometryOut> output_iterator;
-
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- GeometryOut& geometry_out,
- Strategy const& strategy)
- {
- typedef typename boost::range_value<GeometryOut>::type OneOut;
-
- intersection_insert
- <
- Tag1, Tag2, typename geometry::tag<OneOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<OneOut>::value,
- Geometry1, Geometry2,
- detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, false>::value,
- detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, false>::value,
- detail::overlay::do_reverse<geometry::point_order<OneOut>::value>::value,
- output_iterator, OneOut,
- overlay_intersection,
- Strategy
- >::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy);
-
- return true;
- }
-
-};
-
-
-template
-<
- typename Box1, typename Box2,
- typename BoxOut,
- typename Strategy
->
-struct intersection
- <
- box_tag, box_tag, box_tag,
- Box1, Box2, BoxOut,
- Strategy
- > : public detail::intersection::intersection_box_box
- <
- Box1, Box2, BoxOut,
- Strategy,
- 0, geometry::dimension<Box1>::value
- >
-{};
-
-
-template
-<
- typename Tag1, typename Tag2, typename TagOut,
- typename Geometry1, typename Geometry2,
- typename GeometryOut,
- typename Strategy
->
-struct intersection_reversed
-{
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- GeometryOut& geometry_out,
- Strategy const& strategy)
- {
- return intersection
- <
- Tag2, Tag1, TagOut,
- Geometry2, Geometry1,
- GeometryOut, Strategy
- >::apply(geometry2, geometry1, geometry_out, strategy);
- }
-};
-
-
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-/*!
-\brief \brief_calc2{intersection}
-\ingroup intersection
-\details \details_calc2{intersection, spatial set theoretic intersection}.
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which
- the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box)
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param geometry_out The output geometry, either a multi_point, multi_polygon,
- multi_linestring, or a box (for intersection of two boxes)
-
-\qbk{[include reference/algorithms/intersection.qbk]}
-*/
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename GeometryOut
->
-inline bool intersection(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- GeometryOut& geometry_out)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
- typedef strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename geometry::point_type<Geometry1>::type
- > strategy;
-
-
- return boost::mpl::if_c
- <
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::intersection_reversed
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- Geometry1, Geometry2, GeometryOut, strategy
- >,
- dispatch::intersection
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- Geometry1, Geometry2, GeometryOut, strategy
- >
- >::type::apply(geometry1, geometry2, geometry_out, strategy());
-}
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/intersection/interface.hpp>
+#include <boost/geometry/algorithms/detail/intersection/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP
diff --git a/boost/geometry/algorithms/intersects.hpp b/boost/geometry/algorithms/intersects.hpp
index f367f2e258..1bb85aa3bb 100644
--- a/boost/geometry/algorithms/intersects.hpp
+++ b/boost/geometry/algorithms/intersects.hpp
@@ -1,8 +1,13 @@
// 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.
+// 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-2014.
+// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+
+// 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.
@@ -21,6 +26,9 @@
#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>
+
namespace boost { namespace geometry
{
@@ -43,37 +51,29 @@ inline bool intersects(Geometry const& geometry)
{
concept::check<Geometry const>();
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
typedef detail::overlay::turn_info
<
- typename geometry::point_type<Geometry>::type
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
- std::deque<turn_info> turns;
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry>::type,
- Geometry,
- Geometry,
- typename geometry::point_type<Geometry>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
+ std::deque<turn_info> turns;
typedef detail::overlay::get_turn_info
<
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- turn_info,
detail::overlay::assign_null_policy
- > TurnPolicy;
+ > turn_policy;
+
+ rescale_policy_type robust_policy;
detail::disjoint::disjoint_interrupt_policy policy;
detail::self_get_turn_points::get_turns
- <
- Geometry,
- std::deque<turn_info>,
- TurnPolicy,
- detail::disjoint::disjoint_interrupt_policy
- >::apply(geometry, turns, policy);
+ <
+ turn_policy
+ >::apply(geometry, robust_policy, turns, policy);
return policy.has_intersections;
}
diff --git a/boost/geometry/algorithms/is_simple.hpp b/boost/geometry/algorithms/is_simple.hpp
new file mode 100644
index 0000000000..f48c957dfc
--- /dev/null
+++ b/boost/geometry/algorithms/is_simple.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
+
+#include <boost/geometry/algorithms/detail/is_simple/interface.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/implementation.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
diff --git a/boost/geometry/algorithms/is_valid.hpp b/boost/geometry/algorithms/is_valid.hpp
new file mode 100644
index 0000000000..24dc5f7737
--- /dev/null
+++ b/boost/geometry/algorithms/is_valid.hpp
@@ -0,0 +1,16 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
+
+#include <boost/geometry/algorithms/detail/is_valid/interface.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/implementation.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
diff --git a/boost/geometry/algorithms/length.hpp b/boost/geometry/algorithms/length.hpp
index de53a39e8f..6cbec5303e 100644
--- a/boost/geometry/algorithms/length.hpp
+++ b/boost/geometry/algorithms/length.hpp
@@ -1,8 +1,13 @@
// 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.
+// 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 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -16,18 +21,32 @@
#include <iterator>
+#include <boost/concept_check.hpp>
#include <boost/range.hpp>
+#include <boost/mpl/fold.hpp>
+#include <boost/mpl/greater.hpp>
#include <boost/mpl/if.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/mpl/int.hpp>
+#include <boost/mpl/set.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/transform.hpp>
#include <boost/type_traits.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/strategies/distance.hpp>
@@ -43,9 +62,10 @@ namespace detail { namespace length
{
-template<typename Segment, typename Strategy>
+template<typename Segment>
struct segment_length
{
+ template <typename Strategy>
static inline typename default_length_result<Segment>::type apply(
Segment const& segment, Strategy const& strategy)
{
@@ -63,14 +83,16 @@ struct segment_length
\note for_each could be used here, now that point_type is changed by boost
range iterator
*/
-template<typename Range, typename Strategy, closure_selector Closure>
+template<typename Range, closure_selector Closure>
struct range_length
{
typedef typename default_length_result<Range>::type return_type;
+ template <typename Strategy>
static inline return_type apply(
Range const& range, Strategy const& strategy)
{
+ boost::ignore_unused_variable_warning(strategy);
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_iterator
<
@@ -106,35 +128,111 @@ namespace dispatch
{
-template <typename Tag, typename Geometry, typename Strategy>
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct length : detail::calculate_null
- <
- typename default_length_result<Geometry>::type,
- Geometry,
- Strategy
- >
-{};
+{
+ typedef typename default_length_result<Geometry>::type return_type;
+ template <typename Strategy>
+ static inline return_type apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return calculate_null::apply<return_type>(geometry, strategy);
+ }
+};
-template <typename Geometry, typename Strategy>
-struct length<linestring_tag, Geometry, Strategy>
- : detail::length::range_length<Geometry, Strategy, closed>
+
+template <typename Geometry>
+struct length<Geometry, linestring_tag>
+ : detail::length::range_length<Geometry, closed>
{};
// RING: length is currently 0; it might be argued that it is the "perimeter"
-template <typename Geometry, typename Strategy>
-struct length<segment_tag, Geometry, Strategy>
- : detail::length::segment_length<Geometry, Strategy>
+template <typename Geometry>
+struct length<Geometry, segment_tag>
+ : detail::length::segment_length<Geometry>
{};
+template <typename MultiLinestring>
+struct length<MultiLinestring, multi_linestring_tag> : detail::multi_sum
+{
+ template <typename Strategy>
+ static inline typename default_length_result<MultiLinestring>::type
+ apply(MultiLinestring const& multi, Strategy const& strategy)
+ {
+ return multi_sum::apply
+ <
+ typename default_length_result<MultiLinestring>::type,
+ detail::length::range_length
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ closed // no need to close it explicitly
+ >
+ >(multi, strategy);
+
+ }
+};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_variant {
+
+template <typename Geometry>
+struct length
+{
+ template <typename Strategy>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return dispatch::length<Geometry>::apply(geometry, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct length<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ typedef typename default_length_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
+ >::type result_type;
+
+ template <typename Strategy>
+ struct visitor
+ : static_visitor<result_type>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ inline typename default_length_result<Geometry>::type
+ operator()(Geometry const& geometry) const
+ {
+ return length<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline result_type apply(
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy
+ )
+ {
+ return apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{length}
\ingroup length
@@ -147,24 +245,20 @@ struct length<segment_tag, Geometry, Strategy>
\qbk{[length] [length_output]}
*/
template<typename Geometry>
-inline typename default_length_result<Geometry>::type length(
- Geometry const& geometry)
+inline typename default_length_result<Geometry>::type
+length(Geometry const& geometry)
{
concept::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
+ // TODO put this into a resolve_strategy stage
typedef typename strategy::distance::services::default_strategy
<
- point_tag, typename point_type<Geometry>::type
+ point_tag, point_tag, typename point_type<Geometry>::type
>::type strategy_type;
- return dispatch::length
- <
- typename tag<Geometry>::type,
- Geometry,
- strategy_type
- >::apply(geometry, strategy_type());
+ return resolve_variant::length<Geometry>::apply(geometry, strategy_type());
}
@@ -183,19 +277,14 @@ inline typename default_length_result<Geometry>::type length(
\qbk{[length_with_strategy] [length_with_strategy_output]}
*/
template<typename Geometry, typename Strategy>
-inline typename default_length_result<Geometry>::type length(
- Geometry const& geometry, Strategy const& strategy)
+inline typename default_length_result<Geometry>::type
+length(Geometry const& geometry, Strategy const& strategy)
{
concept::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
-
- return dispatch::length
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, strategy);
+
+ return resolve_variant::length<Geometry>::apply(geometry, strategy);
}
diff --git a/boost/geometry/algorithms/not_implemented.hpp b/boost/geometry/algorithms/not_implemented.hpp
index 008f111cc8..cd40a2772f 100644
--- a/boost/geometry/algorithms/not_implemented.hpp
+++ b/boost/geometry/algorithms/not_implemented.hpp
@@ -18,7 +18,6 @@
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tags.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
namespace boost { namespace geometry
diff --git a/boost/geometry/algorithms/num_geometries.hpp b/boost/geometry/algorithms/num_geometries.hpp
index 20f35e90d2..d37d0bfabe 100644
--- a/boost/geometry/algorithms/num_geometries.hpp
+++ b/boost/geometry/algorithms/num_geometries.hpp
@@ -1,8 +1,13 @@
// 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.
+// 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 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -17,7 +22,12 @@
#include <cstddef>
-#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_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/tags.hpp>
@@ -25,6 +35,8 @@
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/counting.hpp>
+
namespace boost { namespace geometry
{
@@ -35,30 +47,74 @@ namespace dispatch
{
-template <typename Tag, typename Geometry>
-struct num_geometries
+template
+<
+ typename Geometry,
+ typename Tag = typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ single_tag,
+ multi_tag
+ >::type
+>
+struct num_geometries: not_implemented<Tag>
+{};
+
+
+template <typename Geometry>
+struct num_geometries<Geometry, single_tag>
+ : detail::counting::other_count<1>
+{};
+
+
+template <typename MultiGeometry>
+struct num_geometries<MultiGeometry, multi_tag>
{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
+ static inline std::size_t apply(MultiGeometry const& multi_geometry)
+ {
+ return boost::size(multi_geometry);
+ }
};
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
template <typename Geometry>
-struct num_geometries<single_tag, Geometry>
+struct num_geometries
{
- static inline std::size_t apply(Geometry const&)
+ static inline std::size_t apply(Geometry const& geometry)
{
- return 1;
+ concept::check<Geometry const>();
+
+ return dispatch::num_geometries<Geometry>::apply(geometry);
}
};
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_geometries<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_geometries<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
-
-} // namespace dispatch
-#endif
+} // namespace resolve_variant
/*!
@@ -74,18 +130,7 @@ struct num_geometries<single_tag, Geometry>
template <typename Geometry>
inline std::size_t num_geometries(Geometry const& geometry)
{
- concept::check<Geometry const>();
-
- return dispatch::num_geometries
- <
- typename tag_cast
- <
- typename tag<Geometry>::type,
- single_tag,
- multi_tag
- >::type,
- Geometry
- >::apply(geometry);
+ return resolve_variant::num_geometries<Geometry>::apply(geometry);
}
diff --git a/boost/geometry/algorithms/num_interior_rings.hpp b/boost/geometry/algorithms/num_interior_rings.hpp
index 2149f46576..e198b37a75 100644
--- a/boost/geometry/algorithms/num_interior_rings.hpp
+++ b/boost/geometry/algorithms/num_interior_rings.hpp
@@ -1,8 +1,14 @@
// 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.
+// 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 2014.
+// Modifications copyright (c) 2014, 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.
@@ -18,11 +24,19 @@
#include <boost/range.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/counting.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
namespace boost { namespace geometry
{
@@ -32,19 +46,15 @@ namespace dispatch
{
-template <typename Tag, typename Geometry>
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct num_interior_rings
-{
- static inline std::size_t apply(Geometry const& )
- {
- return 0;
- }
-};
+ : detail::counting::other_count<0>
+{};
template <typename Polygon>
-struct num_interior_rings<polygon_tag, Polygon>
+struct num_interior_rings<Polygon, polygon_tag>
{
static inline std::size_t apply(Polygon const& polygon)
{
@@ -54,8 +64,56 @@ struct num_interior_rings<polygon_tag, Polygon>
};
+template <typename MultiPolygon>
+struct num_interior_rings<MultiPolygon, multi_polygon_tag>
+ : detail::counting::multi_count
+ <
+ num_interior_rings
+ <
+ typename boost::range_value<MultiPolygon const>::type
+ >
+ >
+{};
+
+
} // namespace dispatch
-#endif
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct num_interior_rings
+{
+ static inline std::size_t apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+
+ return dispatch::num_interior_rings<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_interior_rings<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_interior_rings<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
/*!
@@ -74,11 +132,7 @@ struct num_interior_rings<polygon_tag, Polygon>
template <typename Geometry>
inline std::size_t num_interior_rings(Geometry const& geometry)
{
- return dispatch::num_interior_rings
- <
- typename tag<Geometry>::type,
- Geometry
- >::apply(geometry);
+ return resolve_variant::num_interior_rings<Geometry>::apply(geometry);
}
diff --git a/boost/geometry/algorithms/num_points.hpp b/boost/geometry/algorithms/num_points.hpp
index c480068f43..4c2ad3b08c 100644
--- a/boost/geometry/algorithms/num_points.hpp
+++ b/boost/geometry/algorithms/num_points.hpp
@@ -1,8 +1,14 @@
// 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.
+// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -16,76 +22,55 @@
#include <cstddef>
-#include <boost/mpl/assert.hpp>
+#include <boost/mpl/size_t.hpp>
+
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/core/exterior_ring.hpp>
-#include <boost/geometry/core/interior_rings.hpp>
-#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/counting.hpp>
-#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace num_points
{
-template <typename Range>
+template <bool AddForOpen>
struct range_count
{
- static inline std::size_t apply(Range const& range, bool add_for_open)
+ template <typename Range>
+ static inline std::size_t apply(Range const& range)
{
std::size_t n = boost::size(range);
- if (add_for_open && n > 0)
- {
- closure_selector const s = geometry::closure<Range>::value;
-
- if (s == open)
- {
- if (geometry::disjoint(*boost::begin(range), *(boost::begin(range) + n - 1)))
- {
- return n + 1;
- }
- }
- }
- return n;
- }
-};
-
-template <typename Geometry, std::size_t D>
-struct other_count
-{
- static inline std::size_t apply(Geometry const&, bool)
- {
- return D;
- }
-};
-
-template <typename Polygon>
-struct polygon_count
-{
- static inline std::size_t apply(Polygon const& poly, bool add_for_open)
- {
- typedef typename geometry::ring_type<Polygon>::type ring_type;
-
- std::size_t n = range_count<ring_type>::apply(
- exterior_ring(poly), add_for_open);
-
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ if (AddForOpen
+ && n > 0
+ && geometry::closure<Range>::value == open
+ )
{
- n += range_count<ring_type>::apply(*it, add_for_open);
+ return n + 1;
}
-
return n;
}
};
@@ -98,50 +83,107 @@ struct polygon_count
namespace dispatch
{
-template <typename GeometryTag, typename Geometry>
-struct num_points
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry>)
- );
-};
+template
+<
+ typename Geometry,
+ bool AddForOpen,
+ typename Tag = typename tag_cast
+ <
+ typename tag<Geometry>::type, multi_tag
+ >::type
+>
+struct num_points: not_implemented<Tag>
+{};
-template <typename Geometry>
-struct num_points<point_tag, Geometry>
- : detail::num_points::other_count<Geometry, 1>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, point_tag>
+ : detail::counting::other_count<1>
{};
-template <typename Geometry>
-struct num_points<box_tag, Geometry>
- : detail::num_points::other_count<Geometry, 4>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, box_tag>
+ : detail::counting::other_count<(1 << geometry::dimension<Geometry>::value)>
{};
-template <typename Geometry>
-struct num_points<segment_tag, Geometry>
- : detail::num_points::other_count<Geometry, 2>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, segment_tag>
+ : detail::counting::other_count<2>
{};
-template <typename Geometry>
-struct num_points<linestring_tag, Geometry>
- : detail::num_points::range_count<Geometry>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, linestring_tag>
+ : detail::num_points::range_count<AddForOpen>
{};
-template <typename Geometry>
-struct num_points<ring_tag, Geometry>
- : detail::num_points::range_count<Geometry>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, ring_tag>
+ : detail::num_points::range_count<AddForOpen>
{};
-template <typename Geometry>
-struct num_points<polygon_tag, Geometry>
- : detail::num_points::polygon_count<Geometry>
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, polygon_tag>
+ : detail::counting::polygon_count
+ <
+ detail::num_points::range_count<AddForOpen>
+ >
+{};
+
+template <typename Geometry, bool AddForOpen>
+struct num_points<Geometry, AddForOpen, multi_tag>
+ : detail::counting::multi_count
+ <
+ num_points<typename boost::range_value<Geometry>::type, AddForOpen>
+ >
{};
} // namespace dispatch
#endif
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct num_points
+{
+ static inline std::size_t apply(Geometry const& geometry,
+ bool add_for_open)
+ {
+ concept::check<Geometry const>();
+
+ return add_for_open
+ ? dispatch::num_points<Geometry, true>::apply(geometry)
+ : dispatch::num_points<Geometry, false>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_points<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ bool m_add_for_open;
+
+ visitor(bool add_for_open): m_add_for_open(add_for_open) {}
+
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_points<Geometry>::apply(geometry, m_add_for_open);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ bool add_for_open)
+ {
+ return boost::apply_visitor(visitor(add_for_open), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{number of points}
\ingroup num_points
@@ -156,15 +198,13 @@ struct num_points<polygon_tag, Geometry>
template <typename Geometry>
inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false)
{
- concept::check<Geometry const>();
-
- return dispatch::num_points
- <
- typename tag_cast<typename tag<Geometry>::type, multi_tag>::type,
- Geometry
- >::apply(geometry, add_for_open);
+ return resolve_variant::num_points<Geometry>::apply(geometry, add_for_open);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/num_segments.hpp b/boost/geometry/algorithms/num_segments.hpp
new file mode 100644
index 0000000000..cbb5685967
--- /dev/null
+++ b/boost/geometry/algorithms/num_segments.hpp
@@ -0,0 +1,204 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP
+
+#include <cstddef>
+
+#include <boost/mpl/size_t.hpp>
+#include <boost/mpl/times.hpp>
+
+#include <boost/range.hpp>
+
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/counting.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace num_segments
+{
+
+
+struct range_count
+{
+ template <typename Range>
+ static inline std::size_t apply(Range const& range)
+ {
+ std::size_t n = boost::size(range);
+ if ( n <= 1 )
+ {
+ return 0;
+ }
+
+ return
+ geometry::closure<Range>::value == open
+ ?
+ n
+ :
+ static_cast<std::size_t>(n - 1);
+ }
+};
+
+}} // namespace detail::num_segments
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct num_segments
+ : not_implemented<Tag>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, point_tag>
+ : detail::counting::other_count<0>
+{};
+
+// the number of segments (1-dimensional faces) of the hypercube is
+// given by the formula: d * 2^(d-1), where d is the dimension of the
+// hypercube; see also:
+// http://en.wikipedia.org/wiki/Hypercube
+template <typename Geometry>
+struct num_segments<Geometry, box_tag>
+ : detail::counting::other_count
+ <
+ geometry::dimension<Geometry>::value
+ * (1 << (geometry::dimension<Geometry>::value - 1))
+ >
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, segment_tag>
+ : detail::counting::other_count<1>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, linestring_tag>
+ : detail::num_segments::range_count
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, ring_tag>
+ : detail::num_segments::range_count
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, polygon_tag>
+ : detail::counting::polygon_count<detail::num_segments::range_count>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, multi_point_tag>
+ : detail::counting::other_count<0>
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, multi_linestring_tag>
+ : detail::counting::multi_count
+ <
+ num_segments< typename boost::range_value<Geometry>::type>
+ >
+{};
+
+template <typename Geometry>
+struct num_segments<Geometry, multi_polygon_tag>
+ : detail::counting::multi_count
+ <
+ num_segments< typename boost::range_value<Geometry>::type>
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+namespace resolve_variant
+{
+
+
+template <typename Geometry>
+struct num_segments
+{
+ static inline std::size_t apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+
+ return dispatch::num_segments<Geometry>::apply(geometry);
+ }
+};
+
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct num_segments<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<std::size_t>
+ {
+ template <typename Geometry>
+ inline std::size_t operator()(Geometry const& geometry) const
+ {
+ return num_segments<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline std::size_t
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+
+} // namespace resolve_variant
+
+
+
+/*!
+\brief \brief_calc{number of segments}
+\ingroup num_segments
+\details \details_calc{num_segments, number of segments}.
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_calc{number of segments}
+
+\qbk{[include reference/algorithms/num_segments.qbk]}
+*/
+template <typename Geometry>
+inline std::size_t num_segments(Geometry const& geometry)
+{
+ return resolve_variant::num_segments<Geometry>::apply(geometry);
+}
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP
diff --git a/boost/geometry/algorithms/overlaps.hpp b/boost/geometry/algorithms/overlaps.hpp
index 2f854b4fdd..f724a544fd 100644
--- a/boost/geometry/algorithms/overlaps.hpp
+++ b/boost/geometry/algorithms/overlaps.hpp
@@ -4,6 +4,9 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,18 +14,22 @@
// 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_OVERLAPS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP
#include <cstddef>
-#include <boost/mpl/assert.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/detail/relate/relate.hpp>
+
namespace boost { namespace geometry
{
@@ -32,13 +39,12 @@ namespace detail { namespace overlaps
template
<
- typename Box1,
- typename Box2,
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)
{
@@ -84,8 +90,6 @@ struct box_box_loop
box_box_loop
<
- Box1,
- Box2,
Dimension + 1,
DimensionCount
>::apply(b1, b2, overlaps, one_in_two, two_in_one);
@@ -94,24 +98,19 @@ struct box_box_loop
template
<
- typename Box1,
- typename Box2,
std::size_t DimensionCount
>
-struct box_box_loop<Box1, Box2, DimensionCount, DimensionCount>
+struct box_box_loop<DimensionCount, DimensionCount>
{
+ template <typename Box1, typename Box2>
static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
{
}
};
-template
-<
- typename Box1,
- typename Box2
->
struct box_box
{
+ template <typename Box1, typename Box2>
static inline bool apply(Box1 const& b1, Box2 const& b2)
{
bool overlaps = true;
@@ -119,8 +118,6 @@ struct box_box
bool within2 = true;
box_box_loop
<
- Box1,
- Box2,
0,
dimension<Box1>::type::value
>::apply(b1, b2, overlaps, within1, within2);
@@ -134,8 +131,6 @@ struct box_box
}
};
-
-
}} // namespace detail::overlaps
#endif // DOXYGEN_NO_DETAIL
@@ -148,29 +143,26 @@ namespace dispatch
template
<
- typename Tag1,
- typename Tag2,
typename Geometry1,
- typename Geometry2
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
>
struct overlaps
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<Geometry1, Geometry2>)
- );
-};
+ : detail::relate::relate_base
+ <
+ detail::relate::static_mask_overlaps_type,
+ Geometry1,
+ Geometry2
+ >
+{};
template <typename Box1, typename Box2>
-struct overlaps<box_tag, box_tag, Box1, Box2>
- : detail::overlaps::box_box<Box1, Box2>
+struct overlaps<Box1, Box2, box_tag, box_tag>
+ : detail::overlaps::box_box
{};
-
-
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -178,6 +170,10 @@ struct overlaps<box_tag, box_tag, Box1, Box2>
/*!
\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]}
@@ -190,8 +186,6 @@ inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
return dispatch::overlaps
<
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2);
diff --git a/boost/geometry/algorithms/perimeter.hpp b/boost/geometry/algorithms/perimeter.hpp
index adeb0b05b0..0ec153c1f4 100644
--- a/boost/geometry/algorithms/perimeter.hpp
+++ b/boost/geometry/algorithms/perimeter.hpp
@@ -1,8 +1,13 @@
// 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.
+// 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 2014.
+// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+
+// 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.
@@ -14,16 +19,22 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP
+#include <boost/range/metafunctions.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/strategies/default_length_result.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
+#include <boost/geometry/algorithms/detail/multi_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
-
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/default_length_result.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
namespace boost { namespace geometry
{
@@ -33,40 +44,59 @@ namespace dispatch
{
// Default perimeter is 0.0, specializations implement calculated values
-template <typename Tag, typename Geometry, typename Strategy>
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct perimeter : detail::calculate_null
- <
- typename default_length_result<Geometry>::type,
- Geometry,
- Strategy
- >
-{};
+{
+ typedef typename default_length_result<Geometry>::type return_type;
+
+ template <typename Strategy>
+ static inline return_type apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return calculate_null::apply<return_type>(geometry, strategy);
+ }
+};
-template <typename Geometry, typename Strategy>
-struct perimeter<ring_tag, Geometry, Strategy>
+template <typename Geometry>
+struct perimeter<Geometry, ring_tag>
: detail::length::range_length
<
Geometry,
- Strategy,
closure<Geometry>::value
>
{};
-template <typename Polygon, typename Strategy>
-struct perimeter<polygon_tag, Polygon, Strategy>
- : detail::calculate_polygon_sum
- <
- typename default_length_result<Polygon>::type,
- Polygon,
- Strategy,
- detail::length::range_length
+template <typename Polygon>
+struct perimeter<Polygon, polygon_tag> : detail::calculate_polygon_sum
+{
+ typedef typename default_length_result<Polygon>::type return_type;
+ typedef detail::length::range_length
<
typename ring_type<Polygon>::type,
- Strategy,
closure<Polygon>::value
- >
- >
-{};
+ > policy;
+
+ template <typename Strategy>
+ static inline return_type apply(Polygon const& polygon, Strategy const& strategy)
+ {
+ return calculate_polygon_sum::apply<return_type, policy>(polygon, strategy);
+ }
+};
+
+template <typename MultiPolygon>
+struct perimeter<MultiPolygon, multi_polygon_tag> : detail::multi_sum
+{
+ typedef typename default_length_result<MultiPolygon>::type return_type;
+
+ template <typename Strategy>
+ static inline return_type apply(MultiPolygon const& multi, Strategy const& strategy)
+ {
+ return multi_sum::apply
+ <
+ return_type,
+ perimeter<typename boost::range_value<MultiPolygon>::type>
+ >(multi, strategy);
+ }
+};
// box,n-sphere: to be implemented
@@ -75,6 +105,82 @@ struct perimeter<polygon_tag, Polygon, Strategy>
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+struct perimeter
+{
+ template <typename Geometry, typename Strategy>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ return dispatch::perimeter<Geometry>::apply(geometry, strategy);
+ }
+
+ template <typename Geometry>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, default_strategy)
+ {
+ typedef typename strategy::distance::services::default_strategy
+ <
+ point_tag, point_tag, typename point_type<Geometry>::type
+ >::type strategy_type;
+
+ return dispatch::perimeter<Geometry>::apply(geometry, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct perimeter
+{
+ template <typename Strategy>
+ static inline typename default_length_result<Geometry>::type
+ apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ concept::check<Geometry const>();
+ return resolve_strategy::perimeter::apply(geometry, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct perimeter<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ typedef typename default_length_result
+ <
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
+ >::type result_type;
+
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<result_type>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry>
+ typename default_length_result<Geometry>::type
+ operator()(Geometry const& geometry) const
+ {
+ return perimeter<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline result_type
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{perimeter}
\ingroup perimeter
@@ -90,22 +196,8 @@ template<typename Geometry>
inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry)
{
- concept::check<Geometry const>();
-
- typedef typename point_type<Geometry>::type point_type;
- typedef typename strategy::distance::services::default_strategy
- <
- point_tag, point_type
- >::type strategy_type;
-
// detail::throw_on_empty_input(geometry);
-
- return dispatch::perimeter
- <
- typename tag<Geometry>::type,
- Geometry,
- strategy_type
- >::apply(geometry, strategy_type());
+ return resolve_variant::perimeter<Geometry>::apply(geometry, default_strategy());
}
/*!
@@ -126,16 +218,8 @@ template<typename Geometry, typename Strategy>
inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry, Strategy const& strategy)
{
- concept::check<Geometry const>();
-
// detail::throw_on_empty_input(geometry);
-
- return dispatch::perimeter
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, strategy);
+ return resolve_variant::perimeter<Geometry>::apply(geometry, strategy);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/point_on_surface.hpp b/boost/geometry/algorithms/point_on_surface.hpp
new file mode 100644
index 0000000000..3fa83bfe6f
--- /dev/null
+++ b/boost/geometry/algorithms/point_on_surface.hpp
@@ -0,0 +1,327 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// 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.
+
+// 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_POINT_ON_SURFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP
+
+
+#include <cstddef>
+
+#include <numeric>
+
+#include <boost/concept_check.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/extreme_points.hpp>
+
+#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace point_on_surface
+{
+
+template <typename CoordinateType, int Dimension>
+struct specific_coordinate_first
+{
+ CoordinateType const m_value_to_be_first;
+
+ inline specific_coordinate_first(CoordinateType value_to_be_skipped)
+ : m_value_to_be_first(value_to_be_skipped)
+ {}
+
+ template <typename Point>
+ inline bool operator()(Point const& lhs, Point const& rhs)
+ {
+ CoordinateType const lh = geometry::get<Dimension>(lhs);
+ CoordinateType const rh = geometry::get<Dimension>(rhs);
+
+ // If both lhs and rhs equal m_value_to_be_first,
+ // we should handle conform if lh < rh = FALSE
+ // The first condition meets that, keep it first
+ if (geometry::math::equals(rh, m_value_to_be_first))
+ {
+ // Handle conform lh < -INF, which is always false
+ return false;
+ }
+
+ if (geometry::math::equals(lh, m_value_to_be_first))
+ {
+ // Handle conform -INF < rh, which is always true
+ return true;
+ }
+
+ return lh < rh;
+ }
+};
+
+template <int Dimension, typename Collection, typename Value, typename Predicate>
+inline bool max_value(Collection const& collection, Value& the_max, Predicate const& predicate)
+{
+ bool first = true;
+ for (typename Collection::const_iterator it = collection.begin(); it != collection.end(); ++it)
+ {
+ if (! it->empty())
+ {
+ Value the_value = geometry::get<Dimension>(*std::max_element(it->begin(), it->end(), predicate));
+ if (first || the_value > the_max)
+ {
+ the_max = the_value;
+ first = false;
+ }
+ }
+ }
+ return ! first;
+}
+
+
+template <int Dimension, typename Value>
+struct select_below
+{
+ Value m_value;
+ inline select_below(Value const& v)
+ : m_value(v)
+ {}
+
+ template <typename Intruder>
+ inline bool operator()(Intruder const& intruder) const
+ {
+ if (intruder.empty())
+ {
+ return true;
+ }
+ Value max = geometry::get<Dimension>(*std::max_element(intruder.begin(), intruder.end(), detail::extreme_points::compare<Dimension>()));
+ return geometry::math::equals(max, m_value) || max < m_value;
+ }
+};
+
+template <int Dimension, typename Value>
+struct adapt_base
+{
+ Value m_value;
+ inline adapt_base(Value const& v)
+ : m_value(v)
+ {}
+
+ template <typename Intruder>
+ inline void operator()(Intruder& intruder) const
+ {
+ if (intruder.size() >= 3)
+ {
+ detail::extreme_points::move_along_vector<Dimension>(intruder, m_value);
+ }
+ }
+};
+
+template <int Dimension, typename Value>
+struct min_of_intruder
+{
+ template <typename Intruder>
+ inline bool operator()(Intruder const& lhs, Intruder const& rhs) const
+ {
+ Value lhs_min = geometry::get<Dimension>(*std::min_element(lhs.begin(), lhs.end(), detail::extreme_points::compare<Dimension>()));
+ Value rhs_min = geometry::get<Dimension>(*std::min_element(rhs.begin(), rhs.end(), detail::extreme_points::compare<Dimension>()));
+ return lhs_min < rhs_min;
+ }
+};
+
+
+template <typename Point, typename P>
+inline void calculate_average(Point& point, std::vector<P> const& points)
+{
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+ typedef typename std::vector<P>::const_iterator iterator_type;
+ typedef typename std::vector<P>::size_type size_type;
+
+ coordinate_type x = 0;
+ coordinate_type y = 0;
+
+ iterator_type end = points.end();
+ for ( iterator_type it = points.begin() ; it != end ; ++it)
+ {
+ x += geometry::get<0>(*it);
+ y += geometry::get<1>(*it);
+ }
+
+ size_type const count = points.size();
+ geometry::set<0>(point, x / count);
+ geometry::set<1>(point, y / count);
+}
+
+
+template <int Dimension, typename Extremes, typename Intruders, typename CoordinateType>
+inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders& intruders, CoordinateType const& max_intruder)
+{
+ // This function handles self-tangencies.
+ // Self-tangencies use, as usual, the major part of code...
+
+ // ___ e
+ // /|\ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // / /\ | \ \ .
+ // i2 i1
+
+ // The picture above shows the extreme (outside, "e") and two intruders ("i1","i2")
+ // Assume that "i1" is self-tangent with the extreme, in one point at the top
+ // Now the "penultimate" value is searched, this is is the top of i2
+ // Then everything including and below (this is "i2" here) is removed
+ // Then the base of "i1" and of "e" is adapted to this penultimate value
+ // It then looks like:
+
+ // b ___ e
+ // /|\ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // / | \ \ .
+ // a c i1
+
+ // Then intruders (here "i1" but there may be more) are sorted from left to right
+ // Finally points "a","b" and "c" (in this order) are selected as a new triangle.
+ // This triangle will have a centroid which is inside (assumed that intruders left segment
+ // is not equal to extremes left segment, but that polygon would be invalid)
+
+ // Find highest non-self tangent intrusion, if any
+ CoordinateType penultimate_value;
+ specific_coordinate_first<CoordinateType, Dimension> pu_compare(max_intruder);
+ if (max_value<Dimension>(intruders, penultimate_value, pu_compare))
+ {
+ // Throw away all intrusions <= this value, and of the kept one set this as base.
+ select_below<Dimension, CoordinateType> predicate(penultimate_value);
+ intruders.erase
+ (
+ std::remove_if(boost::begin(intruders), boost::end(intruders), predicate),
+ boost::end(intruders)
+ );
+ adapt_base<Dimension, CoordinateType> fe_predicate(penultimate_value);
+ // Sort from left to right (or bottom to top if Dimension=0)
+ std::for_each(boost::begin(intruders), boost::end(intruders), fe_predicate);
+
+ // Also adapt base of extremes
+ detail::extreme_points::move_along_vector<Dimension>(extremes, penultimate_value);
+ }
+ // Then sort in 1-Dim. Take first to calc centroid.
+ std::sort(boost::begin(intruders), boost::end(intruders), min_of_intruder<1 - Dimension, CoordinateType>());
+
+ Extremes triangle;
+ triangle.reserve(3);
+
+ // Make a triangle of first two points of extremes (the ramp, from left to right), and last point of first intruder (which goes from right to left)
+ std::copy(extremes.begin(), extremes.begin() + 2, std::back_inserter(triangle));
+ triangle.push_back(intruders.front().back());
+
+ // (alternatively we could use the last two points of extremes, and first point of last intruder...):
+ //// ALTERNATIVE: std::copy(extremes.rbegin(), extremes.rbegin() + 2, std::back_inserter(triangle));
+ //// ALTERNATIVE: triangle.push_back(intruders.back().front());
+
+ // Now replace extremes with this smaller subset, a triangle, such that centroid calculation will result in a point inside
+ extremes = triangle;
+}
+
+template <int Dimension, typename Geometry, typename Point>
+inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
+{
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
+ std::vector<point_type> extremes;
+
+ typedef std::vector<std::vector<point_type> > intruders_type;
+ intruders_type intruders;
+ geometry::extreme_points<Dimension>(geometry, extremes, intruders);
+
+ if (extremes.size() < 3)
+ {
+ return false;
+ }
+
+ // If there are intruders, find the max.
+ if (! intruders.empty())
+ {
+ coordinate_type max_intruder;
+ detail::extreme_points::compare<Dimension> compare;
+ if (max_value<Dimension>(intruders, max_intruder, compare))
+ {
+ coordinate_type max_extreme = geometry::get<Dimension>(*std::max_element(extremes.begin(), extremes.end(), detail::extreme_points::compare<Dimension>()));
+ if (max_extreme > max_intruder)
+ {
+ detail::extreme_points::move_along_vector<Dimension>(extremes, max_intruder);
+ }
+ else
+ {
+ replace_extremes_for_self_tangencies<Dimension>(extremes, intruders, max_intruder);
+ }
+ }
+ }
+
+ // Now calculate the average/centroid of the (possibly adapted) extremes
+ calculate_average(point, extremes);
+
+ return true;
+}
+
+}} // namespace detail::point_on_surface
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\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)
+{
+ concept::check<Point>();
+ concept::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))
+ {
+ // For invalid polygons, we might try X-direction
+ detail::point_on_surface::calculate_point_on_surface<0>(geometry, point);
+ }
+}
+
+/*!
+\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
+\return The Point guaranteed to lie on the surface of the Geometry
+ */
+template<typename Geometry>
+inline typename geometry::point_type<Geometry>::type
+return_point_on_surface(Geometry const& geometry)
+{
+ typename geometry::point_type<Geometry>::type result;
+ geometry::point_on_surface(geometry, result);
+ return result;
+}
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP
diff --git a/boost/geometry/algorithms/remove_spikes.hpp b/boost/geometry/algorithms/remove_spikes.hpp
new file mode 100644
index 0000000000..e62ea9fe3d
--- /dev/null
+++ b/boost/geometry/algorithms/remove_spikes.hpp
@@ -0,0 +1,280 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+
+// 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_REMOVE_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
+
+#include <deque>
+
+#include <boost/range.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/interior_rings.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/point_is_spike_or_equal.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
+
+
+/*
+Remove spikes from a ring/polygon.
+Ring (having 8 vertices, including closing vertex)
++------+
+| |
+| +--+
+| | ^this "spike" is removed, can be located outside/inside the ring
++------+
+(the actualy determination if it is removed is done by a strategy)
+
+*/
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+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)
+ {
+ std::size_t n = boost::size(range);
+ std::size_t const min_num_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Range>::value
+ >::value - 1; // subtract one: a polygon with only one spike should result into one point
+ if (n < min_num_points)
+ {
+ return;
+ }
+
+ std::deque<point_type> cleaned;
+ for (typename boost::range_iterator<Range const>::type it = boost::begin(range);
+ it != boost::end(range); ++it)
+ {
+ // Add point
+ cleaned.push_back(*it);
+
+ while(cleaned.size() >= 3
+ && detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2)))
+ {
+ // Remove pen-ultimate point causing the spike (or which was equal)
+ cleaned.erase(cleaned.end() - 2);
+ }
+ }
+
+ // For a closed-polygon, remove closing point, this makes checking first point(s) easier and consistent
+ if (geometry::closure<Range>::value == geometry::closed)
+ {
+ cleaned.pop_back();
+ }
+
+ bool found = false;
+ do
+ {
+ 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()))
+ {
+ 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()))
+ {
+ cleaned.pop_front();
+ found = true;
+ }
+ }
+ while (found);
+
+ if (cleaned.size() == 2)
+ {
+ // Ticket #9871: open polygon with only two points.
+ // the second point forms, by definition, a spike
+ cleaned.pop_back();
+ }
+
+ // Close if necessary
+ if (geometry::closure<Range>::value == geometry::closed)
+ {
+ cleaned.push_back(cleaned.front());
+ }
+
+ // Copy output
+ geometry::clear(range);
+ std::copy(cleaned.begin(), cleaned.end(), std::back_inserter(range));
+ }
+};
+
+
+template <typename Polygon>
+struct polygon_remove_spikes
+{
+ static inline void apply(Polygon& polygon)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+
+ typedef range_remove_spikes<ring_type> per_range;
+ per_range::apply(exterior_ring(polygon));
+
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(polygon);
+
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ per_range::apply(*it);
+ }
+ }
+};
+
+
+template <typename MultiGeometry, typename SingleVersion>
+struct multi_remove_spikes
+{
+ static inline void apply(MultiGeometry& multi)
+ {
+ for (typename boost::range_iterator<MultiGeometry>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ SingleVersion::apply(*it);
+ }
+ }
+};
+
+
+}} // namespace detail::remove_spikes
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct remove_spikes
+{
+ static inline void apply(Geometry&)
+ {}
+};
+
+
+template <typename Ring>
+struct remove_spikes<Ring, ring_tag>
+ : detail::remove_spikes::range_remove_spikes<Ring>
+{};
+
+
+
+template <typename Polygon>
+struct remove_spikes<Polygon, polygon_tag>
+ : detail::remove_spikes::polygon_remove_spikes<Polygon>
+{};
+
+
+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
+ >
+ >
+{};
+
+
+} // namespace dispatch
+#endif
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct remove_spikes
+{
+ static void apply(Geometry& geometry)
+ {
+ concept::check<Geometry>();
+ dispatch::remove_spikes<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ remove_spikes<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+ \ingroup remove_spikes
+ \tparam Geometry geometry type
+ \param geometry the geometry to make remove_spikes
+*/
+template <typename Geometry>
+inline void remove_spikes(Geometry& geometry)
+{
+ resolve_variant::remove_spikes<Geometry>::apply(geometry);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
diff --git a/boost/geometry/algorithms/reverse.hpp b/boost/geometry/algorithms/reverse.hpp
index bf0ef2d9a9..17b23ffdfb 100644
--- a/boost/geometry/algorithms/reverse.hpp
+++ b/boost/geometry/algorithms/reverse.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,9 +18,15 @@
#include <algorithm>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -32,9 +39,9 @@ namespace detail { namespace reverse
{
-template <typename Range>
struct range_reverse
{
+ template <typename Range>
static inline void apply(Range& range)
{
std::reverse(boost::begin(range), boost::end(range));
@@ -42,21 +49,20 @@ struct range_reverse
};
-template <typename Polygon>
-struct polygon_reverse
+struct polygon_reverse: private range_reverse
{
+ template <typename Polygon>
static inline void apply(Polygon& polygon)
{
- typedef typename geometry::ring_type<Polygon>::type ring_type;
+ range_reverse::apply(exterior_ring(polygon));
- typedef range_reverse<ring_type> per_range;
- per_range::apply(exterior_ring(polygon));
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(polygon);
- typename interior_return_type<Polygon>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_range::apply(*it);
+ range_reverse::apply(*it);
}
}
};
@@ -71,11 +77,7 @@ namespace dispatch
{
-template
-<
- typename Tag,
- typename Geometry
->
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct reverse
{
static inline void apply(Geometry&)
@@ -84,27 +86,82 @@ struct reverse
template <typename Ring>
-struct reverse<ring_tag, Ring>
- : detail::reverse::range_reverse<Ring>
+struct reverse<Ring, ring_tag>
+ : detail::reverse::range_reverse
{};
template <typename LineString>
-struct reverse<linestring_tag, LineString>
- : detail::reverse::range_reverse<LineString>
+struct reverse<LineString, linestring_tag>
+ : detail::reverse::range_reverse
{};
template <typename Polygon>
-struct reverse<polygon_tag, Polygon>
- : detail::reverse::polygon_reverse<Polygon>
+struct reverse<Polygon, polygon_tag>
+ : detail::reverse::polygon_reverse
{};
+template <typename Geometry>
+struct reverse<Geometry, multi_linestring_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::reverse::range_reverse
+ >
+{};
+
+
+template <typename Geometry>
+struct reverse<Geometry, multi_polygon_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::reverse::polygon_reverse
+ >
+{};
+
+
+
} // namespace dispatch
#endif
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct reverse
+{
+ static void apply(Geometry& geometry)
+ {
+ concept::check<Geometry>();
+ dispatch::reverse<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct reverse<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ reverse<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Reverses the points within a geometry
\details Generic function to reverse a geometry. It resembles the std::reverse
@@ -119,13 +176,7 @@ struct reverse<polygon_tag, Polygon>
template <typename Geometry>
inline void reverse(Geometry& geometry)
{
- concept::check<Geometry>();
-
- dispatch::reverse
- <
- typename tag<Geometry>::type,
- Geometry
- >::apply(geometry);
+ resolve_variant::reverse<Geometry>::apply(geometry);
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/simplify.hpp b/boost/geometry/algorithms/simplify.hpp
index 225321d303..101b1324e1 100644
--- a/boost/geometry/algorithms/simplify.hpp
+++ b/boost/geometry/algorithms/simplify.hpp
@@ -14,27 +14,30 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
-
#include <cstddef>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
#include <boost/geometry/strategies/concepts/simplify_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
-#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
namespace boost { namespace geometry
{
@@ -43,12 +46,11 @@ namespace boost { namespace geometry
namespace detail { namespace simplify
{
-template<typename Range, typename Strategy>
struct simplify_range_insert
{
- template <typename OutputIterator, typename Distance>
+ template<typename Range, typename Strategy, typename OutputIterator, typename Distance>
static inline void apply(Range const& range, OutputIterator out,
- Distance const& max_distance, Strategy const& strategy)
+ Distance const& max_distance, Strategy const& strategy)
{
if (boost::size(range) <= 2 || max_distance < 0)
{
@@ -62,12 +64,11 @@ struct simplify_range_insert
};
-template<typename Range, typename Strategy>
struct simplify_copy
{
- template <typename Distance>
+ template <typename Range, typename Strategy, typename Distance>
static inline void apply(Range const& range, Range& out,
- Distance const& , Strategy const& )
+ Distance const& , Strategy const& )
{
std::copy
(
@@ -77,10 +78,10 @@ struct simplify_copy
};
-template<typename Range, typename Strategy, std::size_t Minimum>
+template<std::size_t Minimum>
struct simplify_range
{
- template <typename Distance>
+ template <typename Range, typename Strategy, typename Distance>
static inline void apply(Range const& range, Range& out,
Distance const& max_distance, Strategy const& strategy)
{
@@ -101,14 +102,11 @@ struct simplify_range
if (boost::size(range) <= int(Minimum) || max_distance < 0.0)
{
- simplify_copy<Range, Strategy>::apply
- (
- range, out, max_distance, strategy
- );
+ simplify_copy::apply(range, out, max_distance, strategy);
}
else
{
- simplify_range_insert<Range, Strategy>::apply
+ simplify_range_insert::apply
(
range, std::back_inserter(out), max_distance, strategy
);
@@ -116,16 +114,56 @@ struct simplify_range
}
};
-template<typename Polygon, typename Strategy>
struct simplify_polygon
{
- template <typename Distance>
- static inline void apply(Polygon const& poly_in, Polygon& poly_out,
+private:
+
+ template
+ <
+ std::size_t Minimum,
+ typename IteratorIn,
+ typename IteratorOut,
+ typename Distance,
+ typename Strategy
+ >
+ static inline void iterate(IteratorIn begin, IteratorIn end,
+ IteratorOut it_out,
+ Distance const& max_distance, Strategy const& strategy)
+ {
+ for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out)
+ {
+ simplify_range<Minimum>::apply(*it_in, *it_out, max_distance, strategy);
+ }
+ }
+
+ template
+ <
+ std::size_t Minimum,
+ typename InteriorRingsIn,
+ typename InteriorRingsOut,
+ typename Distance,
+ typename Strategy
+ >
+ static inline void apply_interior_rings(
+ InteriorRingsIn const& interior_rings_in,
+ InteriorRingsOut& interior_rings_out,
Distance const& max_distance, Strategy const& strategy)
{
- typedef typename ring_type<Polygon>::type ring_type;
+ traits::resize<InteriorRingsOut>::apply(interior_rings_out,
+ boost::size(interior_rings_in));
- int const Minimum = core_detail::closure::minimum_ring_size
+ iterate<Minimum>(
+ boost::begin(interior_rings_in), boost::end(interior_rings_in),
+ boost::begin(interior_rings_out),
+ max_distance, strategy);
+ }
+
+public:
+ template <typename Polygon, typename Strategy, typename Distance>
+ static inline void apply(Polygon const& poly_in, Polygon& poly_out,
+ Distance const& max_distance, Strategy const& strategy)
+ {
+ std::size_t const minimum = core_detail::closure::minimum_ring_size
<
geometry::closure<Polygon>::value
>::value;
@@ -133,29 +171,34 @@ struct simplify_polygon
// Note that if there are inner rings, and distance is too large,
// they might intersect with the outer ring in the output,
// while it didn't in the input.
- simplify_range<ring_type, Strategy, Minimum>::apply(exterior_ring(poly_in),
- exterior_ring(poly_out),
- max_distance, strategy);
+ simplify_range<minimum>::apply(exterior_ring(poly_in),
+ exterior_ring(poly_out),
+ max_distance, strategy);
- traits::resize
- <
- typename boost::remove_reference
- <
- typename traits::interior_mutable_type<Polygon>::type
- >::type
- >::apply(interior_rings(poly_out), num_interior_rings(poly_in));
-
- typename interior_return_type<Polygon const>::type rings_in
- = interior_rings(poly_in);
- typename interior_return_type<Polygon>::type rings_out
- = interior_rings(poly_out);
- BOOST_AUTO_TPL(it_out, boost::begin(rings_out));
- for (BOOST_AUTO_TPL(it_in, boost::begin(rings_in));
- it_in != boost::end(rings_in);
- ++it_in, ++it_out)
+ apply_interior_rings<minimum>(interior_rings(poly_in),
+ interior_rings(poly_out),
+ max_distance, strategy);
+ }
+};
+
+
+template<typename Policy>
+struct simplify_multi
+{
+ template <typename MultiGeometry, typename Strategy, typename Distance>
+ static inline void apply(MultiGeometry const& multi, MultiGeometry& out,
+ Distance const& max_distance, Strategy const& strategy)
+ {
+ traits::resize<MultiGeometry>::apply(out, boost::size(multi));
+
+ typename boost::range_iterator<MultiGeometry>::type it_out
+ = boost::begin(out);
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it_in = boost::begin(multi);
+ it_in != boost::end(multi);
+ ++it_in, ++it_out)
{
- simplify_range<ring_type, Strategy, Minimum>::apply(*it_in,
- *it_out, max_distance, strategy);
+ Policy::apply(*it_in, *it_out, max_distance, strategy);
}
}
};
@@ -169,15 +212,18 @@ struct simplify_polygon
namespace dispatch
{
-template <typename Tag, typename Geometry, typename Strategy>
-struct simplify
-{
-};
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct simplify: not_implemented<Tag>
+{};
-template <typename Point, typename Strategy>
-struct simplify<point_tag, Point, Strategy>
+template <typename Point>
+struct simplify<Point, point_tag>
{
- template <typename Distance>
+ template <typename Distance, typename Strategy>
static inline void apply(Point const& point, Point& out,
Distance const& , Strategy const& )
{
@@ -186,22 +232,15 @@ struct simplify<point_tag, Point, Strategy>
};
-template <typename Linestring, typename Strategy>
-struct simplify<linestring_tag, Linestring, Strategy>
- : detail::simplify::simplify_range
- <
- Linestring,
- Strategy,
- 2
- >
+template <typename Linestring>
+struct simplify<Linestring, linestring_tag>
+ : detail::simplify::simplify_range<2>
{};
-template <typename Ring, typename Strategy>
-struct simplify<ring_tag, Ring, Strategy>
+template <typename Ring>
+struct simplify<Ring, ring_tag>
: detail::simplify::simplify_range
<
- Ring,
- Strategy,
core_detail::closure::minimum_ring_size
<
geometry::closure<Ring>::value
@@ -209,38 +248,46 @@ struct simplify<ring_tag, Ring, Strategy>
>
{};
-template <typename Polygon, typename Strategy>
-struct simplify<polygon_tag, Polygon, Strategy>
+template <typename Polygon>
+struct simplify<Polygon, polygon_tag>
: detail::simplify::simplify_polygon
- <
- Polygon,
- Strategy
- >
{};
-template <typename Tag, typename Geometry, typename Strategy>
-struct simplify_insert
-{
-};
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct simplify_insert: not_implemented<Tag>
+{};
-template <typename Linestring, typename Strategy>
-struct simplify_insert<linestring_tag, Linestring, Strategy>
+template <typename Linestring>
+struct simplify_insert<Linestring, linestring_tag>
: detail::simplify::simplify_range_insert
- <
- Linestring,
- Strategy
- >
{};
-template <typename Ring, typename Strategy>
-struct simplify_insert<ring_tag, Ring, Strategy>
+template <typename Ring>
+struct simplify_insert<Ring, ring_tag>
: detail::simplify::simplify_range_insert
- <
- Ring,
- Strategy
- >
+{};
+
+template <typename MultiPoint>
+struct simplify<MultiPoint, multi_point_tag>
+ : detail::simplify::simplify_copy
+{};
+
+
+template <typename MultiLinestring>
+struct simplify<MultiLinestring, multi_linestring_tag>
+ : detail::simplify::simplify_multi<detail::simplify::simplify_range<2> >
+{};
+
+
+template <typename MultiPolygon>
+struct simplify<MultiPolygon, multi_polygon_tag>
+ : detail::simplify::simplify_multi<detail::simplify::simplify_polygon>
{};
@@ -248,6 +295,146 @@ struct simplify_insert<ring_tag, Ring, Strategy>
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy
+{
+
+struct simplify
+{
+ template <typename Geometry, typename Distance, typename Strategy>
+ static inline void apply(Geometry const& geometry,
+ Geometry& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
+ }
+
+ template <typename Geometry, typename Distance>
+ static inline void apply(Geometry const& geometry,
+ Geometry& out,
+ Distance const& max_distance,
+ default_strategy)
+ {
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag, point_type
+ >::type ds_strategy_type;
+
+ typedef strategy::simplify::douglas_peucker
+ <
+ point_type, ds_strategy_type
+ > strategy_type;
+
+ BOOST_CONCEPT_ASSERT(
+ (concept::SimplifyStrategy<strategy_type, point_type>)
+ );
+
+ apply(geometry, out, max_distance, strategy_type());
+ }
+};
+
+struct simplify_insert
+{
+ template
+ <
+ typename Geometry,
+ typename OutputIterator,
+ typename Distance,
+ typename Strategy
+ >
+ static inline void apply(Geometry const& geometry,
+ OutputIterator& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy);
+ }
+
+ template <typename Geometry, typename OutputIterator, typename Distance>
+ static inline void apply(Geometry const& geometry,
+ OutputIterator& out,
+ Distance const& max_distance,
+ default_strategy)
+ {
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename strategy::distance::services::default_strategy
+ <
+ point_tag, segment_tag, point_type
+ >::type ds_strategy_type;
+
+ typedef strategy::simplify::douglas_peucker
+ <
+ point_type, ds_strategy_type
+ > strategy_type;
+
+ BOOST_CONCEPT_ASSERT(
+ (concept::SimplifyStrategy<strategy_type, point_type>)
+ );
+
+ apply(geometry, out, max_distance, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct simplify
+{
+ template <typename Distance, typename Strategy>
+ static inline void apply(Geometry const& geometry,
+ Geometry& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ resolve_strategy::simplify::apply(geometry, out, max_distance, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct simplify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Distance, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ Distance const& m_max_distance;
+ Strategy const& m_strategy;
+
+ visitor(Distance const& max_distance, Strategy const& strategy)
+ : m_max_distance(max_distance)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry, Geometry& out) const
+ {
+ simplify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
+ }
+ };
+
+ template <typename Distance, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
+ Distance const& max_distance,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(
+ visitor<Distance, Strategy>(max_distance, strategy),
+ geometry,
+ out
+ );
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Simplify a geometry using a specified strategy
\ingroup simplify
@@ -271,16 +458,9 @@ inline void simplify(Geometry const& geometry, Geometry& out,
{
concept::check<Geometry>();
- BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) );
-
geometry::clear(out);
- dispatch::simplify
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, out, max_distance, strategy);
+ resolve_variant::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
}
@@ -306,18 +486,7 @@ inline void simplify(Geometry const& geometry, Geometry& out,
{
concept::check<Geometry>();
- typedef typename point_type<Geometry>::type point_type;
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag, point_type
- >::type ds_strategy_type;
-
- typedef strategy::simplify::douglas_peucker
- <
- point_type, ds_strategy_type
- > strategy_type;
-
- simplify(geometry, out, max_distance, strategy_type());
+ simplify(geometry, out, max_distance, default_strategy());
}
@@ -343,17 +512,11 @@ namespace detail { namespace simplify
*/
template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy>
inline void simplify_insert(Geometry const& geometry, OutputIterator out,
- Distance const& max_distance, Strategy const& strategy)
+ Distance const& max_distance, Strategy const& strategy)
{
concept::check<Geometry const>();
- BOOST_CONCEPT_ASSERT( (geometry::concept::SimplifyStrategy<Strategy>) );
- dispatch::simplify_insert
- <
- typename tag<Geometry>::type,
- Geometry,
- Strategy
- >::apply(geometry, out, max_distance, strategy);
+ resolve_strategy::simplify_insert::apply(geometry, out, max_distance, strategy);
}
/*!
@@ -369,30 +532,13 @@ inline void simplify_insert(Geometry const& geometry, OutputIterator out,
*/
template<typename Geometry, typename OutputIterator, typename Distance>
inline void simplify_insert(Geometry const& geometry, OutputIterator out,
- Distance const& max_distance)
+ Distance const& max_distance)
{
- typedef typename point_type<Geometry>::type point_type;
-
// Concept: output point type = point type of input geometry
concept::check<Geometry const>();
- concept::check<point_type>();
+ concept::check<typename point_type<Geometry>::type>();
- typedef typename strategy::distance::services::default_strategy
- <
- segment_tag, point_type
- >::type ds_strategy_type;
-
- typedef strategy::simplify::douglas_peucker
- <
- point_type, ds_strategy_type
- > strategy_type;
-
- dispatch::simplify_insert
- <
- typename tag<Geometry>::type,
- Geometry,
- strategy_type
- >::apply(geometry, out, max_distance, strategy_type());
+ simplify_insert(geometry, out, max_distance, default_strategy());
}
}} // namespace detail::simplify
diff --git a/boost/geometry/algorithms/sym_difference.hpp b/boost/geometry/algorithms/sym_difference.hpp
index 6394576de4..de34c9c7b0 100644
--- a/boost/geometry/algorithms/sym_difference.hpp
+++ b/boost/geometry/algorithms/sym_difference.hpp
@@ -46,11 +46,14 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
@@ -59,36 +62,21 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
out = geometry::dispatch::intersection_insert
<
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
+ GeometryOut,
overlay_difference,
- Strategy
- >::apply(geometry1, geometry2, out, strategy);
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
+ >::apply(geometry1, geometry2, robust_policy, out, strategy);
out = geometry::dispatch::intersection_insert
<
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<GeometryOut>::value,
Geometry2, Geometry1,
+ GeometryOut,
+ overlay_difference,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, true>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- overlay_difference,
- Strategy
- >::apply(geometry2, geometry1, out, strategy);
+ geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
+ >::apply(geometry2, geometry1, robust_policy, out, strategy);
return out;
}
@@ -112,10 +100,12 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out)
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy, OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
@@ -126,10 +116,11 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ RobustPolicy
> strategy_type;
- return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type());
+ return sym_difference_insert<GeometryOut>(geometry1, geometry2, robust_policy, out, strategy_type());
}
}} // namespace detail::sym_difference
@@ -165,8 +156,17 @@ inline void sym_difference(Geometry1 const& geometry1,
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
detail::sym_difference::sym_difference_insert<geometry_out>(
- geometry1, geometry2,
+ geometry1, geometry2, robust_policy,
std::back_inserter(output_collection));
}
diff --git a/boost/geometry/algorithms/touches.hpp b/boost/geometry/algorithms/touches.hpp
index 7d424af428..a06071d428 100644
--- a/boost/geometry/algorithms/touches.hpp
+++ b/boost/geometry/algorithms/touches.hpp
@@ -3,6 +3,10 @@
// 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.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,6 +15,8 @@
// 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_TOUCHES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
@@ -18,70 +24,511 @@
#include <deque>
#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/detail/overlay/get_turns.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/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate.hpp>
namespace boost { namespace geometry
{
-namespace detail { namespace touches
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace touches
{
-template <typename Turn>
-inline bool ok_for_touch(Turn const& turn)
-{
- return turn.both(detail::overlay::operation_union)
- || turn.both(detail::overlay::operation_blocked)
- || turn.combination(detail::overlay::operation_union, detail::overlay::operation_blocked)
- ;
-}
+// Box/Box
-template <typename Turns>
-inline bool has_only_turns(Turns const& turns)
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box_loop
{
- bool has_touch = false;
- typedef typename boost::range_iterator<Turns const>::type iterator_type;
- for (iterator_type it = boost::begin(turns); it != boost::end(turns); ++it)
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
{
- if (it->has(detail::overlay::operation_intersection))
+ 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_ASSERT(min1 <= max1 && min2 <= max2);
+
+ if ( max1 < min2 || max2 < min1 )
{
return false;
}
- switch(it->method)
+ 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>
+ static inline bool apply(Box1 const& b1, Box2 const& b2)
+ {
+ 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>
+struct check_each_ring_for_within
+{
+ bool has_within;
+ Geometry const& m_geometry;
+
+ inline check_each_ring_for_within(Geometry const& g)
+ : has_within(false)
+ , m_geometry(g)
+ {}
+
+ 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) )
{
- case detail::overlay::method_crosses:
- return false;
- case detail::overlay::method_equal:
- // Segment spatially equal means: at the right side
- // the polygon internally overlaps. So return false.
- return false;
- case detail::overlay::method_touch:
- case detail::overlay::method_touch_interior:
- case detail::overlay::method_collinear:
- if (ok_for_touch(*it))
- {
- has_touch = true;
- }
- else
- {
- return false;
- }
- break;
- case detail::overlay::method_none :
- case detail::overlay::method_disjoint :
- case detail::overlay::method_error :
- break;
+ has_within = true;
}
}
- return has_touch;
+};
+
+template <typename FirstGeometry, typename SecondGeometry>
+inline bool rings_containing(FirstGeometry const& geometry1,
+ SecondGeometry const& geometry2)
+{
+ check_each_ring_for_within<FirstGeometry> checker(geometry1);
+ geometry::detail::for_each_range(geometry2, checker);
+ return checker.has_within;
}
+template <typename Geometry1, typename Geometry2>
+struct areal_areal
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ 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, robust_policy, turns, policy);
+
+ return policy.result()
+ && ! geometry::detail::touches::rings_containing(geometry1, geometry2)
+ && ! geometry::detail::touches::rings_containing(geometry2, geometry1);
+ }
+};
+
+// P/*
+
+struct use_point_in_geometry
+{
+ template <typename Point, typename Geometry>
+ static inline bool apply(Point const& point, Geometry const& geometry)
+ {
+ return detail::within::point_in_geometry(point, geometry) == 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>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ return touches<Geometry2, Geometry1>::apply(g2, g1);
+ }
+};
+
+// P/P
+
+template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
+struct touches<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, pointlike_tag, false>
+{
+ static inline bool apply(Geometry1 const& , Geometry2 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_base
+ <
+ detail::relate::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_base
+ <
+ detail::relate::static_mask_touches_type,
+ Linear,
+ Areal
+ >
+{};
+
+// A/L
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, true>
+ : detail::relate::relate_base
+ <
+ detail::relate::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::touches::areal_areal<Areal1, Areal2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct touches
+{
+ static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return dispatch::touches<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+
+ visitor(Geometry2 const& geometry2): m_geometry2(geometry2) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry2), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+
+ visitor(Geometry1 const& geometry1): m_geometry1(geometry1) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(geometry1), 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)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, geometry2);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
+ {
+ return boost::apply_visitor(visitor(), geometry1, geometry2);
+ }
+};
+
+template <typename Geometry>
+struct self_touches
+{
+ static bool apply(Geometry const& geometry)
+ {
+ concept::check<Geometry const>();
+
+ 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;
+ rescale_policy_type robust_policy;
+ detail::self_get_turn_points::get_turns
+ <
+ policy_type
+ >::apply(geometry, 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)}
@@ -99,32 +546,7 @@ inline bool has_only_turns(Turns const& turns)
template <typename Geometry>
inline bool touches(Geometry const& geometry)
{
- concept::check<Geometry const>();
-
- typedef detail::overlay::turn_info
- <
- typename geometry::point_type<Geometry>::type
- > turn_info;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- turn_info,
- detail::overlay::assign_null_policy
- > policy_type;
-
- std::deque<turn_info> turns;
- detail::self_get_turn_points::no_interrupt_policy policy;
- detail::self_get_turn_points::get_turns
- <
- Geometry,
- std::deque<turn_info>,
- policy_type,
- detail::self_get_turn_points::no_interrupt_policy
- >::apply(geometry, turns, policy);
-
- return detail::touches::has_only_turns(turns);
+ return resolve_variant::self_touches<Geometry>::apply(geometry);
}
@@ -143,39 +565,10 @@ inline bool touches(Geometry const& geometry)
template <typename Geometry1, typename Geometry2>
inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
-
-
- typedef detail::overlay::turn_info
- <
- typename geometry::point_type<Geometry1>::type
- > turn_info;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type,
- turn_info,
- detail::overlay::assign_null_policy
- > policy_type;
-
- std::deque<turn_info> turns;
- detail::get_turns::no_interrupt_policy policy;
- boost::geometry::get_turns
- <
- false, false,
- detail::overlay::assign_null_policy
- >(geometry1, geometry2, turns, policy);
-
- return detail::touches::has_only_turns(turns)
- && ! geometry::detail::disjoint::rings_containing(geometry1, geometry2)
- && ! geometry::detail::disjoint::rings_containing(geometry2, geometry1)
- ;
+ return resolve_variant::touches<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
-
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
diff --git a/boost/geometry/algorithms/transform.hpp b/boost/geometry/algorithms/transform.hpp
index 22b45dc77e..1d6e8d0a35 100644
--- a/boost/geometry/algorithms/transform.hpp
+++ b/boost/geometry/algorithms/transform.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,10 +19,14 @@
#include <iterator>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/core/cs.hpp>
@@ -30,7 +35,9 @@
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/ring_type.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/transform.hpp>
@@ -41,9 +48,9 @@ namespace boost { namespace geometry
namespace detail { namespace transform
{
-template <typename Point1, typename Point2, typename Strategy>
struct transform_point
{
+ template <typename Point1, typename Point2, typename Strategy>
static inline bool apply(Point1 const& p1, Point2& p2,
Strategy const& strategy)
{
@@ -52,9 +59,9 @@ struct transform_point
};
-template <typename Box1, typename Box2, typename Strategy>
struct transform_box
{
+ template <typename Box1, typename Box2, typename Strategy>
static inline bool apply(Box1 const& b1, Box2& b2,
Strategy const& strategy)
{
@@ -91,9 +98,9 @@ struct transform_box
}
};
-template <typename Geometry1, typename Geometry2, typename Strategy>
struct transform_box_or_segment
{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& source, Geometry2& target,
Strategy const& strategy)
{
@@ -133,12 +140,7 @@ inline bool transform_range_out(Range const& range,
it != boost::end(range);
++it)
{
- if (! transform_point
- <
- typename point_type<Range>::type,
- PointOut,
- Strategy
- >::apply(*it, point_out, strategy))
+ if (! transform_point::apply(*it, point_out, strategy))
{
return false;
}
@@ -148,14 +150,12 @@ inline bool transform_range_out(Range const& range,
}
-template <typename Polygon1, typename Polygon2, typename Strategy>
struct transform_polygon
{
+ template <typename Polygon1, typename Polygon2, typename Strategy>
static inline bool apply(Polygon1 const& poly1, Polygon2& poly2,
Strategy const& strategy)
{
- typedef typename ring_type<Polygon1>::type ring1_type;
- typedef typename ring_type<Polygon2>::type ring2_type;
typedef typename point_type<Polygon2>::type point2_type;
geometry::clear(poly2);
@@ -175,16 +175,20 @@ struct transform_polygon
>::type
>::apply(interior_rings(poly2), num_interior_rings(poly1));
- typename interior_return_type<Polygon1 const>::type rings1
- = interior_rings(poly1);
- typename interior_return_type<Polygon2>::type rings2
- = interior_rings(poly2);
- BOOST_AUTO_TPL(it1, boost::begin(rings1));
- BOOST_AUTO_TPL(it2, boost::begin(rings2));
- for ( ; it1 != boost::end(interior_rings(poly1)); ++it1, ++it2)
+ typename interior_return_type<Polygon1 const>::type
+ rings1 = interior_rings(poly1);
+ typename interior_return_type<Polygon2>::type
+ rings2 = interior_rings(poly2);
+
+ typename detail::interior_iterator<Polygon1 const>::type
+ it1 = boost::begin(rings1);
+ typename detail::interior_iterator<Polygon2>::type
+ it2 = boost::begin(rings2);
+ for ( ; it1 != boost::end(rings1); ++it1, ++it2)
{
- if (!transform_range_out<point2_type>(*it1,
- std::back_inserter(*it2), strategy))
+ if ( ! transform_range_out<point2_type>(*it1,
+ std::back_inserter(*it2),
+ strategy) )
{
return false;
}
@@ -211,9 +215,9 @@ struct select_strategy
>::type type;
};
-template <typename Range1, typename Range2, typename Strategy>
struct transform_range
{
+ template <typename Range1, typename Range2, typename Strategy>
static inline bool apply(Range1 const& range1,
Range2& range2, Strategy const& strategy)
{
@@ -226,6 +230,36 @@ struct transform_range
}
};
+
+/*!
+ \brief Is able to transform any multi-geometry, calling the single-version as policy
+*/
+template <typename Policy>
+struct transform_multi
+{
+ template <typename Multi1, typename Multi2, typename S>
+ static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy)
+ {
+ traits::resize<Multi2>::apply(multi2, boost::size(multi1));
+
+ typename boost::range_iterator<Multi1 const>::type it1
+ = boost::begin(multi1);
+ typename boost::range_iterator<Multi2>::type it2
+ = boost::begin(multi2);
+
+ for (; it1 != boost::end(multi1); ++it1, ++it2)
+ {
+ if (! Policy::apply(*it1, *it2, strategy))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+
}} // namespace detail::transform
#endif // DOXYGEN_NO_DETAIL
@@ -236,58 +270,166 @@ namespace dispatch
template
<
- typename Tag1, typename Tag2,
typename Geometry1, typename Geometry2,
- typename Strategy
+ typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
+ typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type
>
struct transform {};
-template <typename Point1, typename Point2, typename Strategy>
-struct transform<point_tag, point_tag, Point1, Point2, Strategy>
- : detail::transform::transform_point<Point1, Point2, Strategy>
+template <typename Point1, typename Point2>
+struct transform<Point1, Point2, point_tag, point_tag>
+ : detail::transform::transform_point
{
};
-template <typename Linestring1, typename Linestring2, typename Strategy>
+template <typename Linestring1, typename Linestring2>
struct transform
<
- linestring_tag, linestring_tag,
- Linestring1, Linestring2, Strategy
+ Linestring1, Linestring2,
+ linestring_tag, linestring_tag
>
- : detail::transform::transform_range<Linestring1, Linestring2, Strategy>
+ : detail::transform::transform_range
{
};
-template <typename Range1, typename Range2, typename Strategy>
-struct transform<ring_tag, ring_tag, Range1, Range2, Strategy>
- : detail::transform::transform_range<Range1, Range2, Strategy>
+template <typename Range1, typename Range2>
+struct transform<Range1, Range2, ring_tag, ring_tag>
+ : detail::transform::transform_range
{
};
-template <typename Polygon1, typename Polygon2, typename Strategy>
-struct transform<polygon_tag, polygon_tag, Polygon1, Polygon2, Strategy>
- : detail::transform::transform_polygon<Polygon1, Polygon2, Strategy>
+template <typename Polygon1, typename Polygon2>
+struct transform<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : detail::transform::transform_polygon
{
};
-template <typename Box1, typename Box2, typename Strategy>
-struct transform<box_tag, box_tag, Box1, Box2, Strategy>
- : detail::transform::transform_box<Box1, Box2, Strategy>
+template <typename Box1, typename Box2>
+struct transform<Box1, Box2, box_tag, box_tag>
+ : detail::transform::transform_box
{
};
-template <typename Segment1, typename Segment2, typename Strategy>
-struct transform<segment_tag, segment_tag, Segment1, Segment2, Strategy>
- : detail::transform::transform_box_or_segment<Segment1, Segment2, Strategy>
+template <typename Segment1, typename Segment2>
+struct transform<Segment1, Segment2, segment_tag, segment_tag>
+ : detail::transform::transform_box_or_segment
{
};
+template <typename Multi1, typename Multi2>
+struct transform
+ <
+ Multi1, Multi2,
+ multi_tag, multi_tag
+ >
+ : detail::transform::transform_multi
+ <
+ dispatch::transform
+ <
+ typename boost::range_value<Multi1>::type,
+ typename boost::range_value<Multi2>::type
+ >
+ >
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+struct transform
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2& geometry2,
+ Strategy const& strategy)
+ {
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2>();
+
+ return dispatch::transform<Geometry1, Geometry2>::apply(
+ geometry1,
+ geometry2,
+ strategy
+ );
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2& geometry2,
+ default_strategy)
+ {
+ return apply(
+ geometry1,
+ geometry2,
+ typename detail::transform::select_strategy<Geometry1, Geometry2>::type()
+ );
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct transform
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2& geometry2,
+ Strategy const& strategy)
+ {
+ return resolve_strategy::transform::apply(
+ geometry1,
+ geometry2,
+ strategy
+ );
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct transform<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ inline bool operator()(Geometry1 const& geometry1) const
+ {
+ return transform<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& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief Transforms from one geometry to another geometry \brief_strategy
\ingroup transform
@@ -307,19 +449,8 @@ template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2,
Strategy const& strategy)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2>();
-
- typedef dispatch::transform
- <
- typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
- typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
- Geometry1,
- Geometry2,
- Strategy
- > transform_type;
-
- return transform_type::apply(geometry1, geometry2, strategy);
+ return resolve_variant::transform<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, strategy);
}
@@ -337,11 +468,7 @@ inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2,
template <typename Geometry1, typename Geometry2>
inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2>();
-
- typename detail::transform::select_strategy<Geometry1, Geometry2>::type strategy;
- return transform(geometry1, geometry2, strategy);
+ return transform(geometry1, geometry2, default_strategy());
}
diff --git a/boost/geometry/algorithms/union.hpp b/boost/geometry/algorithms/union.hpp
index 28d8e5dc0b..ff16c60ea1 100644
--- a/boost/geometry/algorithms/union.hpp
+++ b/boost/geometry/algorithms/union.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// 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.
+
+// Contributed and/or modified by Menelaos Karavelas, 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
@@ -10,15 +15,18 @@
#define BOOST_GEOMETRY_ALGORITHMS_UNION_HPP
-#include <boost/mpl/if.hpp>
-
#include <boost/range/metafunctions.hpp>
#include <boost/geometry/core/is_areal.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
namespace boost { namespace geometry
@@ -30,170 +38,146 @@ namespace dispatch
template
<
- // tag dispatching:
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ typename TagIn1 = typename tag<Geometry1>::type,
+ typename TagIn2 = typename tag<Geometry2>::type,
+ typename TagOut = typename tag<GeometryOut>::type,
+ bool Areal1 = geometry::is_areal<Geometry1>::value,
+ bool Areal2 = geometry::is_areal<Geometry2>::value,
+ bool ArealOut = geometry::is_areal<GeometryOut>::value,
+ bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct union_insert: not_implemented<TagIn1, TagIn2, TagOut>
+{};
+
+
+// If reversal is needed, perform it first
+
+template
+<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
typename TagIn1, typename TagIn2, typename TagOut,
- // metafunction finetuning helpers:
bool Areal1, bool Areal2, bool ArealOut,
- // real types
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
- typename GeometryOut,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct union_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ TagIn1, TagIn2, TagOut,
+ Areal1, Areal2, ArealOut,
+ Reverse1, Reverse2, ReverseOut,
+ true
+ >: union_insert<Geometry2, Geometry1, GeometryOut>
{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES
- , (types<Geometry1, Geometry2, GeometryOut>)
- );
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Geometry1 const& g1,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ return union_insert
+ <
+ Geometry2, Geometry1, GeometryOut
+ >::apply(g2, g1, robust_policy, out, strategy);
+ }
};
template
<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
typename TagIn1, typename TagIn2, typename TagOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
- typename GeometryOut,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct union_insert
<
+ Geometry1, Geometry2, GeometryOut,
TagIn1, TagIn2, TagOut,
true, true, true,
- Geometry1, Geometry2,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- Strategy
+ false
> : detail::overlay::overlay
- <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, overlay_union, Strategy>
+ <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, overlay_union>
{};
-
+// dispatch for union of non-areal geometries
template
<
- typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
- bool Areal1, bool Areal2, bool ArealOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- typename Strategy
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ typename TagIn1, typename TagIn2, typename TagOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
-struct union_insert_reversed
-{
- static inline OutputIterator apply(Geometry1 const& g1,
- Geometry2 const& g2, OutputIterator out,
- Strategy const& strategy)
- {
- return union_insert
- <
- GeometryTag2, GeometryTag1, GeometryTag3,
- Areal2, Areal1, ArealOut,
- Geometry2, Geometry1,
- Reverse2, Reverse1, ReverseOut,
- OutputIterator, GeometryOut,
- Strategy
- >::apply(g2, g1, out, strategy);
- }
-};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+struct union_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ TagIn1, TagIn2, TagOut,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ > : union_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
+ typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
+ TagOut,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ >
+{};
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace union_
-{
+// dispatch for union of linear geometries
template
<
- typename GeometryOut,
- typename Geometry1, typename Geometry2,
- typename OutputIterator,
- typename Strategy
+ typename Linear1, typename Linear2, typename LineStringOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
-inline OutputIterator insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- OutputIterator out,
- Strategy const& strategy)
-{
- return boost::mpl::if_c
+struct union_insert
+ <
+ Linear1, Linear2, LineStringOut,
+ linear_tag, linear_tag, linestring_tag,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ > : detail::overlay::linear_linear_linestring
<
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- dispatch::union_insert_reversed
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- Strategy
- >,
- dispatch::union_insert
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- Strategy
- >
- >::type::apply(geometry1, geometry2, out, strategy);
-}
+ Linear1, Linear2, LineStringOut, overlay_union
+ >
+{};
-/*!
-\brief_calc2{union} \brief_strategy
-\ingroup union
-\details \details_calc2{union_insert, spatial set theoretic union}
- \brief_strategy. details_insert{union}
-\tparam GeometryOut output geometry type, must be specified
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam OutputIterator output iterator
-\tparam Strategy \tparam_strategy_overlay
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param out \param_out{union}
-\param strategy \param_strategy{union}
-\return \return_out
-\qbk{distinguish,with strategy}
-*/
+// dispatch for point-like geometries
template
<
- typename GeometryOut,
- typename Geometry1,
- typename Geometry2,
- typename OutputIterator,
- typename Strategy
+ typename PointLike1, typename PointLike2, typename PointOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
-inline OutputIterator union_insert(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- OutputIterator out,
- Strategy const& strategy)
-{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- concept::check<GeometryOut>();
+struct union_insert
+ <
+ PointLike1, PointLike2, PointOut,
+ pointlike_tag, pointlike_tag, point_tag,
+ false, false, false,
+ Reverse1, Reverse2, ReverseOut,
+ false
+ > : detail::overlay::union_pointlike_pointlike_point
+ <
+ PointLike1, PointLike2, PointOut
+ >
+{};
- return detail::union_::insert<GeometryOut>(geometry1, geometry2, out, strategy);
-}
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace union_
+{
/*!
\brief_calc2{union}
@@ -224,15 +208,28 @@ inline OutputIterator union_insert(Geometry1 const& geometry1,
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
+ typedef typename geometry::rescale_overlay_policy_type
+ <
+ Geometry1,
+ Geometry2
+ >::type rescale_policy_type;
+
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ rescale_policy_type
> strategy;
- return union_insert<GeometryOut>(geometry1, geometry2, out, strategy());
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
+ return dispatch::union_insert
+ <
+ Geometry1, Geometry2, GeometryOut
+ >::apply(geometry1, geometry2, robust_policy, out, strategy());
}
diff --git a/boost/geometry/algorithms/unique.hpp b/boost/geometry/algorithms/unique.hpp
index 3bbf479f9b..fed9f8af4b 100644
--- a/boost/geometry/algorithms/unique.hpp
+++ b/boost/geometry/algorithms/unique.hpp
@@ -3,6 +3,7 @@
// 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.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -17,10 +18,12 @@
#include <algorithm>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/policies/compare.hpp>
@@ -34,9 +37,9 @@ namespace detail { namespace unique
{
-template <typename Range, typename ComparePolicy>
struct range_unique
{
+ template <typename Range, typename ComparePolicy>
static inline void apply(Range& range, ComparePolicy const& policy)
{
typename boost::range_iterator<Range>::type it
@@ -52,26 +55,41 @@ struct range_unique
};
-template <typename Polygon, typename ComparePolicy>
struct polygon_unique
{
+ template <typename Polygon, typename ComparePolicy>
static inline void apply(Polygon& polygon, ComparePolicy const& policy)
{
- typedef typename geometry::ring_type<Polygon>::type ring_type;
+ range_unique::apply(exterior_ring(polygon), policy);
- typedef range_unique<ring_type, ComparePolicy> per_range;
- per_range::apply(exterior_ring(polygon), policy);
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(polygon);
- typename interior_return_type<Polygon>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_range::apply(*it, policy);
+ range_unique::apply(*it, policy);
}
}
};
+template <typename Policy>
+struct multi_unique
+{
+ template <typename MultiGeometry, typename ComparePolicy>
+ static inline void apply(MultiGeometry& multi, ComparePolicy const& compare)
+ {
+ for (typename boost::range_iterator<MultiGeometry>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, compare);
+ }
+ }
+};
+
}} // namespace detail::unique
#endif // DOXYGEN_NO_DETAIL
@@ -85,32 +103,50 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename ComparePolicy
+ typename Tag = typename tag<Geometry>::type
>
struct unique
{
+ template <typename ComparePolicy>
static inline void apply(Geometry&, ComparePolicy const& )
{}
};
-template <typename Ring, typename ComparePolicy>
-struct unique<ring_tag, Ring, ComparePolicy>
- : detail::unique::range_unique<Ring, ComparePolicy>
+template <typename Ring>
+struct unique<Ring, ring_tag>
+ : detail::unique::range_unique
+{};
+
+
+template <typename LineString>
+struct unique<LineString, linestring_tag>
+ : detail::unique::range_unique
+{};
+
+
+template <typename Polygon>
+struct unique<Polygon, polygon_tag>
+ : detail::unique::polygon_unique
{};
-template <typename LineString, typename ComparePolicy>
-struct unique<linestring_tag, LineString, ComparePolicy>
- : detail::unique::range_unique<LineString, ComparePolicy>
+// For points, unique is not applicable and does nothing
+// (Note that it is not "spatially unique" but that it removes duplicate coordinates,
+// like std::unique does). Spatially unique is "dissolve" which can (or will be)
+// possible for multi-points as well, removing points at the same location.
+
+
+template <typename MultiLineString>
+struct unique<MultiLineString, multi_linestring_tag>
+ : detail::unique::multi_unique<detail::unique::range_unique>
{};
-template <typename Polygon, typename ComparePolicy>
-struct unique<polygon_tag, Polygon, ComparePolicy>
- : detail::unique::polygon_unique<Polygon, ComparePolicy>
+template <typename MultiPolygon>
+struct unique<MultiPolygon, multi_polygon_tag>
+ : detail::unique::multi_unique<detail::unique::polygon_unique>
{};
@@ -139,12 +175,7 @@ inline void unique(Geometry& geometry)
> policy;
- dispatch::unique
- <
- typename tag<Geometry>::type,
- Geometry,
- policy
- >::apply(geometry, policy());
+ dispatch::unique<Geometry>::apply(geometry, policy());
}
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp
index f1f0993d77..f66b1ed1c6 100644
--- a/boost/geometry/algorithms/within.hpp
+++ b/boost/geometry/algorithms/within.hpp
@@ -4,6 +4,9 @@
// 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.
+// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -11,14 +14,19 @@
// 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_WITHIN_HPP
#define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP
#include <cstddef>
+#include <boost/concept_check.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/make.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
@@ -34,131 +42,47 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/strategies/within.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/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
-{
+namespace detail { namespace within {
-
-template
-<
- typename Point,
- typename Ring,
- iterate_direction Direction,
- closure_selector Closure,
- typename Strategy
->
-struct point_in_ring
+struct use_point_in_geometry
{
- BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) );
-
- static inline int apply(Point const& point, Ring const& ring,
- Strategy const& strategy)
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
- if (int(boost::size(ring))
- < core_detail::closure::minimum_ring_size<Closure>::value)
- {
- return -1;
- }
-
- typedef typename reversible_view<Ring const, Direction>::type rev_view_type;
- typedef typename closeable_view
- <
- rev_view_type const, Closure
- >::type cl_view_type;
- typedef typename boost::range_iterator<cl_view_type const>::type iterator_type;
-
- rev_view_type rev_view(ring);
- cl_view_type view(rev_view);
- typename Strategy::state_type state;
- iterator_type it = boost::begin(view);
- iterator_type end = boost::end(view);
-
- bool stop = false;
- for (iterator_type previous = it++;
- it != end && ! stop;
- ++previous, ++it)
- {
- if (! strategy.apply(point, *previous, *it, state))
- {
- stop = true;
- }
- }
-
- return strategy.result(state);
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1;
}
};
-
-// Polygon: in exterior ring, and if so, not within interior ring(s)
-template
-<
- typename Point,
- typename Polygon,
- iterate_direction Direction,
- closure_selector Closure,
- typename Strategy
->
-struct point_in_polygon
+struct use_relate
{
- BOOST_CONCEPT_ASSERT( (geometry::concept::WithinStrategyPolygonal<Strategy>) );
-
- static inline int apply(Point const& point, Polygon const& poly,
- Strategy const& strategy)
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/)
{
- int const code = point_in_ring
- <
- Point,
- typename ring_type<Polygon>::type,
- Direction,
- Closure,
- Strategy
- >::apply(point, exterior_ring(poly), strategy);
-
- if (code == 1)
- {
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings));
- it != boost::end(rings);
- ++it)
- {
- int const interior_code = point_in_ring
- <
- Point,
- typename ring_type<Polygon>::type,
- Direction,
- Closure,
- Strategy
- >::apply(point, *it, strategy);
-
- if (interior_code != -1)
- {
- // If 0, return 0 (touch)
- // If 1 (inside hole) return -1 (outside polygon)
- // If -1 (outside hole) check other holes if any
- return -interior_code;
- }
- }
- }
- return code;
+ return Strategy::apply(geometry1, geometry2);
}
};
}} // namespace detail::within
#endif // DOXYGEN_NO_DETAIL
-
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -170,7 +94,8 @@ template
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
-struct within: not_implemented<Tag1, Tag2>
+struct within
+ : not_implemented<Tag1, Tag2>
{};
@@ -180,6 +105,7 @@ 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);
}
};
@@ -191,48 +117,349 @@ struct within<Box1, Box2, box_tag, box_tag>
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
{
- template <typename Strategy>
- static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy)
+
+struct within
+{
+ 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_ring
+ concept::within::check
<
- Point,
- Ring,
- order_as_direction<geometry::point_order<Ring>::value>::value,
- geometry::closure<Ring>::value,
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
- >::apply(point, ring, strategy) == 1;
+ >();
+
+ 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 point_type<Geometry1>::type point_type1;
+ typedef typename point_type<Geometry2>::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag<Geometry1>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type1>::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag<point_type2>::type, spherical_tag
+ >::type,
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return apply(geometry1, geometry2, strategy_type());
}
};
-template <typename Point, typename Polygon>
-struct within<Point, Polygon, point_tag, polygon_tag>
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct within
{
template <typename Strategy>
- static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy)
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
{
- return detail::within::point_in_polygon
- <
- Point,
- Polygon,
- order_as_direction<geometry::point_order<Polygon>::value>::value,
- geometry::closure<Polygon>::value,
- Strategy
- >::apply(point, polygon, strategy) == 1;
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return resolve_strategy::within::apply(geometry1,
+ geometry2,
+ strategy);
}
};
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
+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
+ );
+ }
+};
+
+}
/*!
@@ -259,36 +486,11 @@ struct within<Point, Polygon, point_tag, polygon_tag>
template<typename Geometry1, typename Geometry2>
inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- typedef typename point_type<Geometry1>::type point_type1;
- typedef typename point_type<Geometry2>::type point_type2;
-
- typedef typename strategy::within::services::default_strategy
+ return resolve_variant::within
<
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag<Geometry1>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- typename tag_cast
- <
- typename cs_tag<point_type1>::type, spherical_tag
- >::type,
- typename tag_cast
- <
- typename cs_tag<point_type2>::type, spherical_tag
- >::type,
Geometry1,
Geometry2
- >::type strategy_type;
-
- return dispatch::within
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy_type());
+ >::apply(geometry1, geometry2, default_strategy());
}
/*!
@@ -321,18 +523,7 @@ template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
- concept::within::check
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- Strategy
- >();
- concept::check<Geometry1 const>();
- concept::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- return dispatch::within
+ return resolve_variant::within
<
Geometry1,
Geometry2