summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail')
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp221
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp45
-rw-r--r--boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp38
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp10
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp27
-rw-r--r--boost/geometry/algorithms/detail/covered_by/implementation.hpp280
-rw-r--r--boost/geometry/algorithms/detail/covered_by/interface.hpp261
-rw-r--r--boost/geometry/algorithms/detail/direction_code.hpp221
-rw-r--r--boost/geometry/algorithms/detail/disjoint/box_box.hpp13
-rw-r--r--boost/geometry/algorithms/detail/disjoint/implementation.hpp4
-rw-r--r--boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp249
-rw-r--r--boost/geometry/algorithms/detail/disjoint/segment_box.hpp167
-rw-r--r--boost/geometry/algorithms/detail/envelope/segment.hpp125
-rw-r--r--boost/geometry/algorithms/detail/equals/implementation.hpp397
-rw-r--r--boost/geometry/algorithms/detail/equals/interface.hpp317
-rw-r--r--boost/geometry/algorithms/detail/extreme_points.hpp93
-rw-r--r--boost/geometry/algorithms/detail/get_left_turns.hpp40
-rw-r--r--boost/geometry/algorithms/detail/has_self_intersections.hpp2
-rw-r--r--boost/geometry/algorithms/detail/intersects/implementation.hpp88
-rw-r--r--boost/geometry/algorithms/detail/intersects/interface.hpp115
-rw-r--r--boost/geometry/algorithms/detail/is_simple/linear.hpp48
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_spikes.hpp15
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp2
-rw-r--r--boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp13
-rw-r--r--boost/geometry/algorithms/detail/is_valid/linear.hpp36
-rw-r--r--boost/geometry/algorithms/detail/is_valid/multipolygon.hpp75
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp155
-rw-r--r--boost/geometry/algorithms/detail/is_valid/ring.hpp7
-rw-r--r--boost/geometry/algorithms/detail/multi_modify.hpp16
-rw-r--r--boost/geometry/algorithms/detail/occupation_info.hpp19
-rw-r--r--boost/geometry/algorithms/detail/overlaps/implementation.hpp156
-rw-r--r--boost/geometry/algorithms/detail/overlaps/interface.hpp124
-rw-r--r--boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp166
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp136
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp1
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segments.hpp34
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp172
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrichment_info.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp121
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp41
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_relative_order.hpp32
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp14
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp2
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp34
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_colocations.hpp148
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp143
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp46
-rw-r--r--boost/geometry/algorithms/detail/overlay/is_self_turn.hpp68
-rw-r--r--boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp24
-rw-r--r--boost/geometry/algorithms/detail/overlay/linear_linear.hpp10
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp134
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp69
-rw-r--r--boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp178
-rw-r--r--boost/geometry/algorithms/detail/overlay/ring_properties.hpp19
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp114
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp151
-rw-r--r--boost/geometry/algorithms/detail/overlay/sort_by_side.hpp160
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal.hpp434
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp306
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp42
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp408
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp11
-rw-r--r--boost/geometry/algorithms/detail/partition.hpp294
-rw-r--r--boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp76
-rw-r--r--boost/geometry/algorithms/detail/point_on_border.hpp193
-rw-r--r--boost/geometry/algorithms/detail/relate/implementation.hpp11
-rw-r--r--boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp568
-rw-r--r--boost/geometry/algorithms/detail/relate/point_geometry.hpp38
-rw-r--r--boost/geometry/algorithms/detail/relate/point_point.hpp54
-rw-r--r--boost/geometry/algorithms/detail/relate/topology_check.hpp244
-rw-r--r--boost/geometry/algorithms/detail/sections/section_functions.hpp96
-rw-r--r--boost/geometry/algorithms/detail/sections/sectionalize.hpp194
-rw-r--r--boost/geometry/algorithms/detail/touches/implementation.hpp459
-rw-r--r--boost/geometry/algorithms/detail/touches/interface.hpp321
-rw-r--r--boost/geometry/algorithms/detail/within/implementation.hpp306
-rw-r--r--boost/geometry/algorithms/detail/within/interface.hpp304
-rw-r--r--boost/geometry/algorithms/detail/within/multi_point.hpp268
78 files changed, 8522 insertions, 1527 deletions
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
index 029053dda3..a149f1dd46 100644
--- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -122,7 +122,8 @@ struct buffer_range
typename DistanceStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline
void add_join(Collection& collection,
@@ -133,18 +134,19 @@ struct buffer_range
Point const& input,
output_point_type const& perp1,
output_point_type const& perp2,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
- RobustPolicy const& )
+ RobustPolicy const& ,
+ Strategy const& strategy) // side strategy
{
output_point_type intersection_point;
geometry::assign_zero(intersection_point);
- strategy::buffer::join_selector join
- = get_join_type(penultimate_input, previous_input, input);
- if (join == strategy::buffer::join_convex)
+ geometry::strategy::buffer::join_selector join
+ = get_join_type(penultimate_input, previous_input, input, strategy);
+ if (join == geometry::strategy::buffer::join_convex)
{
// Calculate the intersection-point formed by the two sides.
// It might be that the two sides are not convex, but continue
@@ -157,23 +159,23 @@ struct buffer_range
switch(join)
{
- case strategy::buffer::join_continue :
+ case geometry::strategy::buffer::join_continue :
// No join, we get two consecutive sides
break;
- case strategy::buffer::join_concave :
+ case geometry::strategy::buffer::join_concave :
{
std::vector<output_point_type> range_out;
range_out.push_back(prev_perp2);
range_out.push_back(previous_input);
- collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
+ collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
range_out.clear();
range_out.push_back(previous_input);
range_out.push_back(perp1);
- collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
+ collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
}
break;
- case strategy::buffer::join_spike :
+ case geometry::strategy::buffer::join_spike :
{
// For linestrings, only add spike at one side to avoid
// duplicates
@@ -183,7 +185,7 @@ struct buffer_range
collection.set_current_ring_concave();
}
break;
- case strategy::buffer::join_convex :
+ case geometry::strategy::buffer::join_convex :
{
// The corner is convex, we create a join
// TODO (future) - avoid a separate vector, add the piece directly
@@ -193,7 +195,7 @@ struct buffer_range
distance.apply(previous_input, input, side),
range_out))
{
- collection.add_piece(strategy::buffer::buffered_join,
+ collection.add_piece(geometry::strategy::buffer::buffered_join,
previous_input, range_out);
}
}
@@ -201,27 +203,24 @@ struct buffer_range
}
}
- static inline strategy::buffer::join_selector get_join_type(
+ template <typename Strategy>
+ static inline geometry::strategy::buffer::join_selector get_join_type(
output_point_type const& p0,
output_point_type const& p1,
- output_point_type const& p2)
+ output_point_type const& p2,
+ Strategy const& strategy) // side strategy
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<output_point_type>::type
- >::type side_strategy;
-
- int const side = side_strategy::apply(p0, p1, p2);
- return side == -1 ? strategy::buffer::join_convex
- : side == 1 ? strategy::buffer::join_concave
+ int const side = strategy.apply(p0, p1, p2);
+ return side == -1 ? geometry::strategy::buffer::join_convex
+ : side == 1 ? geometry::strategy::buffer::join_concave
: parallel_continue
(
get<0>(p2) - get<0>(p1),
get<1>(p2) - get<1>(p1),
get<0>(p1) - get<0>(p0),
get<1>(p1) - get<1>(p0)
- ) ? strategy::buffer::join_continue
- : strategy::buffer::join_spike;
+ ) ? geometry::strategy::buffer::join_continue
+ : geometry::strategy::buffer::join_spike;
}
template
@@ -232,16 +231,18 @@ struct buffer_range
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code iterate(Collection& collection,
+ static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
+ Strategy const& strategy, // side strategy
output_point_type& first_p1,
output_point_type& first_p2,
output_point_type& last_p1,
@@ -273,7 +274,7 @@ struct buffer_range
* pup: penultimate_point
*/
- strategy::buffer::result_code result = strategy::buffer::result_no_output;
+ geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
bool first = true;
Iterator it = begin;
@@ -284,25 +285,25 @@ struct buffer_range
for (Iterator prev = it++; it != end; ++it)
{
generated_side.clear();
- strategy::buffer::result_code error_code
+ geometry::strategy::buffer::result_code error_code
= side_strategy.apply(*prev, *it, side,
distance_strategy, generated_side);
- if (error_code == strategy::buffer::result_no_output)
+ if (error_code == geometry::strategy::buffer::result_no_output)
{
// Because input is simplified, this is improbable,
// but it can happen for degenerate geometries
// Further handling of this side is skipped
continue;
}
- else if (error_code == strategy::buffer::result_error_numerical)
+ else if (error_code == geometry::strategy::buffer::result_error_numerical)
{
return error_code;
}
BOOST_GEOMETRY_ASSERT(! generated_side.empty());
- result = strategy::buffer::result_normal;
+ result = geometry::strategy::buffer::result_normal;
if (! first)
{
@@ -312,7 +313,7 @@ struct buffer_range
*it, generated_side.front(), generated_side.back(),
side,
distance_strategy, join_strategy, end_strategy,
- robust_policy);
+ robust_policy, strategy);
}
collection.add_side_piece(*prev, *it, generated_side, first);
@@ -350,7 +351,8 @@ struct buffer_multi
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline void apply(Multi const& multi,
Collection& collection,
@@ -359,7 +361,8 @@ struct buffer_multi
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
for (typename boost::range_iterator<Multi const>::type
it = boost::begin(multi);
@@ -369,7 +372,7 @@ struct buffer_multi
Policy::apply(*it, collection,
distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
}
}
};
@@ -396,9 +399,9 @@ inline void buffer_point(Point const& point, Collection& collection,
collection.start_new_ring();
std::vector<OutputPointType> range_out;
point_strategy.apply(point, distance_strategy, range_out);
- collection.add_piece(strategy::buffer::buffered_point, range_out, false);
+ collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
collection.set_piece_center(point);
- collection.finish_ring(strategy::buffer::result_normal);
+ collection.finish_ring(geometry::strategy::buffer::result_normal);
}
@@ -436,7 +439,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline void apply(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
@@ -444,7 +448,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
JoinStrategy const& ,
EndStrategy const& ,
PointStrategy const& point_strategy,
- RobustPolicy const& )
+ RobustPolicy const& ,
+ Strategy const& ) // side strategy
{
detail::buffer::buffer_point
<
@@ -472,29 +477,32 @@ struct buffer_inserter_ring
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code iterate(Collection& collection,
+ static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
output_point_type first_p1, first_p2, last_p1, last_p2;
typedef detail::buffer::buffer_range<RingOutput> buffer_range;
- strategy::buffer::result_code result
+ geometry::strategy::buffer::result_code result
= buffer_range::iterate(collection, begin, end,
side,
- distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ distance_strategy, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1, first_p2, last_p1, last_p2);
// Generate closing join
- if (result == strategy::buffer::result_normal)
+ if (result == geometry::strategy::buffer::result_normal)
{
buffer_range::add_join(collection,
*(end - 2),
@@ -502,7 +510,7 @@ struct buffer_inserter_ring
*(begin + 1), first_p1, first_p2,
side,
distance_strategy, join_strategy, end_strategy,
- robust_policy);
+ robust_policy, strategy);
}
// Buffer is closed automatically by last closing corner
@@ -517,21 +525,23 @@ struct buffer_inserter_ring
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code apply(RingInput const& ring,
+ static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
RingInput simplified;
detail::buffer::simplify_input(ring, distance, simplified);
- strategy::buffer::result_code code = strategy::buffer::result_no_output;
+ geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
std::size_t const min_points = core_detail::closure::minimum_ring_size
@@ -546,18 +556,20 @@ struct buffer_inserter_ring
{
// Walk backwards (rings will be reversed afterwards)
code = iterate(collection, boost::rbegin(view), boost::rend(view),
- strategy::buffer::buffer_side_right,
- distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ geometry::strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy);
}
else
{
code = iterate(collection, boost::begin(view), boost::end(view),
- strategy::buffer::buffer_side_left,
- distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ geometry::strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy);
}
}
- if (code == strategy::buffer::result_no_output && n >= 1)
+ if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated ring
detail::buffer::buffer_point<output_point_type>
@@ -586,23 +598,25 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code apply(RingInput const& ring,
+ static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
collection.start_new_ring();
- strategy::buffer::result_code const code
+ geometry::strategy::buffer::result_code const code
= buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
collection, distance,
side_strategy, join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
collection.finish_ring(code);
return code;
}
@@ -627,16 +641,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code iterate(Collection& collection,
+ static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
+ Strategy const& strategy, // side strategy
output_point_type& first_p1)
{
input_point_type const& ultimate_point = *(end - 1);
@@ -647,18 +663,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
// we have it already from the first phase (left).
// But for the first pass, we have to generate it
output_point_type reverse_p1;
- if (side == strategy::buffer::buffer_side_right)
+ if (side == geometry::strategy::buffer::buffer_side_right)
{
reverse_p1 = first_p1;
}
else
{
std::vector<output_point_type> generated_side;
- strategy::buffer::result_code code
+ geometry::strategy::buffer::result_code code
= side_strategy.apply(ultimate_point, penultimate_point,
- strategy::buffer::buffer_side_right,
+ geometry::strategy::buffer::buffer_side_right,
distance_strategy, generated_side);
- if (code != strategy::buffer::result_normal)
+ if (code != geometry::strategy::buffer::result_normal)
{
// No output or numerical error
return code;
@@ -668,16 +684,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p2, last_p1, last_p2;
- strategy::buffer::result_code result
+ geometry::strategy::buffer::result_code result
= detail::buffer::buffer_range<output_ring_type>::iterate(collection,
begin, end, side,
- distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ distance_strategy, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1, first_p2, last_p1, last_p2);
- if (result == strategy::buffer::result_normal)
+ if (result == geometry::strategy::buffer::result_normal)
{
std::vector<output_point_type> range_out;
- end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
+ end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
+ side, distance_strategy, range_out);
collection.add_endcap(end_strategy, range_out, ultimate_point);
}
return result;
@@ -691,20 +709,23 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection,
+ static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
+ Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
Linestring simplified;
detail::buffer::simplify_input(linestring, distance, simplified);
- strategy::buffer::result_code code = strategy::buffer::result_no_output;
+ geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
if (n > 1)
{
@@ -712,21 +733,23 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p1;
code = iterate(collection,
boost::begin(simplified), boost::end(simplified),
- strategy::buffer::buffer_side_left,
- distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ geometry::strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1);
- if (code == strategy::buffer::result_normal)
+ if (code == geometry::strategy::buffer::result_normal)
{
code = iterate(collection,
boost::rbegin(simplified), boost::rend(simplified),
- strategy::buffer::buffer_side_right,
- distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ geometry::strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1);
}
collection.finish_ring(code);
}
- if (code == strategy::buffer::result_no_output && n >= 1)
+ if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated linestring
detail::buffer::buffer_point<output_point_type>
@@ -763,7 +786,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline
void iterate(Iterator begin, Iterator end,
@@ -774,15 +798,16 @@ private:
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
+ Strategy const& strategy, // side strategy
bool is_interior)
{
for (Iterator it = begin; it != end; ++it)
{
collection.start_new_ring();
- strategy::buffer::result_code const code
+ geometry::strategy::buffer::result_code const code
= policy::apply(*it, collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
collection.finish_ring(code, is_interior);
}
@@ -797,7 +822,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline
void apply_interior_rings(InteriorRings const& interior_rings,
@@ -807,12 +833,13 @@ private:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
iterate(boost::begin(interior_rings), boost::end(interior_rings),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy, true);
+ robust_policy, strategy, true);
}
public:
@@ -824,7 +851,8 @@ public:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline void apply(PolygonInput const& polygon,
Collection& collection,
@@ -833,16 +861,17 @@ public:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
{
collection.start_new_ring();
- strategy::buffer::result_code const code
+ geometry::strategy::buffer::result_code const code
= policy::apply(exterior_ring(polygon), collection,
distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
collection.finish_ring(code, false,
geometry::num_interior_rings(polygon) > 0u);
@@ -851,7 +880,7 @@ public:
apply_interior_rings(interior_rings(polygon),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
}
};
@@ -945,7 +974,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
>::apply(geometry_input, collection,
distance_strategy, side_strategy, join_strategy,
end_strategy, point_strategy,
- robust_policy);
+ robust_policy, intersection_strategy.get_side_strategy());
collection.get_turns();
collection.classify_turns(linear);
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
index 7fbbb790bb..c0d906fe62 100644
--- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -142,10 +142,20 @@ struct buffered_piece_collection
robust_point_type
>::type robust_comparable_radius_type;
- typedef typename strategy::side::services::default_strategy
+ typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
+
+ typedef typename IntersectionStrategy::template area_strategy
+ <
+ point_type
+ >::type area_strategy_type;
+
+ typedef typename IntersectionStrategy::template area_strategy
<
- typename cs_tag<point_type>::type
- >::type side_strategy;
+ robust_point_type
+ >::type robust_area_strategy_type;
+
+ typedef typename area_strategy_type::return_type area_result_type;
+ typedef typename robust_area_strategy_type::return_type robust_area_result_type;
typedef typename geometry::rescale_policy_type
<
@@ -306,7 +316,10 @@ struct buffered_piece_collection
cluster_type m_clusters;
- IntersectionStrategy const& m_intersection_strategy;
+ IntersectionStrategy m_intersection_strategy;
+ side_strategy_type m_side_strategy;
+ area_strategy_type m_area_strategy;
+ robust_area_strategy_type m_robust_area_strategy;
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -321,6 +334,9 @@ struct buffered_piece_collection
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
, m_intersection_strategy(intersection_strategy)
+ , m_side_strategy(intersection_strategy.get_side_strategy())
+ , m_area_strategy(intersection_strategy.template get_area_strategy<point_type>())
+ , m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>())
, m_robust_policy(robust_policy)
{}
@@ -478,7 +494,7 @@ struct buffered_piece_collection
for (typename occupation_map_type::iterator it = occupation_map.begin();
it != occupation_map.end(); ++it)
{
- it->second.get_left_turns(it->first, m_turns);
+ it->second.get_left_turns(it->first, m_turns, m_side_strategy);
}
}
@@ -699,7 +715,7 @@ struct buffered_piece_collection
++it)
{
piece& pc = *it;
- if (geometry::area(pc.robust_ring) < 0)
+ if (geometry::area(pc.robust_ring, m_robust_area_strategy) < 0)
{
// Rings can be ccw:
// - in a concave piece
@@ -1220,14 +1236,9 @@ struct buffered_piece_collection
inline void enrich()
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Ring>::type
- >::type side_strategy_type;
-
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
m_clusters, offsetted_rings, offsetted_rings,
- m_robust_policy, side_strategy_type());
+ m_robust_policy, m_side_strategy);
}
// Discards all rings which do have not-OK intersection points only.
@@ -1314,7 +1325,7 @@ struct buffered_piece_collection
buffered_ring<Ring>& ring = *it;
if (! ring.has_intersections()
&& boost::size(ring) > 0u
- && geometry::area(ring) < 0)
+ && geometry::area(ring, m_area_strategy) < 0)
{
if (! point_coveredby_original(geometry::range::front(ring)))
{
@@ -1391,7 +1402,7 @@ struct buffered_piece_collection
template <typename GeometryOutput, typename OutputIterator>
inline OutputIterator assign(OutputIterator out) const
{
- typedef detail::overlay::ring_properties<point_type> properties;
+ typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
@@ -1407,7 +1418,7 @@ struct buffered_piece_collection
if (! it->has_intersections()
&& ! it->is_untouched_outside_original)
{
- properties p = properties(*it);
+ properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
@@ -1423,7 +1434,7 @@ struct buffered_piece_collection
it != boost::end(traversed_rings);
++it, ++index)
{
- properties p = properties(*it);
+ properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);
@@ -1431,7 +1442,7 @@ struct buffered_piece_collection
}
}
- detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
+ detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, m_intersection_strategy, true);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
}
diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
index 178c7bcafe..5c012e7151 100644
--- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
+++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
@@ -126,26 +127,31 @@ class piece_turn_visitor
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
- signed_size_type& index, int dir, Box const& other_bounding_box)
+ signed_size_type& index, int dir,
+ Box const& this_bounding_box,
+ Box const& other_bounding_box)
{
for(; it_begin != it_beyond
&& it_begin + 1 != it_beyond
&& detail::section::preceding<Dimension>(dir, *(it_begin + 1),
- other_bounding_box, m_robust_policy);
+ this_bounding_box,
+ other_bounding_box,
+ m_robust_policy);
++it_begin, index++)
{}
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
- int dir, Box const& other_bounding_box)
+ int dir, Box const& this_bounding_box,
+ Box const& other_bounding_box)
{
while (it_beyond != it_begin
&& it_beyond - 1 != it_begin
&& it_beyond - 2 != it_begin)
{
if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
- other_bounding_box, m_robust_policy))
+ this_bounding_box, other_bounding_box, m_robust_policy))
{
--it_beyond;
}
@@ -191,23 +197,23 @@ class piece_turn_visitor
// Set begin/end of monotonic ranges, in both x/y directions
signed_size_type index1 = sec1_first_index;
move_begin_iterator<0>(it1_first, it1_beyond, index1,
- section1.directions[0], section2.bounding_box);
+ section1.directions[0], section1.bounding_box, section2.bounding_box);
move_end_iterator<0>(it1_first, it1_beyond,
- section1.directions[0], section2.bounding_box);
+ section1.directions[0], section1.bounding_box, section2.bounding_box);
move_begin_iterator<1>(it1_first, it1_beyond, index1,
- section1.directions[1], section2.bounding_box);
+ section1.directions[1], section1.bounding_box, section2.bounding_box);
move_end_iterator<1>(it1_first, it1_beyond,
- section1.directions[1], section2.bounding_box);
+ section1.directions[1], section1.bounding_box, section2.bounding_box);
signed_size_type index2 = sec2_first_index;
move_begin_iterator<0>(it2_first, it2_beyond, index2,
- section2.directions[0], section1.bounding_box);
+ section2.directions[0], section2.bounding_box, section1.bounding_box);
move_end_iterator<0>(it2_first, it2_beyond,
- section2.directions[0], section1.bounding_box);
+ section2.directions[0], section2.bounding_box, section1.bounding_box);
move_begin_iterator<1>(it2_first, it2_beyond, index2,
- section2.directions[1], section1.bounding_box);
+ section2.directions[1], section2.bounding_box, section1.bounding_box);
move_end_iterator<1>(it2_first, it2_beyond,
- section2.directions[1], section1.bounding_box);
+ section2.directions[1], section2.bounding_box, section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;
@@ -272,7 +278,7 @@ public:
{}
template <typename Section>
- inline void apply(Section const& section1, Section const& section2,
+ inline bool apply(Section const& section1, Section const& section2,
bool first = true)
{
boost::ignore_unused_variable_warning(first);
@@ -285,12 +291,14 @@ public:
|| is_adjacent(piece1, piece2)
|| is_on_same_convex_ring(piece1, piece2)
|| detail::disjoint::disjoint_box_box(section1.bounding_box,
- section2.bounding_box) )
+ section2.bounding_box) )
{
- return;
+ return true;
}
calculate_turns(piece1, piece2, section1, section2);
+
+ return true;
}
};
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
index da1d084d32..e7cc97539f 100644
--- a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
@@ -212,27 +212,27 @@ public:
{}
template <typename Turn, typename Original>
- inline void apply(Turn const& turn, Original const& original, bool first = true)
+ inline bool apply(Turn const& turn, Original const& original, bool first = true)
{
boost::ignore_unused_variable_warning(first);
if (turn.location != location_ok || turn.within_original)
{
// Skip all points already processed
- return;
+ return true;
}
if (geometry::disjoint(turn.robust_point, original.m_box))
{
// Skip all disjoint
- return;
+ return true;
}
int const code = point_in_original(turn.robust_point, original);
if (code == -1)
{
- return;
+ return true;
}
Turn& mutable_turn = m_mutable_turns[turn.turn_index];
@@ -259,6 +259,8 @@ public:
mutable_turn.within_original = true;
mutable_turn.count_in_original = 1;
}
+
+ return true;
}
private :
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
index d7146befb9..d23a3b3fd6 100644
--- a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016 Oracle and/or its affiliates.
@@ -686,32 +687,32 @@ public:
{}
template <typename Turn, typename Piece>
- inline void apply(Turn const& turn, Piece const& piece, bool first = true)
+ inline bool apply(Turn const& turn, Piece const& piece, bool first = true)
{
boost::ignore_unused_variable_warning(first);
if (turn.count_within > 0)
{
// Already inside - no need to check again
- return;
+ return true;
}
if (piece.type == strategy::buffer::buffered_flat_end
|| piece.type == strategy::buffer::buffered_concave)
{
// Turns cannot be located within flat-end or concave pieces
- return;
+ return true;
}
if (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
{
// Easy check: if the turn is not in the envelope, we can safely return
- return;
+ return true;
}
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
{
- return;
+ return true;
}
// TODO: mutable_piece to make some on-demand preparations in analyse
@@ -733,11 +734,11 @@ public:
if (cd < piece.robust_min_comparable_radius)
{
mutable_turn.count_within++;
- return;
+ return true;
}
if (cd > piece.robust_max_comparable_radius)
{
- return;
+ return true;
}
}
@@ -749,20 +750,20 @@ public:
switch(analyse_code)
{
case analyse_disjoint :
- return;
+ return true;
case analyse_on_offsetted :
mutable_turn.count_on_offsetted++; // value is not used anymore
- return;
+ return true;
case analyse_on_original_boundary :
mutable_turn.count_on_original_boundary++;
- return;
+ return true;
case analyse_within :
mutable_turn.count_within++;
- return;
+ return true;
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
case analyse_near_offsetted :
mutable_turn.count_within_near_offsetted++;
- return;
+ return true;
#endif
default :
break;
@@ -790,6 +791,8 @@ public:
{
mutable_turn.count_within++;
}
+
+ return true;
}
};
diff --git a/boost/geometry/algorithms/detail/covered_by/implementation.hpp b/boost/geometry/algorithms/detail/covered_by/implementation.hpp
new file mode 100644
index 0000000000..3df8b7783d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/covered_by/implementation.hpp
@@ -0,0 +1,280 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
+#include <boost/geometry/algorithms/detail/within/implementation.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace covered_by {
+
+struct use_point_in_geometry
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0;
+ }
+};
+
+struct use_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename detail::de9im::static_mask_covered_by_type
+ <
+ Geometry1, Geometry2
+ >::type covered_by_mask;
+ return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy);
+ }
+};
+
+}} // namespace detail::covered_by
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Point, typename Box>
+struct covered_by<Point, Box, point_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
+ {
+ ::boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(point, box);
+ }
+};
+
+template <typename Box1, typename Box2>
+struct covered_by<Box1, Box2, box_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ assert_dimension_equal<Box1, Box2>();
+ ::boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(box1, box2);
+ }
+};
+
+
+// P/P
+
+template <typename Point1, typename Point2>
+struct covered_by<Point1, Point2, point_tag, point_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPoint>
+struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Point>
+struct covered_by<MultiPoint, Point, multi_point_tag, point_tag>
+ : public detail::within::multi_point_point
+{};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct covered_by<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
+ : public detail::within::multi_point_multi_point
+{};
+
+// P/L
+
+template <typename Point, typename Segment>
+struct covered_by<Point, Segment, point_tag, segment_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename Linestring>
+struct covered_by<Point, Linestring, point_tag, linestring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiLinestring>
+struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Segment>
+struct covered_by<MultiPoint, Segment, multi_point_tag, segment_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename Linestring>
+struct covered_by<MultiPoint, Linestring, multi_point_tag, linestring_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename MultiLinestring>
+struct covered_by<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag>
+ : public detail::within::multi_point_multi_geometry<false>
+{};
+
+// P/A
+
+template <typename Point, typename Ring>
+struct covered_by<Point, Ring, point_tag, ring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename Polygon>
+struct covered_by<Point, Polygon, point_tag, polygon_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPolygon>
+struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Ring>
+struct covered_by<MultiPoint, Ring, multi_point_tag, ring_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename Polygon>
+struct covered_by<MultiPoint, Polygon, multi_point_tag, polygon_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename MultiPolygon>
+struct covered_by<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag>
+ : public detail::within::multi_point_multi_geometry<false>
+{};
+
+// L/L
+
+template <typename Linestring1, typename Linestring2>
+struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename MultiLinestring>
+struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Linestring>
+struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring1, typename MultiLinestring2>
+struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+// L/A
+
+template <typename Linestring, typename Ring>
+struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Ring>
+struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename Polygon>
+struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Polygon>
+struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename MultiPolygon>
+struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename MultiPolygon>
+struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+// A/A
+
+template <typename Ring1, typename Ring2>
+struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Ring, typename Polygon>
+struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon, typename Ring>
+struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Ring, typename MultiPolygon>
+struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon, typename Ring>
+struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon, typename MultiPolygon>
+struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon, typename Polygon>
+struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon1, typename MultiPolygon2>
+struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/covered_by/interface.hpp b/boost/geometry/algorithms/detail/covered_by/interface.hpp
new file mode 100644
index 0000000000..6599078210
--- /dev/null
+++ b/boost/geometry/algorithms/detail/covered_by/interface.hpp
@@ -0,0 +1,261 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
+
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/detail/within/interface.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
+#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct covered_by
+ : not_implemented<Tag1, Tag2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy {
+
+struct covered_by
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::within::check
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ Strategy
+ >();
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return covered_by::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct covered_by
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return resolve_strategy::covered_by
+ ::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2), m_strategy(strategy) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1), m_strategy(strategy) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct covered_by<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check12{is inside or on border}
+\ingroup covered_by
+\details \details_check12{covered_by, is inside or on border}.
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be inside or on the border of the second geometry
+\param geometry2 \param_geometry which might cover the first geometry
+\return true if geometry1 is inside of or on the border of geometry2,
+ else false
+\note The default strategy is used for covered_by detection
+
+\qbk{[include reference/algorithms/covered_by.qbk]}
+
+ */
+template<typename Geometry1, typename Geometry2>
+inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, default_strategy());
+}
+
+/*!
+\brief \brief_check12{is inside or on border} \brief_strategy
+\ingroup covered_by
+\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be inside or on the border of the second geometry
+\param geometry2 \param_geometry which might cover the first geometry
+\param strategy strategy to be used
+\return true if geometry1 is inside of or on the border of geometry2,
+ else false
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/covered_by.qbk]}
+
+*/
+template<typename Geometry1, typename Geometry2, typename Strategy>
+inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, strategy);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/direction_code.hpp b/boost/geometry/algorithms/detail/direction_code.hpp
index 26d53ab4e5..c5c5221109 100644
--- a/boost/geometry/algorithms/detail/direction_code.hpp
+++ b/boost/geometry/algorithms/detail/direction_code.hpp
@@ -2,10 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,14 +18,22 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
+
+#include <boost/mpl/assert.hpp>
+
namespace boost { namespace geometry
{
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
+
+// TODO: remove
template <std::size_t Index, typename Point1, typename Point2>
inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
{
@@ -37,35 +46,204 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
}
-// Gives sense of direction for point p, collinear w.r.t. segment (a,b)
-// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
-// Returns 1 if p goes forward, so extends (a,b)
-// Returns 0 if p is equal with b, or if (a,b) is degenerate
-// Note that it does not do any collinearity test, that should be done before
-template <typename Point1, typename Point2>
-inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
- const Point2& p)
+template <typename Point, typename CSTag = typename cs_tag<Point>::type>
+struct direction_code_impl
+{
+ BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
+};
+
+template <typename Point>
+struct direction_code_impl<Point, cartesian_tag>
{
- // Suppose segment = (4 3,4 4) and p =(4 2)
- // Then sign_a1 = 1 and sign_p1 = 1 -> goes backward -> return -1
+ template <typename Point1, typename Point2>
+ static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
+ Point2 const& p)
+ {
+ typedef typename geometry::select_coordinate_type
+ <
+ Point1, Point2
+ >::type calc_t;
+
+ if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a))
+ && math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a)))
+ || (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p))
+ && math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) )
+ {
+ return 0;
+ }
+
+ calc_t x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a);
+ calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a);
+ calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p);
+ calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p);
+
+ calc_t ax = (std::min)(math::abs(x1), math::abs(x2));
+ calc_t ay = (std::min)(math::abs(y1), math::abs(y2));
+
+ int s1 = 0, s2 = 0;
+ if (ax >= ay)
+ {
+ s1 = x1 > 0 ? 1 : -1;
+ s2 = x2 > 0 ? 1 : -1;
+ }
+ else
+ {
+ s1 = y1 > 0 ? 1 : -1;
+ s2 = y2 > 0 ? 1 : -1;
+ }
- int const sign_a0 = sign_of_difference<0>(segment_b, segment_a);
- int const sign_a1 = sign_of_difference<1>(segment_b, segment_a);
+ return s1 == s2 ? -1 : 1;
+ }
+};
- if (sign_a0 == 0 && sign_a1 == 0)
+template <typename Point>
+struct direction_code_impl<Point, spherical_equatorial_tag>
+{
+ template <typename Point1, typename Point2>
+ static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
+ Point2 const& p)
{
- return 0;
+ typedef typename coordinate_type<Point1>::type coord1_t;
+ typedef typename coordinate_type<Point2>::type coord2_t;
+ typedef typename coordinate_system<Point1>::type::units units_t;
+ typedef typename coordinate_system<Point2>::type::units units2_t;
+ BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
+ NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
+ (units_t, units2_t));
+
+ typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
+ typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
+ typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
+ typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
+
+ coord1_t const a0 = geometry::get<0>(segment_a);
+ coord1_t const a1 = geometry::get<1>(segment_a);
+ coord1_t const b0 = geometry::get<0>(segment_b);
+ coord1_t const b1 = geometry::get<1>(segment_b);
+ coord2_t const p0 = geometry::get<0>(p);
+ coord2_t const p1 = geometry::get<1>(p);
+ coord1_t const pi_half1 = constants1::max_latitude();
+ coord2_t const pi_half2 = constants2::max_latitude();
+ calc_t const pi = constants::half_period();
+ calc_t const pi_half = constants::max_latitude();
+ calc_t const c0 = 0;
+
+ if ( (math::equals(b0, a0) && math::equals(b1, a1))
+ || (math::equals(b0, p0) && math::equals(b1, p1)) )
+ {
+ return 0;
+ }
+
+ bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
+ bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
+ bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
+
+ if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
+ || (is_p_pole && math::sign(b1) == math::sign(p1))) )
+ {
+ return 0;
+ }
+
+ // NOTE: as opposed to the implementation for cartesian CS
+ // here point b is the origin
+
+ calc_t const dlon1 = math::longitude_distance_signed<units_t>(b0, a0);
+ calc_t const dlon2 = math::longitude_distance_signed<units_t>(b0, p0);
+
+ bool is_antilon1 = false, is_antilon2 = false;
+ calc_t const dlat1 = latitude_distance_signed(b1, a1, dlon1, pi, is_antilon1);
+ calc_t const dlat2 = latitude_distance_signed(b1, p1, dlon2, pi, is_antilon2);
+
+ calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
+ c0 :
+ (std::min)(is_antilon1 ? c0 : math::abs(dlon1),
+ is_antilon2 ? c0 : math::abs(dlon2));
+ calc_t my = (std::min)(math::abs(dlat1),
+ math::abs(dlat2));
+
+ int s1 = 0, s2 = 0;
+ if (mx >= my)
+ {
+ s1 = dlon1 > 0 ? 1 : -1;
+ s2 = dlon2 > 0 ? 1 : -1;
+ }
+ else
+ {
+ s1 = dlat1 > 0 ? 1 : -1;
+ s2 = dlat2 > 0 ? 1 : -1;
+ }
+
+ return s1 == s2 ? -1 : 1;
}
- int const sign_p0 = sign_of_difference<0>(segment_b, p);
- int const sign_p1 = sign_of_difference<1>(segment_b, p);
+ template <typename T>
+ static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, T const& pi, bool & is_antilon)
+ {
+ T const c0 = 0;
+
+ T res = lat2 - lat1;
+
+ is_antilon = math::equals(math::abs(lon_ds), pi);
+ if (is_antilon)
+ {
+ res = lat2 + lat1;
+ if (res >= c0)
+ res = pi - res;
+ else
+ res = -pi - res;
+ }
- if (sign_p0 == 0 && sign_p1 == 0)
+ return res;
+ }
+};
+
+template <typename Point>
+struct direction_code_impl<Point, spherical_polar_tag>
+{
+ template <typename Point1, typename Point2>
+ static inline int apply(Point1 segment_a, Point1 segment_b,
+ Point2 p)
{
- return 0;
+ typedef math::detail::constants_on_spheroid
+ <
+ typename coordinate_type<Point1>::type,
+ typename coordinate_system<Point1>::type::units
+ > constants1;
+ typedef math::detail::constants_on_spheroid
+ <
+ typename coordinate_type<Point2>::type,
+ typename coordinate_system<Point2>::type::units
+ > constants2;
+
+ geometry::set<1>(segment_a,
+ constants1::max_latitude() - geometry::get<1>(segment_a));
+ geometry::set<1>(segment_b,
+ constants1::max_latitude() - geometry::get<1>(segment_b));
+ geometry::set<1>(p,
+ constants2::max_latitude() - geometry::get<1>(p));
+
+ return direction_code_impl
+ <
+ Point, spherical_equatorial_tag
+ >::apply(segment_a, segment_b, p);
}
+};
+
+template <typename Point>
+struct direction_code_impl<Point, geographic_tag>
+ : direction_code_impl<Point, spherical_equatorial_tag>
+{};
- return sign_a0 == sign_p0 && sign_a1 == sign_p1 ? -1 : 1;
+// Gives sense of direction for point p, collinear w.r.t. segment (a,b)
+// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
+// Returns 1 if p goes forward, so extends (a,b)
+// Returns 0 if p is equal with b, or if (a,b) is degenerate
+// Note that it does not do any collinearity test, that should be done before
+template <typename Point1, typename Point2>
+inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
+ Point2 const& p)
+{
+ return direction_code_impl<Point1>::apply(segment_a, segment_b, p);
}
@@ -73,7 +251,6 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
#endif //DOXYGEN_NO_DETAIL
-
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
index f830f8161c..87618939b8 100644
--- a/boost/geometry/algorithms/detail/disjoint/box_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
@@ -121,9 +121,18 @@ struct box_box<Box1, Box2, 0, DimensionCount, spherical_tag>
// calculate positive longitude translation with b1_min as origin
calc_t const diff_min = math::longitude_distance_unsigned<units_t>(b1_min, b2_min);
calc_t const b2_min_transl = b1_min + diff_min; // always right of b1_min
+ calc_t b2_max_transl = b2_min_transl - constants::period() + diff2;
- if (b2_min_transl > b1_max // b2_min right of b1_max
- && b2_min_transl - constants::period() + diff2 < b1_min) // b2_max left of b1_min
+ // if the translation is too close then use the original point
+ // note that math::abs(b2_max_transl - b2_max) takes values very
+ // close to k*2*constants::period() for k=0,1,2,...
+ if (math::abs(b2_max_transl - b2_max) < constants::period() / 2)
+ {
+ b2_max_transl = b2_max;
+ }
+
+ if (b2_min_transl > b1_max // b2_min right of b1_max
+ && b2_max_transl < b1_min) // b2_max left of b1_min
{
return true;
}
diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
index d482c4a5a9..3a3d9865d1 100644
--- a/boost/geometry/algorithms/detail/disjoint/implementation.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013-2014.
-// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013-2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
index 7c1a93cdb7..f8d3e3c593 100644
--- a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -30,7 +31,9 @@
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/less.hpp>
@@ -117,15 +120,21 @@ private:
}
};
- // TODO: After adding non-cartesian Segment envelope to the library
- // this policy should be modified to take envelope strategy.
+ template <typename EnvelopeStrategy>
struct expand_box_segment
{
+ explicit expand_box_segment(EnvelopeStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
template <typename Box, typename Segment>
- static inline void apply(Box& total, Segment const& segment)
+ inline void apply(Box& total, Segment const& segment) const
{
- geometry::expand(total, geometry::return_envelope<Box>(segment));
+ geometry::expand(total,
+ geometry::return_envelope<Box>(segment, m_strategy));
}
+
+ EnvelopeStrategy const& m_strategy;
};
struct overlaps_box_point
@@ -134,32 +143,24 @@ private:
static inline bool apply(Box const& box, Point const& point)
{
// The default strategy is enough in this case
- typedef typename strategy::disjoint::services::default_strategy
- <
- Point, Box
- >::type strategy_type;
- return ! dispatch::disjoint<Point, Box>::apply(point, box, strategy_type());
+ return ! detail::disjoint::disjoint_point_box(point, box);
}
};
- // TODO: After implementing disjoint Segment/Box for non-cartesian geometries
- // this strategy should be passed here.
- // TODO: This Segment/Box strategy should somehow be derived from Point/Segment strategy
- // which by default is winding containing CS-specific side strategy
- // TODO: disjoint Segment/Box will be called in this case which may take
- // quite long in non-cartesian CS. So we should consider passing range of bounding boxes
- // of segments after calculating them once.
+ template <typename DisjointStrategy>
struct overlaps_box_segment
{
+ explicit overlaps_box_segment(DisjointStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
template <typename Box, typename Segment>
- static inline bool apply(Box const& box, Segment const& segment)
+ inline bool apply(Box const& box, Segment const& segment) const
{
- typedef typename strategy::disjoint::services::default_strategy
- <
- Segment, Box
- >::type strategy_type;
- return ! dispatch::disjoint<Segment, Box>::apply(segment, box, strategy_type());
+ return ! dispatch::disjoint<Segment, Box>::apply(segment, box, m_strategy);
}
+
+ DisjointStrategy const& m_strategy;
};
template <typename PtSegStrategy>
@@ -172,13 +173,15 @@ private:
{}
template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ inline bool apply(Item1 const& item1, Item2 const& item2)
{
if (! m_intersection_found
&& ! dispatch::disjoint<Item1, Item2>::apply(item1, item2, m_strategy))
{
m_intersection_found = true;
+ return false;
}
+ return true;
}
inline bool intersection_found() const { return m_intersection_found; }
@@ -219,12 +222,22 @@ public:
{
item_visitor_type<Strategy> visitor(strategy);
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type;
+
+ // TODO: disjoint Segment/Box may be called in partition multiple times
+ // possibly for non-cartesian segments which could be slow. We should consider
+ // passing a range of bounding boxes of segments after calculating them once.
+ // Alternatively instead of a range of segments a range of Segment/Envelope pairs
+ // should be passed, where envelope would be lazily calculated when needed the first time
geometry::partition
<
geometry::model::box<typename point_type<MultiPoint>::type>
>::apply(multipoint, segment_range(linear), visitor,
- expand_box_point(), overlaps_box_point(),
- expand_box_segment(), overlaps_box_segment());
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()),
+ overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy()));
return ! visitor.intersection_found();
}
@@ -237,6 +250,176 @@ public:
};
+template <typename MultiPoint, typename SingleGeometry>
+class multi_point_single_geometry
+{
+public:
+ template <typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point, SingleGeometry const& single_geometry, Strategy const& strategy)
+ {
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<SingleGeometry>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+
+ box2_type box2;
+ geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
+ geometry::detail::expand_by_epsilon(box2);
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ // The default strategy is enough for Point/Box
+ if (! detail::disjoint::disjoint_point_box(*it, box2)
+ && ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template <typename Strategy>
+ static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point, Strategy const& strategy)
+ {
+ return apply(multi_point, single_geometry, strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename MultiGeometry>
+class multi_point_multi_geometry
+{
+private:
+ struct expand_box_point
+ {
+ template <typename Box, typename Point>
+ static inline void apply(Box& total, Point const& point)
+ {
+ geometry::expand(total, point);
+ }
+ };
+
+ struct expand_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ inline void apply(Box& total, BoxPair const& box_pair) const
+ {
+ geometry::expand(total, box_pair.first);
+ }
+ };
+
+ struct overlaps_box_point
+ {
+ template <typename Box, typename Point>
+ static inline bool apply(Box const& box, Point const& point)
+ {
+ // The default strategy is enough for Point/Box
+ return ! detail::disjoint::disjoint_point_box(point, box);
+ }
+ };
+
+ struct overlaps_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ inline bool apply(Box const& box, BoxPair const& box_pair) const
+ {
+ // The default strategy is enough for Box/Box
+ return ! detail::disjoint::disjoint_box_box(box_pair.first, box);
+ }
+ };
+
+ template <typename PtSegStrategy>
+ class item_visitor_type
+ {
+ public:
+ item_visitor_type(MultiGeometry const& multi_geometry,
+ PtSegStrategy const& strategy)
+ : m_intersection_found(false)
+ , m_multi_geometry(multi_geometry)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Point, typename BoxPair>
+ inline bool apply(Point const& point, BoxPair const& box_pair)
+ {
+ typedef typename boost::range_value<MultiGeometry>::type single_type;
+
+ // The default strategy is enough for Point/Box
+ if (! m_intersection_found
+ && ! detail::disjoint::disjoint_point_box(point, box_pair.first)
+ && ! dispatch::disjoint<Point, single_type>::apply(point, range::at(m_multi_geometry, box_pair.second), m_strategy))
+ {
+ m_intersection_found = true;
+ return false;
+ }
+ return true;
+ }
+
+ inline bool intersection_found() const { return m_intersection_found; }
+
+ private:
+ bool m_intersection_found;
+ MultiGeometry const& m_multi_geometry;
+ PtSegStrategy const& m_strategy;
+ };
+ // structs for partition -- end
+
+public:
+ template <typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Strategy const& strategy)
+ {
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point1_type> box1_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+
+ typename Strategy::envelope_strategy_type const
+ envelope_strategy = strategy.get_envelope_strategy();
+
+ std::size_t count2 = boost::size(multi_geometry);
+ std::vector<box_pair_type> boxes(count2);
+ for (std::size_t i = 0 ; i < count2 ; ++i)
+ {
+ geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
+ geometry::detail::expand_by_epsilon(boxes[i].first);
+ boxes[i].second = i;
+ }
+
+ item_visitor_type<Strategy> visitor(multi_geometry, strategy);
+
+ geometry::partition
+ <
+ box1_type
+ >::apply(multi_point, boxes, visitor,
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_box_pair(),
+ overlaps_box_box_pair());
+
+ return ! visitor.intersection_found();
+ }
+
+ template <typename Strategy>
+ static inline bool apply(MultiGeometry const& multi_geometry, MultiPoint const& multi_point, Strategy const& strategy)
+ {
+ return apply(multi_point, multi_geometry, strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename Areal, typename Tag = typename tag<Areal>::type>
+struct multipoint_areal
+ : multi_point_single_geometry<MultiPoint, Areal>
+{};
+
+template <typename MultiPoint, typename Areal>
+struct multipoint_areal<MultiPoint, Areal, multi_polygon_tag>
+ : multi_point_multi_geometry<MultiPoint, Areal>
+{};
+
+
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
@@ -321,6 +504,22 @@ struct disjoint
{};
+template <typename Areal, typename MultiPoint, std::size_t DimensionCount>
+struct disjoint
+ <
+ Areal, MultiPoint, DimensionCount, areal_tag, multi_point_tag, false
+ > : detail::disjoint::multipoint_areal<MultiPoint, Areal>
+{};
+
+
+template <typename MultiPoint, typename Areal, std::size_t DimensionCount>
+struct disjoint
+ <
+ MultiPoint, Areal, DimensionCount, multi_point_tag, areal_tag, false
+ > : detail::disjoint::multipoint_areal<MultiPoint, Areal>
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
index c2741ce72c..fe849e1091 100644
--- a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
@@ -8,8 +8,9 @@
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -24,9 +25,18 @@
#include <cstddef>
#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
+#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+#include <boost/geometry/formulas/vertex_longitude.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
namespace boost { namespace geometry
{
@@ -36,10 +46,161 @@ namespace boost { namespace geometry
namespace detail { namespace disjoint
{
+template <typename CS_Tag>
+struct disjoint_segment_box_sphere_or_spheroid
+{
+private:
+
+ template <typename CT>
+ static inline void swap(CT& lon1,
+ CT& lat1,
+ CT& lon2,
+ CT& lat2)
+ {
+ std::swap(lon1, lon2);
+ std::swap(lat1, lat2);
+ }
+
+
+public:
+
+ template <typename Segment, typename Box, typename Strategy>
+ static inline bool apply(Segment const& segment,
+ Box const& box,
+ Strategy const& azimuth_strategy)
+ {
+ assert_dimension_equal<Segment, Box>();
+
+ typedef typename point_type<Segment>::type segment_point_type;
+ typedef typename cs_tag<Segment>::type segment_cs_type;
+
+ segment_point_type p0, p1;
+ geometry::detail::assign_point_from_index<0>(segment, p0);
+ geometry::detail::assign_point_from_index<1>(segment, p1);
+
+ // Simplest cases first
+
+ // Case 1: if box contains one of segment's endpoints then they are not disjoint
+ if (! disjoint_point_box(p0, box) || ! disjoint_point_box(p1, box))
+ {
+ return false;
+ }
+
+ // Case 2: disjoint if bounding boxes are disjoint
+
+ typedef typename coordinate_type<segment_point_type>::type CT;
+
+ segment_point_type p0_normalized =
+ geometry::detail::return_normalized<segment_point_type>(p0);
+ segment_point_type p1_normalized =
+ geometry::detail::return_normalized<segment_point_type>(p1);
+
+ CT lon1 = geometry::get_as_radian<0>(p0_normalized);
+ CT lat1 = geometry::get_as_radian<1>(p0_normalized);
+ CT lon2 = geometry::get_as_radian<0>(p1_normalized);
+ CT lat2 = geometry::get_as_radian<1>(p1_normalized);
+
+ if (lon1 > lon2)
+ {
+ swap(lon1, lat1, lon2, lat2);
+ }
+
+ //Compute alp1 outside envelope and pass it to envelope_segment_impl
+ //in order for it to be used later in the algorithm
+ CT alp1;
+
+ azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1);
+
+ geometry::model::box<segment_point_type> box_seg;
+
+ geometry::detail::envelope::envelope_segment_impl<segment_cs_type>
+ ::template apply<geometry::radian>(lon1, lat1,
+ lon2, lat2,
+ box_seg,
+ azimuth_strategy,
+ alp1);
+ if (disjoint_box_box(box, box_seg))
+ {
+ return true;
+ }
+
+ // Case 3: test intersection by comparing angles
+
+ CT a_b0, a_b1, a_b2, a_b3;
+
+ CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box);
+ CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box);
+ CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box);
+ CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box);
+
+ azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0);
+ azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1);
+ azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2);
+ azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3);
+
+ bool b0 = alp1 > a_b0;
+ bool b1 = alp1 > a_b1;
+ bool b2 = alp1 > a_b2;
+ bool b3 = alp1 > a_b3;
+
+ // if not all box points on the same side of the segment then
+ // there is an intersection
+ if (!(b0 && b1 && b2 && b3) && (b0 || b1 || b2 || b3))
+ {
+ return false;
+ }
+
+ // Case 4: The only intersection case not covered above is when all four
+ // points of the box are above (below) the segment in northern (southern)
+ // hemisphere. Then we have to compute the vertex of the segment
+
+ CT vertex_lat;
+ CT lat_sum = lat1 + lat2;
+
+ if ((b0 && b1 && b2 && b3 && lat_sum > CT(0))
+ || (!(b0 && b1 && b2 && b3) && lat_sum < CT(0)))
+ {
+ CT b_lat_below; //latitude of box closest to equator
+
+ if (lat_sum > CT(0))
+ {
+ vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
+ b_lat_below = b_lat_min;
+ } else {
+ vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg);
+ b_lat_below = b_lat_max;
+ }
+
+ //optimization TODO: computing the spherical longitude should suffice for
+ // the majority of cases
+ CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag>
+ ::apply(lon1, lat1,
+ lon2, lat2,
+ vertex_lat,
+ alp1,
+ azimuth_strategy);
+
+ // Check if the vertex point is within the band defined by the
+ // minimum and maximum longitude of the box; if yes, then return
+ // false if the point is above the min latitude of the box; return
+ // true in all other cases
+ if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max
+ && std::abs(vertex_lat) > std::abs(b_lat_below))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
struct disjoint_segment_box
{
template <typename Segment, typename Box, typename Strategy>
- static inline bool apply(Segment const& segment, Box const& box, Strategy const& strategy)
+ static inline bool apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy)
{
return strategy.apply(segment, box);
}
@@ -56,7 +217,7 @@ namespace dispatch
template <typename Segment, typename Box, std::size_t DimensionCount>
struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
- : detail::disjoint::disjoint_segment_box
+ : detail::disjoint::disjoint_segment_box
{};
diff --git a/boost/geometry/algorithms/detail/envelope/segment.hpp b/boost/geometry/algorithms/detail/envelope/segment.hpp
index 7631e84883..7e37194968 100644
--- a/boost/geometry/algorithms/detail/envelope/segment.hpp
+++ b/boost/geometry/algorithms/detail/envelope/segment.hpp
@@ -130,19 +130,16 @@ private:
CalculationType& lat1,
CalculationType& lon2,
CalculationType& lat2,
+ CalculationType a1,
+ CalculationType a2,
Strategy const& strategy)
{
// coordinates are assumed to be in radians
BOOST_GEOMETRY_ASSERT(lon1 <= lon2);
- CalculationType lon1_rad = math::as_radian<Units>(lon1);
CalculationType lat1_rad = math::as_radian<Units>(lat1);
- CalculationType lon2_rad = math::as_radian<Units>(lon2);
CalculationType lat2_rad = math::as_radian<Units>(lat2);
- CalculationType a1, a2;
- strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2);
-
if (lat1 > lat2)
{
std::swap(lat1, lat2);
@@ -189,12 +186,11 @@ private:
}
}
- template <typename Units, typename CalculationType, typename Strategy>
- static inline void apply(CalculationType& lon1,
- CalculationType& lat1,
- CalculationType& lon2,
- CalculationType& lat2,
- Strategy const& strategy)
+ template <typename Units, typename CalculationType>
+ static inline void special_cases(CalculationType& lon1,
+ CalculationType& lat1,
+ CalculationType& lon2,
+ CalculationType& lat2)
{
typedef math::detail::constants_on_spheroid
<
@@ -249,23 +245,19 @@ private:
lon1 += constants::period();
swap(lon1, lat1, lon2, lat2);
}
-
- compute_box_corners<Units>(lon1, lat1, lon2, lat2, strategy);
}
-public:
- template <
- typename Units,
- typename CalculationType,
- typename Box,
- typename Strategy
- >
- static inline void apply(CalculationType lon1,
- CalculationType lat1,
- CalculationType lon2,
- CalculationType lat2,
- Box& mbr,
- Strategy const& strategy)
+ template
+ <
+ typename Units,
+ typename CalculationType,
+ typename Box
+ >
+ static inline void create_box(CalculationType lon1,
+ CalculationType lat1,
+ CalculationType lon2,
+ CalculationType lat2,
+ Box& mbr)
{
typedef typename coordinate_type<Box>::type box_coordinate_type;
@@ -276,8 +268,6 @@ public:
helper_box_type radian_mbr;
- apply<Units>(lon1, lat1, lon2, lat2, strategy);
-
geometry::set
<
min_corner, 0
@@ -300,6 +290,85 @@ public:
transform_units(radian_mbr, mbr);
}
+
+
+ template <typename Units, typename CalculationType, typename Strategy>
+ static inline void apply(CalculationType& lon1,
+ CalculationType& lat1,
+ CalculationType& lon2,
+ CalculationType& lat2,
+ Strategy const& strategy)
+ {
+ special_cases<Units>(lon1, lat1, lon2, lat2);
+
+ CalculationType lon1_rad = math::as_radian<Units>(lon1);
+ CalculationType lat1_rad = math::as_radian<Units>(lat1);
+ CalculationType lon2_rad = math::as_radian<Units>(lon2);
+ CalculationType lat2_rad = math::as_radian<Units>(lat2);
+ CalculationType alp1, alp2;
+ strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, alp1, alp2);
+
+ compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy);
+ }
+
+ template <typename Units, typename CalculationType, typename Strategy>
+ static inline void apply(CalculationType& lon1,
+ CalculationType& lat1,
+ CalculationType& lon2,
+ CalculationType& lat2,
+ Strategy const& strategy,
+ CalculationType alp1)
+ {
+ special_cases<Units>(lon1, lat1, lon2, lat2);
+
+ CalculationType lon1_rad = math::as_radian<Units>(lon1);
+ CalculationType lat1_rad = math::as_radian<Units>(lat1);
+ CalculationType lon2_rad = math::as_radian<Units>(lon2);
+ CalculationType lat2_rad = math::as_radian<Units>(lat2);
+ CalculationType alp2;
+ strategy.apply(lon2_rad, lat2_rad, lon1_rad, lat1_rad, alp2);
+ alp2 += math::pi<CalculationType>();
+
+ compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy);
+ }
+
+public:
+ template
+ <
+ typename Units,
+ typename CalculationType,
+ typename Box,
+ typename Strategy
+ >
+ static inline void apply(CalculationType lon1,
+ CalculationType lat1,
+ CalculationType lon2,
+ CalculationType lat2,
+ Box& mbr,
+ Strategy const& strategy)
+ {
+ apply<Units>(lon1, lat1, lon2, lat2, strategy);
+ create_box<Units>(lon1, lat1, lon2, lat2, mbr);
+ }
+
+ template
+ <
+ typename Units,
+ typename CalculationType,
+ typename Box,
+ typename Strategy
+ >
+ static inline void apply(CalculationType lon1,
+ CalculationType lat1,
+ CalculationType lon2,
+ CalculationType lat2,
+ Box& mbr,
+ Strategy const& strategy,
+ CalculationType alp1)
+ {
+ apply<Units>(lon1, lat1, lon2, lat2, strategy, alp1);
+ create_box<Units>(lon1, lat1, lon2, lat2, mbr);
+ }
};
template <std::size_t Dimension, std::size_t DimensionCount>
diff --git a/boost/geometry/algorithms/detail/equals/implementation.hpp b/boost/geometry/algorithms/detail/equals/implementation.hpp
new file mode 100644
index 0000000000..310059a427
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/implementation.hpp
@@ -0,0 +1,397 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014, 2015, 2016, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+#include <vector>
+
+#include <boost/range.hpp>
+#include <boost/type_traits/is_base_of.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+// For trivial checks
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/length.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
+#include <boost/geometry/algorithms/detail/equals/interface.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
+#include <boost/geometry/algorithms/relate.hpp>
+
+#include <boost/geometry/views/detail/indexed_point_view.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace equals
+{
+
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct point_point
+{
+ template <typename Point1, typename Point2, typename Strategy>
+ static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
+ {
+ return ! detail::disjoint::point_point
+ <
+ Point1, Point2,
+ Dimension, DimensionCount
+ >::apply(point1, point2, strategy);
+ }
+};
+
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
+ || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
+ {
+ return false;
+ }
+ return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy);
+ }
+};
+
+template <std::size_t DimensionCount>
+struct box_box<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& , Box2 const& , Strategy const& )
+ {
+ return true;
+ }
+};
+
+
+struct segment_segment
+{
+ template <typename Segment1, typename Segment2, typename Strategy>
+ static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& )
+ {
+ return equals::equals_point_point(
+ indexed_point_view<Segment1 const, 0>(segment1),
+ indexed_point_view<Segment2 const, 0>(segment2) )
+ ? equals::equals_point_point(
+ indexed_point_view<Segment1 const, 1>(segment1),
+ indexed_point_view<Segment2 const, 1>(segment2) )
+ : ( equals::equals_point_point(
+ indexed_point_view<Segment1 const, 0>(segment1),
+ indexed_point_view<Segment2 const, 1>(segment2) )
+ && equals::equals_point_point(
+ indexed_point_view<Segment1 const, 1>(segment1),
+ indexed_point_view<Segment2 const, 0>(segment2) )
+ );
+ }
+};
+
+
+struct area_check
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return geometry::math::equals(
+ geometry::area(geometry1,
+ strategy.template get_area_strategy<Geometry1>()),
+ geometry::area(geometry2,
+ strategy.template get_area_strategy<Geometry2>()));
+ }
+};
+
+
+struct length_check
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return geometry::math::equals(
+ geometry::length(geometry1,
+ strategy.template get_distance_strategy<Geometry1>()),
+ geometry::length(geometry2,
+ strategy.template get_distance_strategy<Geometry2>()));
+ }
+};
+
+
+template <typename Geometry1, typename Geometry2, typename IntersectionStrategy>
+struct collected_vector
+{
+ typedef typename geometry::select_most_precise
+ <
+ typename select_coordinate_type
+ <
+ Geometry1, Geometry2
+ >::type,
+ double
+ >::type calculation_type;
+
+ typedef geometry::collected_vector
+ <
+ calculation_type,
+ Geometry1,
+ typename IntersectionStrategy::side_strategy_type
+ > type;
+};
+
+template <typename TrivialCheck>
+struct equals_by_collection
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ if (! TrivialCheck::apply(geometry1, geometry2, strategy))
+ {
+ return false;
+ }
+
+ typedef typename collected_vector
+ <
+ Geometry1, Geometry2, Strategy
+ >::type collected_vector_type;
+
+ std::vector<collected_vector_type> c1, c2;
+
+ geometry::collect_vectors(c1, geometry1);
+ geometry::collect_vectors(c2, geometry2);
+
+ if (boost::size(c1) != boost::size(c2))
+ {
+ return false;
+ }
+
+ std::sort(c1.begin(), c1.end());
+ std::sort(c2.begin(), c2.end());
+
+ // Just check if these vectors are equal.
+ return std::equal(c1.begin(), c1.end(), c2.begin());
+ }
+};
+
+template<typename Geometry1, typename Geometry2>
+struct equals_by_relate
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_equals_type,
+ Geometry1,
+ Geometry2
+ >
+{};
+
+// If collect_vectors which is a SideStrategy-dispatched optimization
+// is implemented in a way consistent with the Intersection/Side Strategy
+// then collect_vectors is used, otherwise relate is used.
+// NOTE: the result could be conceptually different for invalid
+// geometries in different coordinate systems because collect_vectors
+// and relate treat invalid geometries differently.
+template<typename TrivialCheck>
+struct equals_by_collection_or_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ typedef typename boost::is_base_of
+ <
+ nyi::not_implemented_tag,
+ typename collected_vector
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ >::type enable_relate_type;
+
+ return apply(geometry1, geometry2, strategy, enable_relate_type());
+ }
+
+private:
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy,
+ boost::false_type /*enable_relate*/)
+ {
+ return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy,
+ boost::true_type /*enable_relate*/)
+ {
+ return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+};
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
+struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
+ : detail::equals::point_point<0, DimensionCount>
+{};
+
+template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse>
+struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, DimensionCount, Reverse>
+ : detail::equals::equals_by_relate<MultiPoint1, MultiPoint2>
+{};
+
+template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
+struct equals<Point, MultiPoint, point_tag, multi_point_tag, DimensionCount, Reverse>
+ : detail::equals::equals_by_relate<Point, MultiPoint>
+{};
+
+template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
+struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
+ : detail::equals::box_box<0, DimensionCount>
+{};
+
+
+template <typename Ring1, typename Ring2, bool Reverse>
+struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Polygon1, typename Polygon2, bool Reverse>
+struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse>
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename Ring, bool Reverse>
+struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Ring, typename Box, bool Reverse>
+struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename Box, bool Reverse>
+struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
+{};
+
+template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse>
+struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reverse>
+ : detail::equals::segment_segment
+{};
+
+template <typename LineString1, typename LineString2, bool Reverse>
+struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<LineString1, LineString2>
+{};
+
+template <typename LineString, typename MultiLineString, bool Reverse>
+struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<LineString, MultiLineString>
+{};
+
+template <typename MultiLineString1, typename MultiLineString2, bool Reverse>
+struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2>
+{};
+
+
+template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse>
+struct equals
+ <
+ MultiPolygon1, MultiPolygon2,
+ multi_polygon_tag, multi_polygon_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename MultiPolygon, bool Reverse>
+struct equals
+ <
+ Polygon, MultiPolygon,
+ polygon_tag, multi_polygon_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+template <typename MultiPolygon, typename Ring, bool Reverse>
+struct equals
+ <
+ MultiPolygon, Ring,
+ multi_polygon_tag, ring_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
+
diff --git a/boost/geometry/algorithms/detail/equals/interface.hpp b/boost/geometry/algorithms/detail/equals/interface.hpp
new file mode 100644
index 0000000000..eacf95e9fe
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/interface.hpp
@@ -0,0 +1,317 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014, 2015, 2016, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP
+
+
+#include <cstddef>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type,
+ std::size_t DimensionCount = dimension<Geometry1>::type::value,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct equals: not_implemented<Tag1, Tag2>
+{};
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2,
+ std::size_t DimensionCount
+>
+struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true>
+ : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
+ {
+ return equals
+ <
+ Geometry2, Geometry1,
+ Tag2, Tag1,
+ DimensionCount,
+ false
+ >::apply(g2, g1, strategy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct equals
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return dispatch::equals
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return dispatch::equals
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct equals
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::check_concepts_and_equal_dimensions
+ <
+ Geometry1 const,
+ Geometry2 const
+ >();
+
+ return resolve_strategy::equals
+ ::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ inline bool operator()(Geometry1 const& geometry1) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2, m_strategy);
+ }
+
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ inline bool operator()(Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2, m_strategy);
+ }
+
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct equals<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ inline bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, m_strategy);
+ }
+
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check{are spatially equal}
+\details \details_check12{equals, is spatially equal}. Spatially equal means
+ that the same point set is included. A box can therefore be spatially equal
+ to a ring or a polygon, or a linestring can be spatially equal to a
+ multi-linestring or a segment. This only works theoretically, not all
+ combinations are implemented yet.
+\ingroup equals
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Equals}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{equals}
+\return \return_check2{are spatially equal}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/equals.qbk]}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool equals(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::equals
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+/*!
+\brief \brief_check{are spatially equal}
+\details \details_check12{equals, is spatially equal}. Spatially equal means
+ that the same point set is included. A box can therefore be spatially equal
+ to a ring or a polygon, or a linestring can be spatially equal to a
+ multi-linestring or a segment. This only works theoretically, not all
+ combinations are implemented yet.
+\ingroup equals
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{are spatially equal}
+
+\qbk{[include reference/algorithms/equals.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, default_strategy());
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP
+
diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp
index 65795cd05b..61e984ee3c 100644
--- a/boost/geometry/algorithms/detail/extreme_points.hpp
+++ b/boost/geometry/algorithms/detail/extreme_points.hpp
@@ -5,6 +5,11 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -117,12 +122,6 @@ struct extreme_points_on_ring
typedef typename boost::range_iterator<Ring const>::type range_iterator;
typedef typename geometry::point_type<Ring>::type point_type;
- typedef typename geometry::strategy::side::services::default_strategy
- <
- typename geometry::cs_tag<point_type>::type
- >::type side_strategy;
-
-
template <typename CirclingIterator, typename Points>
static inline bool extend(CirclingIterator& it,
std::size_t n,
@@ -214,10 +213,11 @@ struct extreme_points_on_ring
return true;
}
- template <typename Extremes, typename Intruders, typename CirclingIterator>
+ template <typename Extremes, typename Intruders, typename CirclingIterator, typename SideStrategy>
static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
Extremes const& extremes,
- Intruders& intruders)
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
if (boost::size(extremes) < 3)
{
@@ -238,8 +238,8 @@ struct extreme_points_on_ring
if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
{
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
- int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
- int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
+ int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
+ int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
// If not lying left from any of the extemes side
if (first_side != 1 && last_side != 1)
@@ -263,10 +263,11 @@ struct extreme_points_on_ring
}
}
- template <typename Extremes, typename Intruders>
+ template <typename Extremes, typename Intruders, typename SideStrategy>
static inline void get_intruders(Ring const& ring,
Extremes const& extremes,
- Intruders& intruders)
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n >= 3)
@@ -275,12 +276,12 @@ struct extreme_points_on_ring
geometry::ever_circling_range_iterator<Ring const> right(ring);
++right;
- get_intruders(ring, left, right, extremes, intruders);
+ get_intruders(ring, left, right, extremes, intruders, strategy);
}
}
- template <typename Iterator>
- static inline bool right_turn(Ring const& ring, Iterator it)
+ template <typename Iterator, typename SideStrategy>
+ static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy)
{
typename std::iterator_traits<Iterator>::difference_type const index
= std::distance(boost::begin(ring), it);
@@ -295,8 +296,8 @@ struct extreme_points_on_ring
}
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
- int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
- int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
+ int const first_side = strategy.apply(*(right - 1), *right, *left) * factor;
+ int const last_side = strategy.apply(*left, *(left + 1), *right) * factor;
//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
@@ -306,8 +307,11 @@ struct extreme_points_on_ring
// Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
- template <typename Extremes, typename Intruders>
- static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Ring const& ring,
+ Extremes& extremes,
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n < 3)
@@ -321,7 +325,7 @@ struct extreme_points_on_ring
compare<Dimension> smaller;
for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
{
- if (smaller(*max_it, *it) && right_turn(ring, it))
+ if (smaller(*max_it, *it) && right_turn(ring, it, strategy))
{
max_it = it;
}
@@ -365,7 +369,7 @@ struct extreme_points_on_ring
std::copy(points.begin(), points.end(), std::back_inserter(extremes));
- get_intruders(ring, left, right, extremes, intruders);
+ get_intruders(ring, left, right, extremes, intruders, strategy);
return true;
}
@@ -403,8 +407,9 @@ struct extreme_points<Ring, Dimension, ring_tag>
template<typename Polygon, std::size_t Dimension>
struct extreme_points<Polygon, Dimension, polygon_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders,
+ SideStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef detail::extreme_points::extreme_points_on_ring
@@ -412,7 +417,8 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
ring_type, Dimension
> ring_implementation;
- if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
+ if (! ring_implementation::apply(geometry::exterior_ring(polygon),
+ extremes, intruders, strategy))
{
return false;
}
@@ -423,7 +429,7 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
- ring_implementation::get_intruders(*it, extremes, intruders);
+ ring_implementation::get_intruders(*it, extremes, intruders, strategy);
}
return true;
@@ -433,8 +439,9 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
template<typename Box>
struct extreme_points<Box, 1, box_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
+ SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -446,8 +453,9 @@ struct extreme_points<Box, 1, box_tag>
template<typename Box>
struct extreme_points<Box, 0, box_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
+ SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -460,8 +468,9 @@ struct extreme_points<Box, 0, box_tag>
template<typename MultiPolygon, std::size_t Dimension>
struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(MultiPolygon const& multi, Extremes& extremes,
+ Intruders& intruders, SideStrategy const& strategy)
{
// Get one for the very first polygon, that is (for the moment) enough.
// It is not guaranteed the "extreme" then, but for the current purpose
@@ -473,7 +482,7 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
typename boost::range_value<MultiPolygon const>::type,
Dimension,
polygon_tag
- >::apply(*boost::begin(multi), extremes, intruders);
+ >::apply(*boost::begin(multi), extremes, intruders, strategy);
}
return false;
@@ -489,8 +498,18 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
for Edge=0 in dimension 0, the right side)
\note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
*/
-template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
-inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
+template
+<
+ std::size_t Edge,
+ typename Geometry,
+ typename Extremes,
+ typename Intruders,
+ typename SideStrategy
+>
+inline bool extreme_points(Geometry const& geometry,
+ Extremes& extremes,
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
concepts::check<Geometry const>();
@@ -509,7 +528,11 @@ inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intrude
const
>();
- return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
+ return dispatch::extreme_points
+ <
+ Geometry,
+ Edge
+ >::apply(geometry, extremes, intruders, strategy);
}
diff --git a/boost/geometry/algorithms/detail/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp
index 95ab98c236..e9f6a50859 100644
--- a/boost/geometry/algorithms/detail/get_left_turns.hpp
+++ b/boost/geometry/algorithms/detail/get_left_turns.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -60,17 +65,14 @@ inline int squared_length(Vector const& vector)
}
-template <typename Point>
+template <typename Point, typename SideStrategy>
struct angle_less
{
typedef Point vector_type;
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type side_strategy_type;
- angle_less(Point const& origin)
+ angle_less(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
+ , m_strategy(strategy)
{}
template <typename Angle>
@@ -89,8 +91,7 @@ struct angle_less
return quadrant_p < quadrant_q;
}
// Same quadrant, check if p is located left of q
- int const side = side_strategy_type::apply(m_origin, q.point,
- p.point);
+ int const side = m_strategy.apply(m_origin, q.point, p.point);
if (side != 0)
{
return side == 1;
@@ -114,19 +115,17 @@ struct angle_less
private:
Point m_origin;
+ SideStrategy m_strategy;
};
-template <typename Point>
+template <typename Point, typename SideStrategy>
struct angle_equal_to
{
typedef Point vector_type;
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type side_strategy_type;
-
- inline angle_equal_to(Point const& origin)
+
+ inline angle_equal_to(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
+ , m_strategy(strategy)
{}
template <typename Angle>
@@ -143,13 +142,13 @@ struct angle_equal_to
return false;
}
// Same quadrant, check if p/q are collinear
- int const side = side_strategy_type::apply(m_origin, q.point,
- p.point);
+ int const side = m_strategy.apply(m_origin, q.point, p.point);
return side == 0;
}
private:
Point m_origin;
+ SideStrategy m_strategy;
};
template <typename AngleCollection, typename Turns>
@@ -193,13 +192,14 @@ inline void get_left_turns(AngleCollection const& sorted_angles,
//! Returns the number of clusters
-template <typename Point, typename AngleCollection>
-inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin)
+template <typename Point, typename AngleCollection, typename SideStrategy>
+inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin,
+ SideStrategy const& strategy)
{
// Assign same cluster_index for all turns in same direction
BOOST_GEOMETRY_ASSERT(boost::size(sorted) >= 4u);
- angle_equal_to<Point> comparator(origin);
+ angle_equal_to<Point, SideStrategy> comparator(origin, strategy);
typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
std::size_t cluster_index = 0;
diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp
index 9a388a4d80..c34bb217a6 100644
--- a/boost/geometry/algorithms/detail/has_self_intersections.hpp
+++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp
@@ -81,7 +81,7 @@ inline bool has_self_intersections(Geometry const& geometry,
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
- geometry::self_turns<detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
+ detail::self_get_turn_points::self_turns<false, detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
diff --git a/boost/geometry/algorithms/detail/intersects/implementation.hpp b/boost/geometry/algorithms/detail/intersects/implementation.hpp
new file mode 100644
index 0000000000..2379168e83
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersects/implementation.hpp
@@ -0,0 +1,88 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013-2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP
+
+
+#include <deque>
+
+#include <boost/geometry/algorithms/detail/intersects/interface.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/implementation.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersects
+{
+
+template <typename Geometry>
+struct self_intersects
+{
+ static bool apply(Geometry const& geometry)
+ {
+ concepts::check<Geometry const>();
+
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry, Geometry
+ >::type strategy_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
+
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ std::deque<turn_info> turns;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+ strategy_type strategy;
+ rescale_policy_type robust_policy;
+
+ detail::disjoint::disjoint_interrupt_policy policy;
+ detail::self_get_turn_points::get_turns
+ <
+ false, turn_policy
+ >::apply(geometry, strategy, robust_policy, turns, policy, 0);
+ return policy.has_intersections;
+ }
+};
+
+}} // namespace detail::intersects
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/intersects/interface.hpp b/boost/geometry/algorithms/detail/intersects/interface.hpp
new file mode 100644
index 0000000000..8940a426f3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersects/interface.hpp
@@ -0,0 +1,115 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013-2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP
+
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/interface.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersects
+{
+
+// Forward declaration
+template <typename Geometry>
+struct self_intersects;
+
+}} // namespace detail::intersects
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\brief \brief_check{has at least one intersection (crossing or self-tangency)}
+\note This function can be called for one geometry (self-intersection) and
+ also for two geometries (intersection)
+\ingroup intersects
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is self-intersecting}
+
+\qbk{distinguish,one geometry}
+\qbk{[def __one_parameter__]}
+\qbk{[include reference/algorithms/intersects.qbk]}
+*/
+template <typename Geometry>
+inline bool intersects(Geometry const& geometry)
+{
+ return detail::intersects::self_intersects<Geometry>::apply(geometry);
+}
+
+
+/*!
+\brief \brief_check2{have at least one intersection}
+\ingroup intersects
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Intersects}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{intersects}
+\return \return_check2{intersect each other}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/intersects.qbk]}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool intersects(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return ! geometry::disjoint(geometry1, geometry2, strategy);
+}
+
+
+/*!
+\brief \brief_check2{have at least one intersection}
+\ingroup intersects
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{intersect each other}
+
+\qbk{distinguish,two geometries}
+\qbk{[include reference/algorithms/intersects.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return ! geometry::disjoint(geometry1, geometry2);
+}
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp
index 52b9d9d1c8..5acf56c5b1 100644
--- a/boost/geometry/algorithms/detail/is_simple/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -219,12 +219,12 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
detail::self_get_turn_points::get_turns
<
- turn_policy
+ false, turn_policy
>::apply(linear,
strategy,
detail::no_rescale_policy(),
turns,
- interrupt_policy);
+ interrupt_policy, 0);
detail::is_valid::debug_print_turns(turns.begin(), turns.end());
debug_print_boundary_points(linear);
@@ -236,7 +236,9 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
template <typename Linestring, bool CheckSelfIntersections = true>
struct is_simple_linestring
{
- static inline bool apply(Linestring const& linestring)
+ template <typename Strategy>
+ static inline bool apply(Linestring const& linestring,
+ Strategy const& strategy)
{
simplicity_failure_policy policy;
return ! boost::empty(linestring)
@@ -247,7 +249,7 @@ struct is_simple_linestring
&& ! detail::is_valid::has_spikes
<
Linestring, closed
- >::apply(linestring, policy);
+ >::apply(linestring, policy, strategy.get_side_strategy());
}
};
@@ -258,7 +260,10 @@ struct is_simple_linestring<Linestring, true>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
- return is_simple_linestring<Linestring, false>::apply(linestring)
+ return is_simple_linestring
+ <
+ Linestring, false
+ >::apply(linestring, strategy)
&& ! has_self_intersections(linestring, strategy);
}
};
@@ -267,23 +272,44 @@ struct is_simple_linestring<Linestring, true>
template <typename MultiLinestring>
struct is_simple_multilinestring
{
+private:
+ template <typename Strategy>
+ struct per_linestring
+ {
+ per_linestring(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Linestring>
+ inline bool apply(Linestring const& linestring) const
+ {
+ return detail::is_simple::is_simple_linestring
+ <
+ Linestring,
+ false // do not compute self-intersections
+ >::apply(linestring, m_strategy);
+ }
+
+ Strategy const& m_strategy;
+ };
+
+public:
template <typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
Strategy const& strategy)
{
+ typedef per_linestring<Strategy> per_ls;
+
// check each of the linestrings for simplicity
// but do not compute self-intersections yet; these will be
// computed for the entire multilinestring
if ( ! detail::check_iterator_range
<
- is_simple_linestring
- <
- typename boost::range_value<MultiLinestring>::type,
- false // do not compute self-intersections
- >,
+ per_ls, // do not compute self-intersections
true // allow empty multilinestring
>::apply(boost::begin(multilinestring),
- boost::end(multilinestring))
+ boost::end(multilinestring),
+ per_ls(strategy))
)
{
return false;
diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
index aa90e52db6..96efec79cd 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014-2015, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -91,8 +92,9 @@ struct has_spikes
return std::find_if(second, last, not_equal(*first));
}
- template <typename VisitPolicy>
- static inline bool apply(Range const& range, VisitPolicy& visitor)
+ template <typename VisitPolicy, typename SideStrategy>
+ static inline bool apply(Range const& range, VisitPolicy& visitor,
+ SideStrategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -124,9 +126,8 @@ struct has_spikes
while (next != boost::end(view))
{
- if ( geometry::detail::point_is_spike_or_equal(*prev,
- *next,
- *cur) )
+ if ( geometry::detail::point_is_spike_or_equal(*prev, *next, *cur,
+ strategy) )
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
@@ -146,7 +147,7 @@ struct has_spikes
boost::rend(view));
iterator next = find_different_from_first(cur, boost::end(view));
- if (detail::point_is_spike_or_equal(*prev, *next, *cur))
+ if (detail::point_is_spike_or_equal(*prev, *next, *cur, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
index b91dc6a697..b36e9f38b7 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
@@ -86,7 +86,7 @@ public:
IsAcceptableTurn
> interrupt_policy;
- geometry::self_turns<turn_policy>(geometry,
+ detail::self_get_turn_points::self_turns<false, turn_policy>(geometry,
strategy,
robust_policy,
turns,
diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
index 0d80d6f6c0..fccc0ffdb7 100644
--- a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
@@ -138,10 +138,17 @@ public:
}
operation_type const op = acceptable_operation<MultiPolygon>::value;
+ if ( base::check_turn(turn, method_touch_interior, op)
+ || base::check_turn(turn, method_touch, op))
+ {
+ return true;
+ }
- return base::check_turn(turn, method_touch_interior, op)
- || base::check_turn(turn, method_touch, op)
- ;
+ // Turn is acceptable only in case of a touch(interior) and both lines
+ // (polygons) do not cross
+ return (turn.method == method_touch
+ || turn.method == method_touch_interior)
+ && turn.touch_only;
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp
index 6bc6b86cf8..39cb36ef5b 100644
--- a/boost/geometry/algorithms/detail/is_valid/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp
@@ -43,9 +43,10 @@ namespace detail { namespace is_valid
template <typename Linestring>
struct is_valid_linestring
{
- template <typename VisitPolicy>
+ template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
if (has_invalid_coordinate<Linestring>::apply(linestring, visitor))
{
@@ -75,15 +76,12 @@ struct is_valid_linestring
{
return visitor.template apply<no_failure>();
}
- return ! has_spikes<Linestring, closed>::apply(linestring, visitor);
- }
- template <typename VisitPolicy, typename Strategy>
- static inline bool apply(Linestring const& linestring,
- VisitPolicy& visitor,
- Strategy const&)
- {
- return apply(linestring, visitor);
+ return ! has_spikes
+ <
+ Linestring, closed
+ >::apply(linestring, visitor,
+ strategy.get_side_strategy());
}
};
@@ -132,10 +130,13 @@ class is_valid
>
{
private:
- template <typename VisitPolicy>
+ template <typename VisitPolicy, typename Strategy>
struct per_linestring
{
- per_linestring(VisitPolicy& policy) : m_policy(policy) {}
+ per_linestring(VisitPolicy& policy, Strategy const& strategy)
+ : m_policy(policy)
+ , m_strategy(strategy)
+ {}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
@@ -143,17 +144,18 @@ private:
return detail::is_valid::is_valid_linestring
<
Linestring
- >::apply(linestring, m_policy);
+ >::apply(linestring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
+ Strategy const& m_strategy;
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
VisitPolicy& visitor,
- Strategy const&)
+ Strategy const& strategy)
{
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries && boost::empty(multilinestring)))
@@ -161,13 +163,15 @@ public:
return visitor.template apply<no_failure>();
}
+ typedef per_linestring<VisitPolicy, Strategy> per_ls;
+
return detail::check_iterator_range
<
- per_linestring<VisitPolicy>,
+ per_ls,
false // do not check for empty multilinestring (done above)
>::apply(boost::begin(multilinestring),
boost::end(multilinestring),
- per_linestring<VisitPolicy>(visitor));
+ per_ls(visitor, strategy));
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
index 84dacc57f1..ed24b13810 100644
--- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
@@ -76,45 +76,66 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline
bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
boost::ignore_unused(visitor);
- // collect all polygons that have turns
+ // collect all polygons that have crossing turns
std::set<signed_size_type> multi_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
- multi_indices.insert(tit->operations[0].seg_id.multi_index);
- multi_indices.insert(tit->operations[1].seg_id.multi_index);
+ if (! tit->touch_only)
+ {
+ multi_indices.insert(tit->operations[0].seg_id.multi_index);
+ multi_indices.insert(tit->operations[1].seg_id.multi_index);
+ }
}
+ typedef geometry::model::box<typename point_type<MultiPolygon>::type> box_type;
+ typedef typename base::template partition_item<PolygonIterator, box_type> item_type;
+
// put polygon iterators without turns in a vector
- std::vector<PolygonIterator> polygon_iterators;
+ std::vector<item_type> polygon_iterators;
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
++it, ++multi_index)
{
if (multi_indices.find(multi_index) == multi_indices.end())
{
- polygon_iterators.push_back(it);
+ polygon_iterators.push_back(item_type(it));
}
}
- typename base::item_visitor_type item_visitor;
+ // prepare strategies
+ typedef typename std::iterator_traits<PolygonIterator>::value_type polygon_type;
+ typedef typename Strategy::template point_in_geometry_strategy
+ <
+ polygon_type, polygon_type
+ >::type within_strategy_type;
+ within_strategy_type const within_strategy
+ = strategy.template get_point_in_geometry_strategy<polygon_type, polygon_type>();
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ envelope_strategy_type const envelope_strategy
+ = strategy.get_envelope_strategy();
+
+ // call partition to check if polygons are disjoint from each other
+ typename base::template item_visitor_type<within_strategy_type> item_visitor(within_strategy);
geometry::partition
<
geometry::model::box<typename point_type<MultiPolygon>::type>
>::apply(polygon_iterators, item_visitor,
- typename base::expand_box(),
- typename base::overlaps_box());
+ typename base::template expand_box<envelope_strategy_type>(envelope_strategy),
+ typename base::template overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -155,13 +176,15 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool apply(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
@@ -185,7 +208,8 @@ private:
if (! Predicate::apply(*it,
filtered_turns_first,
filtered_turns_beyond,
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -200,19 +224,21 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool have_holes_inside(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_holes_inside
>::apply(polygons_first, polygons_beyond,
- turns_first, turns_beyond, visitor);
+ turns_first, turns_beyond, visitor, strategy);
}
@@ -221,19 +247,21 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool have_connected_interior(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_connected_interior
>::apply(polygons_first, polygons_beyond,
- turns_first, turns_beyond, visitor);
+ turns_first, turns_beyond, visitor, strategy);
}
@@ -307,7 +335,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -320,7 +349,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -332,7 +362,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
- visitor);
+ visitor,
+ strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
index f7e22fb8d2..5c6229b793 100644
--- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
@@ -1,5 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
+
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -43,6 +45,7 @@
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -142,43 +145,103 @@ protected:
};
+ // Iterator value_type is a Ring or Polygon
+ template <typename Iterator, typename Box>
+ struct partition_item
+ {
+ explicit partition_item(Iterator it)
+ : m_it(it)
+ , m_is_initialized(false)
+ {}
+
+ Iterator get() const
+ {
+ return m_it;
+ }
+
+ template <typename EnvelopeStrategy>
+ Box const& get_envelope(EnvelopeStrategy const& strategy) const
+ {
+ if (! m_is_initialized)
+ {
+ m_box = geometry::return_envelope<Box>(*m_it, strategy);
+ m_is_initialized = true;
+ }
+ return m_box;
+ }
+
+ private:
+ Iterator m_it;
+ mutable Box m_box;
+ mutable bool m_is_initialized;
+ };
+
// structs for partition -- start
+ template <typename EnvelopeStrategy>
struct expand_box
{
+ explicit expand_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
+
template <typename Box, typename Iterator>
- static inline void apply(Box& total, Iterator const& it)
+ inline void apply(Box& total, partition_item<Iterator, Box> const& item) const
{
- geometry::expand(total, geometry::return_envelope<Box>(*it));
+ geometry::expand(total, item.get_envelope(m_strategy));
}
+ EnvelopeStrategy const& m_strategy;
};
+ template <typename EnvelopeStrategy>
struct overlaps_box
{
+ explicit overlaps_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
+
template <typename Box, typename Iterator>
- static inline bool apply(Box const& box, Iterator const& it)
+ inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const
{
- return ! geometry::disjoint(*it, box);
+ return ! geometry::disjoint(item.get_envelope(m_strategy), box);
}
+
+ EnvelopeStrategy const& m_strategy;
};
+ template <typename WithinStrategy>
struct item_visitor_type
{
bool items_overlap;
+ WithinStrategy const& m_strategy;
+
+ explicit item_visitor_type(WithinStrategy const& strategy)
+ : items_overlap(false)
+ , m_strategy(strategy)
+ {}
- item_visitor_type() : items_overlap(false) {}
+ template <typename Item>
+ inline bool is_within(Item const& first, Item const& second)
+ {
+ typename point_type<Polygon>::type point;
+ typedef detail::point_on_border::point_on_range<true> pob;
+
+ // TODO: this should check for a point on the interior, instead
+ // of on border. Or it should check using the overlap function.
+
+ return pob::apply(point, points_begin(first), points_end(first))
+ && geometry::within(point, second, m_strategy);
+ }
- template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ template <typename Iterator, typename Box>
+ inline bool apply(partition_item<Iterator, Box> const& item1,
+ partition_item<Iterator, Box> const& item2)
{
if (! items_overlap
- && (geometry::within(*points_begin(*item1), *item2)
- || geometry::within(*points_begin(*item2), *item1))
- )
+ && (is_within(*item1.get(), *item2.get())
+ || is_within(*item2.get(), *item1.get())))
{
items_overlap = true;
+ return false; // interrupt
}
+ return true;
}
};
// structs for partition -- end
@@ -189,14 +252,16 @@ protected:
typename RingIterator,
typename ExteriorRing,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool are_holes_inside(RingIterator rings_first,
RingIterator rings_beyond,
ExteriorRing const& exterior_ring,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -217,6 +282,14 @@ protected:
}
}
+ // prepare strategy
+ typedef typename std::iterator_traits<RingIterator>::value_type inter_ring_type;
+ typename Strategy::template point_in_geometry_strategy
+ <
+ inter_ring_type, ExteriorRing
+ >::type const in_exterior_strategy
+ = strategy.template get_point_in_geometry_strategy<inter_ring_type, ExteriorRing>();
+
signed_size_type ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
@@ -224,7 +297,7 @@ protected:
// do not examine interior rings that have turns with the
// exterior ring
if (ring_indices.find(ring_index) == ring_indices.end()
- && ! geometry::covered_by(range::front(*it), exterior_ring))
+ && ! geometry::covered_by(range::front(*it), exterior_ring, in_exterior_strategy))
{
return visitor.template apply<failure_interior_rings_outside>();
}
@@ -237,26 +310,42 @@ protected:
ring_indices.insert(tit->operations[1].seg_id.ring_index);
}
+ typedef geometry::model::box<typename point_type<Polygon>::type> box_type;
+ typedef partition_item<RingIterator, box_type> item_type;
+
// put iterators for interior rings without turns in a vector
- std::vector<RingIterator> ring_iterators;
+ std::vector<item_type> ring_iterators;
ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
{
if (ring_indices.find(ring_index) == ring_indices.end())
{
- ring_iterators.push_back(it);
+ ring_iterators.push_back(item_type(it));
}
}
- // call partition to check is interior rings are disjoint from
+ // prepare strategies
+ typedef typename Strategy::template point_in_geometry_strategy
+ <
+ inter_ring_type, inter_ring_type
+ >::type in_interior_strategy_type;
+ in_interior_strategy_type const in_interior_strategy
+ = strategy.template get_point_in_geometry_strategy<inter_ring_type, inter_ring_type>();
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ envelope_strategy_type const envelope_strategy
+ = strategy.get_envelope_strategy();
+
+ // call partition to check if interior rings are disjoint from
// each other
- item_visitor_type item_visitor;
+ item_visitor_type<in_interior_strategy_type> item_visitor(in_interior_strategy);
geometry::partition
<
- geometry::model::box<typename point_type<Polygon>::type>
- >::apply(ring_iterators, item_visitor, expand_box(), overlaps_box());
+ box_type
+ >::apply(ring_iterators, item_visitor,
+ expand_box<envelope_strategy_type>(envelope_strategy),
+ overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -273,35 +362,40 @@ protected:
typename InteriorRings,
typename ExteriorRing,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool are_holes_inside(InteriorRings const& interior_rings,
ExteriorRing const& exterior_ring,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return are_holes_inside(boost::begin(interior_rings),
boost::end(interior_rings),
exterior_ring,
first,
beyond,
- visitor);
+ visitor,
+ strategy);
}
struct has_holes_inside
{
- template <typename TurnIterator, typename VisitPolicy>
+ template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return are_holes_inside(geometry::interior_rings(polygon),
geometry::exterior_ring(polygon),
first,
beyond,
- visitor);
+ visitor,
+ strategy);
}
};
@@ -310,11 +404,12 @@ protected:
struct has_connected_interior
{
- template <typename TurnIterator, typename VisitPolicy>
+ template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& )
{
boost::ignore_unused(visitor);
@@ -388,7 +483,8 @@ public:
if (! has_holes_inside::apply(polygon,
turns.begin(), turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -399,7 +495,8 @@ public:
return has_connected_interior::apply(polygon,
turns.begin(),
turns.end(),
- visitor);
+ visitor,
+ strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp
index 9ab68fdc48..0b95950430 100644
--- a/boost/geometry/algorithms/detail/is_valid/ring.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp
@@ -115,7 +115,10 @@ struct is_properly_oriented
geometry::closure<Ring>::value
> ring_area_type;
- typedef typename default_area_result<Ring>::type area_result_type;
+ typedef typename Strategy::template area_strategy
+ <
+ point_type
+ >::type::return_type area_result_type;
typename ring_area_predicate
<
@@ -195,7 +198,7 @@ struct is_valid_ring
return
is_topologically_closed<Ring, closure>::apply(ring, visitor)
&& ! has_duplicates<Ring, closure>::apply(ring, visitor)
- && ! has_spikes<Ring, closure>::apply(ring, visitor)
+ && ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy())
&& (! CheckSelfIntersections
|| has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);
diff --git a/boost/geometry/algorithms/detail/multi_modify.hpp b/boost/geometry/algorithms/detail/multi_modify.hpp
index f0b9ddd3e6..23187f9323 100644
--- a/boost/geometry/algorithms/detail/multi_modify.hpp
+++ b/boost/geometry/algorithms/detail/multi_modify.hpp
@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -40,6 +44,18 @@ struct multi_modify
Policy::apply(*it);
}
}
+
+ template <typename Strategy>
+ static inline void apply(MultiGeometry& multi, Strategy const& strategy)
+ {
+ typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, strategy);
+ }
+ }
};
diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp
index 4048d59d75..fc74f0cc7f 100644
--- a/boost/geometry/algorithms/detail/occupation_info.hpp
+++ b/boost/geometry/algorithms/detail/occupation_info.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -99,12 +104,18 @@ public :
}
}
- template <typename RobustPoint, typename Turns>
- inline void get_left_turns(RobustPoint const& origin, Turns& turns)
+ template <typename RobustPoint, typename Turns, typename SideStrategy>
+ inline void get_left_turns(RobustPoint const& origin, Turns& turns,
+ SideStrategy const& strategy)
{
+ typedef detail::left_turns::angle_less
+ <
+ typename AngleInfo::point_type,
+ SideStrategy
+ > angle_less;
+
// Sort on angle
- std::sort(m_angles.begin(), m_angles.end(),
- detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
+ std::sort(m_angles.begin(), m_angles.end(), angle_less(origin, strategy));
// Group same-angled elements
std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);
diff --git a/boost/geometry/algorithms/detail/overlaps/implementation.hpp b/boost/geometry/algorithms/detail/overlaps/implementation.hpp
new file mode 100644
index 0000000000..49f44bef81
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlaps/implementation.hpp
@@ -0,0 +1,156 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014, 2015, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/relate.hpp>
+#include <boost/geometry/algorithms/detail/overlaps/interface.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlaps
+{
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box_loop
+{
+ template <typename Box1, typename Box2>
+ static inline void apply(Box1 const& b1, Box2 const& b2,
+ bool& overlaps, bool& one_in_two, bool& two_in_one)
+ {
+ assert_dimension_equal<Box1, Box2>();
+
+ typedef typename coordinate_type<Box1>::type coordinate_type1;
+ typedef typename coordinate_type<Box2>::type coordinate_type2;
+
+ coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
+ coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
+ coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
+ coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
+
+ // We might use the (not yet accepted) Boost.Interval
+ // submission in the future
+
+ // If:
+ // B1: |-------|
+ // B2: |------|
+ // in any dimension -> no overlap
+ if (max1 <= min2 || min1 >= max2)
+ {
+ overlaps = false;
+ return;
+ }
+
+ // If:
+ // B1: |--------------------|
+ // B2: |-------------|
+ // in all dimensions -> within, then no overlap
+ // B1: |--------------------|
+ // B2: |-------------|
+ // this is "within-touch" -> then no overlap. So use < and >
+ if (min1 < min2 || max1 > max2)
+ {
+ one_in_two = false;
+ }
+
+ // Same other way round
+ if (min2 < min1 || max2 > max1)
+ {
+ two_in_one = false;
+ }
+
+ box_box_loop
+ <
+ Dimension + 1,
+ DimensionCount
+ >::apply(b1, b2, overlaps, one_in_two, two_in_one);
+ }
+};
+
+template
+<
+ std::size_t DimensionCount
+>
+struct box_box_loop<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2>
+ static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
+ {
+ }
+};
+
+struct box_box
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
+ {
+ bool overlaps = true;
+ bool within1 = true;
+ bool within2 = true;
+ box_box_loop
+ <
+ 0,
+ dimension<Box1>::type::value
+ >::apply(b1, b2, overlaps, within1, within2);
+
+ /*
+ \see http://docs.codehaus.org/display/GEOTDOC/02+Geometry+Relationships#02GeometryRelationships-Overlaps
+ where is stated that "inside" is not an "overlap",
+ this is true and is implemented as such.
+ */
+ return overlaps && ! within1 && ! within2;
+ }
+};
+
+}} // namespace detail::overlaps
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Box1, typename Box2>
+struct overlaps<Box1, Box2, box_tag, box_tag>
+ : detail::overlaps::box_box
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/overlaps/interface.hpp b/boost/geometry/algorithms/detail/overlaps/interface.hpp
new file mode 100644
index 0000000000..f9f6a853fd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlaps/interface.hpp
@@ -0,0 +1,124 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014, 2015, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
+
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct overlaps
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_overlaps_type,
+ Geometry1,
+ Geometry2
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief \brief_check2{overlap}
+\ingroup overlaps
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Overlaps}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{overlaps}
+\return \return_check2{overlap}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/overlaps.qbk]}
+*/
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool overlaps(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return dispatch::overlaps
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+/*!
+\brief \brief_check2{overlap}
+\ingroup overlaps
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{overlap}
+
+\qbk{[include reference/algorithms/overlaps.qbk]}
+*/
+template <typename Geometry1, typename Geometry2>
+inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return dispatch::overlaps
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy_type());
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
index df62a1f2f6..106ecaad07 100644
--- a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
@@ -24,8 +24,12 @@ struct ring_with_direction
{
ring_identifier ring_id;
direction_type direction;
- bool only_turn_on_ring;
+ std::size_t turn_index;
+ int operation_index;
+ operation_type operation;
+ signed_size_type region_id;
+ bool isolated;
inline bool operator<(ring_with_direction const& other) const
{
@@ -36,7 +40,11 @@ struct ring_with_direction
ring_with_direction()
: direction(dir_unknown)
- , only_turn_on_ring(false)
+ , turn_index(-1)
+ , operation_index(0)
+ , operation(operation_none)
+ , region_id(-1)
+ , isolated(false)
{}
};
@@ -50,28 +58,168 @@ struct rank_with_rings
{
}
+ inline bool all_equal(direction_type dir_type) const
+ {
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ if (it->direction != dir_type)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
inline bool all_to() const
{
+ return all_equal(sort_by_side::dir_to);
+ }
+
+ inline bool all_from() const
+ {
+ return all_equal(sort_by_side::dir_from);
+ }
+
+ inline bool has_only(operation_type op) const
+ {
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (rwd.operation != op)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ //! Check if set has both op1 and op2, but no others
+ inline bool has_only_both(operation_type op1, operation_type op2) const
+ {
+ bool has1 = false;
+ bool has2 = false;
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
- if (it->direction == sort_by_side::dir_from)
+ const ring_with_direction& rwd = *it;
+
+ if (rwd.operation == op1) { has1 = true; }
+ else if (rwd.operation == op2) { has2 = true; }
+ else { return false; }
+ }
+ return has1 && has2;
+ }
+
+ inline bool is_isolated() const
+ {
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (! rwd.isolated)
{
return false;
}
}
return true;
}
+
+ inline bool has_unique_region_id() const
+ {
+ int region_id = -1;
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (region_id == -1)
+ {
+ region_id = rwd.region_id;
+ }
+ else if (rwd.region_id != region_id)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ inline int region_id() const
+ {
+ int region_id = -1;
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (region_id == -1)
+ {
+ region_id = rwd.region_id;
+ }
+ else if (rwd.region_id != region_id)
+ {
+ return -1;
+ }
+ }
+ return region_id;
+ }
+
+ template <typename Turns>
+ inline bool traversable(Turns const& turns) const
+ {
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type turn_operation_type;
+
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ turn_type const& turn = turns[rwd.turn_index];
+ turn_operation_type const& op = turn.operations[rwd.operation_index];
+
+ // TODO: this is still necessary, but makes it order-dependent
+ // which should not be done.
+
+ // This would obsolete the whole function and should be solved
+ // in a different way
+ if (op.visited.finalized() || op.visited.visited())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
};
-template <typename Sbs>
-inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation)
+template <typename Sbs, typename Turns>
+inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation,
+ Turns const& turns,
+ operation_type target_operation)
{
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type turn_operation_type;
+
aggregation.clear();
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
typename Sbs::rp const& ranked_point = sbs.m_ranked_points[i];
+ turn_type const& turn = turns[ranked_point.turn_index];
+
+ turn_operation_type const& op = turn.operations[ranked_point.operation_index];
+
+ if (! ((target_operation == operation_union && ranked_point.rank == 0)
+ || op.operation == target_operation
+ || op.operation == operation_continue
+ || (op.operation == operation_blocked && ranked_point.direction == dir_from)))
+ {
+ // Always take rank 0 (because self-turns are blocked)
+ // Don't consider union/blocked (aggregate is only used for intersections)
+ // Blocked is allowed for from
+ continue;
+ }
+
if (aggregation.empty() || aggregation.back().rank != ranked_point.rank)
{
rank_with_rings current;
@@ -81,10 +229,14 @@ inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& a
ring_with_direction rwd;
segment_identifier const& sid = ranked_point.seg_id;
+
rwd.ring_id = ring_identifier(sid.source_index, sid.multi_index, sid.ring_index);
rwd.direction = ranked_point.direction;
- rwd.only_turn_on_ring = ranked_point.only_turn_on_ring;
-
+ rwd.turn_index = ranked_point.turn_index;
+ rwd.operation_index = ranked_point.operation_index;
+ rwd.operation = op.operation;
+ rwd.region_id = op.enriched.region_id;
+ rwd.isolated = op.enriched.isolated;
aggregation.back().rings.insert(rwd);
}
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
index 03c06c28d1..fb73840798 100644
--- a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
+++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -63,8 +63,9 @@ inline bool points_equal_or_close(Point1 const& point1,
}
-template <typename Range, typename Point, typename RobustPolicy>
+template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
inline void append_no_dups_or_spikes(Range& range, Point const& point,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
@@ -92,6 +93,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
&& point_is_spike_or_equal(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
+ strategy,
robust_policy))
{
// Use the Concept/traits, so resize and append again
@@ -100,8 +102,9 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
}
}
-template <typename Range, typename RobustPolicy>
+template <typename Range, typename SideStrategy, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
std::size_t const minsize
@@ -135,7 +138,7 @@ inline void clean_closing_dups_and_spikes(Range& range,
// Check if closing point is a spike (this is so if the second point is
// considered as a spike w.r.t. the last segment)
- if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
+ if (point_is_spike_or_equal(*second, *ultimate, *first, strategy, robust_policy))
{
range::erase(range, first);
if (BOOST_GEOMETRY_CONDITION(closed))
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 2408b4b68e..78160f5204 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -20,7 +20,8 @@
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
-#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/geometries/box.hpp>
@@ -37,50 +38,88 @@ namespace detail { namespace overlay
template
<
typename Item,
+ typename InnerGeometry,
typename Geometry1, typename Geometry2,
- typename RingCollection
+ typename RingCollection,
+ typename Strategy
+>
+static inline bool within_selected_input(Item const& item2,
+ InnerGeometry const& inner_geometry,
+ ring_identifier const& outer_id,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RingCollection const& collection,
+ Strategy const& strategy)
+{
+ typedef typename geometry::tag<Geometry1>::type tag1;
+ typedef typename geometry::tag<Geometry2>::type tag2;
+
+ // NOTE: range_in_geometry first checks the item2.point and then
+ // if this point is on boundary it checks points of inner_geometry
+ // ring until a point inside/outside other geometry ring is found
+ switch (outer_id.source_index)
+ {
+ // covered_by
+ case 0 :
+ return range_in_geometry(item2.point, inner_geometry,
+ get_ring<tag1>::apply(outer_id, geometry1), strategy) >= 0;
+ case 1 :
+ return range_in_geometry(item2.point, inner_geometry,
+ get_ring<tag2>::apply(outer_id, geometry2), strategy) >= 0;
+ case 2 :
+ return range_in_geometry(item2.point, inner_geometry,
+ get_ring<void>::apply(outer_id, collection), strategy) >= 0;
+ }
+ return false;
+}
+
+template
+<
+ typename Item,
+ typename Geometry1, typename Geometry2,
+ typename RingCollection,
+ typename Strategy
>
-static inline bool within_selected_input(Item const& item2, ring_identifier const& ring_id,
+static inline bool within_selected_input(Item const& item2,
+ ring_identifier const& inner_id, ring_identifier const& outer_id,
Geometry1 const& geometry1, Geometry2 const& geometry2,
- RingCollection const& collection)
+ RingCollection const& collection,
+ Strategy const& strategy)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
- switch (ring_id.source_index)
+ switch (inner_id.source_index)
{
case 0 :
- return geometry::within(item2.point,
- get_ring<tag1>::apply(ring_id, geometry1));
- break;
+ return within_selected_input(item2,
+ get_ring<tag1>::apply(inner_id, geometry1),
+ outer_id, geometry1, geometry2, collection, strategy);
case 1 :
- return geometry::within(item2.point,
- get_ring<tag2>::apply(ring_id, geometry2));
- break;
+ return within_selected_input(item2,
+ get_ring<tag2>::apply(inner_id, geometry2),
+ outer_id, geometry1, geometry2, collection, strategy);
case 2 :
- return geometry::within(item2.point,
- get_ring<void>::apply(ring_id, collection));
- break;
+ return within_selected_input(item2,
+ get_ring<void>::apply(inner_id, collection),
+ outer_id, geometry1, geometry2, collection, strategy);
}
return false;
}
-template <typename Point>
+template <typename Point, typename AreaType>
struct ring_info_helper
{
- typedef typename geometry::default_area_result<Point>::type area_type;
-
ring_identifier id;
- area_type real_area;
- area_type abs_area;
+ AreaType real_area;
+ AreaType abs_area;
model::box<Point> envelope;
inline ring_info_helper()
: real_area(0), abs_area(0)
{}
- inline ring_info_helper(ring_identifier i, area_type a)
+ inline ring_info_helper(ring_identifier i, AreaType const& a)
: id(i), real_area(a), abs_area(geometry::math::abs(a))
{}
};
@@ -104,7 +143,14 @@ struct ring_info_helper_ovelaps_box
}
};
-template <typename Geometry1, typename Geometry2, typename Collection, typename RingMap>
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Collection,
+ typename RingMap,
+ typename Strategy
+>
struct assign_visitor
{
typedef typename RingMap::mapped_type ring_info_type;
@@ -113,26 +159,27 @@ struct assign_visitor
Geometry2 const& m_geometry2;
Collection const& m_collection;
RingMap& m_ring_map;
+ Strategy const& m_strategy;
bool m_check_for_orientation;
-
inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c,
- RingMap& map, bool check)
+ RingMap& map, Strategy const& strategy, bool check)
: m_geometry1(g1)
, m_geometry2(g2)
, m_collection(c)
, m_ring_map(map)
+ , m_strategy(strategy)
, m_check_for_orientation(check)
{}
template <typename Item>
- inline void apply(Item const& outer, Item const& inner, bool first = true)
+ inline bool apply(Item const& outer, Item const& inner, bool first = true)
{
if (first && outer.abs_area < inner.abs_area)
{
// Apply with reversed arguments
apply(inner, outer, false);
- return;
+ return true;
}
if (m_check_for_orientation
@@ -141,8 +188,10 @@ struct assign_visitor
{
ring_info_type& inner_in_map = m_ring_map[inner.id];
- if (geometry::within(inner_in_map.point, outer.envelope)
- && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
+ if (geometry::covered_by(inner_in_map.point, outer.envelope)
+ && within_selected_input(inner_in_map, inner.id, outer.id,
+ m_geometry1, m_geometry2, m_collection,
+ m_strategy)
)
{
// Assign a parent if there was no earlier parent, or the newly
@@ -155,6 +204,8 @@ struct assign_visitor
}
}
}
+
+ return true;
}
};
@@ -165,12 +216,14 @@ template
<
typename Geometry1, typename Geometry2,
typename RingCollection,
- typename RingMap
+ typename RingMap,
+ typename Strategy
>
inline void assign_parents(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RingCollection const& collection,
RingMap& ring_map,
+ Strategy const& strategy,
bool check_for_orientation = false)
{
typedef typename geometry::tag<Geometry1>::type tag1;
@@ -179,11 +232,15 @@ inline void assign_parents(Geometry1 const& geometry1,
typedef typename RingMap::mapped_type ring_info_type;
typedef typename ring_info_type::point_type point_type;
typedef model::box<point_type> box_type;
+ typedef typename Strategy::template area_strategy
+ <
+ point_type
+ >::type::return_type area_result_type;
typedef typename RingMap::iterator map_iterator_type;
{
- typedef ring_info_helper<point_type> helper;
+ typedef ring_info_helper<point_type, area_result_type> helper;
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
@@ -204,17 +261,21 @@ inline void assign_parents(Geometry1 const& geometry1,
{
case 0 :
geometry::envelope(get_ring<tag1>::apply(it->first, geometry1),
- item.envelope);
+ item.envelope, strategy.get_envelope_strategy());
break;
case 1 :
geometry::envelope(get_ring<tag2>::apply(it->first, geometry2),
- item.envelope);
+ item.envelope, strategy.get_envelope_strategy());
break;
case 2 :
geometry::envelope(get_ring<void>::apply(it->first, collection),
- item.envelope);
+ item.envelope, strategy.get_envelope_strategy());
break;
}
+
+ // Expand envelope slightly
+ expand_by_epsilon(item.envelope);
+
if (item.real_area > 0)
{
count_positive++;
@@ -257,8 +318,9 @@ inline void assign_parents(Geometry1 const& geometry1,
assign_visitor
<
Geometry1, Geometry2,
- RingCollection, RingMap
- > visitor(geometry1, geometry2, collection, ring_map, check_for_orientation);
+ RingCollection, RingMap,
+ Strategy
+ > visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation);
geometry::partition
<
@@ -315,18 +377,20 @@ template
<
typename Geometry,
typename RingCollection,
- typename RingMap
+ typename RingMap,
+ typename Strategy
>
inline void assign_parents(Geometry const& geometry,
RingCollection const& collection,
RingMap& ring_map,
+ Strategy const& strategy,
bool check_for_orientation)
{
// Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
- assign_parents(geometry, empty, collection, ring_map, check_for_orientation);
+ assign_parents(geometry, empty, collection, ring_map, strategy, check_for_orientation);
}
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
index 795523d7a0..0e9bfe2ea0 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -20,6 +20,7 @@
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
index fe1a034f8b..c6f540a978 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
@@ -2,8 +2,8 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -36,6 +36,7 @@
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
+#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/util/range.hpp>
@@ -56,12 +57,14 @@ struct copy_segments_ring
<
typename Ring,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -108,7 +111,7 @@ struct copy_segments_ring
for (signed_size_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
+ detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy);
}
}
};
@@ -118,20 +121,23 @@ class copy_segments_linestring
{
private:
// remove spikes
- template <typename RangeOut, typename Point, typename RobustPolicy>
+ template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
boost::true_type const&)
{
detail::overlay::append_no_dups_or_spikes(current_output, point,
+ strategy,
robust_policy);
}
// keep spikes
- template <typename RangeOut, typename Point, typename RobustPolicy>
+ template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
+ SideStrategy const&,
RobustPolicy const&,
boost::false_type const&)
{
@@ -143,12 +149,14 @@ public:
<
typename LineString,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(LineString const& ls,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -169,7 +177,7 @@ public:
for (signed_size_type i = 0; i < count; ++i, ++it)
{
- append_to_output(current_output, *it, robust_policy,
+ append_to_output(current_output, *it, strategy, robust_policy,
boost::integral_constant<bool, RemoveSpikes>());
}
}
@@ -182,12 +190,14 @@ struct copy_segments_polygon
<
typename Polygon,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -198,6 +208,7 @@ struct copy_segments_polygon
? geometry::exterior_ring(polygon)
: range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, to_index,
+ strategy,
robust_policy,
current_output
);
@@ -212,12 +223,14 @@ struct copy_segments_box
<
typename Box,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -238,7 +251,7 @@ struct copy_segments_box
for (signed_size_type i = 0; i < count; i++, index++)
{
detail::overlay::append_no_dups_or_spikes(current_output,
- bp[index % 5], robust_policy);
+ bp[index % 5], strategy, robust_policy);
}
}
@@ -252,12 +265,14 @@ struct copy_segments_multi
<
typename MultiGeometry,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(MultiGeometry const& multi_geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -271,6 +286,7 @@ struct copy_segments_multi
// Call the single-version
Policy::apply(range::at(multi_geometry, seg_id.multi_index),
seg_id, to_index,
+ strategy,
robust_policy,
current_output);
}
@@ -340,12 +356,14 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& range_out)
{
@@ -355,7 +373,7 @@ inline void copy_segments(Geometry const& geometry,
<
typename tag<Geometry>::type,
Reverse
- >::apply(geometry, seg_id, to_index, robust_policy, range_out);
+ >::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index 5cab2b4cb8..47225328df 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -19,20 +24,21 @@
# include <iostream>
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/io/wkt/wkt.hpp>
-# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
+# if ! defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
+# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
+ #endif
#endif
#include <boost/range.hpp>
-#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
-#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
+#include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
-#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
-#include <boost/geometry/strategies/side.hpp>
+
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
@@ -58,7 +64,7 @@ template
typename Turns,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
- typename Strategy
+ typename SideStrategy
>
inline void enrich_sort(Operations& operations,
Turns const& turns,
@@ -66,7 +72,7 @@ inline void enrich_sort(Operations& operations,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
- Strategy const& /*strategy*/)
+ SideStrategy const& strategy)
{
std::sort(boost::begin(operations),
boost::end(operations),
@@ -76,8 +82,9 @@ inline void enrich_sort(Operations& operations,
typename boost::range_value<Operations>::type,
Geometry1, Geometry2,
RobustPolicy,
+ SideStrategy,
Reverse1, Reverse2
- >(turns, for_operation, geometry1, geometry2, robust_policy));
+ >(turns, for_operation, geometry1, geometry2, robust_policy, strategy));
}
@@ -145,7 +152,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
it != boost::end(operations);
++it)
{
- op_type& op = turns[it->turn_index]
+ op_type const& op = turns[it->turn_index]
.operations[it->operation_index];
std::cout << it->turn_index
@@ -171,9 +178,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
template <typename Turns, typename MappedVector>
-inline void create_map(Turns const& turns,
- detail::overlay::operation_type for_operation,
- MappedVector& mapped_vector)
+inline void create_map(Turns const& turns, MappedVector& mapped_vector)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::container_type container_type;
@@ -195,15 +200,6 @@ inline void create_map(Turns const& turns,
continue;
}
- if (for_operation == operation_intersection
- && turn.cluster_id == -1
- && turn.both(operation_union))
- {
- // Only include uu turns if part of cluster (to block potential paths),
- // otherwise they can block possibly viable paths
- continue;
- }
-
std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(turn.operations);
@@ -225,6 +221,56 @@ inline void create_map(Turns const& turns,
}
}
+template <typename Point1, typename Point2>
+inline typename geometry::coordinate_type<Point1>::type
+ distance_measure(Point1 const& a, Point2 const& b)
+{
+ // TODO: use comparable distance for point-point instead - but that
+ // causes currently cycling include problems
+ typedef typename geometry::coordinate_type<Point1>::type ctype;
+ ctype const dx = get<0>(a) - get<0>(b);
+ ctype const dy = get<1>(a) - get<1>(b);
+ return dx * dx + dy * dy;
+}
+
+template <typename Turns>
+inline void calculate_remaining_distance(Turns& turns)
+{
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type op_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ turn_type& turn = *it;
+ if (! turn.both(detail::overlay::operation_continue))
+ {
+ continue;
+ }
+
+ op_type& op0 = turn.operations[0];
+ op_type& op1 = turn.operations[1];
+
+ if (op0.remaining_distance != 0
+ || op1.remaining_distance != 0)
+ {
+ continue;
+ }
+
+ int const to_index0 = op0.enriched.get_next_turn_index();
+ int const to_index1 = op1.enriched.get_next_turn_index();
+ if (to_index1 >= 0
+ && to_index1 >= 0
+ && to_index0 != to_index1)
+ {
+ op0.remaining_distance = distance_measure(turn.point, turns[to_index0].point);
+ op1.remaining_distance = distance_measure(turn.point, turns[to_index1].point);
+ }
+ }
+}
+
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
@@ -239,7 +285,7 @@ inline void create_map(Turns const& turns,
\tparam Clusters type of cluster container
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
-\tparam Strategy side strategy type
+\tparam SideStrategy side strategy type
\param turns container containing intersection points
\param clusters container containing clusters
\param geometry1 \param_geometry
@@ -255,16 +301,21 @@ template
typename Clusters,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
- typename Strategy
+ typename SideStrategy
>
inline void enrich_intersection_points(Turns& turns,
Clusters& clusters,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
- Strategy const& strategy)
+ SideStrategy const& strategy)
{
- static const detail::overlay::operation_type for_operation
+ static const detail::overlay::operation_type target_operation
= detail::overlay::operation_from_overlay<OverlayType>::value;
+ static const detail::overlay::operation_type opposite_operation
+ = target_operation == detail::overlay::operation_union
+ ? detail::overlay::operation_intersection
+ : detail::overlay::operation_union;
+
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef detail::overlay::indexed_turn_operation
@@ -278,27 +329,68 @@ inline void enrich_intersection_points(Turns& turns,
std::vector<indexed_turn_operation>
> mapped_vector_type;
+ bool has_cc = false;
bool const has_colocations
- = detail::overlay::handle_colocations<Reverse1, Reverse2>(turns,
+ = detail::overlay::handle_colocations<Reverse1, Reverse2, OverlayType>(turns,
clusters, geometry1, geometry2);
- // Discard none turns, if any
+ // Discard turns not part of target overlay
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
- if (it->both(detail::overlay::operation_none))
+ turn_type& turn = *it;
+
+ if (turn.both(detail::overlay::operation_none))
+ {
+ turn.discarded = true;
+ continue;
+ }
+
+ if (turn.both(opposite_operation))
{
- it->discarded = true;
+ // For intersections, remove uu to avoid the need to travel
+ // a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33)
+ // Also, for union, discard ii
+ turn.discarded = true;
+ turn.cluster_id = -1;
+ continue;
+ }
+
+ if (detail::overlay::is_self_turn<OverlayType>(turn)
+ && turn.cluster_id < 0
+ && ! turn.both(target_operation))
+ {
+ // Only keep self-uu-turns or self-ii-turns
+ turn.discarded = true;
+ turn.cluster_id = -1;
+ continue;
+ }
+
+ if (! turn.discarded
+ && turn.both(detail::overlay::operation_continue))
+ {
+ has_cc = true;
}
}
+ detail::overlay::discard_closed_turns
+ <
+ OverlayType,
+ target_operation
+ >::apply(turns, geometry1, geometry2);
+ detail::overlay::discard_open_turns
+ <
+ OverlayType,
+ target_operation
+ >::apply(turns, geometry1, geometry2);
+
// Create a map of vectors of indexed operation-types to be able
// to sort intersection points PER RING
mapped_vector_type mapped_vector;
- detail::overlay::create_map(turns, for_operation, mapped_vector);
+ detail::overlay::create_map(turns, mapped_vector);
// No const-iterator; contents of mapped copy is temporary,
// and changed by enrich
@@ -312,7 +404,7 @@ inline void enrich_intersection_points(Turns& turns,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<Reverse1, Reverse2>(
- mit->second, turns, for_operation,
+ mit->second, turns, target_operation,
geometry1, geometry2,
robust_policy, strategy);
}
@@ -331,8 +423,22 @@ inline void enrich_intersection_points(Turns& turns,
if (has_colocations)
{
- detail::overlay::gather_cluster_properties<Reverse1, Reverse2>(
- clusters, turns, for_operation, geometry1, geometry2);
+ // First gather cluster properties (using even clusters with
+ // discarded turns - for open turns), then clean up clusters
+ detail::overlay::gather_cluster_properties
+ <
+ Reverse1,
+ Reverse2,
+ OverlayType
+ >(clusters, turns, target_operation,
+ geometry1, geometry2, strategy);
+
+ detail::overlay::cleanup_clusters(turns, clusters);
+ }
+
+ if (has_cc)
+ {
+ detail::overlay::calculate_remaining_distance(turns);
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
index 2643415343..fdffd665e4 100644
--- a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
@@ -37,10 +37,17 @@ struct enrichment_info
, startable(true)
, count_left(0)
, count_right(0)
+ , rank(-1)
, zone(-1)
- , only_turn_on_ring(false)
+ , region_id(-1)
+ , isolated(false)
{}
+ inline signed_size_type get_next_turn_index() const
+ {
+ return next_ip_index == -1 ? travels_to_ip_index : next_ip_index;
+ }
+
// vertex to which is free travel after this IP,
// so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
// can be -1
@@ -57,8 +64,10 @@ struct enrichment_info
// Counts if polygons left/right of this operation
std::size_t count_left;
std::size_t count_right;
+ signed_size_type rank; // in cluster
signed_size_type zone; // open zone, in cluster
- bool only_turn_on_ring; // True if it is the only turn on a ring (for clusters)
+ signed_size_type region_id;
+ bool isolated;
};
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
index 22807b5140..589e12cc2b 100644
--- a/boost/geometry/algorithms/detail/overlay/follow.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -2,10 +2,10 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
-
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -55,21 +55,14 @@ template
typename Turn,
typename Operation,
typename LineString,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool last_covered_by(Turn const& turn, Operation const& op,
- LineString const& linestring, Polygon const& polygon)
+ LineString const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
- // Check any point between the this one and the first IP
- typedef typename geometry::point_type<LineString>::type point_type;
- point_type point_in_between;
- detail::point_on_border::midpoint_helper
- <
- point_type,
- 0, dimension<point_type>::value
- >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
-
- return geometry::covered_by(point_in_between, polygon);
+ return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
}
@@ -78,17 +71,19 @@ template
typename Turn,
typename Operation,
typename LineString,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool is_leaving(Turn const& turn, Operation const& op,
bool entered, bool first,
- LineString const& linestring, Polygon const& polygon)
+ LineString const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
if (op.operation == operation_union)
{
return entered
|| turn.method == method_crosses
- || (first && last_covered_by(turn, op, linestring, polygon))
+ || (first && last_covered_by(turn, op, linestring, polygon, strategy))
;
}
return false;
@@ -100,11 +95,13 @@ template
typename Turn,
typename Operation,
typename LineString,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool is_staying_inside(Turn const& turn, Operation const& op,
bool entered, bool first,
- LineString const& linestring, Polygon const& polygon)
+ LineString const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
if (turn.method == method_crosses)
{
@@ -115,7 +112,7 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op,
if (is_entering(turn, op))
{
- return entered || (first && last_covered_by(turn, op, linestring, polygon));
+ return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy));
}
return false;
@@ -126,14 +123,16 @@ template
typename Turn,
typename Operation,
typename Linestring,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
- Linestring const& linestring, Polygon const& polygon)
+ Linestring const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
if (first && (turn.method == method_collinear || turn.method == method_equal))
{
- return last_covered_by(turn, op, linestring, polygon);
+ return last_covered_by(turn, op, linestring, polygon, strategy);
}
return false;
}
@@ -158,6 +157,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -165,6 +165,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type , Point const& point,
Operation const& operation,
+ SideStrategy const& ,
RobustPolicy const& ,
OutputIterator& )
{
@@ -181,6 +182,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -188,6 +190,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& ,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
@@ -196,7 +199,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
detail::copy_segments::copy_segments_linestring
<
false, RemoveSpikes
- >::apply(linestring, segment_id, index, robust_policy, current_piece);
+ >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
if (::boost::size(current_piece) > 1)
{
@@ -235,17 +238,9 @@ struct action_selector<overlay_intersection, RemoveSpikes>
return entered;
}
- template
- <
- typename Point,
- typename Geometry,
- typename RobustPolicy
- >
- static inline bool included(Point const& point,
- Geometry const& geometry,
- RobustPolicy const& )
+ static inline bool included(int inside_value)
{
- return geometry::covered_by(point, geometry);
+ return inside_value >= 0; // covered_by
}
};
@@ -263,6 +258,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -270,11 +266,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::leave(current_piece, linestring, segment_id, index,
- point, operation, robust_policy, out);
+ point, operation, strategy, robust_policy, out);
}
template
@@ -284,6 +281,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -291,11 +289,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
- point, operation, robust_policy, out);
+ point, operation, strategy, robust_policy, out);
}
template
@@ -319,17 +318,9 @@ struct action_selector<overlay_difference, RemoveSpikes>
return ! normal_action::is_entered(entered);
}
- template
- <
- typename Point,
- typename Geometry,
- typename RobustPolicy
- >
- static inline bool included(Point const& point,
- Geometry const& geometry,
- RobustPolicy const& robust_policy)
+ static inline bool included(int inside_value)
{
- return ! normal_action::included(point, geometry, robust_policy);
+ return ! normal_action::included(inside_value);
}
};
@@ -403,33 +394,27 @@ class follow
public :
- template
- <
- typename Point,
- typename Geometry,
- typename RobustPolicy
- >
- static inline bool included(Point const& point,
- Geometry const& geometry,
- RobustPolicy const& robust_policy)
+ static inline bool included(int inside_value)
{
return following::action_selector
<
OverlayType, RemoveSpikes
- >::included(point, geometry, robust_policy);
+ >::included(inside_value);
}
template
<
typename Turns,
typename OutputIterator,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
Turns& turns,
RobustPolicy const& robust_policy,
- OutputIterator out)
+ OutputIterator out,
+ Strategy const& strategy)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -440,6 +425,12 @@ public :
typedef following::action_selector<OverlayType, RemoveSpikes> action;
+ typename Strategy::template point_in_geometry_strategy
+ <
+ LineString, Polygon
+ >::type const pt_in_poly_strategy
+ = strategy.template get_point_in_geometry_strategy<LineString, Polygon>();
+
// Sort intersection points on segments-along-linestring, and distance
// (like in enrich is done for poly/poly)
std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
@@ -454,13 +445,13 @@ public :
{
turn_operation_iterator_type iit = boost::begin(it->operations);
- if (following::was_entered(*it, *iit, first, linestring, polygon))
+ if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Was entered");
entered = true;
}
- if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
+ if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Staying inside");
@@ -473,17 +464,17 @@ public :
entered = true;
action::enter(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
- robust_policy,
+ strategy, robust_policy,
out);
}
- else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
+ else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
action::leave(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
- robust_policy,
+ strategy, robust_policy,
out);
}
first = false;
@@ -497,7 +488,7 @@ public :
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
- robust_policy,
+ strategy, robust_policy,
current_piece);
}
diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
index c249ff57ff..2a374bf0b0 100644
--- a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
@@ -2,12 +2,14 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
-// Copyright (c) 2014-2015, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
-// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
@@ -183,7 +185,8 @@ protected:
typename TurnIterator,
typename TurnOperationIterator,
typename SegmentIdentifier,
- typename OutputIterator
+ typename OutputIterator,
+ typename SideStrategy
>
static inline OutputIterator
process_turn(TurnIterator it,
@@ -193,7 +196,8 @@ protected:
Linestring const& linestring,
LinestringOut& current_piece,
SegmentIdentifier& current_segment_id,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
// We don't rescale linear/linear
detail::no_rescale_policy robust_policy;
@@ -208,7 +212,7 @@ protected:
action::enter(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
- it->point, *op_it, robust_policy, oit);
+ it->point, *op_it, strategy, robust_policy, oit);
}
++enter_count;
}
@@ -223,7 +227,7 @@ protected:
action::leave(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
- it->point, *op_it, robust_policy, oit);
+ it->point, *op_it, strategy, robust_policy, oit);
}
}
else if ( FollowIsolatedPoints
@@ -249,14 +253,16 @@ protected:
template
<
typename SegmentIdentifier,
- typename OutputIterator
+ typename OutputIterator,
+ typename SideStrategy
>
static inline OutputIterator
process_end(bool entered,
Linestring const& linestring,
SegmentIdentifier const& current_segment_id,
LinestringOut& current_piece,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
if ( action::is_entered(entered) )
{
@@ -269,6 +275,7 @@ protected:
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
+ strategy,
robust_policy,
current_piece);
}
@@ -283,11 +290,12 @@ protected:
}
public:
- template <typename TurnIterator, typename OutputIterator>
+ template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(Linestring const& linestring, Linear const&,
TurnIterator first, TurnIterator beyond,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
// Iterate through all intersection points (they are
// ordered along the each line)
@@ -304,7 +312,8 @@ public:
entered, enter_count,
linestring,
current_piece, current_segment_id,
- oit);
+ oit,
+ strategy);
}
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
@@ -318,7 +327,8 @@ public:
return process_end(entered, linestring,
current_segment_id, current_piece,
- oit);
+ oit,
+ strategy);
}
};
@@ -413,11 +423,12 @@ protected:
};
public:
- template <typename TurnIterator, typename OutputIterator>
+ template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(MultiLinestring const& multilinestring, Linear const& linear,
TurnIterator first, TurnIterator beyond,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
BOOST_GEOMETRY_ASSERT( first != beyond );
@@ -447,7 +458,7 @@ public:
has_other_multi_id(current_multi_id));
oit = Base::apply(*(ls_first + current_multi_id),
- linear, per_ls_current, per_ls_next, oit);
+ linear, per_ls_current, per_ls_next, oit, strategy);
signed_size_type next_multi_id = -1;
linestring_iterator ls_next = ls_beyond;
diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
index ea9aa29f19..2eec6af665 100644
--- a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -31,20 +36,15 @@ namespace detail { namespace overlay
but we still need to know which comes first.
Therefore, it is useful that using sides we are able to discover this.
*/
-template <typename Point1>
struct get_relative_order
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point1>::type
- >::type strategy;
-
- template <typename Point>
+ template <typename Point, typename SideStrategy>
static inline int value_via_product(Point const& ti, Point const& tj,
- Point const& ui, Point const& uj, int factor)
+ Point const& ui, Point const& uj, int factor,
+ SideStrategy const& strategy)
{
- int const side_ti_u = strategy::apply(ti, tj, ui);
- int const side_tj_u = strategy::apply(ti, tj, uj);
+ int const side_ti_u = strategy.apply(ti, tj, ui);
+ int const side_tj_u = strategy.apply(ti, tj, uj);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
std::cout << (factor == 1 ? " r//s " : " s//r ")
@@ -57,13 +57,15 @@ struct get_relative_order
}
+ template <typename Point1, typename SideStrategy>
static inline int apply(
Point1 const& pi, Point1 const& pj,
Point1 const& ri, Point1 const& rj,
- Point1 const& si, Point1 const& sj)
+ Point1 const& si, Point1 const& sj,
+ SideStrategy const& strategy)
{
- int const side_ri_p = strategy::apply(pi, pj, ri);
- int const side_si_p = strategy::apply(pi, pj, si);
+ int const side_ri_p = strategy.apply(pi, pj, ri);
+ int const side_si_p = strategy.apply(pi, pj, si);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
int const side_rj_p = strategy::apply(pi, pj, rj);
@@ -72,10 +74,10 @@ struct get_relative_order
std::cout << " s//p: " << side_si_p << " / " << side_sj_p;
#endif
- int value = value_via_product(si, sj, ri, rj, 1);
+ int value = value_via_product(si, sj, ri, rj, 1, strategy);
if (value == 0)
{
- value = value_via_product(ri, rj, si, sj, -1);
+ value = value_via_product(ri, rj, si, sj, -1, strategy);
}
int const order = side_ri_p * side_ri_p * side_si_p * value;
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index 08bc342186..895952c8fc 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -190,6 +190,7 @@ struct touch_interior : public base_turn_handler
// Q turns left on the right side of P (test "MR3")
// Both directions for "intersection"
both(ti, operation_intersection);
+ ti.touch_only = true;
}
else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
{
@@ -197,6 +198,7 @@ struct touch_interior : public base_turn_handler
// Union: take both operation
// Intersection: skip
both(ti, operation_union);
+ ti.touch_only = true;
}
else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
{
@@ -207,6 +209,7 @@ struct touch_interior : public base_turn_handler
unsigned int index = side_qk_q == 1 ? index_q : index_p;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
+ ti.touch_only = true;
}
else if (side_qk_p == 0)
{
@@ -346,6 +349,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == -side_qk_q)
{
ui_else_iu(! q_turns_left, ti);
+ ti.touch_only = true;
return;
}
@@ -358,6 +362,10 @@ struct touch : public base_turn_handler
{
ti.operations[1].operation = operation_blocked;
}
+ else
+ {
+ ti.touch_only = true;
+ }
//block_second(block_q, ti);
return;
}
@@ -373,6 +381,10 @@ struct touch : public base_turn_handler
: side_qi_p1 == 1 || side_qk_p1 == 1
? operation_union
: operation_intersection;
+ if (! block_q)
+ {
+ ti.touch_only = true;
+ }
return;
}
@@ -400,6 +412,7 @@ struct touch : public base_turn_handler
if (side_pk_q1 == side_qk_p1)
{
uu_else_ii(right_to_left, ti);
+ ti.touch_only = true;
return;
}
}
@@ -418,6 +431,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == side_qk_p1)
{
ui_else_iu(right_to_left, ti);
+ ti.touch_only = true;
return;
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
index 5f2cb07faf..f8247cd240 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -66,7 +66,7 @@ struct side_calculator
Qj const& m_qj;
Qk const& m_qk;
- SideStrategy const& m_side_strategy;
+ SideStrategy m_side_strategy;
};
template <typename Point1, typename Point2, typename RobustPolicy>
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index 4e97a84a37..f88dfe8422 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2016, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
@@ -90,6 +90,9 @@ struct no_interrupt_policy
{
static bool const enabled = false;
+ // variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
template <typename Range>
static inline bool apply(Range const&)
{
@@ -230,7 +233,7 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
- it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
+ it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
@@ -248,7 +251,7 @@ public :
next2++;
for (prev2 = it2++, next2++;
- it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
+ it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -356,7 +359,7 @@ private :
// skips to the begin-point, we loose the index or have to recalculate it)
// So we mimic it here
template <typename Range, typename Section, typename Box, typename RobustPolicy>
- static inline void get_start_point_iterator(Section & section,
+ static inline void get_start_point_iterator(Section const& section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
@@ -370,7 +373,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
- for(; it != end && detail::section::preceding<0>(dir, *it, other_bounding_box, robust_policy);
+ for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -418,6 +421,7 @@ struct section_visitor
{
if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box))
{
+ // false if interrupted
return get_turns_in_sections
<
Geometry1,
@@ -425,13 +429,12 @@ struct section_visitor
Reverse1, Reverse2,
Section, Section,
TurnPolicy
- >::apply(
- m_source_id1, m_geometry1, sec1,
- m_source_id2, m_geometry2, sec2,
- false,
- m_intersection_strategy,
- m_rescale_policy,
- m_turns, m_interrupt_policy);
+ >::apply(m_source_id1, m_geometry1, sec1,
+ m_source_id2, m_geometry2, sec2,
+ false,
+ m_intersection_strategy,
+ m_rescale_policy,
+ m_turns, m_interrupt_policy);
}
return true;
}
@@ -473,10 +476,13 @@ public:
sections_type sec1, sec2;
typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
+ typename IntersectionStrategy::envelope_strategy_type const
+ envelope_strategy = intersection_strategy.get_envelope_strategy();
+
geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
- sec1, 0);
+ sec1, envelope_strategy, 0);
geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
- sec2, 1);
+ sec2, envelope_strategy, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
diff --git a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
index 400ed3b881..f3311b34e9 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -262,15 +267,6 @@ inline void handle_colocation_cluster(Turns& turns,
add_cluster_id(other_op, cluster_per_segment, ref_id);
id = ref_id;
}
-
- // In case of colocated xx turns, all other turns may NOT be
- // followed at all. xx cannot be discarded (otherwise colocated
- // turns are followed).
- if (ref_turn.both(operation_blocked))
- {
- turn.discarded = true;
- // We can either set or not set colocated because it is not effective on blocked turns
- }
}
else
{
@@ -331,11 +327,7 @@ inline void assign_cluster_to_turns(Turns& turns,
}
}
-template
-<
- typename Turns,
- typename Clusters
->
+template <typename Turns, typename Clusters>
inline void remove_clusters(Turns& turns, Clusters& clusters)
{
typename Clusters::iterator it = clusters.begin();
@@ -350,17 +342,44 @@ inline void remove_clusters(Turns& turns, Clusters& clusters)
= current_it->second.turn_indices;
if (turn_indices.size() == 1)
{
- signed_size_type turn_index = *turn_indices.begin();
+ signed_size_type const turn_index = *turn_indices.begin();
turns[turn_index].cluster_id = -1;
clusters.erase(current_it);
}
}
}
+template <typename Turns, typename Clusters>
+inline void cleanup_clusters(Turns& turns, Clusters& clusters)
+{
+ // Removes discarded turns from clusters
+ for (typename Clusters::iterator mit = clusters.begin();
+ mit != clusters.end(); ++mit)
+ {
+ cluster_info& cinfo = mit->second;
+ std::set<signed_size_type>& ids = cinfo.turn_indices;
+ for (std::set<signed_size_type>::iterator sit = ids.begin();
+ sit != ids.end(); /* no increment */)
+ {
+ std::set<signed_size_type>::iterator current_it = sit;
+ ++sit;
+
+ signed_size_type const turn_index = *current_it;
+ if (turns[turn_index].discarded)
+ {
+ ids.erase(current_it);
+ }
+ }
+ }
+
+ remove_clusters(turns, clusters);
+}
+
template <typename Turn, typename IdSet>
inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id)
{
turn.discarded = true;
+ // Set cluster id to -1, but don't clear colocated flags
turn.cluster_id = -1;
// To remove it later from clusters
ids.insert(id);
@@ -378,6 +397,13 @@ inline bool is_ie_turn(segment_identifier const& ext_seg_0,
segment_identifier const& int_seg_0,
segment_identifier const& other_seg_1)
{
+ if (ext_seg_0.source_index == ext_seg_1.source_index)
+ {
+ // External turn is a self-turn, dont discard internal turn for this
+ return false;
+ }
+
+
// Compares two segment identifiers from two turns (external / one internal)
// From first turn [0], both are from same polygon (multi_index),
@@ -411,6 +437,7 @@ inline bool is_ie_turn(segment_identifier const& ext_seg_0,
template
<
bool Reverse0, bool Reverse1, // Reverse interpretation interior/exterior
+ overlay_type OverlayType,
typename Turns,
typename Clusters
>
@@ -435,19 +462,6 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
segment_identifier const& seg_0 = turn.operations[0].seg_id;
segment_identifier const& seg_1 = turn.operations[1].seg_id;
- if (turn.both(operation_intersection)
- && Reverse0 == Reverse1)
- {
- if ( is_interior<Reverse0>(seg_0)
- && is_interior<Reverse1>(seg_1))
- {
- // ii touch with, two interior rings
- discard_ie_turn(turn, ids_to_remove, *it);
- }
-
- continue;
- }
-
if (! (turn.both(operation_union)
|| turn.combination(operation_union, operation_blocked)))
{
@@ -487,6 +501,53 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
}
}
+template
+<
+ typename Turns,
+ typename Clusters
+>
+inline void set_colocation(Turns& turns, Clusters const& clusters)
+{
+ typedef std::set<signed_size_type>::const_iterator set_iterator;
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ for (typename Clusters::const_iterator cit = clusters.begin();
+ cit != clusters.end(); ++cit)
+ {
+ cluster_info const& cinfo = cit->second;
+ std::set<signed_size_type> const& ids = cinfo.turn_indices;
+
+ bool has_ii = false;
+ bool has_uu = false;
+ for (set_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ turn_type const& turn = turns[*it];
+ if (turn.both(operation_intersection))
+ {
+ has_ii = true;
+ }
+ if (turn.both(operation_union) || turn.combination(operation_union, operation_blocked))
+ {
+ has_uu = true;
+ }
+ }
+ if (has_ii || has_uu)
+ {
+ for (set_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ turn_type& turn = turns[*it];
+ if (has_ii)
+ {
+ turn.colocated_ii = true;
+ }
+ if (has_uu)
+ {
+ turn.colocated_uu = true;
+ }
+ }
+ }
+ }
+}
// Checks colocated turns and flags combinations of uu/other, possibly a
// combination of a ring touching another geometry's interior ring which is
@@ -498,6 +559,7 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
template
<
bool Reverse1, bool Reverse2,
+ overlay_type OverlayType,
typename Turns,
typename Clusters,
typename Geometry1,
@@ -578,12 +640,13 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
}
assign_cluster_to_turns(turns, clusters, cluster_per_segment);
+ set_colocation(turns, clusters);
discard_interior_exterior_turns
<
do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse1,
- do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2
+ do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2,
+ OverlayType
>(turns, clusters);
- remove_clusters(turns, clusters);
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
std::cout << "*** Colocations " << map.size() << std::endl;
@@ -598,7 +661,8 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
std::cout << geometry::wkt(turns[toi.turn_index].point)
<< std::boolalpha
<< " discarded=" << turns[toi.turn_index].discarded
- << " colocated=" << turns[toi.turn_index].colocated
+ << " colocated(uu)=" << turns[toi.turn_index].colocated_uu
+ << " colocated(ii)=" << turns[toi.turn_index].colocated_ii
<< " " << operation_char(turns[toi.turn_index].operations[0].operation)
<< " " << turns[toi.turn_index].operations[0].seg_id
<< " " << turns[toi.turn_index].operations[0].fraction
@@ -634,14 +698,17 @@ struct is_turn_index
template
<
bool Reverse1, bool Reverse2,
+ overlay_type OverlayType,
typename Turns,
typename Clusters,
typename Geometry1,
- typename Geometry2
+ typename Geometry2,
+ typename SideStrategy
>
inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
operation_type for_operation,
- Geometry1 const& geometry1, Geometry2 const& geometry2)
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ SideStrategy const& strategy)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::point_type point_type;
@@ -651,7 +718,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
// right side
typedef sort_by_side::side_sorter
<
- Reverse1, Reverse2, point_type, std::less<int>
+ Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int>
> sbs_type;
for (typename Clusters::iterator mit = clusters.begin();
@@ -664,11 +731,11 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
continue;
}
- sbs_type sbs;
+ sbs_type sbs(strategy);
point_type turn_point; // should be all the same for all turns in cluster
bool first = true;
- for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
+ for (std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
{
signed_size_type turn_index = *sit;
@@ -689,6 +756,8 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
sbs.find_open();
sbs.assign_zones(for_operation);
+ cinfo.open_count = sbs.open_count(for_operation);
+
// Unset the startable flag for all 'closed' zones
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
@@ -696,6 +765,11 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
turn_type& turn = turns[ranked.turn_index];
turn_operation_type& op = turn.operations[ranked.operation_index];
+ if (for_operation == operation_union && cinfo.open_count == 0)
+ {
+ op.enriched.startable = false;
+ }
+
if (ranked.direction != sort_by_side::dir_to)
{
continue;
@@ -703,6 +777,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
op.enriched.count_left = ranked.count_left;
op.enriched.count_right = ranked.count_right;
+ op.enriched.rank = ranked.rank;
op.enriched.zone = ranked.zone;
if ((for_operation == operation_union
@@ -714,7 +789,6 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
}
}
- cinfo.open_count = sbs.open_count(for_operation);
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
new file mode 100644
index 0000000000..39c55db759
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
@@ -0,0 +1,143 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+struct discard_turns
+{
+ template <typename Turns, typename Geometry0, typename Geometry1>
+ static inline
+ void apply(Turns& , Geometry0 const& , Geometry1 const& )
+ {}
+};
+
+template <overlay_type OverlayType, operation_type OperationType>
+struct discard_closed_turns : discard_turns {};
+
+// It is only implemented for operation_union, not in buffer
+template <>
+struct discard_closed_turns<overlay_union, operation_union>
+{
+
+ template <typename Turns, typename Geometry0, typename Geometry1>
+ static inline
+ void apply(Turns& turns,
+ Geometry0 const& geometry0, Geometry1 const& geometry1)
+ {
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ turn_type& turn = *it;
+
+ if (turn.cluster_id >= 0
+ || turn.discarded
+ || ! is_self_turn<overlay_union>(turn))
+ {
+ continue;
+ }
+
+ bool const within =
+ turn.operations[0].seg_id.source_index == 0
+ ? geometry::within(turn.point, geometry1)
+ : geometry::within(turn.point, geometry0);
+
+ if (within)
+ {
+ // It is in the interior of the other geometry
+ turn.discarded = true;
+ }
+ }
+ }
+};
+
+struct discard_self_intersection_turns
+{
+ template <typename Turns, typename Geometry0, typename Geometry1>
+ static inline
+ void apply(Turns& turns,
+ Geometry0 const& geometry0, Geometry1 const& geometry1)
+ {
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ turn_type& turn = *it;
+
+ if (turn.cluster_id >= 0
+ || turn.discarded
+ || ! is_self_turn<overlay_intersection>(turn))
+ {
+ continue;
+ }
+
+ segment_identifier const& id0 = turn.operations[0].seg_id;
+ segment_identifier const& id1 = turn.operations[1].seg_id;
+ if (id0.multi_index != id1.multi_index
+ || (id0.ring_index == -1 && id1.ring_index == -1)
+ || (id0.ring_index >= 0 && id1.ring_index >= 0))
+ {
+ // Not an ii ring (int/ext) on same ring
+ continue;
+ }
+
+ // It is a non co-located ii self-turn
+ // Check if it is within the other geometry
+ // If not, it can be ignored
+
+ bool const within =
+ turn.operations[0].seg_id.source_index == 0
+ ? geometry::within(turn.point, geometry1)
+ : geometry::within(turn.point, geometry0);
+
+ if (! within)
+ {
+ // It is not within another geometry, discard the turn
+ turn.discarded = true;
+ }
+ }
+ }
+};
+
+template <overlay_type OverlayType, operation_type OperationType>
+struct discard_open_turns : discard_turns {};
+
+// Handler it for intersection
+template <>
+struct discard_open_turns<overlay_intersection, operation_intersection>
+ : discard_self_intersection_turns {};
+
+// For difference, it should be done in a different way (TODO)
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index 3244480f48..7106e7b480 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -30,10 +30,11 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/overlay/clip_linestring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
-#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
@@ -288,6 +289,27 @@ struct intersection_of_linestring_with_areal
>::apply(boost::begin(turns), boost::end(turns));
}
+ template <typename Turns>
+ static inline int inside_or_outside_turn(Turns const& turns)
+ {
+ using namespace overlay;
+ for (typename Turns::const_iterator it = turns.begin();
+ it != turns.end(); ++it)
+ {
+ operation_type op0 = it->operations[0].operation;
+ operation_type op1 = it->operations[1].operation;
+ if (op0 == operation_intersection && op1 == operation_intersection)
+ {
+ return 1; // inside
+ }
+ else if (op0 == operation_union && op1 == operation_union)
+ {
+ return -1; // outside
+ }
+ }
+ return 0;
+ }
+
template
<
typename LineString, typename Areal,
@@ -331,19 +353,21 @@ struct intersection_of_linestring_with_areal
if (no_crossing_turns_or_empty(turns))
{
- // No intersection points, it is either completely
+ // No intersection points, it is either
// inside (interior + borders)
- // or completely outside
+ // or outside (exterior + borders)
- // Use border point (on a segment) to check this
- // (because turn points might skip some cases)
- point_type border_point;
- if (! geometry::point_on_border(border_point, linestring, true))
+ // analyse the turns
+ int inside_value = inside_or_outside_turn(turns);
+ if (inside_value == 0)
{
- return out;
+ // if needed analyse points of a linestring
+ // NOTE: range_in_geometry checks points of a linestring
+ // until a point inside/outside areal is found
+ inside_value = overlay::range_in_geometry(linestring, areal, strategy);
}
-
- if (follower::included(border_point, areal, robust_policy))
+ // add point to the output if conditions are met
+ if (inside_value != 0 && follower::included(inside_value))
{
LineStringOut copy;
geometry::convert(linestring, copy);
@@ -365,7 +389,7 @@ struct intersection_of_linestring_with_areal
(
linestring, areal,
geometry::detail::overlay::operation_intersection,
- turns, robust_policy, out
+ turns, robust_policy, out, strategy
);
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
new file mode 100644
index 0000000000..9cb7a0fca9
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
@@ -0,0 +1,68 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2017-2017 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template <overlay_type OverlayType>
+struct is_self_turn_check
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return turn.operations[0].seg_id.source_index
+ == turn.operations[1].seg_id.source_index;
+ }
+};
+
+template <>
+struct is_self_turn_check<overlay_buffer>
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return false;
+ }
+};
+
+template <>
+struct is_self_turn_check<overlay_dissolve>
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return false;
+ }
+};
+
+
+template <overlay_type OverlayType, typename Turn>
+bool is_self_turn(Turn const& turn)
+{
+ return is_self_turn_check<OverlayType>::apply(turn);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp b/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp
index 21868a2939..dd30635ee2 100644
--- a/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp
+++ b/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -60,6 +65,7 @@ template
typename Indexed,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
+ typename SideStrategy,
bool Reverse1, bool Reverse2
>
struct less_by_segment_ratio
@@ -68,12 +74,14 @@ struct less_by_segment_ratio
, operation_type for_operation
, Geometry1 const& geometry1
, Geometry2 const& geometry2
- , RobustPolicy const& robust_policy)
+ , RobustPolicy const& robust_policy
+ , SideStrategy const& strategy)
: m_turns(turns)
, m_for_operation(for_operation)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_robust_policy(robust_policy)
+ , m_strategy(strategy)
{
}
@@ -84,6 +92,7 @@ private :
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
RobustPolicy const& m_robust_policy;
+ SideStrategy const& m_strategy;
typedef typename geometry::point_type<Geometry1>::type point_type;
@@ -108,13 +117,8 @@ private :
*right.other_seg_id,
si, sj);
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<point_type>::type
- >::type strategy;
-
- int const side_rj_p = strategy::apply(pi, pj, rj);
- int const side_sj_p = strategy::apply(pi, pj, sj);
+ int const side_rj_p = m_strategy.apply(pi, pj, rj);
+ int const side_sj_p = m_strategy.apply(pi, pj, sj);
// Put the one turning left (1; right == -1) as last
if (side_rj_p != side_sj_p)
@@ -122,8 +126,8 @@ private :
return side_rj_p < side_sj_p;
}
- int const side_sj_r = strategy::apply(ri, rj, sj);
- int const side_rj_s = strategy::apply(si, sj, rj);
+ int const side_sj_r = m_strategy.apply(ri, rj, sj);
+ int const side_rj_s = m_strategy.apply(si, sj, rj);
// If they both turn left: the most left as last
// If they both turn right: this is not relevant, but take also here most left
diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
index a74bb33ba1..21d079d95c 100644
--- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
@@ -194,13 +194,15 @@ protected:
typename Turns,
typename LinearGeometry1,
typename LinearGeometry2,
- typename OutputIterator
+ typename OutputIterator,
+ typename IntersectionStrategy
>
static inline OutputIterator
sort_and_follow_turns(Turns& turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
- OutputIterator oit)
+ OutputIterator oit,
+ IntersectionStrategy const& strategy)
{
// remove turns that have no added value
turns::filter_continue_turns
@@ -228,7 +230,7 @@ protected:
FollowIsolatedPoints,
!EnableFilterContinueTurns || OverlayType == overlay_intersection
>::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
- oit);
+ oit, strategy.get_side_strategy());
}
public:
@@ -277,7 +279,7 @@ public:
OverlayType,
EnableFollowIsolatedPoints
&& OverlayType == overlay_intersection
- >(turns, linear1, linear2, oit);
+ >(turns, linear1, linear2, oit, strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index f1af2f1949..10829abd4f 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -28,9 +28,11 @@
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
@@ -87,29 +89,58 @@ struct overlay_null_visitor
{}
};
-template <typename Turns, typename TurnInfoMap>
-inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns)
+template
+<
+ overlay_type OverlayType,
+ typename TurnInfoMap,
+ typename Turns,
+ typename Clusters
+>
+inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::container_type container_type;
+ static const operation_type target_operation
+ = operation_from_overlay<OverlayType>::value;
+ static const operation_type opposite_operation
+ = target_operation == operation_union ? operation_intersection : operation_union;
+
+ signed_size_type turn_index = 0;
for (typename boost::range_iterator<Turns const>::type
it = boost::begin(turns);
it != boost::end(turns);
- ++it)
+ ++it, turn_index++)
{
- typename boost::range_value<Turns>::type const& turn_info = *it;
-
- if (turn_info.discarded
- && ! turn_info.any_blocked()
- && ! turn_info.colocated)
+ typename boost::range_value<Turns>::type const& turn = *it;
+
+ bool const colocated_target = target_operation == operation_union
+ ? turn.colocated_uu : turn.colocated_ii;
+ bool const colocated_opp = target_operation == operation_union
+ ? turn.colocated_ii : turn.colocated_uu;
+ bool const both_opposite = turn.both(opposite_operation);
+
+ bool const traversed
+ = turn.operations[0].visited.finalized()
+ || turn.operations[0].visited.rejected()
+ || turn.operations[1].visited.finalized()
+ || turn.operations[1].visited.rejected()
+ || turn.both(operation_blocked)
+ || turn.combination(opposite_operation, operation_blocked);
+
+ bool is_closed = false;
+ if (turn.cluster_id >= 0 && target_operation == operation_union)
{
- continue;
+ typename Clusters::const_iterator mit = clusters.find(turn.cluster_id);
+ BOOST_ASSERT(mit != clusters.end());
+
+ cluster_info const& cinfo = mit->second;
+ is_closed = cinfo.open_count == 0;
}
for (typename boost::range_iterator<container_type const>::type
- op_it = boost::begin(turn_info.operations);
- op_it != boost::end(turn_info.operations);
+ op_it = boost::begin(turn.operations);
+ op_it != boost::end(turn.operations);
++op_it)
{
ring_identifier const ring_id
@@ -118,7 +149,34 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns)
op_it->seg_id.multi_index,
op_it->seg_id.ring_index
);
- turn_info_map[ring_id].has_normal_turn = true;
+
+ if (traversed || is_closed || ! op_it->enriched.startable)
+ {
+ turn_info_map[ring_id].has_traversed_turn = true;
+ }
+ else if (both_opposite && colocated_target)
+ {
+ // For union: ii, colocated with a uu
+ // For example, two interior rings touch where two exterior rings also touch.
+ // The interior rings are not yet traversed, and should be taken from the input
+
+ // For intersection: uu, colocated with an ii
+ // unless it is two interior inner rings colocated with a uu
+
+ // So don't set has_traversed_turn here
+ }
+ else if (both_opposite && ! is_self_turn<OverlayType>(turn))
+ {
+ // For union, mark any ring with a ii turn as traversed
+ // For intersection, any uu - but not if it is a self-turn
+ turn_info_map[ring_id].has_traversed_turn = true;
+ }
+ else if (colocated_opp && ! colocated_target)
+ {
+ // For union, a turn colocated with ii and NOT with uu/ux
+ // For intersection v.v.
+ turn_info_map[ring_id].has_traversed_turn = true;
+ }
}
}
}
@@ -128,18 +186,27 @@ template
<
typename GeometryOut, overlay_type OverlayType, bool ReverseOut,
typename Geometry1, typename Geometry2,
- typename OutputIterator
+ typename OutputIterator, typename Strategy
>
inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
Geometry2 const& geometry2,
- OutputIterator out)
+ OutputIterator out, Strategy const& strategy)
{
typedef std::deque
<
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
- typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+ typedef typename geometry::point_type<Geometry1>::type point_type1;
+
+ typedef ring_properties
+ <
+ point_type1,
+ typename Strategy::template area_strategy
+ <
+ point_type1
+ >::type::return_type
+ > properties;
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
@@ -164,9 +231,9 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
std::map<ring_identifier, ring_turn_info> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
- select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them);
+ select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
ring_container_type rings;
- assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
+ assign_parents(geometry1, geometry2, rings, all_of_one_of_them, strategy);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
}
@@ -201,7 +268,7 @@ struct overlay
return return_if_one_input_is_empty
<
GeometryOut, OverlayType, ReverseOut
- >(geometry1, geometry2, out);
+ >(geometry1, geometry2, out, strategy);
}
typedef typename geometry::point_type<GeometryOut>::type point_type;
@@ -238,10 +305,20 @@ std::cout << "get turns" << std::endl;
visitor.visit_turns(1, turns);
+#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
+ {
+ self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
+ strategy, robust_policy, turns, policy, 0);
+ self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
+ strategy, robust_policy, turns, policy, 1);
+ }
+#endif
+
+
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
- typename Strategy::side_strategy_type side_strategy;
+ typename Strategy::side_strategy_type side_strategy = strategy.get_side_strategy();
cluster_type clusters;
geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(turns,
@@ -271,33 +348,38 @@ std::cout << "traverse" << std::endl;
);
std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
- get_ring_turn_info(turn_info_per_ring, turns);
+ get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters);
+
+ typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type;
typedef ring_properties
- <
- typename geometry::point_type<GeometryOut>::type
- > properties;
+ <
+ point_type,
+ typename area_strategy_type::return_type
+ > properties;
// Select all rings which are NOT touched by any intersection point
std::map<ring_identifier, properties> selected_ring_properties;
select_rings<OverlayType>(geometry1, geometry2, turn_info_per_ring,
- selected_ring_properties);
+ selected_ring_properties, strategy);
// Add rings created during traversal
{
+ area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
+
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
it != boost::end(rings);
++it)
{
- selected_ring_properties[id] = properties(*it);
+ selected_ring_properties[id] = properties(*it, area_strategy);
selected_ring_properties[id].reversed = ReverseOut;
id.multi_index++;
}
}
- assign_parents(geometry1, geometry2, rings, selected_ring_properties);
+ assign_parents(geometry1, geometry2, rings, selected_ring_properties, strategy);
return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
index a26f54e008..0a7c3bc469 100644
--- a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
@@ -1,5 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
+
// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -127,25 +129,57 @@ class multipoint_linear_point
{
private:
// structs for partition -- start
- struct expand_box
+ struct expand_box_point
{
- template <typename Box, typename Geometry>
- static inline void apply(Box& total, Geometry const& geometry)
+ template <typename Box, typename Point>
+ static inline void apply(Box& total, Point const& point)
{
- geometry::expand(total, geometry::return_envelope<Box>(geometry));
+ geometry::expand(total, point);
}
+ };
+
+ template <typename EnvelopeStrategy>
+ struct expand_box_segment
+ {
+ explicit expand_box_segment(EnvelopeStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+ template <typename Box, typename Segment>
+ inline void apply(Box& total, Segment const& segment) const
+ {
+ geometry::expand(total,
+ geometry::return_envelope<Box>(segment, m_strategy));
+ }
+
+ EnvelopeStrategy const& m_strategy;
};
- struct overlaps_box
+ struct overlaps_box_point
{
- template <typename Box, typename Geometry>
- static inline bool apply(Box const& box, Geometry const& geometry)
+ template <typename Box, typename Point>
+ static inline bool apply(Box const& box, Point const& point)
{
- return ! geometry::disjoint(geometry, box);
+ return ! geometry::disjoint(point, box);
}
};
+ template <typename DisjointStrategy>
+ struct overlaps_box_segment
+ {
+ explicit overlaps_box_segment(DisjointStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Box, typename Segment>
+ inline bool apply(Box const& box, Segment const& segment) const
+ {
+ return ! geometry::disjoint(segment, box, m_strategy);
+ }
+
+ DisjointStrategy const& m_strategy;
+ };
+
template <typename OutputIterator, typename Strategy>
class item_visitor_type
{
@@ -156,12 +190,14 @@ private:
{}
template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ inline bool apply(Item1 const& item1, Item2 const& item2)
{
action_selector_pl_l
<
PointOut, overlay_intersection
>::apply(item1, Policy::apply(item1, item2, m_strategy), m_oit);
+
+ return true;
}
private:
@@ -202,16 +238,25 @@ private:
{
item_visitor_type<OutputIterator, Strategy> item_visitor(oit, strategy);
- segment_range rng(linear);
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type;
+ // TODO: disjoint Segment/Box may be called in partition multiple times
+ // possibly for non-cartesian segments which could be slow. We should consider
+ // passing a range of bounding boxes of segments after calculating them once.
+ // Alternatively instead of a range of segments a range of Segment/Envelope pairs
+ // should be passed, where envelope would be lazily calculated when needed the first time
geometry::partition
<
geometry::model::box
<
typename boost::range_value<MultiPoint>::type
>
- >::apply(multipoint, rng, item_visitor,
- expand_box(), overlaps_box());
+ >::apply(multipoint, segment_range(linear), item_visitor,
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()),
+ overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy()));
return oit;
}
diff --git a/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp b/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp
new file mode 100644
index 0000000000..d4a47abecf
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp
@@ -0,0 +1,178 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP
+
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type
+>
+struct points_range
+{
+ typedef geometry::point_iterator<Geometry const> iterator_type;
+
+ explicit points_range(Geometry const& geometry)
+ : m_geometry(geometry)
+ {}
+
+ iterator_type begin() const
+ {
+ return geometry::points_begin(m_geometry);
+ }
+
+ iterator_type end() const
+ {
+ return geometry::points_end(m_geometry);
+ }
+
+ Geometry const& m_geometry;
+};
+// Specialized because point_iterator doesn't support boxes
+template <typename Box>
+struct points_range<Box, box_tag>
+{
+ typedef typename geometry::point_type<Box>::type point_type;
+ typedef const point_type * iterator_type;
+
+ explicit points_range(Box const& box)
+ {
+ detail::assign_box_corners(box,
+ m_corners[0], m_corners[1], m_corners[2], m_corners[3]);
+ }
+
+ iterator_type begin() const
+ {
+ return m_corners;
+ }
+
+ iterator_type end() const
+ {
+ return m_corners + 4;
+ }
+
+ point_type m_corners[4];
+};
+
+template
+<
+ typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type
+>
+struct point_in_geometry_helper
+{
+ template <typename Point, typename Strategy>
+ static inline int apply(Point const& point, Geometry const& geometry,
+ Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(point, geometry, strategy);
+ }
+};
+// Specialized because point_in_geometry doesn't support Boxes
+template <typename Box>
+struct point_in_geometry_helper<Box, box_tag>
+{
+ template <typename Point, typename Strategy>
+ static inline int apply(Point const& point, Box const& box,
+ Strategy const&)
+ {
+ return geometry::covered_by(point, box) ? 1 : -1;
+ }
+};
+
+// This function returns
+// when it finds a point of geometry1 inside or outside geometry2
+template <typename Geometry1, typename Geometry2, typename Strategy>
+static inline int range_in_geometry(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy,
+ bool skip_first = false)
+{
+ int result = 0;
+ points_range<Geometry1> points(geometry1);
+ typedef typename points_range<Geometry1>::iterator_type iterator_type;
+ iterator_type const end = points.end();
+ iterator_type it = points.begin();
+ if (it == end)
+ {
+ return result;
+ }
+ else if (skip_first)
+ {
+ ++it;
+ }
+
+ typename Strategy::template point_in_geometry_strategy
+ <
+ Geometry1, Geometry2
+ >::type const in_strategy
+ = strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>();
+
+ for ( ; it != end; ++it)
+ {
+ result = point_in_geometry_helper<Geometry2>::apply(*it, geometry2, in_strategy);
+ if (result != 0)
+ {
+ return result;
+ }
+ }
+ // all points contained entirely by the boundary
+ return result;
+}
+
+// This function returns if first_point1 is inside or outside geometry2 or
+// when it finds a point of geometry1 inside or outside geometry2
+template <typename Point1, typename Geometry1, typename Geometry2, typename Strategy>
+inline int range_in_geometry(Point1 const& first_point1,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ // check a point on border of geometry1 first
+ int result = point_in_geometry_helper<Geometry2>::apply(first_point1, geometry2,
+ strategy.template get_point_in_geometry_strategy<Point1, Geometry2>());
+ if (result == 0)
+ {
+ // if a point is on boundary of geometry2
+ // check points of geometry1 until point inside/outside is found
+ // NOTE: skip first point because it should be already tested above
+ result = range_in_geometry(geometry1, geometry2, strategy, true);
+ }
+ return result;
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
index 0f2da67b62..7dbc5d5fab 100644
--- a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
+++ b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
@@ -2,6 +2,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -23,11 +27,11 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
-template <typename Point>
+template <typename Point, typename AreaType>
struct ring_properties
{
typedef Point point_type;
- typedef typename default_area_result<Point>::type area_type;
+ typedef AreaType area_type;
bool valid;
@@ -52,17 +56,14 @@ struct ring_properties
, parent_area(-1)
{}
- template <typename RingOrBox>
- inline ring_properties(RingOrBox const& ring_or_box)
+ template <typename RingOrBox, typename AreaStrategy>
+ inline ring_properties(RingOrBox const& ring_or_box, AreaStrategy const& strategy)
: reversed(false)
, discarded(false)
, parent_area(-1)
{
- this->area = geometry::area(ring_or_box);
- // We should take a point somewhere in the middle of the ring,
- // to avoid taking a point on a (self)tangency,
- // in cases where multiple points come together
- valid = geometry::point_on_border(this->point, ring_or_box, true);
+ this->area = geometry::area(ring_or_box, strategy);
+ valid = geometry::point_on_border(this->point, ring_or_box);
}
inline area_type get_area() const
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index de5eac8acb..67a4f4bb75 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -3,6 +3,10 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -18,9 +22,10 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/area.hpp>
-#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
@@ -35,11 +40,11 @@ namespace detail { namespace overlay
struct ring_turn_info
{
- bool has_normal_turn;
+ bool has_traversed_turn;
bool within_other;
ring_turn_info()
- : has_normal_turn(false)
+ : has_traversed_turn(false)
, within_other(false)
{}
};
@@ -54,41 +59,45 @@ namespace dispatch
template <typename Box>
struct select_rings<box_tag, Box>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box, Geometry const& ,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(box);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
- template <typename RingPropertyMap>
+ template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(box);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
};
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring, Geometry const& ,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
- template <typename RingPropertyMap>
+ template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
};
@@ -97,14 +106,15 @@ namespace dispatch
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
- ring_identifier id, RingPropertyMap& ring_properties)
+ ring_identifier id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
- per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties);
+ per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -112,18 +122,19 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
- per_ring::apply(*it, geometry, id, ring_properties);
+ per_ring::apply(*it, geometry, id, ring_properties, strategy);
}
}
- template <typename RingPropertyMap>
+ template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon,
- ring_identifier id, RingPropertyMap& ring_properties)
+ ring_identifier id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
- per_ring::apply(exterior_ring(polygon), id, ring_properties);
+ per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -131,7 +142,7 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
- per_ring::apply(*it, id, ring_properties);
+ per_ring::apply(*it, id, ring_properties, strategy);
}
}
};
@@ -139,9 +150,10 @@ namespace dispatch
template <typename Multi>
struct select_rings<multi_polygon_tag, Multi>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Multi const& multi, Geometry const& geometry,
- ring_identifier id, RingPropertyMap& ring_properties)
+ ring_identifier id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
typedef typename boost::range_iterator
<
@@ -154,7 +166,7 @@ namespace dispatch
for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
{
id.ring_index = -1;
- per_polygon::apply(*it, geometry, id, ring_properties);
+ per_polygon::apply(*it, geometry, id, ring_properties, strategy);
id.multi_index++;
}
}
@@ -221,20 +233,21 @@ struct decide<overlay_intersection>
}
};
-
template
<
overlay_type OverlayType,
typename Geometry1,
typename Geometry2,
typename TurnInfoMap,
- typename RingPropertyMap
+ typename RingPropertyMap,
+ typename Strategy
>
inline void update_ring_selection(Geometry1 const& geometry1,
Geometry2 const& geometry2,
TurnInfoMap const& turn_info_map,
RingPropertyMap const& all_ring_properties,
- RingPropertyMap& selected_ring_properties)
+ RingPropertyMap& selected_ring_properties,
+ Strategy const& strategy)
{
selected_ring_properties.clear();
@@ -252,9 +265,9 @@ inline void update_ring_selection(Geometry1 const& geometry1,
info = tcit->second; // Copy by value
}
- if (info.has_normal_turn)
+ if (info.has_traversed_turn)
{
- // There are normal turns on this ring. It should be traversed, we
+ // This turn is traversed (or blocked),
// don't include the original ring
continue;
}
@@ -263,11 +276,16 @@ inline void update_ring_selection(Geometry1 const& geometry1,
// a point lying on the ring
switch(id.source_index)
{
+ // within
case 0 :
- info.within_other = geometry::within(it->second.point, geometry2);
+ info.within_other = range_in_geometry(it->second.point,
+ geometry1, geometry2,
+ strategy) > 0;
break;
case 1 :
- info.within_other = geometry::within(it->second.point, geometry1);
+ info.within_other = range_in_geometry(it->second.point,
+ geometry2, geometry1,
+ strategy) > 0;
break;
}
@@ -290,23 +308,30 @@ template
typename Geometry1,
typename Geometry2,
typename RingTurnInfoMap,
- typename RingPropertyMap
+ typename RingPropertyMap,
+ typename Strategy
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
RingTurnInfoMap const& turn_info_per_ring,
- RingPropertyMap& selected_ring_properties)
+ RingPropertyMap& selected_ring_properties,
+ Strategy const& strategy)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
- ring_identifier(0, -1, -1), all_ring_properties);
+ ring_identifier(0, -1, -1), all_ring_properties,
+ strategy.template get_area_strategy<point1_type>());
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
- ring_identifier(1, -1, -1), all_ring_properties);
+ ring_identifier(1, -1, -1), all_ring_properties,
+ strategy.template get_area_strategy<point2_type>());
update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
- all_ring_properties, selected_ring_properties);
+ all_ring_properties, selected_ring_properties,
+ strategy);
}
template
@@ -314,20 +339,25 @@ template
overlay_type OverlayType,
typename Geometry,
typename RingTurnInfoMap,
- typename RingPropertyMap
+ typename RingPropertyMap,
+ typename Strategy
>
inline void select_rings(Geometry const& geometry,
RingTurnInfoMap const& turn_info_per_ring,
- RingPropertyMap& selected_ring_properties)
+ RingPropertyMap& selected_ring_properties,
+ Strategy const& strategy)
{
typedef typename geometry::tag<Geometry>::type tag;
+ typedef typename geometry::point_type<Geometry>::type point_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag, Geometry>::apply(geometry,
- ring_identifier(0, -1, -1), all_ring_properties);
+ ring_identifier(0, -1, -1), all_ring_properties,
+ strategy.template get_area_strategy<point_type>());
update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
- all_ring_properties, selected_ring_properties);
+ all_ring_properties, selected_ring_properties,
+ strategy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 8540ef98a0..5e9d8efa8e 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
@@ -22,12 +23,14 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
@@ -57,12 +60,9 @@ struct no_interrupt_policy
};
-
-
-class self_ip_exception : public geometry::exception {};
-
template
<
+ bool Reverse,
typename Geometry,
typename Turns,
typename TurnPolicy,
@@ -77,17 +77,20 @@ struct self_section_visitor
RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
+ std::size_t m_source_index;
inline self_section_visitor(Geometry const& g,
IntersectionStrategy const& is,
RobustPolicy const& rp,
Turns& turns,
- InterruptPolicy& ip)
+ InterruptPolicy& ip,
+ std::size_t source_index)
: m_geometry(g)
, m_intersection_strategy(is)
, m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
+ , m_source_index(source_index)
{}
template <typename Section>
@@ -97,26 +100,21 @@ struct self_section_visitor
&& ! sec1.duplicate
&& ! sec2.duplicate)
{
- detail::get_turns::get_turns_in_sections
+ // false if interrupted
+ return detail::get_turns::get_turns_in_sections
<
Geometry, Geometry,
- false, false,
+ Reverse, Reverse,
Section, Section,
TurnPolicy
- >::apply(
- 0, m_geometry, sec1,
- 0, m_geometry, sec2,
- false,
- m_intersection_strategy,
- m_rescale_policy,
- m_turns, m_interrupt_policy);
- }
- if (BOOST_GEOMETRY_CONDITION(m_interrupt_policy.has_intersections))
- {
- // TODO: we should give partition an interrupt policy.
- // Now we throw, and catch below, to stop the partition loop.
- throw self_ip_exception();
+ >::apply(m_source_index, m_geometry, sec1,
+ m_source_index, m_geometry, sec2,
+ false,
+ m_intersection_strategy,
+ m_rescale_policy,
+ m_turns, m_interrupt_policy);
}
+
return true;
}
@@ -124,7 +122,7 @@ struct self_section_visitor
-template<typename TurnPolicy>
+template <bool Reverse, typename TurnPolicy>
struct get_turns
{
template <typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
@@ -133,7 +131,8 @@ struct get_turns
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy,
Turns& turns,
- InterruptPolicy& interrupt_policy)
+ InterruptPolicy& interrupt_policy,
+ std::size_t source_index)
{
typedef model::box
<
@@ -149,29 +148,24 @@ struct get_turns
typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
sections_type sec;
- geometry::sectionalize<false, dimensions>(geometry, robust_policy, sec);
+ geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec,
+ intersection_strategy.get_envelope_strategy());
self_section_visitor
<
- Geometry,
+ Reverse, Geometry,
Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy
- > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy);
+ > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index);
- try
- {
- geometry::partition
- <
- box_type
- >::apply(sec, visitor,
- detail::section::get_section_box(),
- detail::section::overlaps_section_box());
- }
- catch(self_ip_exception const& )
- {
- return false;
- }
+ // false if interrupted
+ geometry::partition
+ <
+ box_type
+ >::apply(sec, visitor,
+ detail::section::get_section_box(),
+ detail::section::overlaps_section_box());
- return true;
+ return ! interrupt_policy.has_intersections;
}
};
@@ -186,6 +180,7 @@ namespace dispatch
template
<
+ bool Reverse,
typename GeometryTag,
typename Geometry,
typename TurnPolicy
@@ -197,26 +192,28 @@ struct self_get_turn_points
template
<
+ bool Reverse,
typename Ring,
typename TurnPolicy
>
struct self_get_turn_points
<
- ring_tag, Ring,
+ Reverse, ring_tag, Ring,
TurnPolicy
>
- : detail::self_get_turn_points::get_turns<TurnPolicy>
+ : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
{};
template
<
+ bool Reverse,
typename Box,
typename TurnPolicy
>
struct self_get_turn_points
<
- box_tag, Box,
+ Reverse, box_tag, Box,
TurnPolicy
>
{
@@ -226,7 +223,8 @@ struct self_get_turn_points
Strategy const& ,
RobustPolicy const& ,
Turns& ,
- InterruptPolicy& )
+ InterruptPolicy& ,
+ std::size_t)
{
return true;
}
@@ -235,29 +233,31 @@ struct self_get_turn_points
template
<
+ bool Reverse,
typename Polygon,
typename TurnPolicy
>
struct self_get_turn_points
<
- polygon_tag, Polygon,
+ Reverse, polygon_tag, Polygon,
TurnPolicy
>
- : detail::self_get_turn_points::get_turns<TurnPolicy>
+ : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
{};
template
<
+ bool Reverse,
typename MultiPolygon,
typename TurnPolicy
>
struct self_get_turn_points
<
- multi_polygon_tag, MultiPolygon,
+ Reverse, multi_polygon_tag, MultiPolygon,
TurnPolicy
>
- : detail::self_get_turn_points::get_turns<TurnPolicy>
+ : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
{};
@@ -265,6 +265,45 @@ struct self_get_turn_points
#endif // DOXYGEN_NO_DISPATCH
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace self_get_turn_points
+{
+
+// Version where Reverse can be specified manually. TODO:
+// can most probably be merged with self_get_turn_points::get_turn
+template
+<
+ bool Reverse,
+ typename AssignPolicy,
+ typename Geometry,
+ typename IntersectionStrategy,
+ typename RobustPolicy,
+ typename Turns,
+ typename InterruptPolicy
+>
+inline void self_turns(Geometry const& geometry,
+ IntersectionStrategy const& strategy,
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy,
+ std::size_t source_index = 0)
+{
+ concepts::check<Geometry const>();
+
+ typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
+
+ dispatch::self_get_turn_points
+ <
+ Reverse,
+ typename tag<Geometry>::type,
+ Geometry,
+ turn_policy
+ >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
+}
+
+}} // namespace detail::self_get_turn_points
+#endif // DOXYGEN_NO_DETAIL
+
/*!
\brief Calculate self intersections of a geometry
\ingroup overlay
@@ -290,18 +329,22 @@ template
inline void self_turns(Geometry const& geometry,
IntersectionStrategy const& strategy,
RobustPolicy const& robust_policy,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ Turns& turns,
+ InterruptPolicy& interrupt_policy,
+ std::size_t source_index = 0)
{
concepts::check<Geometry const>();
- typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
+ static bool const reverse = detail::overlay::do_reverse
+ <
+ geometry::point_order<Geometry>::value
+ >::value;
- dispatch::self_get_turn_points
+ detail::self_get_turn_points::self_turns
<
- typename tag<Geometry>::type,
- Geometry,
- turn_policy
- >::apply(geometry, strategy, robust_policy, turns, interrupt_policy);
+ reverse,
+ AssignPolicy
+ >(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
}
diff --git a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
index bbba623eee..5ad2e41b12 100644
--- a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
+++ b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -10,11 +15,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_BY_SIDE_HPP
#include <algorithm>
+#include <map>
#include <vector>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
-#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
{
@@ -37,7 +45,6 @@ struct ranked_point
, count_left(0)
, count_right(0)
, operation(operation_none)
- , only_turn_on_ring(false)
{}
template <typename Op>
@@ -53,7 +60,6 @@ struct ranked_point
, count_right(0)
, operation(op.operation)
, seg_id(op.seg_id)
- , only_turn_on_ring(op.enriched.only_turn_on_ring)
{}
Point point;
@@ -66,7 +72,6 @@ struct ranked_point
std::size_t count_right;
operation_type operation;
segment_identifier seg_id;
- bool only_turn_on_ring;
};
struct less_by_turn_index
@@ -105,17 +110,13 @@ struct less_false
}
};
-template <typename Point, typename LessOnSame, typename Compare>
+template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare>
struct less_by_side
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type side;
-
- less_by_side(const Point& p1, const Point& p2)
+ less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy)
: m_p1(p1)
, m_p2(p2)
+ , m_strategy(strategy)
{}
template <typename T>
@@ -124,8 +125,8 @@ struct less_by_side
LessOnSame on_same;
Compare compare;
- int const side_first = side::apply(m_p1, m_p2, first.point);
- int const side_second = side::apply(m_p1, m_p2, second.point);
+ int const side_first = m_strategy.apply(m_p1, m_p2, first.point);
+ int const side_second = m_strategy.apply(m_p1, m_p2, second.point);
if (side_first == 0 && side_second == 0)
{
@@ -165,7 +166,7 @@ struct less_by_side
// They are both left, both right, and/or both collinear (with each other and/or with p1,p2)
// Check mutual side
- int const side_second_wrt_first = side::apply(m_p2, first.point, second.point);
+ int const side_second_wrt_first = m_strategy.apply(m_p2, first.point, second.point);
if (side_second_wrt_first == 0)
{
@@ -183,10 +184,19 @@ struct less_by_side
private :
Point m_p1, m_p2;
+ SideStrategy const& m_strategy;
};
// Sorts vectors in counter clockwise order (by default)
-template <bool Reverse1, bool Reverse2, typename Point, typename Compare>
+template
+<
+ bool Reverse1,
+ bool Reverse2,
+ overlay_type OverlayType,
+ typename Point,
+ typename SideStrategy,
+ typename Compare
+>
struct side_sorter
{
typedef ranked_point<Point> rp;
@@ -215,13 +225,14 @@ private :
};
public :
- inline void set_origin(Point const& origin)
- {
- m_origin = origin;
- }
+ side_sorter(SideStrategy const& strategy)
+ : m_origin_count(0)
+ , m_origin_segment_distance(0)
+ , m_strategy(strategy)
+ {}
template <typename Operation, typename Geometry1, typename Geometry2>
- void add(Operation const& op, signed_size_type turn_index, signed_size_type op_index,
+ Point add(Operation const& op, signed_size_type turn_index, signed_size_type op_index,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
bool is_origin)
@@ -233,11 +244,63 @@ public :
m_ranked_points.push_back(rp(point1, turn_index, op_index, dir_from, op));
m_ranked_points.push_back(rp(point_to, turn_index, op_index, dir_to, op));
-
if (is_origin)
{
m_origin = point1;
+ m_origin_count++;
}
+ return point1;
+ }
+
+ template <typename Operation, typename Geometry1, typename Geometry2>
+ void add(Operation const& op, signed_size_type turn_index, signed_size_type op_index,
+ segment_identifier const& departure_seg_id,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ bool check_origin)
+ {
+ Point const point1 = add(op, turn_index, op_index, geometry1, geometry2, false);
+
+ if (check_origin)
+ {
+ bool const is_origin
+ = op.seg_id.source_index == departure_seg_id.source_index
+ && op.seg_id.ring_index == departure_seg_id.ring_index
+ && op.seg_id.multi_index == departure_seg_id.multi_index;
+
+ if (is_origin)
+ {
+ int const segment_distance = calculate_segment_distance(op, departure_seg_id, geometry1, geometry2);
+ if (m_origin_count == 0 ||
+ segment_distance < m_origin_segment_distance)
+ {
+ m_origin = point1;
+ m_origin_segment_distance = segment_distance;
+ }
+ m_origin_count++;
+ }
+ }
+ }
+
+ template <typename Operation, typename Geometry1, typename Geometry2>
+ static int calculate_segment_distance(Operation const& op,
+ segment_identifier const& departure_seg_id,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ if (op.seg_id.segment_index >= departure_seg_id.segment_index)
+ {
+ return op.seg_id.segment_index - departure_seg_id.segment_index;
+ }
+ // Take wrap into account
+ // Suppose ring_count=10 (10 points, 9 segments), dep.seg_id=7, op.seg_id=2, then distance=10-9+2
+ // Generic function (is this used somewhere else too?)
+ ring_identifier const rid(op.seg_id.source_index, op.seg_id.multi_index, op.seg_id.ring_index);
+ int const segment_count
+ (op.seg_id.source_index == 0
+ ? geometry::num_points(detail::overlay::get_ring<typename geometry::tag<Geometry1>::type>::apply(rid, geometry1))
+ : geometry::num_points(detail::overlay::get_ring<typename geometry::tag<Geometry2>::type>::apply(rid, geometry2)));
+ return ((segment_count - 1) - departure_seg_id.segment_index) + op.seg_id.segment_index;
}
void apply(Point const& turn_point)
@@ -249,8 +312,8 @@ public :
// to give colinear points
// Sort by side and assign rank
- less_by_side<Point, less_by_index, Compare> less_unique(m_origin, turn_point);
- less_by_side<Point, less_false, Compare> less_non_unique(m_origin, turn_point);
+ less_by_side<Point, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy);
+ less_by_side<Point, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy);
std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique);
@@ -269,7 +332,7 @@ public :
}
template <signed_size_type segment_identifier::*Member, typename Map>
- void find_open_generic(Map& handled)
+ void find_open_generic(Map& handled, bool check)
{
for (std::size_t i = 0; i < m_ranked_points.size(); i++)
{
@@ -280,6 +343,11 @@ public :
}
signed_size_type const& index = ranked.seg_id.*Member;
+ if (check && (index < 0 || index > 1))
+ {
+ // Should not occur
+ continue;
+ }
if (! handled[index])
{
find_polygons_for_source<Member>(index, i);
@@ -290,36 +358,23 @@ public :
void find_open()
{
- // TODO: we might pass Buffer as overlay_type, instead on the fly below
- bool one_source = true;
- for (std::size_t i = 0; i < m_ranked_points.size(); i++)
- {
- const rp& ranked = m_ranked_points[i];
- signed_size_type const& src = ranked.seg_id.source_index;
- if (src != 0)
- {
- one_source = false;
- break;
- }
- }
-
- if (one_source)
+ if (OverlayType == overlay_buffer)
{
- // by multi index
+ // For buffers, use piece index
std::map<signed_size_type, bool> handled;
find_open_generic
<
&segment_identifier::piece_index
- >(handled);
+ >(handled, false);
}
else
{
- // by source (there should only source 0,1) TODO assert this
+ // For other operations, by source (there should only source 0,1)
bool handled[2] = {false, false};
find_open_generic
<
&segment_identifier::source_index
- >(handled);
+ >(handled, true);
}
}
@@ -361,11 +416,19 @@ public :
}
}
+ bool has_origin() const
+ {
+ return m_origin_count > 0;
+ }
+
//private :
typedef std::vector<rp> container_type;
container_type m_ranked_points;
Point m_origin;
+ std::size_t m_origin_count;
+ int m_origin_segment_distance;
+ SideStrategy m_strategy;
private :
@@ -439,9 +502,10 @@ private :
void find_polygons_for_source(signed_size_type the_index,
std::size_t start_index)
{
- int state = 1; // 'closed', because start_index is "from", arrives at the turn
- std::size_t last_from_rank = m_ranked_points[start_index].rank;
- std::size_t previous_rank = m_ranked_points[start_index].rank;
+ bool in_polygon = true; // Because start_index is "from", arrives at the turn
+ rp const& start_rp = m_ranked_points[start_index];
+ std::size_t last_from_rank = start_rp.rank;
+ std::size_t previous_rank = start_rp.rank;
for (std::size_t index = move<Member>(the_index, start_index);
;
@@ -449,7 +513,7 @@ private :
{
rp& ranked = m_ranked_points[index];
- if (ranked.rank != previous_rank && state == 0)
+ if (ranked.rank != previous_rank && ! in_polygon)
{
assign_ranks(last_from_rank, previous_rank - 1, 1);
assign_ranks(last_from_rank + 1, previous_rank, 2);
@@ -463,11 +527,11 @@ private :
if (ranked.direction == dir_from)
{
last_from_rank = ranked.rank;
- state++;
+ in_polygon = true;
}
else if (ranked.direction == dir_to)
{
- state--;
+ in_polygon = false;
}
previous_rank = ranked.rank;
diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp
index bc828920e9..69d62b788b 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@@ -14,7 +19,9 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -37,9 +44,13 @@ namespace detail { namespace overlay
template <typename Turn, typename Operation>
#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
inline void debug_traverse(Turn const& turn, Operation op,
- std::string const& header)
+ std::string const& header, bool condition = true)
{
- std::cout << header
+ if (! condition)
+ {
+ return;
+ }
+ std::cout << " " << header
<< " at " << op.seg_id
<< " meth: " << method_char(turn.method)
<< " op: " << operation_char(op.operation)
@@ -55,7 +66,7 @@ inline void debug_traverse(Turn const& turn, Operation op,
}
}
#else
-inline void debug_traverse(Turn const& , Operation, const char*)
+inline void debug_traverse(Turn const& , Operation, const char*, bool = true)
{
}
#endif
@@ -88,6 +99,7 @@ template
typename Turns,
typename Clusters,
typename RobustPolicy,
+ typename SideStrategy,
typename Visitor
>
struct traversal
@@ -101,18 +113,20 @@ struct traversal
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef sort_by_side::side_sorter
<
- Reverse1, Reverse2,
- point_type, side_compare_type
+ Reverse1, Reverse2, OverlayType,
+ point_type, SideStrategy, side_compare_type
> sbs_type;
inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2,
Turns& turns, Clusters const& clusters,
- RobustPolicy const& robust_policy, Visitor& visitor)
+ RobustPolicy const& robust_policy, SideStrategy const& strategy,
+ Visitor& visitor)
: m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
, m_clusters(clusters)
, m_robust_policy(robust_policy)
+ , m_strategy(strategy)
, m_visitor(visitor)
{
}
@@ -133,11 +147,38 @@ struct traversal
}
}
+ //! Sets visited for ALL turns traveling to the same turn
+ inline void set_visited_in_cluster(signed_size_type cluster_id,
+ signed_size_type rank)
+ {
+ typename Clusters::const_iterator mit = m_clusters.find(cluster_id);
+ BOOST_ASSERT(mit != m_clusters.end());
+
+ cluster_info const& cinfo = mit->second;
+ std::set<signed_size_type> const& ids = cinfo.turn_indices;
+
+ for (typename std::set<signed_size_type>::const_iterator it = ids.begin();
+ it != ids.end(); ++it)
+ {
+ signed_size_type const turn_index = *it;
+ turn_type& turn = m_turns[turn_index];
+
+ for (int i = 0; i < 2; i++)
+ {
+ turn_operation_type& op = turn.operations[i];
+ if (op.visited.none()
+ && op.enriched.rank == rank)
+ {
+ op.visited.set_visited();
+ }
+ }
+ }
+ }
inline void set_visited(turn_type& turn, turn_operation_type& op)
{
- // On "continue", set "visited" for ALL directions in this turn
if (op.operation == detail::overlay::operation_continue)
{
+ // On "continue", all go in same direction so set "visited" for ALL
for (int i = 0; i < 2; i++)
{
turn_operation_type& turn_op = turn.operations[i];
@@ -151,6 +192,10 @@ struct traversal
{
op.visited.set_visited();
}
+ if (turn.cluster_id >= 0)
+ {
+ set_visited_in_cluster(turn.cluster_id, op.enriched.rank);
+ }
}
inline bool is_visited(turn_type const& , turn_operation_type const& op,
@@ -160,8 +205,8 @@ struct traversal
}
inline bool select_source(signed_size_type turn_index,
- segment_identifier const& seg_id1,
- segment_identifier const& seg_id2) const
+ segment_identifier const& candidate_seg_id,
+ segment_identifier const& previous_seg_id) const
{
// For uu/ii, only switch sources if indicated
turn_type const& turn = m_turns[turn_index];
@@ -170,8 +215,16 @@ struct traversal
{
// Buffer does not use source_index (always 0)
return turn.switch_source
- ? seg_id1.multi_index != seg_id2.multi_index
- : seg_id1.multi_index == seg_id2.multi_index;
+ ? candidate_seg_id.multi_index != previous_seg_id.multi_index
+ : candidate_seg_id.multi_index == previous_seg_id.multi_index;
+ }
+
+ if (is_self_turn<OverlayType>(turn))
+ {
+ // Also, if it is a self-turn, stay on same ring (multi/ring)
+ return turn.switch_source
+ ? candidate_seg_id.multi_index != previous_seg_id.multi_index
+ : candidate_seg_id.multi_index == previous_seg_id.multi_index;
}
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
@@ -185,16 +238,8 @@ struct traversal
}
#endif
return turn.switch_source
- ? seg_id1.source_index != seg_id2.source_index
- : seg_id1.source_index == seg_id2.source_index;
- }
-
- inline
- signed_size_type get_next_turn_index(turn_operation_type const& op) const
- {
- return op.enriched.next_ip_index == -1
- ? op.enriched.travels_to_ip_index
- : op.enriched.next_ip_index;
+ ? candidate_seg_id.source_index != previous_seg_id.source_index
+ : candidate_seg_id.source_index == previous_seg_id.source_index;
}
inline bool traverse_possible(signed_size_type turn_index) const
@@ -220,39 +265,39 @@ struct traversal
{
// For "cc", take either one, but if there is a starting one,
// take that one. If next is dead end, skip that one.
+ // If both are valid candidates, take the one with minimal remaining
+ // distance (important for #mysql_23023665 in buffer).
- bool result = false;
-
+ // Initialize with 0, automatically assigned on first result
typename turn_operation_type::comparable_distance_type
- max_remaining_distance = 0;
+ min_remaining_distance = 0;
+
+ bool result = false;
for (int i = 0; i < 2; i++)
{
turn_operation_type const& op = turn.operations[i];
- signed_size_type const next_turn_index = get_next_turn_index(op);
+ signed_size_type const next_turn_index = op.enriched.get_next_turn_index();
- if (! result && traverse_possible(next_turn_index))
+ if (! traverse_possible(next_turn_index))
{
- max_remaining_distance = op.remaining_distance;
- selected_op_index = i;
- debug_traverse(turn, op, " Candidate");
- result = true;
+ continue;
}
- if (result)
+ if (! result
+ || next_turn_index == start_turn_index
+ || op.remaining_distance < min_remaining_distance)
{
- if (next_turn_index == start_turn_index)
- {
- selected_op_index = i;
- debug_traverse(turn, op, " Candidate cc override (start)");
- }
- else if (op.remaining_distance > max_remaining_distance)
- {
- max_remaining_distance = op.remaining_distance;
- selected_op_index = i;
- debug_traverse(turn, op, " Candidate cc override (remaining)");
- }
+ debug_traverse(turn, op, "First candidate cc", ! result);
+ debug_traverse(turn, op, "Candidate cc override (start)",
+ result && next_turn_index == start_turn_index);
+ debug_traverse(turn, op, "Candidate cc override (remaining)",
+ result && op.remaining_distance < min_remaining_distance);
+
+ selected_op_index = i;
+ min_remaining_distance = op.remaining_distance;
+ result = true;
}
}
@@ -262,7 +307,7 @@ struct traversal
inline
bool select_noncc_operation(turn_type const& turn,
signed_size_type turn_index,
- segment_identifier const& seg_id,
+ segment_identifier const& previous_seg_id,
int& selected_op_index) const
{
bool result = false;
@@ -273,10 +318,10 @@ struct traversal
if (op.operation == target_operation
&& ! op.visited.finished()
- && (! result || select_source(turn_index, op.seg_id, seg_id)))
+ && (! result || select_source(turn_index, op.seg_id, previous_seg_id)))
{
selected_op_index = i;
- debug_traverse(turn, op, " Candidate");
+ debug_traverse(turn, op, "Candidate");
result = true;
}
}
@@ -305,7 +350,7 @@ struct traversal
}
if (result)
{
- debug_traverse(turn, turn.operations[selected_op_index], " Accepted");
+ debug_traverse(turn, turn.operations[selected_op_index], "Accepted");
}
return result;
@@ -336,108 +381,164 @@ struct traversal
}
inline bool select_from_cluster_union(signed_size_type& turn_index,
- int& op_index, signed_size_type start_turn_index,
- sbs_type const& sbs, bool is_touching) const
+ int& op_index, sbs_type& sbs) const
{
+ std::vector<sort_by_side::rank_with_rings> aggregation;
+ sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_union);
+
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+
+ // Take the first one outgoing for the incoming region
std::size_t selected_rank = 0;
- std::size_t min_rank = 0;
- bool result = false;
- for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
+ for (std::size_t i = 1; i < aggregation.size(); i++)
+ {
+ sort_by_side::rank_with_rings const& rwr = aggregation[i];
+ if (rwr.all_to()
+ && rwr.region_id() == incoming.region_id())
+ {
+ selected_rank = rwr.rank;
+ break;
+ }
+ }
+
+ for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++)
{
typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
- if (result && ranked_point.rank > selected_rank)
+ if (ranked_point.rank == selected_rank
+ && ranked_point.direction == sort_by_side::dir_to)
{
- return result;
+ turn_index = ranked_point.turn_index;
+ op_index = ranked_point.operation_index;
+
+ turn_type const& turn = m_turns[turn_index];
+ turn_operation_type const& op = turn.operations[op_index];
+
+ if (op.enriched.count_left == 0
+ && op.enriched.count_right > 0
+ && ! op.visited.finalized())
+ {
+ // In some cases interior rings might be generated with polygons
+ // on both sides
+
+ // TODO: this should be finetuned such that checking
+ // finalized is not necessary
+ return true;
+ }
}
+ }
+ return false;
+ }
- turn_type const& ranked_turn = m_turns[ranked_point.turn_index];
- turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.operation_index];
- if (result && ranked_op.visited.finalized())
+ inline bool all_operations_of_type(sort_by_side::rank_with_rings const& rwr,
+ operation_type op_type,
+ sort_by_side::direction_type dir) const
+ {
+ typedef std::set<sort_by_side::ring_with_direction>::const_iterator sit_type;
+ for (sit_type it = rwr.rings.begin(); it != rwr.rings.end(); ++it)
+ {
+ sort_by_side::ring_with_direction const& rwd = *it;
+ if (rwd.direction != dir)
{
- // One of the arcs in the same direction as the selected result
- // is already traversed.
return false;
}
-
- if (! is_touching && ranked_op.visited.finalized())
+ turn_type const& turn = m_turns[rwd.turn_index];
+ if (! turn.both(op_type))
{
- // Skip this one, go to next
- min_rank = ranked_point.rank;
- continue;
+ return false;
}
- if (ranked_point.direction == sort_by_side::dir_to
- && (ranked_point.rank > min_rank
- || ranked_turn.both(operation_continue)))
+ // Check if this is not yet taken
+ turn_operation_type const& op = turn.operations[rwd.operation_index];
+ if (op.visited.finalized())
{
- if (ranked_op.enriched.count_left == 0
- && ranked_op.enriched.count_right > 0)
- {
- if (result && ranked_point.turn_index != start_turn_index)
- {
- // Don't override - only override if arrive at start
- continue;
- }
-
- turn_index = ranked_point.turn_index;
- op_index = ranked_point.operation_index;
-
- result = true;
- selected_rank = ranked_point.rank;
- }
- else if (! is_touching)
- {
- return result;
- }
+ return false;
}
+
}
- return result;
+ return true;
}
inline bool analyze_cluster_intersection(signed_size_type& turn_index,
- int& op_index,
- sbs_type const& sbs) const
+ int& op_index, sbs_type const& sbs) const
{
std::vector<sort_by_side::rank_with_rings> aggregation;
- sort_by_side::aggregate_operations(sbs, aggregation);
+ sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_intersection);
std::size_t selected_rank = 0;
- for (std::size_t i = 0; i < aggregation.size(); i++)
+
+ // Detect specific pattern(s)
+ bool const detected
+ = intersection_pattern_common_interior1(selected_rank, aggregation)
+ || intersection_pattern_common_interior2(selected_rank, aggregation)
+ || intersection_pattern_common_interior3(selected_rank, aggregation)
+ || intersection_pattern_common_interior4(selected_rank, aggregation)
+ ;
+
+ if (! detected)
{
- sort_by_side::rank_with_rings const& rwr = aggregation[i];
+ int incoming_region_id = 0;
+ std::set<int> outgoing_region_ids;
- if (i > 1
- && i - 1 == selected_rank
- && rwr.rings.size() == 1)
+ for (std::size_t i = 0; i < aggregation.size(); i++)
{
- sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
+ sort_by_side::rank_with_rings const& rwr = aggregation[i];
- if (rwd.only_turn_on_ring)
+ if (rwr.all_to()
+ && rwr.traversable(m_turns)
+ && selected_rank == 0)
{
- // Find if this arriving ring was leaving previously
- sort_by_side::ring_with_direction leaving = rwd;
- leaving.direction = sort_by_side::dir_to;
-
- sort_by_side::rank_with_rings const& previous = aggregation[i - 1];
+ // Take the first (= right) where segments leave,
+ // having the polygon on the right side
+ selected_rank = rwr.rank;
+ }
- if (previous.rings.size() == 1
- && previous.rings.count(leaving) == 1)
- {
- // It arrives back - if this is one of the selected, unselect it
- selected_rank = 0;
- }
+ if (rwr.all_from()
+ && selected_rank > 0
+ && outgoing_region_ids.empty())
+ {
+ // Incoming
+ break;
}
- }
- if (rwr.all_to())
- {
- if (selected_rank == 0)
+ if (incoming_region_id == 0)
{
- // Take the first (= right) where segments leave,
- // having the polygon on the right side
- selected_rank = rwr.rank;
+ sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
+ turn_type const& turn = m_turns[rwd.turn_index];
+ incoming_region_id = turn.operations[rwd.operation_index].enriched.region_id;
+ }
+ else
+ {
+ if (rwr.rings.size() == 1)
+ {
+ sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
+ turn_type const& turn = m_turns[rwd.turn_index];
+ if (rwd.direction == sort_by_side::dir_to
+ && turn.both(operation_intersection))
+ {
+
+ turn_operation_type const& op = turn.operations[rwd.operation_index];
+ if (op.enriched.region_id != incoming_region_id
+ && op.enriched.isolated)
+ {
+ outgoing_region_ids.insert(op.enriched.region_id);
+ }
+ }
+ else if (! outgoing_region_ids.empty())
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ int const region_id = turn.operations[i].enriched.region_id;
+ if (outgoing_region_ids.count(region_id) == 1)
+ {
+ selected_rank = 0;
+ outgoing_region_ids.erase(region_id);
+ }
+ }
+ }
+ }
}
}
}
@@ -458,7 +559,7 @@ struct traversal
{
// This direction is already traveled before, the same
// cannot be traveled again
- return false;
+ continue;
}
// Take the last turn from this rank
@@ -479,10 +580,9 @@ struct traversal
}
inline bool select_turn_from_cluster(signed_size_type& turn_index,
- int& op_index, bool& is_touching,
+ int& op_index,
signed_size_type start_turn_index,
- segment_identifier const& previous_seg_id,
- bool is_start) const
+ segment_identifier const& previous_seg_id) const
{
bool const is_union = target_operation == operation_union;
@@ -495,15 +595,14 @@ struct traversal
cluster_info const& cinfo = mit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
- sbs_type sbs;
-
- bool has_origin = false;
+ sbs_type sbs(m_strategy);
for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
{
signed_size_type cluster_turn_index = *sit;
turn_type const& cluster_turn = m_turns[cluster_turn_index];
+ bool const departure_turn = cluster_turn_index == turn_index;
if (cluster_turn.discarded)
{
// Defensive check, discarded turns should not be in cluster
@@ -512,79 +611,27 @@ struct traversal
for (int i = 0; i < 2; i++)
{
- turn_operation_type const& op = cluster_turn.operations[i];
- bool is_origin = false;
- if (cluster_turn_index == turn_index)
- {
- // Check if this is the origin
- if (OverlayType == overlay_buffer)
- {
- is_origin = op.seg_id.multi_index == previous_seg_id.multi_index;
- }
- else
- {
- is_origin = op.seg_id.source_index
- == previous_seg_id.source_index;
- }
- if (is_origin)
- {
- has_origin = true;
- }
- }
-
- sbs.add(op, cluster_turn_index, i, m_geometry1, m_geometry2,
- is_origin);
+ sbs.add(cluster_turn.operations[i],
+ cluster_turn_index, i, previous_seg_id,
+ m_geometry1, m_geometry2,
+ departure_turn);
}
}
- if (! has_origin)
+ if (! sbs.has_origin())
{
return false;
}
-
sbs.apply(turn.point);
bool result = false;
if (is_union)
{
- #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
- is_touching = cinfo.open_count > 1;
- if (is_touching)
- {
- if (cinfo.switch_source)
- {
- is_touching = false;
- std::cout << "CLUSTER: SWITCH SOURCES at " << turn_index << std::endl;
- }
- else
- {
- std::cout << "CLUSTER: CONTINUE at " << turn_index << std::endl;
- }
- }
- #else
- is_touching = cinfo.open_count > 1 && ! cinfo.switch_source;
- #endif
-
- if (is_touching)
- {
- sbs.reverse();
- }
-
- result = select_from_cluster_union(turn_index, op_index, start_turn_index, sbs,
- is_touching);
+ result = select_from_cluster_union(turn_index, op_index, sbs);
}
else
{
- if (is_start
- && turn.both(operation_intersection)
- && turn.operations[op_index].enriched.only_turn_on_ring)
- {
- // For an ii (usually interior ring), only turn on ring,
- // reverse to take first exit
- sbs.reverse();
- }
-
result = analyze_cluster_intersection(turn_index, op_index, sbs);
}
return result;
@@ -594,26 +641,27 @@ struct traversal
turn_type const& current_turn,
segment_identifier const& previous_seg_id)
{
- sbs_type sbs;
+ sbs_type sbs(m_strategy);
// Add this turn to the sort-by-side sorter
- bool has_origin = false;
for (int i = 0; i < 2; i++)
{
- turn_operation_type const& op = current_turn.operations[i];
- bool const is_origin = op.seg_id.source_index
- == previous_seg_id.source_index;
- has_origin = has_origin || is_origin;
- sbs.add(op, turn_index, i, m_geometry1, m_geometry2, is_origin);
+ sbs.add(current_turn.operations[i],
+ turn_index, i, previous_seg_id,
+ m_geometry1, m_geometry2,
+ true);
}
- if (! has_origin)
+ if (! sbs.has_origin())
{
return false;
}
sbs.apply(current_turn.point);
- return analyze_cluster_intersection(turn_index, op_index, sbs);
+
+ bool result = analyze_cluster_intersection(turn_index, op_index, sbs);
+
+ return result;
}
inline void change_index_for_self_turn(signed_size_type& to_vertex_index,
@@ -712,7 +760,6 @@ struct traversal
bool select_turn(signed_size_type start_turn_index, int start_op_index,
signed_size_type& turn_index,
int& op_index,
- bool& is_touching,
int previous_op_index,
signed_size_type previous_turn_index,
segment_identifier const& previous_seg_id,
@@ -737,8 +784,8 @@ struct traversal
if (current_turn.cluster_id < 0
&& current_turn.both(operation_intersection))
{
- if (analyze_ii_intersection(turn_index, op_index, current_turn,
- previous_seg_id))
+ if (analyze_ii_intersection(turn_index, op_index,
+ current_turn, previous_seg_id))
{
return true;
}
@@ -747,8 +794,8 @@ struct traversal
if (current_turn.cluster_id >= 0)
{
- if (! select_turn_from_cluster(turn_index, op_index, is_touching,
- start_turn_index, previous_seg_id, is_start))
+ if (! select_turn_from_cluster(turn_index, op_index,
+ start_turn_index, previous_seg_id))
{
return false;
}
@@ -786,6 +833,7 @@ private :
Turns& m_turns;
Clusters const& m_clusters;
RobustPolicy const& m_robust_policy;
+ SideStrategy m_strategy;
Visitor& m_visitor;
};
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp b/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
new file mode 100644
index 0000000000..12279d762f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
@@ -0,0 +1,306 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
+
+#include <cstddef>
+#include <vector>
+
+#include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp>
+#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+inline bool check_pairs(std::vector<sort_by_side::rank_with_rings> const& aggregation,
+ signed_size_type incoming_region_id,
+ std::size_t first, std::size_t last)
+{
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+
+ for (std::size_t i = first; i <= last; i += 2)
+ {
+ sort_by_side::rank_with_rings const& curr = aggregation[i];
+ sort_by_side::rank_with_rings const& next = aggregation[i + 1];
+ int const curr_id = curr.region_id();
+ int const next_id = next.region_id();
+
+ bool const possible =
+ curr.rings.size() == 2
+ && curr.is_isolated()
+ && curr.has_unique_region_id()
+ && next.rings.size() == 2
+ && next.is_isolated()
+ && next.has_unique_region_id()
+ && curr_id == next_id
+ && curr_id != incoming_region_id;
+
+ if (! possible)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+inline bool intersection_pattern_common_interior1(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: coming from exterior ring, encountering an isolated
+ // parallel interior ring, which should be skipped, and the first
+ // left (normally intersection takes first right) should be taken.
+ // Solves cases #case_133_multi
+ // and #case_recursive_boxes_49
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 1
+ && incoming.has_only(operation_intersection);
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 1
+ && outgoing.has_only(operation_intersection)
+ && outgoing.region_id() == incoming.region_id();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 2))
+ {
+ selected_rank = n - 1;
+ return true;
+ }
+ return false;
+}
+
+inline bool intersection_pattern_common_interior2(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: coming from two exterior rings, encountering two isolated
+ // equal interior rings
+
+ // See (for example, for ii) #case_recursive_boxes_53:
+
+ // INCOMING:
+ // Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {13[1] (s:1, m:0) i F rgn: 1 ISO}
+
+ // PAIR:
+ // Rank 1 {13[0] (s:0, r:1, m:0) i T rgn: 3 ISO ->16} {11[1] (s:1, r:5, m:0) i T rgn: 3 ISO ->16}
+ // Rank 2 {13[0] (s:0, r:1, m:0) i F rgn: 3 ISO} {11[1] (s:1, r:5, m:0) i F rgn: 3 ISO}
+
+ // LEAVING (in the same direction, take last one)
+ // Rank 3 {11[0] (s:0, m:0) i T rgn: 1 ISO ->10} {13[1] (s:1, m:0) i T rgn: 1 ISO ->10}
+
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 2
+ && incoming.has_unique_region_id();
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 2
+ && outgoing.has_unique_region_id()
+ && outgoing.region_id() == incoming.region_id();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ bool const operation_ok =
+ (incoming.has_only(operation_continue) && outgoing.has_only(operation_continue))
+ || (incoming.has_only(operation_intersection) && outgoing.has_only(operation_intersection));
+
+ if (! operation_ok)
+ {
+ return false;
+ }
+
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 2))
+ {
+ selected_rank = n - 1;
+ return true;
+ }
+ return false;
+}
+
+inline bool intersection_pattern_common_interior3(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: approaches colocated turn (exterior+interior) from two
+ // different directions, and both leaves in the same direction
+
+ // See #case_136_multi:
+ // INCOMING:
+ //Rank 0 {10[0] (s:0, m:0) c F rgn: 1 ISO}
+
+ // PAIR:
+ //Rank 1 {14[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->16} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->16}
+ //Rank 2 {14[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
+
+ // LEAVING (select this one):
+ //Rank 3 {10[0] (s:0, m:0) c T rgn: 1 ISO ->12} {10[1] (s:1, m:0) c T rgn: 1 ISO ->12}
+
+ // ADDITIONALLY: (other polygon coming in)
+ //Rank 4 {10[1] (s:1, m:0) c F rgn: 1 ISO}
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation[n - 2];
+ sort_by_side::rank_with_rings const& last = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 1
+ && incoming.has_only(operation_continue);
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 2
+ && outgoing.has_only(operation_continue)
+ && outgoing.has_unique_region_id()
+ && outgoing.region_id() == incoming.region_id()
+ && last.all_from()
+ && last.rings.size() == 1
+ && last.region_id() == incoming.region_id()
+ && last.all_from();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
+ {
+ selected_rank = n - 2;
+ return true;
+ }
+ return false;
+}
+
+
+inline bool intersection_pattern_common_interior4(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: approaches colocated turn (exterior+interior) from same
+ // direction, but leaves in two different directions
+
+ // See #case_137_multi:
+
+ // INCOMING:
+ //Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {10[1] (s:1, m:0) i F rgn: 1 ISO}
+
+ // PAIR:
+ //Rank 1 {13[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->15} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->15}
+ //Rank 2 {13[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
+
+ // LEAVING (in two different directions, take last one)
+ //Rank 3 {10[1] (s:1, m:0) i T rgn: 1 ISO ->0}
+ //Rank 4 {11[0] (s:0, m:0) i T rgn: 1 ISO ->12}
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& extra = aggregation[n - 2];
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 2
+ && incoming.has_unique_region_id()
+ && incoming.has_only(operation_intersection);
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 1
+ && outgoing.has_only(operation_intersection)
+ && outgoing.region_id() == incoming.region_id()
+ && extra.all_to()
+ && extra.rings.size() == 1
+ && extra.has_only(operation_intersection)
+ && extra.region_id() == incoming.region_id();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
+ {
+ selected_rank = n - 1;
+ return true;
+ }
+ return false;
+}
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
index 9ab82a77c1..af643a822b 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
@@ -49,9 +49,13 @@ template
>
struct traversal_ring_creator
{
- typedef traversal<Reverse1, Reverse2, OverlayType,
- Geometry1, Geometry2, Turns, Clusters, RobustPolicy, Visitor>
- traversal_type;
+ typedef traversal
+ <
+ Reverse1, Reverse2, OverlayType,
+ Geometry1, Geometry2, Turns, Clusters,
+ RobustPolicy, typename IntersectionStrategy::side_strategy_type,
+ Visitor
+ > traversal_type;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
@@ -63,7 +67,9 @@ struct traversal_ring_creator
Turns& turns, Clusters const& clusters,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy, Visitor& visitor)
- : m_trav(geometry1, geometry2, turns, clusters, robust_policy,visitor)
+ : m_trav(geometry1, geometry2, turns, clusters,
+ robust_policy, intersection_strategy.get_side_strategy(),
+ visitor)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
@@ -103,12 +109,14 @@ struct traversal_ring_creator
{
geometry::copy_segments<Reverse1>(m_geometry1,
previous_op.seg_id, to_vertex_index,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy, current_ring);
}
else
{
geometry::copy_segments<Reverse2>(m_geometry2,
previous_op.seg_id, to_vertex_index,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy, current_ring);
}
}
@@ -127,10 +135,8 @@ struct traversal_ring_creator
m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start");
}
- bool is_touching = false;
if (! m_trav.select_turn(start_turn_index, start_op_index,
turn_index, op_index,
- is_touching,
previous_op_index, previous_turn_index, previous_seg_id,
is_start))
{
@@ -154,6 +160,7 @@ struct traversal_ring_creator
turn_type& current_turn = m_turns[turn_index];
turn_operation_type& op = current_turn.operations[op_index];
detail::overlay::append_no_dups_or_spikes(current_ring, current_turn.point,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy);
// Register the visit
@@ -171,6 +178,7 @@ struct traversal_ring_creator
turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
detail::overlay::append_no_dups_or_spikes(ring, start_turn.point,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy);
signed_size_type current_turn_index = start_turn_index;
@@ -273,7 +281,9 @@ struct traversal_ring_creator
if (geometry::num_points(ring) >= min_num_points)
{
- clean_closing_dups_and_spikes(ring, m_robust_policy);
+ clean_closing_dups_and_spikes(ring,
+ m_intersection_strategy.get_side_strategy(),
+ m_robust_policy);
rings.push_back(ring);
m_trav.finalize_visit_info();
@@ -307,11 +317,27 @@ struct traversal_ring_creator
continue;
}
- for (int op_index = 0; op_index < 2; op_index++)
+ if (turn.both(operation_continue))
{
+ // Traverse only one turn, the one with the SMALLEST remaining distance
+ // to avoid skipping a turn in between, which can happen in rare cases
+ // (e.g. #130)
+ turn_operation_type const& op0 = turn.operations[0];
+ turn_operation_type const& op1 = turn.operations[1];
+ int const op_index
+ = op0.remaining_distance <= op1.remaining_distance ? 0 : 1;
+
traverse_with_operation(turn, turn_index, op_index,
rings, finalized_ring_size, state);
}
+ else
+ {
+ for (int op_index = 0; op_index < 2; op_index++)
+ {
+ traverse_with_operation(turn, turn_index, op_index,
+ rings, finalized_ring_size, state);
+ }
+ }
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
index 183131c74b..0b4f393ef4 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
@@ -16,6 +16,7 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -47,10 +48,54 @@ template
>
struct traversal_switch_detector
{
+ enum isolation_type { isolation_unknown = -1, isolation_no = 0, isolation_yes = 1 };
+
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
- // For convenience
+ // Per ring, first turns are collected (in turn_indices), and later
+ // a region_id is assigned
+ struct merged_ring_properties
+ {
+ signed_size_type region_id;
+ std::set<signed_size_type> turn_indices;
+
+ merged_ring_properties()
+ : region_id(-1)
+ {}
+ };
+
+ struct connection_properties
+ {
+ std::size_t count;
+ std::set<signed_size_type> cluster_indices;
+ connection_properties()
+ : count(0)
+ {}
+ };
+
+ typedef std::map<signed_size_type, connection_properties> connection_map;
+
+ // Per region, a set of properties is maintained, including its connections
+ // to other regions
+ struct region_properties
+ {
+ signed_size_type region_id;
+ isolation_type isolated;
+
+ // Maps from connected region_id to their properties
+ connection_map connected_region_counts;
+
+ region_properties()
+ : region_id(-1)
+ , isolated(isolation_unknown)
+ {}
+ };
+
+ // Keeps turn indices per ring
+ typedef std::map<ring_identifier, merged_ring_properties > merge_map;
+ typedef std::map<signed_size_type, region_properties> region_connection_map;
+
typedef std::set<signed_size_type>::const_iterator set_iterator;
inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2,
@@ -62,135 +107,309 @@ struct traversal_switch_detector
, m_clusters(clusters)
, m_robust_policy(robust_policy)
, m_visitor(visitor)
- , m_region_id(0)
{
+ }
+
+ isolation_type get_isolation(region_properties const& properties,
+ signed_size_type parent_region_id,
+ const std::set<signed_size_type>& visited)
+ {
+ if (properties.isolated != isolation_unknown)
+ {
+ return properties.isolated;
+ }
+
+ bool all_colocated = true;
+ int unique_cluster_id = -1;
+ for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
+ all_colocated && it != properties.connected_region_counts.end(); ++it)
+ {
+ connection_properties const& cprop = it->second;
+ if (cprop.cluster_indices.size() != 1)
+ {
+ // Either no cluster (non colocated point), or more clusters
+ all_colocated = false;
+ }
+ int const cluster_id = *cprop.cluster_indices.begin();
+ if (cluster_id == -1)
+ {
+ all_colocated = false;
+ }
+ else if (unique_cluster_id == -1)
+ {
+ unique_cluster_id = cluster_id;
+ }
+ else if (unique_cluster_id != cluster_id)
+ {
+ all_colocated = false;
+ }
+ }
+ if (all_colocated)
+ {
+ return isolation_yes;
+ }
+
+
+ // It is isolated if there is only one connection, or if there are more connections but all
+ // of them are isolated themselves, or if there are more connections
+ // but they are all colocated
+ std::size_t non_isolation_count = 0;
+ bool child_not_isolated = false;
+ for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
+ it != properties.connected_region_counts.end(); ++it)
+ {
+ signed_size_type const region_id = it->first;
+ connection_properties const& cprop = it->second;
+
+ if (region_id == parent_region_id)
+ {
+ // Normal situation, skip its direct parent
+ continue;
+ }
+ if (visited.count(region_id) > 0)
+ {
+ // Find one of its ancestors again, this is a ring. Not isolated.
+ return isolation_no;
+ }
+ if (cprop.count > 1)
+ {
+ return isolation_no;
+ }
+
+ typename region_connection_map::iterator mit = m_connected_regions.find(region_id);
+ if (mit == m_connected_regions.end())
+ {
+ // Should not occur
+ continue;
+ }
+
+ std::set<signed_size_type> vis = visited;
+ vis.insert(parent_region_id);
+ region_properties& prop = mit->second;
+ if (prop.isolated == isolation_unknown)
+ {
+ isolation_type const iso = get_isolation(prop, properties.region_id, vis);
+ prop.isolated = iso;
+ if (iso == isolation_no)
+ {
+ child_not_isolated = true;
+ }
+ }
+ if (prop.isolated == isolation_no)
+ {
+ non_isolation_count++;
+ }
+ }
+
+ return child_not_isolated || non_isolation_count > 1 ? isolation_no : isolation_yes;
}
- static inline bool connects_same_zone(turn_type const& turn)
+ void get_isolated_regions()
{
+ for (typename region_connection_map::iterator it = m_connected_regions.begin();
+ it != m_connected_regions.end(); ++it)
+ {
+ region_properties& properties = it->second;
+ if (properties.isolated == isolation_unknown)
+ {
+ std::set<signed_size_type> visited;
+ properties.isolated = get_isolation(properties, properties.region_id, visited);
+ }
+ }
+ }
+
+ void assign_isolation()
+ {
+ for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
+ {
+ turn_type& turn = m_turns[turn_index];
+
+ for (int op_index = 0; op_index < 2; op_index++)
+ {
+ turn_operation_type& op = turn.operations[op_index];
+ typename region_connection_map::const_iterator mit = m_connected_regions.find(op.enriched.region_id);
+ if (mit != m_connected_regions.end())
+ {
+ region_properties const& prop = mit->second;
+ op.enriched.isolated = prop.isolated == isolation_yes;
+ }
+ }
+ }
+ }
+
+ void assign_regions()
+ {
+ for (typename merge_map::const_iterator it
+ = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
+ {
+ ring_identifier const& ring_id = it->first;
+ merged_ring_properties const& properties = it->second;
+
+ for (set_iterator sit = properties.turn_indices.begin();
+ sit != properties.turn_indices.end(); ++sit)
+ {
+ turn_type& turn = m_turns[*sit];
+
+ for (int i = 0; i < 2; i++)
+ {
+ turn_operation_type& op = turn.operations[i];
+ if (ring_id_by_seg_id(op.seg_id) == ring_id)
+ {
+ op.enriched.region_id = properties.region_id;
+ }
+ }
+ signed_size_type const& id0 = turn.operations[0].enriched.region_id;
+ signed_size_type const& id1 = turn.operations[1].enriched.region_id;
+ if (id0 != id1 && id0 != -1 && id1 != -1)
+ {
+ // Force insertion
+ m_connected_regions[id0].region_id = id0;
+ m_connected_regions[id1].region_id = id1;
+
+ connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1];
+ connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0];
+
+ if (turn.cluster_id < 0)
+ {
+ // Turn is not colocated, add reference to connection
+ prop0.count++;
+ prop1.count++;
+ }
+ else
+ {
+ // Turn is colocated, only add region reference if it was not yet registered
+ if (prop0.cluster_indices.count(turn.cluster_id) == 0)
+ {
+ prop0.count++;
+ }
+ if (prop1.cluster_indices.count(turn.cluster_id) == 0)
+ {
+ prop1.count++;
+ }
+ }
+ // Insert cluster-id (also -1 is inserted - reinsertion of
+ // same cluster id is OK)
+ prop0.cluster_indices.insert(turn.cluster_id);
+ prop1.cluster_indices.insert(turn.cluster_id);
+ }
+ }
+ }
+ }
+
+ inline bool connects_same_region(turn_type const& turn) const
+ {
+ if (turn.discarded)
+ {
+ // Discarded turns don't connect same region (otherwise discarded colocated uu turn
+ // could make a connection)
+ return false;
+ }
+
if (turn.cluster_id == -1)
{
- // If it is a uu/ii-turn (non clustered), it is never same zone
+ // If it is a uu/ii-turn (non clustered), it is never same region
return ! (turn.both(operation_union) || turn.both(operation_intersection));
}
- // It is a cluster, check zones of both operations
- return turn.operations[0].enriched.zone
- == turn.operations[1].enriched.zone;
+ if (operation_from_overlay<OverlayType>::value == operation_union)
+ {
+ // It is a cluster, check zones
+ // (assigned by sort_by_side/handle colocations) of both operations
+ return turn.operations[0].enriched.zone
+ == turn.operations[1].enriched.zone;
+ }
+
+ // If a cluster contains an ii/cc it is not same region (for intersection)
+ typename Clusters::const_iterator it = m_clusters.find(turn.cluster_id);
+ if (it == m_clusters.end())
+ {
+ // Should not occur
+ return true;
+ }
+
+ cluster_info const& cinfo = it->second;
+ for (set_iterator sit = cinfo.turn_indices.begin();
+ sit != cinfo.turn_indices.end(); ++sit)
+ {
+ turn_type const& cluster_turn = m_turns[*sit];
+ if (cluster_turn.both(operation_union)
+ || cluster_turn.both(operation_intersection))
+ {
+ return false;
+ }
+ }
+
+ // It is the same region
+ return false;
}
+
inline int get_region_id(turn_operation_type const& op) const
{
- std::map<ring_identifier, int>::const_iterator it
- = m_regions.find(ring_id_by_seg_id(op.seg_id));
- return it == m_regions.end() ? -1 : it->second;
+ return op.enriched.region_id;
}
- void create_region(ring_identifier const& ring_id, std::set<signed_size_type> const& ring_turn_indices, int region_id = -1)
+
+ void create_region(signed_size_type& new_region_id, ring_identifier const& ring_id,
+ merged_ring_properties& properties, int region_id = -1)
{
- std::map<ring_identifier, int>::const_iterator it = m_regions.find(ring_id);
- if (it != m_regions.end())
+ if (properties.region_id > 0)
{
- // The ring is already gathered in a region, quit
+ // Already handled
return;
}
+
+ // Assign new id if this is a new region
if (region_id == -1)
{
- region_id = m_region_id++;
+ region_id = new_region_id++;
}
// Assign this ring to specified region
- m_regions[ring_id] = region_id;
+ properties.region_id = region_id;
+
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl;
#endif
// Find connecting rings, recursively
- for (set_iterator sit = ring_turn_indices.begin();
- sit != ring_turn_indices.end(); ++sit)
+ for (set_iterator sit = properties.turn_indices.begin();
+ sit != properties.turn_indices.end(); ++sit)
{
signed_size_type const turn_index = *sit;
turn_type const& turn = m_turns[turn_index];
- if (! connects_same_zone(turn))
+ if (! connects_same_region(turn))
{
// This is a non clustered uu/ii-turn, or a cluster connecting different 'zones'
continue;
}
- // This turn connects two rings (interior connected), create the
- // same region
+ // Union: This turn connects two rings (interior connected), create the region
+ // Intersection: This turn connects two rings, set same regions for these two rings
for (int op_index = 0; op_index < 2; op_index++)
{
turn_operation_type const& op = turn.operations[op_index];
ring_identifier connected_ring_id = ring_id_by_seg_id(op.seg_id);
if (connected_ring_id != ring_id)
{
- propagate_region(connected_ring_id, region_id);
+ propagate_region(new_region_id, connected_ring_id, region_id);
}
}
}
}
- void check_turns_per_ring(ring_identifier const& ring_id,
- std::set<signed_size_type> const& ring_turn_indices)
+ void propagate_region(signed_size_type& new_region_id,
+ ring_identifier const& ring_id, int region_id)
{
- bool only_turn_on_ring = true;
- if (ring_turn_indices.size() > 1)
- {
- // More turns on this ring. Only leave only_turn_on_ring true
- // if they are all of the same cluster
- int cluster_id = -1;
- for (set_iterator sit = ring_turn_indices.begin();
- sit != ring_turn_indices.end(); ++sit)
- {
- turn_type const& turn = m_turns[*sit];
- if (turn.cluster_id == -1)
- {
- // Unclustered turn - and there are 2 or more turns
- // so the ring has different turns
- only_turn_on_ring = false;
- break;
- }
-
- // Clustered turn, check if it is the first or same as previous
- if (cluster_id == -1)
- {
- cluster_id = turn.cluster_id;
- }
- else if (turn.cluster_id != cluster_id)
- {
- only_turn_on_ring = false;
- break;
- }
- }
- }
-
- // Assign result to matching operation (a turn is always on two rings)
- for (set_iterator sit = ring_turn_indices.begin();
- sit != ring_turn_indices.end(); ++sit)
- {
- turn_type& turn = m_turns[*sit];
- for (int i = 0; i < 2; i++)
- {
- turn_operation_type& op = turn.operations[i];
- if (ring_id_by_seg_id(op.seg_id) == ring_id)
- {
- op.enriched.only_turn_on_ring = only_turn_on_ring;
- }
- }
- }
- }
-
- void propagate_region(ring_identifier const& ring_id, int region_id)
- {
- std::map<ring_identifier, std::set<signed_size_type> >::const_iterator it = m_turns_per_ring.find(ring_id);
+ typename merge_map::iterator it = m_turns_per_ring.find(ring_id);
if (it != m_turns_per_ring.end())
{
- create_region(ring_id, it->second, region_id);
+ create_region(new_region_id, ring_id, it->second, region_id);
}
}
+
void iterate()
{
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
@@ -199,26 +418,38 @@ struct traversal_switch_detector
// Collect turns per ring
m_turns_per_ring.clear();
- m_regions.clear();
- m_region_id = 1;
+ m_connected_regions.clear();
for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
{
turn_type const& turn = m_turns[turn_index];
+ if (turn.discarded
+ && operation_from_overlay<OverlayType>::value == operation_intersection)
+ {
+ // Discarded turn (union currently still needs it to determine regions)
+ continue;
+ }
+
for (int op_index = 0; op_index < 2; op_index++)
{
turn_operation_type const& op = turn.operations[op_index];
- m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].insert(turn_index);
+ m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].turn_indices.insert(turn_index);
}
}
// All rings having turns are in the map. Now iterate them
- for (std::map<ring_identifier, std::set<signed_size_type> >::const_iterator it
- = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
{
- create_region(it->first, it->second);
- check_turns_per_ring(it->first, it->second);
+ signed_size_type new_region_id = 1;
+ for (typename merge_map::iterator it
+ = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
+ {
+ create_region(new_region_id, it->first, it->second);
+ }
+
+ assign_regions();
+ get_isolated_regions();
+ assign_isolation();
}
// Now that all regions are filled, assign switch_source property
@@ -245,6 +476,10 @@ struct traversal_switch_detector
{
signed_size_type turn_index = *sit;
turn_type const& turn = m_turns[turn_index];
+ if (turn.colocated_ii && ! turn.colocated_uu)
+ {
+ continue;
+ }
for (int oi = 0; oi < 2; oi++)
{
int const region = get_region_id(turn.operations[oi]);
@@ -252,7 +487,7 @@ struct traversal_switch_detector
}
}
// Switch source if this cluster connects the same region
- cinfo.switch_source = regions.size() == 1;
+ cinfo.switch_source = regions.size() <= 1;
}
// Iterate through all uu/ii turns (non-clustered)
@@ -326,13 +561,10 @@ private:
Geometry2 const& m_geometry2;
Turns& m_turns;
Clusters& m_clusters;
+ merge_map m_turns_per_ring;
+ region_connection_map m_connected_regions;
RobustPolicy const& m_robust_policy;
Visitor& m_visitor;
-
- std::map<ring_identifier, int> m_regions;
- std::map<ring_identifier, std::set<signed_size_type> > m_turns_per_ring;
- int m_region_id;
-
};
}} // namespace detail::overlay
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
index e09af126c6..3a4c2e94a1 100644
--- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -89,18 +89,24 @@ struct turn_info
Point point;
method_type method;
+ bool touch_only; // True in case of method touch(interior) and lines do not cross
signed_size_type cluster_id; // For multiple turns on same location, >= 0. Else -1
bool discarded;
- bool colocated;
+
+ // TODO: move this to enriched
+ bool colocated_ii; // Colocated with a ii turn (TODO: or a ix turn)
+ bool colocated_uu; // Colocated with a uu turn or a ux turn
bool switch_source; // For u/u turns which can either switch or not
Container operations;
inline turn_info()
: method(method_none)
+ , touch_only(false)
, cluster_id(-1)
, discarded(false)
- , colocated(false)
+ , colocated_ii(false)
+ , colocated_uu(false)
, switch_source(false)
{}
@@ -133,7 +139,6 @@ struct turn_info
return has(operation_blocked);
}
-
private :
inline bool has12(operation_type type1, operation_type type2) const
{
diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp
index 12c6a54661..db134d548d 100644
--- a/boost/geometry/algorithms/detail/partition.hpp
+++ b/boost/geometry/algorithms/detail/partition.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
@@ -106,11 +107,11 @@ inline void expand_with_elements(Box& total, IteratorVector const& input,
// Match forward_range with itself
template <typename IteratorVector, typename VisitPolicy>
-inline void handle_one(IteratorVector const& input, VisitPolicy& visitor)
+inline bool handle_one(IteratorVector const& input, VisitPolicy& visitor)
{
- if (boost::size(input) == 0)
+ if (boost::empty(input))
{
- return;
+ return true;
}
typedef typename boost::range_iterator<IteratorVector const>::type it_type;
@@ -121,9 +122,14 @@ inline void handle_one(IteratorVector const& input, VisitPolicy& visitor)
it_type it2 = it1;
for (++it2; it2 != boost::end(input); ++it2)
{
- visitor.apply(**it1, **it2);
+ if (! visitor.apply(**it1, **it2))
+ {
+ return false; // interrupt
+ }
}
}
+
+ return true;
}
// Match forward range 1 with forward range 2
@@ -133,7 +139,7 @@ template
typename IteratorVector2,
typename VisitPolicy
>
-inline void handle_two(IteratorVector1 const& input1,
+inline bool handle_two(IteratorVector1 const& input1,
IteratorVector2 const& input2,
VisitPolicy& visitor)
{
@@ -147,9 +153,9 @@ inline void handle_two(IteratorVector1 const& input1,
IteratorVector2 const
>::type iterator_type2;
- if (boost::size(input1) == 0 || boost::size(input2) == 0)
+ if (boost::empty(input1) || boost::empty(input2))
{
- return;
+ return true;
}
for(iterator_type1 it1 = boost::begin(input1);
@@ -160,9 +166,14 @@ inline void handle_two(IteratorVector1 const& input1,
it2 != boost::end(input2);
++it2)
{
- visitor.apply(**it1, **it2);
+ if (! visitor.apply(**it1, **it2))
+ {
+ return false; // interrupt
+ }
}
}
+
+ return true;
}
template <typename IteratorVector>
@@ -223,7 +234,7 @@ class partition_one_range
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void next_level(Box const& box,
+ static inline bool next_level(Box const& box,
IteratorVector const& input,
std::size_t level, std::size_t min_elements,
VisitPolicy& visitor,
@@ -233,7 +244,7 @@ class partition_one_range
{
if (recurse_ok(input, min_elements, level))
{
- partition_one_range
+ return partition_one_range
<
1 - Dimension,
Box
@@ -242,7 +253,7 @@ class partition_one_range
}
else
{
- handle_one(input, visitor);
+ return handle_one(input, visitor);
}
}
@@ -256,18 +267,18 @@ class partition_one_range
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void next_level2(Box const& box,
- IteratorVector const& input1,
- IteratorVector const& input2,
- std::size_t level, std::size_t min_elements,
- VisitPolicy& visitor,
- ExpandPolicy const& expand_policy,
- OverlapsPolicy const& overlaps_policy,
- VisitBoxPolicy& box_policy)
+ static inline bool next_level2(Box const& box,
+ IteratorVector const& input1,
+ IteratorVector const& input2,
+ std::size_t level, std::size_t min_elements,
+ VisitPolicy& visitor,
+ ExpandPolicy const& expand_policy,
+ OverlapsPolicy const& overlaps_policy,
+ VisitBoxPolicy& box_policy)
{
if (recurse_ok(input1, input2, min_elements, level))
{
- partition_two_ranges
+ return partition_two_ranges
<
1 - Dimension, Box
>::apply(box, input1, input2, level + 1, min_elements,
@@ -276,7 +287,7 @@ class partition_one_range
}
else
{
- handle_two(input1, input2, visitor);
+ return handle_two(input1, input2, visitor);
}
}
@@ -289,7 +300,7 @@ public :
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void apply(Box const& box,
+ static inline bool apply(Box const& box,
IteratorVector const& input,
std::size_t level,
std::size_t min_elements,
@@ -308,29 +319,31 @@ public :
input, lower, upper, exceeding,
overlaps_policy);
- if (boost::size(exceeding) > 0)
+ if (! boost::empty(exceeding))
{
// Get the box of exceeding-only
Box exceeding_box = get_new_box(exceeding, expand_policy);
- // Recursively do exceeding elements only, in next dimension they
- // will probably be less exceeding within the new box
- next_level(exceeding_box, exceeding, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
-
- // Switch to two forward ranges, combine exceeding with
- // lower resp upper, but not lower/lower, upper/upper
- next_level2(exceeding_box, exceeding, lower, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
- next_level2(exceeding_box, exceeding, upper, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
+ // Recursively do exceeding elements only, in next dimension they
+ // will probably be less exceeding within the new box
+ if (! (next_level(exceeding_box, exceeding, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)
+ // Switch to two forward ranges, combine exceeding with
+ // lower resp upper, but not lower/lower, upper/upper
+ && next_level2(exceeding_box, exceeding, lower, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)
+ && next_level2(exceeding_box, exceeding, upper, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)) )
+ {
+ return false; // interrupt
+ }
}
// Recursively call operation both parts
- next_level(lower_box, lower, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
- next_level(upper_box, upper, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
+ return next_level(lower_box, lower, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)
+ && next_level(upper_box, upper, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy);
}
};
@@ -352,23 +365,23 @@ class partition_two_ranges
typename OverlapsPolicy2,
typename VisitBoxPolicy
>
- static inline void next_level(Box const& box,
- IteratorVector1 const& input1,
- IteratorVector2 const& input2,
- std::size_t level, std::size_t min_elements,
- VisitPolicy& visitor,
- ExpandPolicy1 const& expand_policy1,
- OverlapsPolicy1 const& overlaps_policy1,
- ExpandPolicy2 const& expand_policy2,
- OverlapsPolicy2 const& overlaps_policy2,
- VisitBoxPolicy& box_policy)
+ static inline bool next_level(Box const& box,
+ IteratorVector1 const& input1,
+ IteratorVector2 const& input2,
+ std::size_t level, std::size_t min_elements,
+ VisitPolicy& visitor,
+ ExpandPolicy1 const& expand_policy1,
+ OverlapsPolicy1 const& overlaps_policy1,
+ ExpandPolicy2 const& expand_policy2,
+ OverlapsPolicy2 const& overlaps_policy2,
+ VisitBoxPolicy& box_policy)
{
- partition_two_ranges
- <
- 1 - Dimension, Box
- >::apply(box, input1, input2, level + 1, min_elements,
- visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ return partition_two_ranges
+ <
+ 1 - Dimension, Box
+ >::apply(box, input1, input2, level + 1, min_elements,
+ visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy);
}
template <typename IteratorVector, typename ExpandPolicy>
@@ -408,17 +421,17 @@ public :
typename OverlapsPolicy2,
typename VisitBoxPolicy
>
- static inline void apply(Box const& box,
- IteratorVector1 const& input1,
- IteratorVector2 const& input2,
- std::size_t level,
- std::size_t min_elements,
- VisitPolicy& visitor,
- ExpandPolicy1 const& expand_policy1,
- OverlapsPolicy1 const& overlaps_policy1,
- ExpandPolicy2 const& expand_policy2,
- OverlapsPolicy2 const& overlaps_policy2,
- VisitBoxPolicy& box_policy)
+ static inline bool apply(Box const& box,
+ IteratorVector1 const& input1,
+ IteratorVector2 const& input2,
+ std::size_t level,
+ std::size_t min_elements,
+ VisitPolicy& visitor,
+ ExpandPolicy1 const& expand_policy1,
+ OverlapsPolicy1 const& overlaps_policy1,
+ ExpandPolicy2 const& expand_policy2,
+ OverlapsPolicy2 const& overlaps_policy2,
+ VisitBoxPolicy& box_policy)
{
box_policy.apply(box, level);
@@ -434,7 +447,7 @@ public :
input2, lower2, upper2, exceeding2,
overlaps_policy2);
- if (boost::size(exceeding1) > 0)
+ if (! boost::empty(exceeding1))
{
// All exceeding from 1 with 2:
@@ -442,13 +455,19 @@ public :
{
Box exceeding_box = get_new_box(exceeding1, exceeding2,
expand_policy1, expand_policy2);
- next_level(exceeding_box, exceeding1, exceeding2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! next_level(exceeding_box, exceeding1, exceeding2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy))
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(exceeding1, exceeding2, visitor);
+ if (! handle_two(exceeding1, exceeding2, visitor))
+ {
+ return false; // interrupt
+ }
}
// All exceeding from 1 with lower and upper of 2:
@@ -458,60 +477,87 @@ public :
if (recurse_ok(lower2, upper2, exceeding1, min_elements, level))
{
Box exceeding_box = get_new_box(exceeding1, expand_policy1);
- next_level(exceeding_box, exceeding1, lower2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
- next_level(exceeding_box, exceeding1, upper2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! (next_level(exceeding_box, exceeding1, lower2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)
+ && next_level(exceeding_box, exceeding1, upper2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(exceeding1, lower2, visitor);
- handle_two(exceeding1, upper2, visitor);
+ if (! (handle_two(exceeding1, lower2, visitor)
+ && handle_two(exceeding1, upper2, visitor)) )
+ {
+ return false; // interrupt
+ }
}
}
- if (boost::size(exceeding2) > 0)
+ if (! boost::empty(exceeding2))
{
// All exceeding from 2 with lower and upper of 1:
if (recurse_ok(lower1, upper1, exceeding2, min_elements, level))
{
Box exceeding_box = get_new_box(exceeding2, expand_policy2);
- next_level(exceeding_box, lower1, exceeding2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
- next_level(exceeding_box, upper1, exceeding2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! (next_level(exceeding_box, lower1, exceeding2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)
+ && next_level(exceeding_box, upper1, exceeding2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(lower1, exceeding2, visitor);
- handle_two(upper1, exceeding2, visitor);
+ if (! (handle_two(lower1, exceeding2, visitor)
+ && handle_two(upper1, exceeding2, visitor)) )
+ {
+ return false; // interrupt
+ }
}
}
if (recurse_ok(lower1, lower2, min_elements, level))
{
- next_level(lower_box, lower1, lower2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! next_level(lower_box, lower1, lower2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(lower1, lower2, visitor);
+ if (! handle_two(lower1, lower2, visitor))
+ {
+ return false; // interrupt
+ }
}
+
if (recurse_ok(upper1, upper2, min_elements, level))
{
- next_level(upper_box, upper1, upper2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! next_level(upper_box, upper1, upper2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(upper1, upper2, visitor);
+ if (! handle_two(upper1, upper2, visitor))
+ {
+ return false; // interrupt
+ }
}
+
+ return true;
}
};
@@ -577,13 +623,13 @@ public:
typename ExpandPolicy,
typename OverlapsPolicy
>
- static inline void apply(ForwardRange const& forward_range,
+ static inline bool apply(ForwardRange const& forward_range,
VisitPolicy& visitor,
ExpandPolicy const& expand_policy,
OverlapsPolicy const& overlaps_policy)
{
- apply(forward_range, visitor, expand_policy, overlaps_policy,
- default_min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range, visitor, expand_policy, overlaps_policy,
+ default_min_elements, detail::partition::visit_no_policy());
}
template
@@ -593,14 +639,14 @@ public:
typename ExpandPolicy,
typename OverlapsPolicy
>
- static inline void apply(ForwardRange const& forward_range,
+ static inline bool apply(ForwardRange const& forward_range,
VisitPolicy& visitor,
ExpandPolicy const& expand_policy,
OverlapsPolicy const& overlaps_policy,
std::size_t min_elements)
{
- apply(forward_range, visitor, expand_policy, overlaps_policy,
- min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range, visitor, expand_policy, overlaps_policy,
+ min_elements, detail::partition::visit_no_policy());
}
template
@@ -611,7 +657,7 @@ public:
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void apply(ForwardRange const& forward_range,
+ static inline bool apply(ForwardRange const& forward_range,
VisitPolicy& visitor,
ExpandPolicy const& expand_policy,
OverlapsPolicy const& overlaps_policy,
@@ -631,7 +677,7 @@ public:
expand_to_range<IncludePolicy1>(forward_range, total,
iterator_vector, expand_policy);
- detail::partition::partition_one_range
+ return detail::partition::partition_one_range
<
0, Box
>::apply(total, iterator_vector, 0, min_elements,
@@ -646,10 +692,15 @@ public:
iterator_type it2 = it1;
for(++it2; it2 != boost::end(forward_range); ++it2)
{
- visitor.apply(*it1, *it2);
+ if (! visitor.apply(*it1, *it2))
+ {
+ return false; // interrupt
+ }
}
}
}
+
+ return true;
}
template
@@ -660,15 +711,15 @@ public:
typename ExpandPolicy1,
typename OverlapsPolicy1
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
OverlapsPolicy1 const& overlaps_policy1)
{
- apply(forward_range1, forward_range2, visitor,
- expand_policy1, overlaps_policy1, expand_policy1, overlaps_policy1,
- default_min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range1, forward_range2, visitor,
+ expand_policy1, overlaps_policy1, expand_policy1, overlaps_policy1,
+ default_min_elements, detail::partition::visit_no_policy());
}
template
@@ -681,7 +732,7 @@ public:
typename ExpandPolicy2,
typename OverlapsPolicy2
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
@@ -689,9 +740,9 @@ public:
ExpandPolicy2 const& expand_policy2,
OverlapsPolicy2 const& overlaps_policy2)
{
- apply(forward_range1, forward_range2, visitor,
- expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2,
- default_min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range1, forward_range2, visitor,
+ expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2,
+ default_min_elements, detail::partition::visit_no_policy());
}
template
@@ -704,7 +755,7 @@ public:
typename ExpandPolicy2,
typename OverlapsPolicy2
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
@@ -713,9 +764,9 @@ public:
OverlapsPolicy2 const& overlaps_policy2,
std::size_t min_elements)
{
- apply(forward_range1, forward_range2, visitor,
- expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy1,
- min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range1, forward_range2, visitor,
+ expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy1,
+ min_elements, detail::partition::visit_no_policy());
}
template
@@ -729,7 +780,7 @@ public:
typename OverlapsPolicy2,
typename VisitBoxPolicy
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
@@ -761,7 +812,7 @@ public:
expand_to_range<IncludePolicy2>(forward_range2, total,
iterator_vector2, expand_policy2);
- detail::partition::partition_two_ranges
+ return detail::partition::partition_two_ranges
<
0, Box
>::apply(total, iterator_vector1, iterator_vector2,
@@ -779,10 +830,15 @@ public:
it2 != boost::end(forward_range2);
++it2)
{
- visitor.apply(*it1, *it2);
+ if (! visitor.apply(*it1, *it2))
+ {
+ return false; // interrupt
+ }
}
}
}
+
+ return true;
}
};
diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
index 607ba81531..b8ea5e30e6 100644
--- a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
+++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
@@ -5,10 +5,11 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -19,11 +20,13 @@
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
+
namespace boost { namespace geometry
{
@@ -32,6 +35,26 @@ namespace boost { namespace geometry
namespace detail
{
+template <typename Point1, typename Point2, typename Point3>
+inline bool collinear_point_is_spike_or_equal(Point1 const& last_point,
+ Point2 const& segment_a,
+ Point3 const& segment_b)
+{
+ // Check if segment is equal
+ int const sgn_x1 = sign_of_difference<0>(last_point, segment_b);
+ int const sgn_y1 = sign_of_difference<1>(last_point, segment_b);
+ if (sgn_x1 == 0 && sgn_y1 == 0)
+ {
+ return true;
+ }
+
+ // Check if segment moves forward
+ int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a);
+ int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a);
+
+ return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
+}
+
// Checks if a point ("last_point") causes a spike w.r.t.
// the specified two other points (segment_a, segment_b)
//
@@ -42,33 +65,29 @@ namespace detail
// So specify last point first, then (a,b)
// The segment's orientation does matter: if lp is to the right of b
// no spike is reported
-template <typename Point1, typename Point2, typename Point3>
-static inline bool point_is_spike_or_equal(Point1 const& last_point,
- Point2 const& segment_a,
- Point3 const& segment_b)
+template
+<
+ typename Point1, typename Point2, typename Point3,
+ typename SideStrategy
+>
+static inline bool point_is_spike_or_equal(Point1 const& last_point, // prev | back
+ Point2 const& segment_a, // next | back - 2
+ Point3 const& segment_b, // curr | back - 1 | spike's vertex
+ SideStrategy const& strategy)
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point1>::type
- >::type side_strategy;
-
- int const side = side_strategy::apply(last_point, segment_a, segment_b);
+ int const side = strategy.apply(segment_a, segment_b, last_point);
if (side == 0)
{
// Last point is collinear w.r.t previous segment.
- // Check if it is equal
- int const sgn_x1 = sign_of_difference<0>(last_point, segment_b);
- int const sgn_y1 = sign_of_difference<1>(last_point, segment_b);
- if (sgn_x1 == 0 && sgn_y1 == 0)
- {
- return true;
- }
-
- // Check if it moves forward
- int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a);
- int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a);
-
- return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
+#ifdef BOOST_GEOMETRY_ENABLE_POINT_IS_SPIKE_OR_EQUAL_TEST
+ bool r1 = collinear_point_is_spike_or_equal(last_point, segment_a, segment_b);
+ bool r2 = direction_code(segment_a, segment_b, last_point) < 1;
+ if (r1 != r2)
+ std::cout << "spike detection failure with: " << r1 << " " << r2 << std::endl;
+ return r2;
+#else
+ return direction_code(segment_a, segment_b, last_point) < 1;
+#endif
}
return false;
}
@@ -78,14 +97,16 @@ template
typename Point1,
typename Point2,
typename Point3,
+ typename SideStrategy,
typename RobustPolicy
>
static inline bool point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
- if (point_is_spike_or_equal(last_point, segment_a, segment_b))
+ if (point_is_spike_or_equal(last_point, segment_a, segment_b, strategy))
{
return true;
}
@@ -111,7 +132,8 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point,
(
last_point_rob,
segment_a_rob,
- segment_b_rob
+ segment_b_rob,
+ strategy
);
}
diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp
index 1c751c23e4..831081aa69 100644
--- a/boost/geometry/algorithms/detail/point_on_border.hpp
+++ b/boost/geometry/algorithms/detail/point_on_border.hpp
@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,6 +22,7 @@
#include <cstddef>
#include <boost/range.hpp>
+#include <boost/static_assert.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
@@ -29,6 +34,8 @@
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/util/condition.hpp>
+
namespace boost { namespace geometry
{
@@ -39,10 +46,10 @@ namespace detail { namespace point_on_border
{
-template<typename Point>
struct get_point
{
- static inline bool apply(Point& destination, Point const& source, bool)
+ template <typename Point>
+ static inline bool apply(Point& destination, Point const& source)
{
destination = source;
return true;
@@ -74,66 +81,77 @@ struct midpoint_helper<Point, DimensionCount, DimensionCount>
};
-template<typename Point, typename Range>
+template <bool Midpoint>
struct point_on_range
{
- static inline bool apply(Point& point, Range const& range, bool midpoint)
+ // Version with iterator
+ template<typename Point, typename Iterator>
+ static inline bool apply(Point& point, Iterator begin, Iterator end)
{
- const std::size_t n = boost::size(range);
- if (midpoint && n > 1)
+ Iterator it = begin;
+ if (it == end)
{
- typedef typename boost::range_iterator
- <
- Range const
- >::type iterator;
-
- iterator it = boost::begin(range);
- iterator prev = it++;
- while (it != boost::end(range)
- && detail::equals::equals_point_point(*it, *prev))
- {
- prev = it++;
- }
- if (it != boost::end(range))
- {
- return midpoint_helper
- <
- Point,
- 0, dimension<Point>::value
- >::apply(point, *prev, *it);
- }
+ return false;
}
- if (n > 0)
+ if (! Midpoint)
{
- geometry::detail::conversion::convert_point_to_point(*boost::begin(range), point);
+ geometry::detail::conversion::convert_point_to_point(*it, point);
return true;
}
+
+ Iterator prev = it++;
+
+ // Go to next non-duplicate point
+ while (it != end
+ && detail::equals::equals_point_point(*it, *prev))
+ {
+ prev = it++;
+ }
+ if (it != end)
+ {
+ return midpoint_helper
+ <
+ Point,
+ 0, dimension<Point>::value
+ >::apply(point, *prev, *it);
+ }
return false;
}
+
+ // Version with range
+ template<typename Point, typename Range>
+ static inline bool apply(Point& point, Range const& range)
+ {
+ typedef typename geometry::cs_tag<Point>::type cs_tag;
+ BOOST_STATIC_ASSERT((! Midpoint || boost::is_same<cs_tag, cartesian_tag>::value));
+
+ return apply(point, boost::begin(range), boost::end(range));
+ }
};
-template<typename Point, typename Polygon>
+template <bool Midpoint>
struct point_on_polygon
{
- static inline bool apply(Point& point, Polygon const& polygon, bool midpoint)
+ template<typename Point, typename Polygon>
+ static inline bool apply(Point& point, Polygon const& polygon)
{
return point_on_range
<
- Point,
- typename ring_type<Polygon>::type
- >::apply(point, exterior_ring(polygon), midpoint);
+ Midpoint
+ >::apply(point, exterior_ring(polygon));
}
};
-template<typename Point, typename Box>
+template <bool Midpoint>
struct point_on_box
{
- static inline bool apply(Point& point, Box const& box, bool midpoint)
+ template<typename Point, typename Box>
+ static inline bool apply(Point& point, Box const& box)
{
- if (midpoint)
+ if (BOOST_GEOMETRY_CONDITION(Midpoint))
{
Point p1, p2;
detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, p1);
@@ -154,15 +172,11 @@ struct point_on_box
};
-template
-<
- typename Point,
- typename MultiGeometry,
- typename Policy
->
+template <typename Policy>
struct point_on_multi
{
- static inline bool apply(Point& point, MultiGeometry const& multi, bool midpoint)
+ template<typename Point, typename MultiGeometry>
+ static inline bool apply(Point& point, MultiGeometry const& multi)
{
// Take a point on the first multi-geometry
// (i.e. the first that is not empty)
@@ -173,7 +187,7 @@ struct point_on_multi
it != boost::end(multi);
++it)
{
- if (Policy::apply(point, *it, midpoint))
+ if (Policy::apply(point, *it))
{
return true;
}
@@ -195,70 +209,57 @@ namespace dispatch
template
<
typename GeometryTag,
- typename Point,
- typename Geometry
+ bool Midpoint
>
struct point_on_border
{};
-template<typename Point>
-struct point_on_border<point_tag, Point, Point>
- : detail::point_on_border::get_point<Point>
+template <bool Midpoint>
+struct point_on_border<point_tag, Midpoint>
+ : detail::point_on_border::get_point
{};
-template<typename Point, typename Linestring>
-struct point_on_border<linestring_tag, Point, Linestring>
- : detail::point_on_border::point_on_range<Point, Linestring>
+template <bool Midpoint>
+struct point_on_border<linestring_tag, Midpoint>
+ : detail::point_on_border::point_on_range<Midpoint>
{};
-template<typename Point, typename Ring>
-struct point_on_border<ring_tag, Point, Ring>
- : detail::point_on_border::point_on_range<Point, Ring>
+template <bool Midpoint>
+struct point_on_border<ring_tag, Midpoint>
+ : detail::point_on_border::point_on_range<Midpoint>
{};
-template<typename Point, typename Polygon>
-struct point_on_border<polygon_tag, Point, Polygon>
- : detail::point_on_border::point_on_polygon<Point, Polygon>
+template <bool Midpoint>
+struct point_on_border<polygon_tag, Midpoint>
+ : detail::point_on_border::point_on_polygon<Midpoint>
{};
-template<typename Point, typename Box>
-struct point_on_border<box_tag, Point, Box>
- : detail::point_on_border::point_on_box<Point, Box>
+template <bool Midpoint>
+struct point_on_border<box_tag, Midpoint>
+ : detail::point_on_border::point_on_box<Midpoint>
{};
-template<typename Point, typename Multi>
-struct point_on_border<multi_polygon_tag, Point, Multi>
+template <bool Midpoint>
+struct point_on_border<multi_polygon_tag, Midpoint>
: detail::point_on_border::point_on_multi
<
- Point,
- Multi,
- detail::point_on_border::point_on_polygon
- <
- Point,
- typename boost::range_value<Multi>::type
- >
+ detail::point_on_border::point_on_polygon<Midpoint>
>
{};
-template<typename Point, typename Multi>
-struct point_on_border<multi_linestring_tag, Point, Multi>
+template <bool Midpoint>
+struct point_on_border<multi_linestring_tag, Midpoint>
: detail::point_on_border::point_on_multi
<
- Point,
- Multi,
- detail::point_on_border::point_on_range
- <
- Point,
- typename boost::range_value<Multi>::type
- >
+ detail::point_on_border::point_on_range<Midpoint>
>
{};
@@ -273,18 +274,12 @@ struct point_on_border<multi_linestring_tag, Point, Multi>
\tparam Geometry geometry type. This also defines the type of the output point
\param point to assign
\param geometry geometry to take point from
-\param midpoint boolean flag, true if the point should not be a vertex, but some point
- in between of two vertices
\return TRUE if successful, else false.
It is only false if polygon/line have no points
\note for a polygon, it is always a point on the exterior ring
-\note for take_midpoint, it is not taken from two consecutive duplicate vertices,
- (unless there are no other).
*/
template <typename Point, typename Geometry>
-inline bool point_on_border(Point& point,
- Geometry const& geometry,
- bool midpoint = false)
+inline bool point_on_border(Point& point, Geometry const& geometry)
{
concepts::check<Point>();
concepts::check<Geometry const>();
@@ -292,12 +287,32 @@ inline bool point_on_border(Point& point,
return dispatch::point_on_border
<
typename tag<Geometry>::type,
- Point,
- Geometry
- >::apply(point, geometry, midpoint);
+ false
+ >::apply(point, geometry);
}
+/*!
+\tparam Midpoint boolean flag, true if the point should not be a vertex, but some point
+ in between of two vertices
+\note for Midpoint, it is not taken from two consecutive duplicate vertices,
+ (unless there are no other).
+ */
+/*
+template <bool Midpoint, typename Point, typename Geometry>
+inline bool point_on_border(Point& point, Geometry const& geometry)
+{
+ concepts::check<Point>();
+ concepts::check<Geometry const>();
+
+ return dispatch::point_on_border
+ <
+ typename tag<Geometry>::type,
+ Midpoint
+ >::apply(point, geometry);
+}
+*/
+
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/relate/implementation.hpp b/boost/geometry/algorithms/detail/relate/implementation.hpp
index 3bd0f806c1..8f7942d46e 100644
--- a/boost/geometry/algorithms/detail/relate/implementation.hpp
+++ b/boost/geometry/algorithms/detail/relate/implementation.hpp
@@ -23,6 +23,7 @@
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
+#include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp>
#include <boost/geometry/strategies/intersection.hpp>
@@ -81,6 +82,16 @@ struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true>
: detail::relate::geometry_point<Geometry, Point>
{};
+template <typename MultiPoint, typename Geometry, typename Tag2, int TopDim2>
+struct relate<MultiPoint, Geometry, multi_point_tag, Tag2, 0, TopDim2, false>
+ : detail::relate::multi_point_geometry<MultiPoint, Geometry>
+{};
+
+template <typename Geometry, typename MultiPoint, typename Tag1, int TopDim1>
+struct relate<Geometry, MultiPoint, Tag1, multi_point_tag, TopDim1, 0, false>
+ : detail::relate::geometry_multi_point<Geometry, MultiPoint>
+{};
+
template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true>
diff --git a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
new file mode 100644
index 0000000000..47c6963b87
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
@@ -0,0 +1,568 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
+
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
+#include <boost/geometry/algorithms/detail/relate/result.hpp>
+#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+
+#include <boost/geometry/core/is_areal.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/index/rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate
+{
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct multi_point_geometry_eb
+{
+ template <typename MultiPoint>
+ static inline bool apply(MultiPoint const& ,
+ detail::relate::topology_check<Geometry> const& )
+ {
+ return true;
+ }
+};
+
+template <typename Geometry>
+struct multi_point_geometry_eb<Geometry, linestring_tag>
+{
+ template <typename Points>
+ struct boundary_visitor
+ {
+ boundary_visitor(Points const& points)
+ : m_points(points)
+ , m_boundary_found(false)
+ {}
+
+ template <typename Point>
+ struct find_pred
+ {
+ find_pred(Point const& point)
+ : m_point(point)
+ {}
+
+ template <typename Pt>
+ bool operator()(Pt const& pt) const
+ {
+ return detail::equals::equals_point_point(pt, m_point);
+ }
+
+ Point const& m_point;
+ };
+
+ template <typename Point>
+ bool apply(Point const& boundary_point)
+ {
+ if (std::find_if(m_points.begin(), m_points.end(), find_pred<Point>(boundary_point)) == m_points.end())
+ {
+ m_boundary_found = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool result() const { return m_boundary_found; }
+
+ private:
+ Points const& m_points;
+ bool m_boundary_found;
+ };
+
+ template <typename MultiPoint>
+ static inline bool apply(MultiPoint const& multi_point,
+ detail::relate::topology_check<Geometry> const& tc)
+ {
+ boundary_visitor<MultiPoint> visitor(multi_point);
+ tc.for_each_boundary_point(visitor);
+ return visitor.result();
+ }
+};
+
+template <typename Geometry>
+struct multi_point_geometry_eb<Geometry, multi_linestring_tag>
+{
+ template <typename Points>
+ struct boundary_visitor
+ {
+ boundary_visitor(Points const& points)
+ : m_points(points)
+ , m_boundary_found(false)
+ {}
+
+ template <typename Point>
+ bool apply(Point const& boundary_point)
+ {
+ if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, relate::less()))
+ {
+ m_boundary_found = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool result() const { return m_boundary_found; }
+
+ private:
+ Points const& m_points;
+ bool m_boundary_found;
+ };
+
+ template <typename MultiPoint>
+ static inline bool apply(MultiPoint const& multi_point,
+ detail::relate::topology_check<Geometry> const& tc)
+ {
+ typedef typename boost::range_value<MultiPoint>::type point_type;
+ typedef std::vector<point_type> points_type;
+ points_type points(boost::begin(multi_point), boost::end(multi_point));
+ std::sort(points.begin(), points.end(), relate::less());
+
+ boundary_visitor<points_type> visitor(points);
+ tc.for_each_boundary_point(visitor);
+ return visitor.result();
+ }
+};
+
+// SingleGeometry - Linear or Areal
+template <typename MultiPoint, typename SingleGeometry, bool Transpose = false>
+struct multi_point_single_geometry
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ SingleGeometry const& single_geometry,
+ Result & result,
+ Strategy const& strategy)
+ {
+ typedef typename point_type<SingleGeometry>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+
+ box2_type box2;
+ geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
+ geometry::detail::expand_by_epsilon(box2);
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ if (! (relate::may_update<interior, interior, '0', Transpose>(result)
+ || relate::may_update<interior, boundary, '0', Transpose>(result)
+ || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
+ {
+ break;
+ }
+
+ // The default strategy is enough for Point/Box
+ if (detail::disjoint::disjoint_point_box(*it, box2))
+ {
+ relate::set<interior, exterior, '0', Transpose>(result);
+ }
+ else
+ {
+ int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy);
+
+ if (in_val > 0) // within
+ {
+ relate::set<interior, interior, '0', Transpose>(result);
+ }
+ else if (in_val == 0)
+ {
+ relate::set<interior, boundary, '0', Transpose>(result);
+ }
+ else // in_val < 0 - not within
+ {
+ relate::set<interior, exterior, '0', Transpose>(result);
+ }
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
+ {
+ return;
+ }
+ }
+
+ typedef detail::relate::topology_check<SingleGeometry> tc_t;
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
+ {
+ tc_t tc(single_geometry);
+
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ && tc.has_interior() )
+ {
+ // TODO: this is not true if a linestring is degenerated to a point
+ // then the interior has topological dimension = 0, not 1
+ relate::set<exterior, interior, tc_t::interior, Transpose>(result);
+ }
+
+ if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
+ && tc.has_boundary() )
+ {
+ if (multi_point_geometry_eb<SingleGeometry>::apply(multi_point, tc))
+ relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ }
+
+ relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
+ }
+};
+
+
+// MultiGeometry - Linear or Areal
+// part of the algorithm calculating II and IB when no IE has to be calculated
+// using partition()
+template <typename MultiPoint, typename MultiGeometry, bool Transpose>
+class multi_point_multi_geometry_ii_ib
+{
+ struct expand_box_point
+ {
+ template <typename Box, typename Point>
+ static inline void apply(Box& total, Point const& point)
+ {
+ geometry::expand(total, point);
+ }
+ };
+
+ struct expand_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ static inline void apply(Box& total, BoxPair const& box_pair)
+ {
+ geometry::expand(total, box_pair.first);
+ }
+ };
+
+ struct overlaps_box_point
+ {
+ template <typename Box, typename Point>
+ static inline bool apply(Box const& box, Point const& point)
+ {
+ // The default strategy is enough for Point/Box
+ return ! detail::disjoint::disjoint_point_box(point, box);
+ }
+ };
+
+ struct overlaps_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ static inline bool apply(Box const& box, BoxPair const& box_pair)
+ {
+ // The default strategy is enough for Box/Box
+ return ! detail::disjoint::disjoint_box_box(box_pair.first, box);
+ }
+ };
+
+ template <typename Result, typename PtSegStrategy>
+ class item_visitor_type
+ {
+ public:
+ item_visitor_type(MultiGeometry const& multi_geometry,
+ detail::relate::topology_check<MultiGeometry> const& tc,
+ Result & result,
+ PtSegStrategy const& strategy)
+ : m_multi_geometry(multi_geometry)
+ , m_tc(tc)
+ , m_result(result)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Point, typename BoxPair>
+ inline bool apply(Point const& point, BoxPair const& box_pair)
+ {
+ // The default strategy is enough for Point/Box
+ if (! detail::disjoint::disjoint_point_box(point, box_pair.first))
+ {
+ typename boost::range_value<MultiGeometry>::type const&
+ single = range::at(m_multi_geometry, box_pair.second);
+
+ int in_val = detail::within::point_in_geometry(point, single, m_strategy);
+
+ if (in_val > 0) // within
+ {
+ relate::set<interior, interior, '0', Transpose>(m_result);
+ }
+ else if (in_val == 0)
+ {
+ if (m_tc.check_boundary_point(point))
+ relate::set<interior, boundary, '0', Transpose>(m_result);
+ else
+ relate::set<interior, interior, '0', Transpose>(m_result);
+ }
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) )
+ {
+ return false;
+ }
+
+ if (! (relate::may_update<interior, interior, '0', Transpose>(m_result)
+ || relate::may_update<interior, boundary, '0', Transpose>(m_result) ) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ private:
+ MultiGeometry const& m_multi_geometry;
+ detail::relate::topology_check<MultiGeometry> const& m_tc;
+ Result & m_result;
+ PtSegStrategy const& m_strategy;
+ };
+
+public:
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point1_type> box1_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ MultiGeometry const& multi_geometry,
+ std::vector<box_pair_type> const& boxes,
+ detail::relate::topology_check<MultiGeometry> const& tc,
+ Result & result,
+ Strategy const& strategy)
+ {
+ item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy);
+
+ geometry::partition
+ <
+ box1_type
+ >::apply(multi_point, boxes, visitor,
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_box_pair(),
+ overlaps_box_box_pair());
+ }
+
+};
+
+// MultiGeometry - Linear or Areal
+// part of the algorithm calculating II, IB and IE
+// using rtree
+template <typename MultiPoint, typename MultiGeometry, bool Transpose>
+struct multi_point_multi_geometry_ii_ib_ie
+{
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point1_type> box1_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+ typedef std::vector<box_pair_type> boxes_type;
+ typedef typename boxes_type::const_iterator boxes_iterator;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ MultiGeometry const& multi_geometry,
+ std::vector<box_pair_type> const& boxes,
+ detail::relate::topology_check<MultiGeometry> const& tc,
+ Result & result,
+ Strategy const& strategy)
+ {
+ index::rtree<box_pair_type, index::rstar<4> > rt(boxes.begin(), boxes.end());
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ if (! (relate::may_update<interior, interior, '0', Transpose>(result)
+ || relate::may_update<interior, boundary, '0', Transpose>(result)
+ || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
+ {
+ return;
+ }
+
+ typename boost::range_value<MultiPoint>::type const& point = *it;
+
+ boxes_type boxes_found;
+ rt.query(index::intersects(point), std::back_inserter(boxes_found));
+
+ bool found_ii_or_ib = false;
+ for (boxes_iterator bi = boxes_found.begin() ; bi != boxes_found.end() ; ++bi)
+ {
+ typename boost::range_value<MultiGeometry>::type const&
+ single = range::at(multi_geometry, bi->second);
+
+ int in_val = detail::within::point_in_geometry(point, single, strategy);
+
+ if (in_val > 0) // within
+ {
+ relate::set<interior, interior, '0', Transpose>(result);
+ found_ii_or_ib = true;
+ }
+ else if (in_val == 0) // on boundary of single
+ {
+ if (tc.check_boundary_point(point))
+ relate::set<interior, boundary, '0', Transpose>(result);
+ else
+ relate::set<interior, interior, '0', Transpose>(result);
+ found_ii_or_ib = true;
+ }
+ }
+
+ // neither interior nor boundary found -> exterior
+ if (found_ii_or_ib == false)
+ {
+ relate::set<interior, exterior, '0', Transpose>(result);
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
+ {
+ return;
+ }
+ }
+ }
+};
+
+// MultiGeometry - Linear or Areal
+template <typename MultiPoint, typename MultiGeometry, bool Transpose = false>
+struct multi_point_multi_geometry
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ MultiGeometry const& multi_geometry,
+ Result & result,
+ Strategy const& strategy)
+ {
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+
+ typename Strategy::envelope_strategy_type const
+ envelope_strategy = strategy.get_envelope_strategy();
+
+ std::size_t count2 = boost::size(multi_geometry);
+ std::vector<box_pair_type> boxes(count2);
+ for (std::size_t i = 0 ; i < count2 ; ++i)
+ {
+ geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
+ geometry::detail::expand_by_epsilon(boxes[i].first);
+ boxes[i].second = i;
+ }
+
+ typedef detail::relate::topology_check<MultiGeometry> tc_t;
+ tc_t tc(multi_geometry);
+
+ if ( relate::may_update<interior, interior, '0', Transpose>(result)
+ || relate::may_update<interior, boundary, '0', Transpose>(result)
+ || relate::may_update<interior, exterior, '0', Transpose>(result) )
+ {
+ // If there is no need to calculate IE, use partition
+ if (! relate::may_update<interior, exterior, '0', Transpose>(result) )
+ {
+ multi_point_multi_geometry_ii_ib<MultiPoint, MultiGeometry, Transpose>
+ ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
+ }
+ else // otherwise use rtree
+ {
+ multi_point_multi_geometry_ii_ib_ie<MultiPoint, MultiGeometry, Transpose>
+ ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
+ }
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
+ {
+ return;
+ }
+
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
+ {
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ && tc.has_interior() )
+ {
+ // TODO: this is not true if a linestring is degenerated to a point
+ // then the interior has topological dimension = 0, not 1
+ relate::set<exterior, interior, tc_t::interior, Transpose>(result);
+ }
+
+ if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
+ && tc.has_boundary() )
+ {
+ if (multi_point_geometry_eb<MultiGeometry>::apply(multi_point, tc))
+ relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ }
+
+ relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
+ }
+
+};
+
+
+template
+<
+ typename MultiPoint, typename Geometry,
+ bool Transpose = false,
+ bool isMulti = boost::is_same
+ <
+ typename tag_cast
+ <
+ typename tag<Geometry>::type, multi_tag
+ >::type,
+ multi_tag
+ >::value
+>
+struct multi_point_geometry
+ : multi_point_single_geometry<MultiPoint, Geometry, Transpose>
+{};
+
+template <typename MultiPoint, typename Geometry, bool Transpose>
+struct multi_point_geometry<MultiPoint, Geometry, Transpose, true>
+ : multi_point_multi_geometry<MultiPoint, Geometry, Transpose>
+{};
+
+
+// transposed result of multi_point_geometry
+template <typename Geometry, typename MultiPoint>
+struct geometry_multi_point
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(Geometry const& geometry, MultiPoint const& multi_point,
+ Result & result, Strategy const& strategy)
+ {
+ multi_point_geometry<MultiPoint, Geometry, true>::apply(multi_point, geometry, result, strategy);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
index a0c6c0d49b..e78a404b21 100644
--- a/boost/geometry/algorithms/detail/relate/point_geometry.hpp
+++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
@@ -60,29 +60,27 @@ struct point_geometry
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
- // the point is on the boundary
- if ( pig == 0 )
+ typedef detail::relate::topology_check<Geometry> tc_t;
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
{
- // NOTE: even for MLs, if there is at least one boundary point,
- // somewhere there must be another one
-
- // check if there are other boundaries outside
- typedef detail::relate::topology_check<Geometry> tc_t;
- //tc_t tc(geometry, point);
- //if ( tc.has_interior )
- relate::set<exterior, interior, tc_t::interior, Transpose>(result);
- //if ( tc.has_boundary )
- relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
- }
- else
- {
- // check if there is a boundary in Geometry
- typedef detail::relate::topology_check<Geometry> tc_t;
- tc_t tc(geometry);
- if ( tc.has_interior )
+ // the point is on the boundary
+ if ( pig == 0 )
+ {
+ // NOTE: even for MLs, if there is at least one boundary point,
+ // somewhere there must be another one
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
- if ( tc.has_boundary )
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ else
+ {
+ // check if there is a boundary in Geometry
+ tc_t tc(geometry);
+ if ( tc.has_interior() )
+ relate::set<exterior, interior, tc_t::interior, Transpose>(result);
+ if ( tc.has_boundary() )
+ relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
}
}
};
diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp
index b41d346f0b..68d8be031e 100644
--- a/boost/geometry/algorithms/detail/relate/point_point.hpp
+++ b/boost/geometry/algorithms/detail/relate/point_point.hpp
@@ -165,22 +165,41 @@ struct multipoint_multipoint
}
}
-// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
+ // The geometry containing smaller number of points will be analysed first
+ if ( boost::size(multi_point1) < boost::size(multi_point2) )
+ {
+ search_both<false>(multi_point1, multi_point2, result);
+ }
+ else
+ {
+ search_both<true>(multi_point2, multi_point1, result);
+ }
-// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
-// so if e.g. only I/I must be analysed we musn't check the other MPt
+ relate::set<exterior, exterior, result_dimension<MultiPoint1>::value>(result);
+ }
-// TODO: Also, the geometry with the smaller number of points may be analysed first
- //if ( boost::size(multi_point1) < boost::size(multi_point2) )
+ template <bool Transpose, typename MPt1, typename MPt2, typename Result>
+ static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt,
+ Result & result)
+ {
+ if ( relate::may_update<interior, interior, '0'>(result)
+ || relate::may_update<interior, exterior, '0'>(result)
+ || relate::may_update<exterior, interior, '0'>(result) )
+ {
+ // NlogN + MlogN
+ bool is_disjoint = search<Transpose>(first_sorted_mpt, first_iterated_mpt, result);
- // NlogN + MlogN
- bool all_handled = search<false>(multi_point1, multi_point2, result);
-
- if ( BOOST_GEOMETRY_CONDITION(all_handled || result.interrupt) )
- return;
+ if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) )
+ return;
+ }
- // MlogM + NlogM
- search<true>(multi_point2, multi_point1, result);
+ if ( relate::may_update<interior, interior, '0'>(result)
+ || relate::may_update<interior, exterior, '0'>(result)
+ || relate::may_update<exterior, interior, '0'>(result) )
+ {
+ // MlogM + NlogM
+ search<! Transpose>(first_iterated_mpt, first_sorted_mpt, result);
+ }
}
template <bool Transpose,
@@ -215,9 +234,6 @@ struct multipoint_multipoint
break;
}
- // an optimization
- bool all_handled = false;
-
if ( found_inside ) // some point of MP2 is equal to some of MP1
{
// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
@@ -234,14 +250,10 @@ struct multipoint_multipoint
{
relate::set<interior, exterior, '0', Transpose>(result);
relate::set<exterior, interior, '0', Transpose>(result);
-
- // if no point is intersecting the other MPt then we musn't analyse the reversed case
- all_handled = true;
}
- relate::set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result);
-
- return all_handled;
+ // if no point is intersecting the other MPt then we musn't analyse the reversed case
+ return ! found_inside;
}
};
diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp
index caa8a3c22d..654999d8fb 100644
--- a/boost/geometry/algorithms/detail/relate/topology_check.hpp
+++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp
@@ -1,22 +1,23 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
-#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
-#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/util/has_nan_coordinate.hpp>
+#include <boost/geometry/util/range.hpp>
+
namespace boost { namespace geometry {
@@ -51,31 +52,63 @@ struct topology_check<Linestring, linestring_tag>
static const char interior = '1';
static const char boundary = '0';
- bool has_interior;
- bool has_boundary;
-
topology_check(Linestring const& ls)
+ : m_ls(ls)
+ , m_is_initialized(false)
+ {}
+
+ bool has_interior() const
{
- init(ls, 0); /*dummy param*/
+ init();
+ return m_has_interior;
}
- template <typename IgnoreBoundaryPoint>
- topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp)
+ bool has_boundary() const
{
- init(ls, ibp); /*dummy param, won't be used*/
+ init();
+ return m_has_boundary;
}
- // Even if some point is on the boundary, if the Linestring has the boundary,
- // there will be second boundary point different than IgnoreBoundaryPoint
- template <typename IgnoreBoundaryPoint>
- void init(Linestring const& ls, IgnoreBoundaryPoint const&)
+ /*template <typename Point>
+ bool check_boundary_point(Point const& point) const
{
- std::size_t count = boost::size(ls);
- has_interior = count > 0;
+ init();
+ return m_has_boundary
+ && ( equals::equals_point_point(point, range::front(m_ls))
+ || equals::equals_point_point(point, range::back(m_ls)) );
+ }*/
+
+ template <typename Visitor>
+ void for_each_boundary_point(Visitor & visitor) const
+ {
+ init();
+ if (m_has_boundary)
+ {
+ if (visitor.apply(range::front(m_ls)))
+ visitor.apply(range::back(m_ls));
+ }
+ }
+
+private:
+ void init() const
+ {
+ if (m_is_initialized)
+ return;
+
+ std::size_t count = boost::size(m_ls);
+ m_has_interior = count > 0;
// NOTE: Linestring with all points equal is treated as 1d linear ring
- has_boundary = count > 1
- && ! detail::equals::equals_point_point(range::front(ls), range::back(ls));
+ m_has_boundary = count > 1
+ && ! detail::equals::equals_point_point(range::front(m_ls), range::back(m_ls));
+
+ m_is_initialized = true;
}
+
+ Linestring const& m_ls;
+ mutable bool m_is_initialized;
+
+ mutable bool m_has_interior;
+ mutable bool m_has_boundary;
};
template <typename MultiLinestring>
@@ -84,29 +117,58 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
static const char interior = '1';
static const char boundary = '0';
- bool has_interior;
- bool has_boundary;
-
topology_check(MultiLinestring const& mls)
+ : m_mls(mls)
+ , m_is_initialized(false)
+ {}
+
+ bool has_interior() const
{
- init(mls, not_ignoring_counter());
+ init();
+ return m_has_interior;
}
- template <typename IgnoreBoundaryPoint>
- topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp)
+ bool has_boundary() const
{
- init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp));
+ init();
+ return m_has_boundary;
}
- template <typename OddCounter>
- void init(MultiLinestring const& mls, OddCounter const& odd_counter)
+ template <typename Point>
+ bool check_boundary_point(Point const& point) const
{
- typedef typename geometry::point_type<MultiLinestring>::type point_type;
- std::vector<point_type> endpoints;
- endpoints.reserve(boost::size(mls) * 2);
+ init();
+
+ if (! m_has_boundary)
+ return false;
+
+ std::size_t count = count_equal(m_endpoints.begin(), m_endpoints.end(), point);
+
+ return count % 2 != 0; // odd count -> boundary
+ }
+
+ template <typename Visitor>
+ void for_each_boundary_point(Visitor & visitor) const
+ {
+ init();
+ if (m_has_boundary)
+ {
+ for_each_boundary_point(m_endpoints.begin(), m_endpoints.end(), visitor);
+ }
+ }
+
+private:
+ void init() const
+ {
+ if (m_is_initialized)
+ return;
+
+ m_endpoints.reserve(boost::size(m_mls) * 2);
+
+ m_has_interior = false;
typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
- for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it )
+ for ( ls_iterator it = boost::begin(m_mls) ; it != boost::end(m_mls) ; ++it )
{
typename boost::range_reference<MultiLinestring const>::type
ls = *it;
@@ -115,7 +177,7 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
if (count > 0)
{
- has_interior = true;
+ m_has_interior = true;
}
if (count > 1)
@@ -138,62 +200,59 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
// is not used anywhere in the code, still it's safer this way
if (! geometry::has_nan_coordinate(front_pt))
{
- endpoints.push_back(front_pt);
+ m_endpoints.push_back(front_pt);
}
if (! geometry::has_nan_coordinate(back_pt))
{
- endpoints.push_back(back_pt);
+ m_endpoints.push_back(back_pt);
}
}
}
}
- has_boundary = false;
+ m_has_boundary = false;
- if ( !endpoints.empty() )
+ if (! m_endpoints.empty() )
{
- std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>());
- has_boundary = odd_counter(endpoints.begin(), endpoints.end());
+ std::sort(m_endpoints.begin(), m_endpoints.end(), relate::less());
+ m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end());
}
+
+ m_is_initialized = true;
}
- struct not_ignoring_counter
+ template <typename It, typename Point>
+ static inline std::size_t count_equal(It first, It last, Point const& point)
{
- template <typename It>
- bool operator()(It first, It last) const
- {
- return find_odd_count(first, last);
- }
- };
+ std::pair<It, It> rng = std::equal_range(first, last, point, relate::less());
+ return (std::size_t)std::distance(rng.first, rng.second);
+ }
- template <typename Point>
- struct ignoring_counter
+ template <typename It>
+ static inline bool find_odd_count(It first, It last)
{
- ignoring_counter(Point const& pt) : m_pt(pt) {}
+ interrupting_visitor visitor;
+ for_each_boundary_point(first, last, visitor);
+ return visitor.found;
+ }
- template <typename It>
- bool operator()(It first, It last) const
+ struct interrupting_visitor
+ {
+ bool found;
+ interrupting_visitor() : found(false) {}
+ template <typename Point>
+ bool apply(Point const&)
{
- typedef typename std::iterator_traits<It>::value_type point_type;
-
- std::pair<It, It> ignore_range
- = std::equal_range(first, last, m_pt,
- geometry::less<point_type>());
-
- if ( find_odd_count(first, ignore_range.first) )
- return true;
-
- return find_odd_count(ignore_range.second, last);
+ found = true;
+ return false;
}
-
- Point const& m_pt;
};
- template <typename It>
- static inline bool find_odd_count(It first, It last)
+ template <typename It, typename Visitor>
+ static void for_each_boundary_point(It first, It last, Visitor& visitor)
{
if ( first == last )
- return false;
+ return;
std::size_t count = 1;
It prev = first;
@@ -203,8 +262,14 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
// the end of the equal points subrange
if ( ! equals::equals_point_point(*first, *prev) )
{
+ // odd count -> boundary
if ( count % 2 != 0 )
- return true;
+ {
+ if (! visitor.apply(*prev))
+ {
+ return;
+ }
+ }
count = 1;
}
@@ -214,8 +279,22 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
}
}
- return count % 2 != 0;
+ // odd count -> boundary
+ if ( count % 2 != 0 )
+ {
+ visitor.apply(*prev);
+ }
}
+
+private:
+ MultiLinestring const& m_mls;
+ mutable bool m_is_initialized;
+
+ mutable bool m_has_interior;
+ mutable bool m_has_boundary;
+
+ typedef typename geometry::point_type<MultiLinestring>::type point_type;
+ mutable std::vector<point_type> m_endpoints;
};
template <typename Ring>
@@ -223,12 +302,11 @@ struct topology_check<Ring, ring_tag>
{
static const char interior = '2';
static const char boundary = '1';
- static const bool has_interior = true;
- static const bool has_boundary = true;
topology_check(Ring const&) {}
- template <typename P>
- topology_check(Ring const&, P const&) {}
+
+ static bool has_interior() { return true; }
+ static bool has_boundary() { return true; }
};
template <typename Polygon>
@@ -236,12 +314,11 @@ struct topology_check<Polygon, polygon_tag>
{
static const char interior = '2';
static const char boundary = '1';
- static const bool has_interior = true;
- static const bool has_boundary = true;
-
+
topology_check(Polygon const&) {}
- template <typename P>
- topology_check(Polygon const&, P const&) {}
+
+ static bool has_interior() { return true; }
+ static bool has_boundary() { return true; }
};
template <typename MultiPolygon>
@@ -249,12 +326,13 @@ struct topology_check<MultiPolygon, multi_polygon_tag>
{
static const char interior = '2';
static const char boundary = '1';
- static const bool has_interior = true;
- static const bool has_boundary = true;
-
+
topology_check(MultiPolygon const&) {}
- template <typename P>
- topology_check(MultiPolygon const&, P const&) {}
+
+ static bool has_interior() { return true; }
+ static bool has_boundary() { return true; }
+ template <typename Point>
+ static bool check_boundary_point(Point const& ) { return true; }
};
}} // namespace detail::relate
diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp
index 7bc5c08046..67df3060c4 100644
--- a/boost/geometry/algorithms/detail/sections/section_functions.hpp
+++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp
@@ -2,8 +2,8 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -30,18 +30,87 @@ namespace detail { namespace section
template
<
std::size_t Dimension,
+ typename Geometry,
+ typename CastedCSTag = typename tag_cast
+ <
+ typename cs_tag<Geometry>::type,
+ spherical_tag
+ >::type
+>
+struct preceding_check
+{
+ template <typename Point, typename Box>
+ static inline bool apply(int dir, Point const& point, Box const& /*point_box*/, Box const& other_box)
+ {
+ return (dir == 1 && get<Dimension>(point) < get<min_corner, Dimension>(other_box))
+ || (dir == -1 && get<Dimension>(point) > get<max_corner, Dimension>(other_box));
+ }
+};
+
+template <typename Geometry>
+struct preceding_check<0, Geometry, spherical_tag>
+{
+ template <typename Point, typename Box>
+ static inline bool apply(int dir, Point const& point, Box const& point_box, Box const& other_box)
+ {
+ typedef typename select_coordinate_type
+ <
+ Point, Box
+ >::type calc_t;
+ typedef typename coordinate_system<Point>::type::units units_t;
+
+ calc_t const c0 = 0;
+
+ if (dir == 1)
+ {
+ calc_t const diff_min = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<min_corner, 0>(other_box), get<0>(point));
+
+ calc_t const diff_min_min = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<min_corner, 0>(other_box), get<min_corner, 0>(point_box));
+
+ return diff_min < c0 && diff_min_min <= c0 && diff_min_min <= diff_min;
+ }
+ else if (dir == -1)
+ {
+ calc_t const diff_max = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<max_corner, 0>(other_box), get<0>(point));
+
+ calc_t const diff_max_max = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<max_corner, 0>(other_box), get<max_corner, 0>(point_box));
+
+ return diff_max > c0 && diff_max_max >= c0 && diff_max <= diff_max_max;
+ }
+
+ return false;
+ }
+};
+
+
+template
+<
+ std::size_t Dimension,
typename Point,
typename RobustBox,
typename RobustPolicy
>
-static inline bool preceding(int dir, Point const& point,
- RobustBox const& robust_box,
- RobustPolicy const& robust_policy)
+static inline bool preceding(int dir,
+ Point const& point,
+ RobustBox const& point_robust_box,
+ RobustBox const& other_robust_box,
+ RobustPolicy const& robust_policy)
{
typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
- return (dir == 1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box))
- || (dir == -1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box));
+ return preceding_check<Dimension, Point>::apply(dir, robust_point, point_robust_box, other_robust_box);
}
template
@@ -51,14 +120,13 @@ template
typename RobustBox,
typename RobustPolicy
>
-static inline bool exceeding(int dir, Point const& point,
- RobustBox const& robust_box,
- RobustPolicy const& robust_policy)
+static inline bool exceeding(int dir,
+ Point const& point,
+ RobustBox const& point_robust_box,
+ RobustBox const& other_robust_box,
+ RobustPolicy const& robust_policy)
{
- typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
- geometry::recalculate(robust_point, point, robust_policy);
- return (dir == 1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box))
- || (dir == -1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box));
+ return preceding<Dimension>(-dir, point, point_robust_box, other_robust_box, robust_policy);
}
diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
index 3ed5b8db07..f1d8e7d231 100644
--- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp
+++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013, 2014, 2015.
-// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013, 2014, 2015, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -29,6 +29,8 @@
#include <boost/mpl/vector_c.hpp>
#include <boost/range.hpp>
#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_fundamental.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
@@ -54,6 +56,7 @@
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
+#include <boost/geometry/strategies/envelope.hpp>
namespace boost { namespace geometry
{
@@ -133,11 +136,21 @@ struct sections : std::vector<section<Box, DimensionCount> >
namespace detail { namespace sectionalize
{
+// NOTE: This utility will NOT work for latitudes, dimension 1 in spherical
+// and geographic coordinate system because in these coordinate systems
+// e.g. a segment on northern hemisphere may go towards greater latitude
+// and then towards lesser latitude.
template
<
+ typename Point,
typename DimensionVector,
std::size_t Index,
- std::size_t Count
+ std::size_t Count,
+ typename CastedCSTag = typename tag_cast
+ <
+ typename cs_tag<Point>::type,
+ spherical_tag
+ >::type
>
struct get_direction_loop
{
@@ -158,21 +171,67 @@ struct get_direction_loop
get_direction_loop
<
+ Point,
DimensionVector,
Index + 1,
- Count
+ Count,
+ CastedCSTag
+ >::apply(seg, directions);
+ }
+};
+
+template
+<
+ typename Point,
+ typename DimensionVector,
+ std::size_t Count
+>
+struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag>
+{
+ typedef typename boost::mpl::at_c<DimensionVector, 0>::type dimension;
+
+ template <typename Segment>
+ static inline void apply(Segment const& seg,
+ int directions[Count])
+ {
+ typedef typename coordinate_type<Segment>::type coordinate_type;
+ typedef typename coordinate_system<Point>::type::units units_t;
+
+ coordinate_type const diff = math::longitude_distance_signed
+ <
+ units_t, coordinate_type
+ >(geometry::get<0, 0>(seg),
+ geometry::get<1, 0>(seg));
+
+ coordinate_type zero = coordinate_type();
+ directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0;
+
+ get_direction_loop
+ <
+ Point,
+ DimensionVector,
+ 1,
+ Count,
+ spherical_tag
>::apply(seg, directions);
}
};
-template <typename DimensionVector, std::size_t Count>
-struct get_direction_loop<DimensionVector, Count, Count>
+template
+<
+ typename Point,
+ typename DimensionVector,
+ std::size_t Count,
+ typename CastedCSTag
+>
+struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag>
{
template <typename Segment>
static inline void apply(Segment const&, int [Count])
{}
};
+
//! Copy one static array to another
template <typename T, std::size_t Index, std::size_t Count>
struct copy_loop
@@ -272,19 +331,21 @@ struct assign_loop<T, Count, Count>
template <typename CSTag>
struct box_first_in_section
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& prev, Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& prev, Point const& curr,
+ Strategy const& strategy)
{
geometry::model::referring_segment<Point const> seg(prev, curr);
- geometry::envelope(seg, box);
+ geometry::envelope(seg, box, strategy);
}
};
template <>
struct box_first_in_section<cartesian_tag>
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& prev, Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& prev, Point const& curr,
+ Strategy const& )
{
geometry::envelope(prev, box);
geometry::expand(box, curr);
@@ -294,19 +355,21 @@ struct box_first_in_section<cartesian_tag>
template <typename CSTag>
struct box_next_in_section
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& prev, Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& prev, Point const& curr,
+ Strategy const& strategy)
{
geometry::model::referring_segment<Point const> seg(prev, curr);
- geometry::expand(box, seg);
+ geometry::expand(box, seg, strategy);
}
};
template <>
struct box_next_in_section<cartesian_tag>
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& , Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& , Point const& curr,
+ Strategy const& )
{
geometry::expand(box, curr);
}
@@ -335,6 +398,30 @@ struct sectionalize_part
ring_identifier ring_id,
std::size_t max_count)
{
+ typedef typename strategy::envelope::services::default_strategy
+ <
+ typename cs_tag<typename Sections::box_type>::type
+ >::type envelope_strategy_type;
+
+ apply(sections, begin, end,
+ robust_policy, envelope_strategy_type(),
+ ring_id, max_count);
+ }
+
+ template
+ <
+ typename Iterator,
+ typename RobustPolicy,
+ typename Sections,
+ typename EnvelopeStrategy
+ >
+ static inline void apply(Sections& sections,
+ Iterator begin, Iterator end,
+ RobustPolicy const& robust_policy,
+ EnvelopeStrategy const& strategy,
+ ring_identifier ring_id,
+ std::size_t max_count)
+ {
boost::ignore_unused_variable_warning(robust_policy);
typedef typename boost::range_value<Sections>::type section_type;
@@ -379,7 +466,7 @@ struct sectionalize_part
int direction_classes[dimension_count] = {0};
get_direction_loop
<
- DimensionVector, 0, dimension_count
+ Point, DimensionVector, 0, dimension_count
>::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
@@ -449,14 +536,14 @@ struct sectionalize_part
// In cartesian this is envelope of previous point expanded with current point
// in non-cartesian this is envelope of a segment
box_first_in_section<typename cs_tag<robust_point_type>::type>
- ::apply(section.bounding_box, previous_robust_point, current_robust_point);
+ ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy);
}
else
{
// In cartesian this is expand with current point
// in non-cartesian this is expand with a segment
box_next_in_section<typename cs_tag<robust_point_type>::type>
- ::apply(section.bounding_box, previous_robust_point, current_robust_point);
+ ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy);
}
section.end_index = index + 1;
@@ -501,11 +588,13 @@ struct sectionalize_range
<
typename Range,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(Range const& range,
RobustPolicy const& robust_policy,
Sections& sections,
+ EnvelopeStrategy const& strategy,
ring_identifier ring_id,
std::size_t max_count)
{
@@ -534,7 +623,7 @@ struct sectionalize_range
sectionalize_part<Point, DimensionVector>::apply(sections,
boost::begin(view), boost::end(view),
- robust_policy, ring_id, max_count);
+ robust_policy, strategy, ring_id, max_count);
}
};
@@ -549,12 +638,15 @@ struct sectionalize_polygon
<
typename Polygon,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(Polygon const& poly,
RobustPolicy const& robust_policy,
Sections& sections,
- ring_identifier ring_id, std::size_t max_count)
+ EnvelopeStrategy const& strategy,
+ ring_identifier ring_id,
+ std::size_t max_count)
{
typedef typename point_type<Polygon>::type point_type;
typedef sectionalize_range
@@ -564,7 +656,7 @@ struct sectionalize_polygon
> per_range;
ring_id.ring_index = -1;
- per_range::apply(exterior_ring(poly), robust_policy, sections, ring_id, max_count);
+ per_range::apply(exterior_ring(poly), robust_policy, sections, strategy, ring_id, max_count);
ring_id.ring_index++;
typename interior_return_type<Polygon const>::type
@@ -572,7 +664,7 @@ struct sectionalize_polygon
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
{
- per_range::apply(*it, robust_policy, sections, ring_id, max_count);
+ per_range::apply(*it, robust_policy, sections, strategy, ring_id, max_count);
}
}
};
@@ -584,11 +676,13 @@ struct sectionalize_box
<
typename Box,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(Box const& box,
RobustPolicy const& robust_policy,
Sections& sections,
+ EnvelopeStrategy const& ,
ring_identifier const& ring_id, std::size_t max_count)
{
typedef typename point_type<Box>::type point_type;
@@ -613,12 +707,15 @@ struct sectionalize_box
points.push_back(lr);
points.push_back(ll);
+ // NOTE: Use cartesian envelope strategy in all coordinate systems
+ // because edges of a box are not geodesic segments
sectionalize_range
<
closed, false,
point_type,
DimensionVector
>::apply(points, robust_policy, sections,
+ strategy::envelope::cartesian_segment<>(),
ring_id, max_count);
}
};
@@ -630,11 +727,15 @@ struct sectionalize_multi
<
typename MultiGeometry,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(MultiGeometry const& multi,
RobustPolicy const& robust_policy,
- Sections& sections, ring_identifier ring_id, std::size_t max_count)
+ Sections& sections,
+ EnvelopeStrategy const& strategy,
+ ring_identifier ring_id,
+ std::size_t max_count)
{
ring_id.multi_index = 0;
for (typename boost::range_iterator<MultiGeometry const>::type
@@ -642,7 +743,7 @@ struct sectionalize_multi
it != boost::end(multi);
++it, ++ring_id.multi_index)
{
- Policy::apply(*it, robust_policy, sections, ring_id, max_count);
+ Policy::apply(*it, robust_policy, sections, strategy, ring_id, max_count);
}
}
};
@@ -814,14 +915,18 @@ template
typename DimensionVector,
typename Geometry,
typename Sections,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename EnvelopeStrategy
>
inline void sectionalize(Geometry const& geometry,
RobustPolicy const& robust_policy,
Sections& sections,
+ EnvelopeStrategy const& strategy,
int source_index = 0,
std::size_t max_count = 10)
{
+ BOOST_STATIC_ASSERT((! boost::is_fundamental<EnvelopeStrategy>::value));
+
concepts::check<Geometry const>();
typedef typename boost::range_value<Sections>::type section_type;
@@ -855,12 +960,39 @@ inline void sectionalize(Geometry const& geometry,
Geometry,
Reverse,
DimensionVector
- >::apply(geometry, robust_policy, sections, ring_id, max_count);
+ >::apply(geometry, robust_policy, sections, strategy, ring_id, max_count);
detail::sectionalize::enlarge_sections(sections);
}
+template
+<
+ bool Reverse,
+ typename DimensionVector,
+ typename Geometry,
+ typename Sections,
+ typename RobustPolicy
+>
+inline void sectionalize(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
+ Sections& sections,
+ int source_index = 0,
+ std::size_t max_count = 10)
+{
+ typedef typename strategy::envelope::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type
+ >::type envelope_strategy_type;
+
+ boost::geometry::sectionalize
+ <
+ Reverse, DimensionVector
+ >(geometry, robust_policy, sections,
+ envelope_strategy_type(),
+ source_index, max_count);
+}
+
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/touches/implementation.hpp b/boost/geometry/algorithms/detail/touches/implementation.hpp
new file mode 100644
index 0000000000..94f1fba581
--- /dev/null
+++ b/boost/geometry/algorithms/detail/touches/implementation.hpp
@@ -0,0 +1,459 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014, 2015, 2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
+
+
+#include <boost/geometry/algorithms/detail/for_each_range.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
+#include <boost/geometry/algorithms/detail/touches/interface.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/num_geometries.hpp>
+#include <boost/geometry/algorithms/relate.hpp>
+
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace touches
+{
+
+// Box/Box
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box_loop
+{
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
+ {
+ typedef typename coordinate_type<Box1>::type coordinate_type1;
+ typedef typename coordinate_type<Box2>::type coordinate_type2;
+
+ coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
+ coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
+ coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
+ coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
+
+ // TODO assert or exception?
+ //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
+
+ if (max1 < min2 || max2 < min1)
+ {
+ return false;
+ }
+
+ if (max1 == min2 || max2 == min1)
+ {
+ touch = true;
+ }
+
+ return box_box_loop
+ <
+ Dimension + 1,
+ DimensionCount
+ >::apply(b1, b2, touch);
+ }
+};
+
+template
+<
+ std::size_t DimensionCount
+>
+struct box_box_loop<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& , Box2 const&, bool &)
+ {
+ return true;
+ }
+};
+
+struct box_box
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
+ {
+ BOOST_STATIC_ASSERT((boost::is_same
+ <
+ typename geometry::coordinate_system<Box1>::type,
+ typename geometry::coordinate_system<Box2>::type
+ >::value
+ ));
+ assert_dimension_equal<Box1, Box2>();
+
+ bool touches = false;
+ bool ok = box_box_loop
+ <
+ 0,
+ dimension<Box1>::type::value
+ >::apply(b1, b2, touches);
+
+ return ok && touches;
+ }
+};
+
+// Areal/Areal
+
+struct areal_interrupt_policy
+{
+ static bool const enabled = true;
+ bool found_touch;
+ bool found_not_touch;
+
+ // dummy variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
+ inline bool result()
+ {
+ return found_touch && !found_not_touch;
+ }
+
+ inline areal_interrupt_policy()
+ : found_touch(false), found_not_touch(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // if already rejected (temp workaround?)
+ if ( found_not_touch )
+ return true;
+
+ typedef typename boost::range_iterator<Range const>::type iterator;
+ for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
+ {
+ if ( it->has(overlay::operation_intersection) )
+ {
+ found_not_touch = true;
+ return true;
+ }
+
+ switch(it->method)
+ {
+ case overlay::method_crosses:
+ found_not_touch = true;
+ return true;
+ case overlay::method_equal:
+ // Segment spatially equal means: at the right side
+ // the polygon internally overlaps. So return false.
+ found_not_touch = true;
+ return true;
+ case overlay::method_touch:
+ case overlay::method_touch_interior:
+ case overlay::method_collinear:
+ if ( ok_for_touch(*it) )
+ {
+ found_touch = true;
+ }
+ else
+ {
+ found_not_touch = true;
+ return true;
+ }
+ break;
+ case overlay::method_none :
+ case overlay::method_disjoint :
+ case overlay::method_error :
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ template <typename Turn>
+ inline bool ok_for_touch(Turn const& turn)
+ {
+ return turn.both(overlay::operation_union)
+ || turn.both(overlay::operation_blocked)
+ || turn.combination(overlay::operation_union, overlay::operation_blocked)
+ ;
+ }
+};
+
+template<typename Geometry, typename PointInRingStrategy>
+struct check_each_ring_for_within
+{
+ bool has_within;
+ Geometry const& m_geometry;
+ PointInRingStrategy const& m_strategy;
+
+ inline check_each_ring_for_within(Geometry const& g, PointInRingStrategy const& strategy)
+ : has_within(false)
+ , m_geometry(g)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Range>
+ inline void apply(Range const& range)
+ {
+ typename geometry::point_type<Range>::type p;
+ geometry::point_on_border(p, range);
+ if ( !has_within && geometry::within(p, m_geometry, m_strategy) )
+ {
+ has_within = true;
+ }
+ }
+};
+
+template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy>
+inline bool rings_containing(FirstGeometry const& geometry1,
+ SecondGeometry const& geometry2,
+ IntersectionStrategy const& strategy)
+{
+ // NOTE: This strategy could be defined inside IntersectionStrategy
+ typedef typename IntersectionStrategy::template point_in_geometry_strategy
+ <
+ FirstGeometry, SecondGeometry
+ >::type point_in_ring_strategy_type;
+
+ point_in_ring_strategy_type point_in_ring_strategy
+ = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>();
+
+ check_each_ring_for_within
+ <
+ FirstGeometry, point_in_ring_strategy_type
+ > checker(geometry1, point_in_ring_strategy);
+ geometry::detail::for_each_range(geometry2, checker);
+ return checker.has_within;
+}
+
+template <typename Geometry1, typename Geometry2>
+struct areal_areal
+{
+ template <typename IntersectionStrategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ IntersectionStrategy const& strategy)
+ {
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ std::deque<turn_info> turns;
+ detail::touches::areal_interrupt_policy policy;
+ rescale_policy_type robust_policy;
+ boost::geometry::get_turns
+ <
+ detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, strategy, robust_policy, turns, policy);
+
+ return policy.result()
+ && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
+ && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
+ }
+};
+
+// P/*
+
+struct use_point_in_geometry
+{
+ template <typename Point, typename Geometry, typename Strategy>
+ static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(point, geometry, strategy) == 0;
+ }
+};
+
+
+}}
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch {
+
+// P/P
+
+template <typename Geometry1, typename Geometry2, typename Tag2>
+struct touches<Geometry1, Geometry2, point_tag, Tag2, pointlike_tag, pointlike_tag, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
+ {
+ return false;
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag2>
+struct touches<Geometry1, Geometry2, multi_point_tag, Tag2, pointlike_tag, pointlike_tag, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
+ {
+ return false;
+ }
+};
+
+// P/*
+
+template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
+struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
+ : detail::touches::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename MultiGeometry, typename Tag2, typename CastedTag2>
+struct touches<MultiPoint, MultiGeometry, multi_point_tag, Tag2, pointlike_tag, CastedTag2, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ MultiPoint,
+ MultiGeometry
+ >
+{};
+
+template <typename Geometry, typename MultiPoint, typename Tag1, typename CastedTag1>
+struct touches<Geometry, MultiPoint, Tag1, multi_point_tag, CastedTag1, pointlike_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Geometry,
+ MultiPoint
+ >
+{};
+
+// Box/Box
+
+template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
+struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
+ : detail::touches::box_box
+{};
+
+template <typename Box1, typename Box2>
+struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
+ : detail::touches::box_box
+{};
+
+// L/L
+
+template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
+struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Linear1,
+ Linear2
+ >
+{};
+
+// L/A
+
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Linear,
+ Areal
+ >
+{};
+
+// A/L
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Areal,
+ Linear
+ >
+{};
+
+// A/A
+
+template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
+struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Areal1,
+ Areal2
+ >
+{};
+
+template <typename Areal1, typename Areal2>
+struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
+ : detail::touches::areal_areal<Areal1, Areal2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct self_touches
+{
+ static bool apply(Geometry const& geometry)
+ {
+ concepts::check<Geometry const>();
+
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry, Geometry
+ >::type strategy_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > policy_type;
+
+ std::deque<turn_info> turns;
+ detail::touches::areal_interrupt_policy policy;
+ strategy_type strategy;
+ rescale_policy_type robust_policy;
+ detail::self_get_turn_points::get_turns
+ <
+ false, policy_type
+ >::apply(geometry, strategy, robust_policy, turns, policy, 0);
+
+ return policy.result();
+ }
+};
+
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/touches/interface.hpp b/boost/geometry/algorithms/detail/touches/interface.hpp
new file mode 100644
index 0000000000..d2e0cc8c4e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/touches/interface.hpp
@@ -0,0 +1,321 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014, 2015, 2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP
+
+
+#include <deque>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/reverse_dispatch.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch {
+
+// TODO: Since CastedTags are used is Reverse needed?
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type,
+ typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
+ typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct touches
+ : not_implemented<Tag1, Tag2>
+{};
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2,
+ typename CastedTag1, typename CastedTag2
+>
+struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
+ : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
+ {
+ return touches<Geometry2, Geometry1>::apply(g2, g1, strategy);
+ }
+};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct touches
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return dispatch::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return dispatch::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct touches
+{
+ template <typename Strategy>
+ static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return resolve_strategy::touches::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+template <typename Geometry>
+struct self_touches;
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return self_touches<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check{has at least one touching point (self-tangency)}
+\note This function can be called for one geometry (self-tangency) and
+ also for two geometries (touch)
+\ingroup touches
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is self-touching}
+
+\qbk{distinguish,one geometry}
+\qbk{[def __one_parameter__]}
+\qbk{[include reference/algorithms/touches.qbk]}
+*/
+template <typename Geometry>
+inline bool touches(Geometry const& geometry)
+{
+ return resolve_variant::self_touches<Geometry>::apply(geometry);
+}
+
+
+/*!
+\brief \brief_check2{have at least one touching point (tangent - non overlapping)}
+\ingroup touches
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{touch each other}
+
+\qbk{distinguish,two geometries}
+\qbk{[include reference/algorithms/touches.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, default_strategy());
+}
+
+/*!
+\brief \brief_check2{have at least one touching point (tangent - non overlapping)}
+\ingroup touches
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Touches}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{touches}
+\return \return_check2{touch each other}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/touches.qbk]}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool touches(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/within/implementation.hpp b/boost/geometry/algorithms/detail/within/implementation.hpp
new file mode 100644
index 0000000000..8f1eba62e6
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/implementation.hpp
@@ -0,0 +1,306 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/within/interface.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/order_as_direction.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+
+#include <boost/geometry/algorithms/detail/within/multi_point.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/relate.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+#include <deque>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+struct use_point_in_geometry
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1;
+ }
+};
+
+struct use_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename detail::de9im::static_mask_within_type
+ <
+ Geometry1, Geometry2
+ >::type within_mask;
+ return geometry::relate(geometry1, geometry2, within_mask(), strategy);
+ }
+};
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Point, typename Box>
+struct within<Point, Box, point_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
+ {
+ boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(point, box);
+ }
+};
+
+template <typename Box1, typename Box2>
+struct within<Box1, Box2, box_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ assert_dimension_equal<Box1, Box2>();
+ boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(box1, box2);
+ }
+};
+
+// P/P
+
+template <typename Point1, typename Point2>
+struct within<Point1, Point2, point_tag, point_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPoint>
+struct within<Point, MultiPoint, point_tag, multi_point_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Point>
+struct within<MultiPoint, Point, multi_point_tag, point_tag>
+ : public detail::within::multi_point_point
+{};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct within<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
+ : public detail::within::multi_point_multi_point
+{};
+
+// P/L
+
+template <typename Point, typename Segment>
+struct within<Point, Segment, point_tag, segment_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename Linestring>
+struct within<Point, Linestring, point_tag, linestring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiLinestring>
+struct within<Point, MultiLinestring, point_tag, multi_linestring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Segment>
+struct within<MultiPoint, Segment, multi_point_tag, segment_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename Linestring>
+struct within<MultiPoint, Linestring, multi_point_tag, linestring_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename MultiLinestring>
+struct within<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag>
+ : public detail::within::multi_point_multi_geometry<true>
+{};
+
+// P/A
+
+template <typename Point, typename Ring>
+struct within<Point, Ring, point_tag, ring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename Polygon>
+struct within<Point, Polygon, point_tag, polygon_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPolygon>
+struct within<Point, MultiPolygon, point_tag, multi_polygon_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Ring>
+struct within<MultiPoint, Ring, multi_point_tag, ring_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename Polygon>
+struct within<MultiPoint, Polygon, multi_point_tag, polygon_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename MultiPolygon>
+struct within<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag>
+ : public detail::within::multi_point_multi_geometry<true>
+{};
+
+// L/L
+
+template <typename Linestring1, typename Linestring2>
+struct within<Linestring1, Linestring2, linestring_tag, linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename MultiLinestring>
+struct within<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Linestring>
+struct within<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring1, typename MultiLinestring2>
+struct within<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
+ : public detail::within::use_relate
+{};
+
+// L/A
+
+template <typename Linestring, typename Ring>
+struct within<Linestring, Ring, linestring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Ring>
+struct within<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename Polygon>
+struct within<Linestring, Polygon, linestring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Polygon>
+struct within<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename MultiPolygon>
+struct within<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename MultiPolygon>
+struct within<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+// A/A
+
+template <typename Ring1, typename Ring2>
+struct within<Ring1, Ring2, ring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Ring, typename Polygon>
+struct within<Ring, Polygon, ring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon, typename Ring>
+struct within<Polygon, Ring, polygon_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct within<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Ring, typename MultiPolygon>
+struct within<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon, typename Ring>
+struct within<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon, typename MultiPolygon>
+struct within<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon, typename Polygon>
+struct within<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon1, typename MultiPolygon2>
+struct within<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#include <boost/geometry/index/rtree.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/within/interface.hpp b/boost/geometry/algorithms/detail/within/interface.hpp
new file mode 100644
index 0000000000..23263604c2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/interface.hpp
@@ -0,0 +1,304 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
+
+
+#include <boost/concept_check.hpp>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/concepts/within_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct within
+ : not_implemented<Tag1, Tag2>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct within
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::within::check
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ Strategy
+ >();
+
+ return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::within::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct within
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return resolve_strategy::within::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return within<Geometry1, Geometry2>::apply(geometry1,
+ m_geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy),
+ geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return within<Geometry1, Geometry2>::apply(m_geometry1,
+ geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy),
+ geometry2
+ );
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct within<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return within<Geometry1, Geometry2>::apply(geometry1,
+ geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy),
+ geometry1,
+ geometry2);
+ }
+};
+
+}
+
+
+/*!
+\brief \brief_check12{is completely inside}
+\ingroup within
+\details \details_check12{within, is completely inside}.
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be within the second geometry
+\param geometry2 \param_geometry which might contain the first geometry
+\return true if geometry1 is completely contained within geometry2,
+ else false
+\note The default strategy is used for within detection
+
+
+\qbk{[include reference/algorithms/within.qbk]}
+
+\qbk{
+[heading Example]
+[within]
+[within_output]
+}
+ */
+template<typename Geometry1, typename Geometry2>
+inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::within
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, default_strategy());
+}
+
+/*!
+\brief \brief_check12{is completely inside} \brief_strategy
+\ingroup within
+\details \details_check12{within, is completely inside}, \brief_strategy. \details_strategy_reasons
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be within the second geometry
+\param geometry2 \param_geometry which might contain the first geometry
+\param strategy strategy to be used
+\return true if geometry1 is completely contained within geometry2,
+ else false
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/within.qbk]}
+\qbk{
+[heading Available Strategies]
+\* [link geometry.reference.strategies.strategy_within_winding Winding (coordinate system agnostic)]
+\* [link geometry.reference.strategies.strategy_within_franklin Franklin (cartesian)]
+\* [link geometry.reference.strategies.strategy_within_crossings_multiply Crossings Multiply (cartesian)]
+
+[heading Example]
+[within_strategy]
+[within_strategy_output]
+
+}
+*/
+template<typename Geometry1, typename Geometry2, typename Strategy>
+inline bool within(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::within
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/within/multi_point.hpp b/boost/geometry/algorithms/detail/within/multi_point.hpp
new file mode 100644
index 0000000000..7e85f33383
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/multi_point.hpp
@@ -0,0 +1,268 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP
+
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/index/rtree.hpp>
+
+#include <boost/geometry/strategies/covered_by.hpp>
+#include <boost/geometry/strategies/disjoint.hpp>
+
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+struct multi_point_point
+{
+ template <typename MultiPoint, typename Point, typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point,
+ Point const& point,
+ Strategy const& strategy)
+ {
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ if (! strategy.apply(*it, point))
+ {
+ return false;
+ }
+ }
+
+ // all points of MultiPoint inside Point
+ return true;
+ }
+};
+
+// NOTE: currently the strategy is ignored, math::equals() is used inside relate::less
+struct multi_point_multi_point
+{
+ template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
+ static inline bool apply(MultiPoint1 const& multi_point1,
+ MultiPoint2 const& multi_point2,
+ Strategy const& /*strategy*/)
+ {
+ typedef typename boost::range_value<MultiPoint2>::type point2_type;
+
+ relate::less const less = relate::less();
+
+ std::vector<point2_type> points2(boost::begin(multi_point2), boost::end(multi_point2));
+ std::sort(points2.begin(), points2.end(), less);
+
+ bool result = false;
+
+ typedef typename boost::range_const_iterator<MultiPoint1>::type iterator;
+ for ( iterator it = boost::begin(multi_point1) ; it != boost::end(multi_point1) ; ++it )
+ {
+ if (! std::binary_search(points2.begin(), points2.end(), *it, less))
+ {
+ return false;
+ }
+ else
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+};
+
+
+// TODO: the complexity could be lesser
+// the second geometry could be "prepared"/sorted
+// For Linear geometries partition could be used
+// For Areal geometries point_in_geometry() would have to call the winding
+// strategy differently, currently it linearly calls the strategy for each
+// segment. So the segments would have to be sorted in a way consistent with
+// the strategy and then the strategy called only for the segments in range.
+template <bool Within>
+struct multi_point_single_geometry
+{
+ template <typename MultiPoint, typename LinearOrAreal, typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point,
+ LinearOrAreal const& linear_or_areal,
+ Strategy const& strategy)
+ {
+ typedef typename boost::range_value<MultiPoint>::type point1_type;
+ typedef typename point_type<LinearOrAreal>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+
+ // Create envelope of geometry
+ box2_type box;
+ geometry::envelope(linear_or_areal, box, strategy.get_envelope_strategy());
+ geometry::detail::expand_by_epsilon(box);
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ point1_type, box2_type
+ >::type point_in_box_type;
+
+ // Test each Point with envelope and then geometry if needed
+ // If in the exterior, break
+ bool result = false;
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ int in_val = 0;
+
+ // exterior of box and of geometry
+ if (! point_in_box_type::apply(*it, box)
+ || (in_val = point_in_geometry(*it, linear_or_areal, strategy)) < 0)
+ {
+ result = false;
+ break;
+ }
+
+ // interior : interior/boundary
+ if (Within ? in_val > 0 : in_val >= 0)
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+};
+
+
+// TODO: same here, probably the complexity could be lesser
+template <bool Within>
+struct multi_point_multi_geometry
+{
+ template <typename MultiPoint, typename LinearOrAreal, typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point,
+ LinearOrAreal const& linear_or_areal,
+ Strategy const& strategy)
+ {
+ typedef typename point_type<LinearOrAreal>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+ static const bool is_linear = is_same
+ <
+ typename tag_cast
+ <
+ typename tag<LinearOrAreal>::type,
+ linear_tag
+ >::type,
+ linear_tag
+ >::value;
+
+ typename Strategy::envelope_strategy_type const
+ envelope_strategy = strategy.get_envelope_strategy();
+
+ // TODO: box pairs could be constructed on the fly, inside the rtree
+
+ // Prepare range of envelopes and ids
+ std::size_t count2 = boost::size(linear_or_areal);
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+ typedef std::vector<box_pair_type> box_pair_vector;
+ box_pair_vector boxes(count2);
+ for (std::size_t i = 0 ; i < count2 ; ++i)
+ {
+ geometry::envelope(linear_or_areal, boxes[i].first, envelope_strategy);
+ geometry::detail::expand_by_epsilon(boxes[i].first);
+ boxes[i].second = i;
+ }
+
+ // Create R-tree
+ index::rtree<box_pair_type, index::rstar<4> > rtree(boxes.begin(), boxes.end());
+
+ // For each point find overlapping envelopes and test corresponding single geometries
+ // If a point is in the exterior break
+ bool result = false;
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ // TODO: investigate the possibility of using satisfies
+ // TODO: investigate the possibility of using iterative queries (optimization below)
+ box_pair_vector inters_boxes;
+ rtree.query(index::intersects(*it), std::back_inserter(inters_boxes));
+
+ bool found_interior = false;
+ bool found_boundary = false;
+ int boundaries = 0;
+
+ typedef typename box_pair_vector::const_iterator iterator;
+ for ( iterator box_it = inters_boxes.begin() ; box_it != inters_boxes.end() ; ++box_it )
+ {
+ int in_val = point_in_geometry(*it, range::at(linear_or_areal, box_it->second), strategy);
+
+ if (in_val > 0)
+ found_interior = true;
+ else if (in_val == 0)
+ ++boundaries;
+
+ // If the result was set previously (interior or
+ // interior/boundary found) the only thing that needs to be
+ // done for other points is to make sure they're not
+ // overlapping the exterior no need to analyse boundaries.
+ if (result && in_val >= 0)
+ {
+ break;
+ }
+ }
+
+ if ( boundaries > 0)
+ {
+ if (is_linear && boundaries % 2 == 0)
+ found_interior = true;
+ else
+ found_boundary = true;
+ }
+
+ // exterior
+ if (! found_interior && ! found_boundary)
+ {
+ result = false;
+ break;
+ }
+
+ // interior : interior/boundary
+ if (Within ? found_interior : (found_interior || found_boundary))
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+};
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP