update boost on linux

This commit is contained in:
Bassem Girgis
2019-08-10 16:06:25 -05:00
parent 76ad52be58
commit 861b918727
5363 changed files with 483306 additions and 116507 deletions

View File

@@ -0,0 +1,62 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2018-2019 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N>
struct box_loop
{
typedef typename coordinate_type<BoxOut>::type coordinate_type;
static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
coordinate_type d = distance;
set<C, D>(box_out, get<C, D>(box_in) + d);
box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out);
}
};
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N>
struct box_loop<BoxIn, BoxOut, T, C, N, N>
{
static inline void apply(BoxIn const&, T const&, BoxOut&) {}
};
// Extends a box with the same amount in all directions
template<typename BoxIn, typename BoxOut, typename T>
inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
assert_dimension_equal<BoxIn, BoxOut>();
static const std::size_t N = dimension<BoxIn>::value;
box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out);
box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out);
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP

View File

@@ -41,10 +41,6 @@
#include <boost/geometry/views/detail/normalized_view.hpp>
#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
#endif
namespace boost { namespace geometry
{
@@ -67,45 +63,21 @@ inline void simplify_input(Range const& range,
// sensitive to small scale input features, however the result will
// look better.
// It also gets rid of duplicate points
#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
geometry::simplify(range, simplified, distance.simplify_distance());
#else
typedef typename boost::range_value<Range>::type point_type;
typedef strategy::distance::detail::projected_point_ax<> ax_type;
typedef typename strategy::distance::services::return_type
typedef typename geometry::point_type<Range>::type point_type;
typedef typename strategy::distance::services::default_strategy
<
strategy::distance::detail::projected_point_ax<>,
point_type,
point_type
>::type return_type;
typedef strategy::distance::detail::projected_point_ax_less
point_tag, segment_tag, point_type
>::type ds_strategy_type;
typedef strategy::simplify::douglas_peucker
<
return_type
> comparator_type;
point_type, ds_strategy_type
> strategy_type;
typedef strategy::simplify::detail::douglas_peucker
<
point_type,
strategy::distance::detail::projected_point_ax<>,
comparator_type
> dp_ax;
geometry::detail::simplify::simplify_range<2>::apply(range,
simplified, distance.simplify_distance(),
strategy_type());
return_type max_distance(distance.simplify_distance() * 2.0,
distance.simplify_distance());
comparator_type comparator(max_distance);
dp_ax strategy(comparator);
geometry::simplify(range, simplified, max_distance, strategy);
#endif
if (boost::size(simplified) == 2
&& geometry::equals(geometry::range::front(simplified),
geometry::range::back(simplified)))
{
traits::resize<Range>::apply(simplified, 1);
}
}
@@ -122,7 +94,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 +106,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 +131,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 +157,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 +167,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 +175,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 +203,19 @@ 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
bool linear,
output_point_type& first_p1,
output_point_type& first_p2,
output_point_type& last_p1,
@@ -273,7 +247,11 @@ struct buffer_range
* pup: penultimate_point
*/
strategy::buffer::result_code result = strategy::buffer::result_no_output;
bool const mark_flat
= linear
&& end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end;
geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
bool first = true;
Iterator it = begin;
@@ -284,25 +262,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,11 +290,16 @@ 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);
if (first && mark_flat)
{
collection.mark_flat_start();
}
penultimate_point = *prev;
ultimate_point = *it;
last_p1 = generated_side.front();
@@ -330,6 +313,12 @@ struct buffer_range
first_p2 = generated_side.back();
}
}
if (mark_flat)
{
collection.mark_flat_end();
}
return result;
}
};
@@ -350,7 +339,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 +349,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 +360,7 @@ struct buffer_multi
Policy::apply(*it, collection,
distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
}
}
};
@@ -393,12 +384,12 @@ inline void buffer_point(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
PointStrategy const& point_strategy)
{
collection.start_new_ring();
collection.start_new_ring(false);
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 +427,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 +436,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 +465,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,
first_p1, first_p2, last_p1, last_p2);
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
false, 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 +498,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 +513,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 +544,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 +586,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
collection.start_new_ring(distance.negative());
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 +629,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 +651,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 +672,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,
first_p1, first_p2, last_p1, last_p2);
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
true, 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,42 +697,47 @@ 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)
{
collection.start_new_ring();
collection.start_new_ring(false);
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 +774,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void iterate(Iterator begin, Iterator end,
@@ -774,15 +786,22 @@ 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
// For exterior rings, it deflates if distance is negative.
// For interior rings, it is vice versa
bool const deflate = is_interior
? ! distance.negative()
: distance.negative();
collection.start_new_ring(deflate);
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 +816,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 +827,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 +845,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 +855,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();
collection.start_new_ring(distance.negative());
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 +874,7 @@ public:
apply_interior_rings(interior_rings(polygon),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
}
};
@@ -927,11 +950,6 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
areal_tag
>::type::value;
bool const linear = boost::is_same
<
typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type,
linear_tag
>::type::value;
dispatch::buffer_inserter
<
@@ -945,10 +963,10 @@ 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);
collection.classify_turns();
if (BOOST_GEOMETRY_CONDITION(areal))
{
collection.check_remaining_points(distance_strategy);

View File

@@ -2,8 +2,8 @@
// 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.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, 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,
@@ -13,10 +13,6 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
# define BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION
#endif
#include <cstddef>
#include <boost/range.hpp>
@@ -26,6 +22,7 @@
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/strategies/buffer.hpp>
@@ -127,6 +124,10 @@ public :
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
detail::overlay::traverse_error_type )
{}
template <typename Rings>
void visit_generated_rings(Rings const& )
{}
};
@@ -177,9 +178,7 @@ struct buffer_turn_info
intersection_location_type location;
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
robust_point_type rob_pi, rob_pj, rob_qi, rob_qj;
#endif
std::size_t count_within;
@@ -189,9 +188,7 @@ struct buffer_turn_info
std::size_t count_on_offsetted;
std::size_t count_on_helper;
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
std::size_t count_within_near_offsetted;
#endif
bool remove_on_multi;
@@ -208,9 +205,7 @@ struct buffer_turn_info
, count_in_original(0)
, count_on_offsetted(0)
, count_on_helper(0)
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
, count_within_near_offsetted(0)
#endif
, remove_on_multi(false)
, count_on_occupied(0)
, count_on_multi(0)

View File

@@ -1,9 +1,10 @@
// 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-2017.
// Modifications copyright (c) 2016-2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2016-2018.
// Modifications copyright (c) 2016-2018 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,
@@ -46,6 +47,7 @@
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -142,10 +144,34 @@ 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::envelope_strategy_type envelope_strategy_type;
typedef typename IntersectionStrategy::expand_strategy_type expand_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
typename cs_tag<point_type>::type
>::type side_strategy;
point_type
>::type area_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
robust_point_type
>::type robust_area_strategy_type;
typedef typename area_strategy_type::template result_type
<
point_type
>::type area_result_type;
typedef typename robust_area_strategy_type::template result_type
<
robust_point_type
>::type robust_area_result_type;
typedef typename strategy::point_in_geometry::services::default_strategy
<
robust_point_type,
robust_ring_type
>::type point_in_geometry_strategy_type;
typedef typename geometry::rescale_policy_type
<
@@ -206,7 +232,10 @@ struct buffered_piece_collection
// 2: half, not part of offsetted rings - part of robust ring
std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end
#endif
bool is_flat_start;
bool is_flat_end;
bool is_deflated;
bool is_convex;
bool is_monotonic_increasing[2]; // 0=x, 1=y
bool is_monotonic_decreasing[2]; // 0=x, 1=y
@@ -234,6 +263,9 @@ struct buffered_piece_collection
, right_index(-1)
, last_segment_index(-1)
, offsetted_count(-1)
, is_flat_start(false)
, is_flat_end(false)
, is_deflated(false)
, is_convex(false)
, robust_min_comparable_radius(0)
, robust_max_comparable_radius(0)
@@ -256,12 +288,14 @@ struct buffered_piece_collection
{}
inline robust_original(robust_ring_type const& ring,
bool is_interior, bool has_interiors)
bool is_interior, bool has_interiors,
envelope_strategy_type const& envelope_strategy,
expand_strategy_type const& expand_strategy)
: m_ring(ring)
, m_is_interior(is_interior)
, m_has_interiors(has_interiors)
{
geometry::envelope(m_ring, m_box);
geometry::envelope(m_ring, m_box, envelope_strategy);
// create monotonic sections in x-dimension
// The dimension is critical because the direction is later used
@@ -269,7 +303,8 @@ struct buffered_piece_collection
// and this strategy is scanning in x direction.
typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
geometry::sectionalize<false, dimensions>(m_ring,
detail::no_rescale_policy(), m_sections);
detail::no_rescale_policy(), m_sections,
envelope_strategy, expand_strategy);
}
robust_ring_type m_ring;
@@ -285,6 +320,8 @@ struct buffered_piece_collection
piece_vector_type m_pieces;
turn_vector_type m_turns;
signed_size_type m_first_piece_index;
bool m_deflate;
bool m_has_deflated;
buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
std::vector<robust_original> robust_originals; // robust representation of the original(s)
@@ -306,7 +343,13 @@ 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;
envelope_strategy_type m_envelope_strategy;
expand_strategy_type m_expand_strategy;
robust_area_strategy_type m_robust_area_strategy;
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -320,7 +363,14 @@ struct buffered_piece_collection
buffered_piece_collection(IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
, m_deflate(false)
, m_has_deflated(false)
, 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_envelope_strategy(intersection_strategy.get_envelope_strategy())
, m_expand_strategy(intersection_strategy.get_expand_strategy())
, m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>())
, m_robust_policy(robust_policy)
{}
@@ -478,11 +528,11 @@ 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);
}
}
inline void classify_turns(bool linear)
inline void classify_turns()
{
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
@@ -491,11 +541,10 @@ struct buffered_piece_collection
{
it->location = inside_buffer;
}
if (it->count_on_original_boundary > 0 && ! linear)
if (it->count_on_original_boundary > 0)
{
it->location = inside_buffer;
}
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
if (it->count_within_near_offsetted > 0)
{
// Within can have in rare cases a rounding issue. We don't discard this
@@ -504,7 +553,94 @@ struct buffered_piece_collection
it->operations[0].enriched.startable = false;
it->operations[1].enriched.startable = false;
}
#endif
}
}
struct deflate_properties
{
bool has_inflated;
std::size_t count;
inline deflate_properties()
: has_inflated(false)
, count(0u)
{}
};
inline void discard_turns_for_deflate()
{
// Deflate cases should have at least 3 points PER deflated original
// to form a correct triangle
// But if there are intersections between a deflated ring and another
// ring, it is all accepted
// In deflate most turns are i/u by nature, but u/u is also possible
std::map<signed_size_type, deflate_properties> properties;
for (typename boost::range_iterator<turn_vector_type const>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
{
const buffer_turn_info_type& turn = *it;
if (turn.location == location_ok)
{
const buffer_turn_operation_type& op0 = turn.operations[0];
const buffer_turn_operation_type& op1 = turn.operations[1];
if (! m_pieces[op0.seg_id.piece_index].is_deflated
|| ! m_pieces[op1.seg_id.piece_index].is_deflated)
{
properties[op0.seg_id.multi_index].has_inflated = true;
properties[op1.seg_id.multi_index].has_inflated = true;
continue;
}
// It is deflated, update counts
for (int i = 0; i < 2; i++)
{
const buffer_turn_operation_type& op = turn.operations[i];
if (op.operation == detail::overlay::operation_union
|| op.operation == detail::overlay::operation_continue)
{
properties[op.seg_id.multi_index].count++;
}
}
}
}
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
{
buffer_turn_info_type& turn = *it;
if (turn.location == location_ok)
{
const buffer_turn_operation_type& op0 = turn.operations[0];
const buffer_turn_operation_type& op1 = turn.operations[1];
signed_size_type const multi0 = op0.seg_id.multi_index;
signed_size_type const multi1 = op1.seg_id.multi_index;
if (multi0 == multi1)
{
const deflate_properties& prop = properties[multi0];
// NOTE: Keep brackets around prop.count
// avoid gcc-bug "parse error in template argument list"
// GCC versions 5.4 and 5.5 (and probably more)
if (! prop.has_inflated && (prop.count) < 3)
{
// Property is not inflated
// Not enough points, this might be caused by <float> where
// detection turn-in-original failed because of numeric errors
turn.location = location_discard;
}
}
else
{
// Two different (possibly deflated) rings
}
}
}
}
@@ -513,6 +649,15 @@ struct buffered_piece_collection
{
// Check if a turn is inside any of the originals
typedef turn_in_original_ovelaps_box
<
typename IntersectionStrategy::disjoint_point_box_strategy_type
> turn_in_original_ovelaps_box_type;
typedef original_ovelaps_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> original_ovelaps_box_type;
turn_in_original_visitor<turn_vector_type> visitor(m_turns);
geometry::partition
<
@@ -520,8 +665,8 @@ struct buffered_piece_collection
include_turn_policy,
detail::partition::include_all_policy
>::apply(m_turns, robust_originals, visitor,
turn_get_box(), turn_in_original_ovelaps_box(),
original_get_box(), original_ovelaps_box());
turn_get_box(), turn_in_original_ovelaps_box_type(),
original_get_box(), original_ovelaps_box_type());
bool const deflate = distance_strategy.negative();
@@ -533,7 +678,7 @@ struct buffered_piece_collection
{
if (deflate && turn.count_in_original <= 0)
{
// For deflate: it is not in original, discard
// For deflate/negative buffers: it is not in original, discard
turn.location = location_discard;
}
else if (! deflate && turn.count_in_original > 0)
@@ -543,6 +688,12 @@ struct buffered_piece_collection
}
}
}
if (m_has_deflated)
{
// Either strategy was negative, or there were interior rings
discard_turns_for_deflate();
}
}
inline bool assert_indices_in_robust_rings() const
@@ -599,46 +750,47 @@ struct buffered_piece_collection
}
}
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// Insert all rescaled turn-points into these rings, to form a
// reliable integer-based ring. All turns can be compared (inside) to this
// rings to see if they are inside.
for (typename boost::range_iterator<piece_vector_type>::type
it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it)
if (! use_side_of_intersection<typename geometry::cs_tag<point_type>::type>::value)
{
piece& pc = *it;
signed_size_type piece_segment_index = pc.first_seg_id.segment_index;
if (! pc.robust_turns.empty())
// Insert all rescaled turn-points into these rings, to form a
// reliable integer-based ring. All turns can be compared (inside) to this
// rings to see if they are inside.
for (typename boost::range_iterator<piece_vector_type>::type
it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it)
{
if (pc.robust_turns.size() > 1u)
piece& pc = *it;
signed_size_type piece_segment_index = pc.first_seg_id.segment_index;
if (! pc.robust_turns.empty())
{
std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
}
// Walk through them, in reverse to insert at right index
signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1;
for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type
rit = boost::const_rbegin(pc.robust_turns);
rit != boost::const_rend(pc.robust_turns);
++rit, --index_offset)
{
signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
BOOST_GEOMETRY_ASSERT
(
index_in_vector > 0
&& index_in_vector < pc.offsetted_count
);
if (pc.robust_turns.size() > 1u)
{
std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
}
// Walk through them, in reverse to insert at right index
signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1;
for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type
rit = boost::const_rbegin(pc.robust_turns);
rit != boost::const_rend(pc.robust_turns);
++rit, --index_offset)
{
signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
BOOST_GEOMETRY_ASSERT
(
index_in_vector > 0
&& index_in_vector < pc.offsetted_count
);
pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
pc.offsetted_count++;
pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
pc.offsetted_count++;
m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
}
}
}
}
BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings());
#endif
BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings());
}
}
template <std::size_t Dimension>
@@ -699,7 +851,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
@@ -714,7 +866,8 @@ struct buffered_piece_collection
// create monotonic sections in y-dimension
typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
geometry::sectionalize<false, dimensions>(pc.robust_ring,
detail::no_rescale_policy(), pc.sections);
detail::no_rescale_policy(), pc.sections,
m_envelope_strategy, m_expand_strategy);
// Determine min/max radius
typedef geometry::model::referring_segment<robust_point_type const>
@@ -778,12 +931,21 @@ struct buffered_piece_collection
> visitor(m_pieces, offsetted_rings, m_turns,
m_intersection_strategy, m_robust_policy);
typedef detail::section::get_section_box
<
typename IntersectionStrategy::expand_box_strategy_type
> get_section_box_type;
typedef detail::section::overlaps_section_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> overlaps_section_box_type;
geometry::partition
<
robust_box_type
>::apply(monotonic_sections, visitor,
detail::section::get_section_box(),
detail::section::overlaps_section_box());
get_section_box_type(),
overlaps_section_box_type());
}
insert_rescaled_piece_turns();
@@ -798,20 +960,31 @@ struct buffered_piece_collection
// Check if it is inside any of the pieces
turn_in_piece_visitor
<
turn_vector_type, piece_vector_type
> visitor(m_turns, m_pieces);
typename geometry::cs_tag<point_type>::type,
turn_vector_type, piece_vector_type,
point_in_geometry_strategy_type
> visitor(m_turns, m_pieces, point_in_geometry_strategy_type());
typedef turn_ovelaps_box
<
typename IntersectionStrategy::disjoint_point_box_strategy_type
> turn_ovelaps_box_type;
typedef piece_ovelaps_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> piece_ovelaps_box_type;
geometry::partition
<
robust_box_type
>::apply(m_turns, m_pieces, visitor,
turn_get_box(), turn_ovelaps_box(),
piece_get_box(), piece_ovelaps_box());
turn_get_box(), turn_ovelaps_box_type(),
piece_get_box(), piece_ovelaps_box_type());
}
}
inline void start_new_ring()
inline void start_new_ring(bool deflate)
{
signed_size_type const n = static_cast<signed_size_type>(offsetted_rings.size());
current_segment_id.source_index = 0;
@@ -823,6 +996,13 @@ struct buffered_piece_collection
current_robust_ring.clear();
m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces));
m_deflate = deflate;
if (deflate)
{
// Pieces contain either deflated exterior rings, or inflated
// interior rings which are effectively deflated too
m_has_deflated = true;
}
}
inline void abort_ring()
@@ -922,7 +1102,7 @@ struct buffered_piece_collection
robust_originals.push_back(
robust_original(current_robust_ring,
is_interior, has_interiors));
is_interior, has_interiors, m_envelope_strategy, m_expand_strategy));
}
}
@@ -957,12 +1137,12 @@ struct buffered_piece_collection
piece pc;
pc.type = type;
pc.index = static_cast<signed_size_type>(boost::size(m_pieces));
pc.is_deflated = m_deflate;
current_segment_id.piece_index = pc.index;
pc.first_seg_id = current_segment_id;
// Assign left/right (for first/last piece per ring they will be re-assigned later)
pc.left_index = pc.index - 1;
pc.right_index = pc.index + 1;
@@ -1039,7 +1219,7 @@ struct buffered_piece_collection
return;
}
geometry::envelope(pc.robust_ring, pc.robust_envelope);
geometry::envelope(pc.robust_ring, pc.robust_envelope, m_envelope_strategy);
geometry::assign_inverse(pc.robust_offsetted_envelope);
for (signed_size_type i = 0; i < pc.offsetted_count; i++)
@@ -1216,18 +1396,31 @@ struct buffered_piece_collection
}
}
inline void mark_flat_start()
{
if (! m_pieces.empty())
{
piece& back = m_pieces.back();
back.is_flat_start = true;
}
}
inline void mark_flat_end()
{
if (! m_pieces.empty())
{
piece& back = m_pieces.back();
back.is_flat_end = true;
}
}
//-------------------------------------------------------------------------
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.
@@ -1252,6 +1445,8 @@ struct buffered_piece_collection
inline bool point_coveredby_original(point_type const& point)
{
typedef typename IntersectionStrategy::disjoint_point_box_strategy_type d_pb_strategy_type;
robust_point_type any_point;
geometry::recalculate(any_point, point, m_robust_policy);
@@ -1268,14 +1463,15 @@ struct buffered_piece_collection
{
robust_original const& original = *it;
if (detail::disjoint::disjoint_point_box(any_point,
original.m_box))
original.m_box,
d_pb_strategy_type()))
{
continue;
}
int const geometry_code
= detail::within::point_in_geometry(any_point,
original.m_ring);
original.m_ring, point_in_geometry_strategy_type());
if (geometry_code == -1)
{
@@ -1314,7 +1510,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)))
{
@@ -1358,12 +1554,14 @@ struct buffered_piece_collection
overlay_buffer,
backtrack_for_buffer
> traverser;
std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
traversed_rings.clear();
buffer_overlay_visitor visitor;
traverser::apply(offsetted_rings, offsetted_rings,
m_intersection_strategy, m_robust_policy,
m_turns, traversed_rings,
turn_info_per_ring,
m_clusters, visitor);
}
@@ -1391,7 +1589,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 +1605,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 +1621,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,8 +1629,10 @@ struct buffered_piece_collection
}
}
detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
selected, m_intersection_strategy);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
m_area_strategy);
}
};

View File

@@ -1,9 +1,10 @@
// 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.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 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,
@@ -13,8 +14,10 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
@@ -32,34 +35,81 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
struct buffer_assign_turn
// Implements a unique_sub_range for a buffered piece,
// the range can return subsequent points
// known as "i", "j" and "k" (and further), indexed as 0,1,2,3
template <typename Ring>
struct unique_sub_range_from_piece
{
static bool const include_no_turn = false;
static bool const include_degenerate = false;
static bool const include_opposite = false;
typedef typename boost::range_iterator<Ring const>::type iterator_type;
typedef typename geometry::point_type<Ring const>::type point_type;
template
<
typename Info,
typename Point1,
typename Point2,
typename IntersectionInfo
>
static inline void apply(Info& info,
Point1 const& /*p1*/,
Point2 const& /*p2*/,
IntersectionInfo const& iinfo)
unique_sub_range_from_piece(Ring const& ring,
iterator_type iterator_at_i, iterator_type iterator_at_j)
: m_ring(ring)
, m_iterator_at_i(iterator_at_i)
, m_iterator_at_j(iterator_at_j)
, m_point_retrieved(false)
{}
static inline bool is_first_segment() { return false; }
static inline bool is_last_segment() { return false; }
static inline std::size_t size() { return 3u; }
inline point_type const& at(std::size_t index) const
{
info.rob_pi = iinfo.rpi();
info.rob_pj = iinfo.rpj();
info.rob_qi = iinfo.rqi();
info.rob_qj = iinfo.rqj();
BOOST_GEOMETRY_ASSERT(index < size());
switch (index)
{
case 0 : return *m_iterator_at_i;
case 1 : return *m_iterator_at_j;
case 2 : return get_point_k();
default : return *m_iterator_at_i;
}
}
private :
inline point_type const& get_point_k() const
{
if (! m_point_retrieved)
{
m_iterator_at_k = advance_one(m_iterator_at_j);
m_point_retrieved = true;
}
return *m_iterator_at_k;
}
inline void circular_advance_one(iterator_type& next) const
{
++next;
if (next == boost::end(m_ring))
{
next = boost::begin(m_ring) + 1;
}
}
inline iterator_type advance_one(iterator_type it) const
{
iterator_type result = it;
circular_advance_one(result);
// TODO: we could also use piece-boundaries
// to check if the point equals the last one
while (geometry::equals(*it, *result))
{
circular_advance_one(result);
}
return result;
}
Ring const& m_ring;
iterator_type m_iterator_at_i;
iterator_type m_iterator_at_j;
mutable iterator_type m_iterator_at_k;
mutable bool m_point_retrieved;
};
#endif
template
<
@@ -100,52 +150,34 @@ class piece_turn_visitor
return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
}
template <typename Range, typename Iterator>
inline void move_to_next_point(Range const& range, Iterator& next) const
{
++next;
if (next == boost::end(range))
{
next = boost::begin(range) + 1;
}
}
template <typename Range, typename Iterator>
inline Iterator next_point(Range const& range, Iterator it) const
{
Iterator result = it;
move_to_next_point(range, result);
// TODO: we could use either piece-boundaries, or comparison with
// robust points, to check if the point equals the last one
while(geometry::equals(*it, *result))
{
move_to_next_point(range, result);
}
return result;
}
template <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 +223,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;
@@ -222,15 +254,19 @@ class piece_turn_visitor
the_model.operations[1].piece_index = piece2.index;
the_model.operations[1].seg_id = piece2.first_seg_id;
the_model.operations[1].seg_id.segment_index = index2; // override
geometry::recalculate(the_model.rob_pi, *prev1, m_robust_policy);
geometry::recalculate(the_model.rob_pj, *it1, m_robust_policy);
iterator next1 = next_point(ring1, it1);
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
iterator it2 = it2_first;
for (iterator prev2 = it2++;
it2 != it2_beyond;
prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
{
iterator next2 = next_point(ring2, it2);
unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2);
geometry::recalculate(the_model.rob_qi, *prev2, m_robust_policy);
geometry::recalculate(the_model.rob_qj, *it2, m_robust_policy);
// TODO: internally get_turn_info calculates robust points.
// But they are already calculated.
@@ -239,20 +275,14 @@ class piece_turn_visitor
// and iterating in sync with them...
typedef detail::overlay::get_turn_info
<
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
buffer_assign_turn
#else
detail::overlay::assign_null_policy
#endif
> turn_policy;
turn_policy::apply(*prev1, *it1, *next1,
*prev2, *it2, *next2,
false, false, false, false,
the_model,
m_intersection_strategy,
m_robust_policy,
std::back_inserter(m_turns));
turn_policy::apply(unique_sub_range1, unique_sub_range2,
the_model,
m_intersection_strategy,
m_robust_policy,
std::back_inserter(m_turns));
}
}
}
@@ -272,10 +302,10 @@ 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);
boost::ignore_unused(first);
typedef typename boost::range_value<Pieces const>::type piece_type;
piece_type const& piece1 = m_pieces[section1.ring_id.source_index];
@@ -285,12 +315,15 @@ 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,
m_intersection_strategy.get_disjoint_box_box_strategy()) )
{
return;
return true;
}
calculate_turns(piece1, piece2, section1, section2);
return true;
}
};

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2016, 2018.
// Modifications copyright (c) 2016-2018 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,
@@ -16,6 +16,7 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/buffer.hpp>
@@ -38,12 +39,14 @@ struct original_get_box
}
};
template <typename DisjointBoxBoxStrategy>
struct original_ovelaps_box
{
template <typename Box, typename Original>
static inline bool apply(Box const& box, Original const& original)
{
return ! detail::disjoint::disjoint_box_box(box, original.m_box);
return ! detail::disjoint::disjoint_box_box(box, original.m_box,
DisjointBoxBoxStrategy());
}
};
@@ -56,6 +59,7 @@ struct include_turn_policy
}
};
template <typename DisjointPointBoxStrategy>
struct turn_in_original_ovelaps_box
{
template <typename Box, typename Turn>
@@ -68,7 +72,7 @@ struct turn_in_original_ovelaps_box
}
return ! geometry::detail::disjoint::disjoint_point_box(
turn.robust_point, box);
turn.robust_point, box, DisjointPointBoxStrategy());
}
};
@@ -212,27 +216,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);
boost::ignore_unused(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 +263,8 @@ public:
mutable_turn.within_original = true;
mutable_turn.count_in_original = 1;
}
return true;
}
private :

View File

@@ -1,9 +1,10 @@
// 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.
// This file was modified by Oracle on 2016, 2018.
// Modifications copyright (c) 2016-2018 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,
@@ -19,6 +20,7 @@
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/algorithms/assign.hpp>
@@ -33,9 +35,8 @@
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
#include <boost/geometry/strategies/cartesian/side_of_intersection.hpp>
#endif
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
namespace boost { namespace geometry
@@ -55,6 +56,7 @@ struct piece_get_box
}
};
template <typename DisjointBoxBoxStrategy>
struct piece_ovelaps_box
{
template <typename Box, typename Piece>
@@ -70,7 +72,8 @@ struct piece_ovelaps_box
return false;
}
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope,
DisjointBoxBoxStrategy());
}
};
@@ -83,12 +86,14 @@ struct turn_get_box
}
};
template <typename DisjointPointBoxStrategy>
struct turn_ovelaps_box
{
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)
{
return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box);
return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box,
DisjointPointBoxStrategy());
}
};
@@ -100,10 +105,8 @@ enum analyse_result
analyse_disjoint,
analyse_within,
analyse_on_original_boundary,
analyse_on_offsetted
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
, analyse_near_offsetted
#endif
analyse_on_offsetted,
analyse_near_offsetted
};
template <typename Point>
@@ -120,85 +123,115 @@ inline bool in_box(Point const& previous,
return geometry::covered_by(point, box);
}
template <typename Point, typename Turn>
inline analyse_result check_segment(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
segment_type const r(previous, current);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 0)
{
return analyse_on_offsetted;
}
if (side == -1 && from_monotonic)
{
return analyse_within;
}
if (side == 1 && from_monotonic)
{
return analyse_disjoint;
}
return analyse_continue;
// meta-programming-structure defining if to use side-of-intersection
// (only for cartesian / only necessary with rescaling)
template <typename Tag>
struct use_side_of_intersection {};
#if defined(BOOST_GEOMETRY_USE_RESCALING)
// With rescaling, let Cartesian use side-of-intersection
template <>
struct use_side_of_intersection<cartesian_tag> { static bool const value = true; };
#else
template <>
struct use_side_of_intersection<cartesian_tag> { static bool const value = false; };
#endif
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
template <>
struct use_side_of_intersection<spherical_tag> { static bool const value = false; };
coordinate_type const twice_area
= side_strategy::template side_value
<
coordinate_type,
coordinate_type
>(previous, current, turn.robust_point);
template <>
struct use_side_of_intersection<geographic_tag> { static bool const value = false; };
if (twice_area == 0)
template <bool UseSideOfIntersection>
struct check_segment {};
// Implementation using side-of-intersection
template <>
struct check_segment<true>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
// Collinear, only on segment if it is covered by its bbox
if (in_box(previous, current, turn.robust_point))
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
segment_type const r(previous, current);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 0)
{
return analyse_on_offsetted;
}
}
else if (twice_area < 0)
{
// It is in the triangle right-of the segment where the
// segment is the hypothenusa. Check if it is close
// (within rounding-area)
if (twice_area * twice_area < geometry::comparable_distance(previous, current)
&& in_box(previous, current, turn.robust_point))
{
return analyse_near_offsetted;
}
else if (from_monotonic)
if (side == -1 && from_monotonic)
{
return analyse_within;
}
if (side == 1 && from_monotonic)
{
return analyse_disjoint;
}
return analyse_continue;
}
else if (twice_area > 0 && from_monotonic)
};
template <>
struct check_segment<false>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
// Left of segment
return analyse_disjoint;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
int const side = side_strategy::apply(previous, current, turn.robust_point);
if (side == 0)
{
// Collinear, only on segment if it is covered by its bbox
if (in_box(previous, current, turn.robust_point))
{
return analyse_on_offsetted;
}
}
else if (side == -1)
{
// It is in the triangle right-of the segment where the
// segment is the hypothenusa. Check if it is close
// (within rounding-area)
if (in_box(previous, current, turn.robust_point))
{
return analyse_near_offsetted;
}
else if (from_monotonic)
{
return analyse_within;
}
}
else if (from_monotonic)
{
// Left of segment
return analyse_disjoint;
}
// Not monotonic, on left or right side: continue analysing
return analyse_continue;
}
};
// Not monotonic, on left or right side: continue analysing
return analyse_continue;
#endif
}
template <bool UseSideOfIntersection>
class analyse_turn_wrt_point_piece {};
class analyse_turn_wrt_point_piece
template <>
class analyse_turn_wrt_point_piece<true>
{
public :
template <typename Turn, typename Piece>
@@ -208,17 +241,9 @@ public :
typedef typename Turn::robust_point_type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
typedef geometry::model::referring_segment<point_type const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
#else
typedef strategy::within::winding<point_type> strategy_type;
typename strategy_type::state_type state;
strategy_type strategy;
boost::ignore_unused(strategy);
#endif
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
@@ -238,7 +263,6 @@ public :
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// First check if it is in range - if it is not, the
// expensive side_of_intersection does not need to be
@@ -269,8 +293,51 @@ public :
return analyse_on_offsetted;
}
}
#else
analyse_result code = check_segment(previous, current, turn, false);
}
}
}
// It is nowhere outside, and not on segment, so it is within
return analyse_within;
}
};
template <>
class analyse_turn_wrt_point_piece<false>
{
public :
template <typename Turn, typename Piece>
static inline analyse_result apply(Turn const& turn, Piece const& piece)
{
typedef typename Piece::section_type section_type;
typedef typename Turn::robust_point_type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
typedef strategy::within::winding<point_type> strategy_type;
typename strategy_type::state_type state;
strategy_type strategy;
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
coordinate_type const point_x = geometry::get<0>(turn.robust_point);
for (std::size_t s = 0; s < piece.sections.size(); s++)
{
section_type const& section = piece.sections[s];
// If point within horizontal range of monotonic section:
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
{
for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
{
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
analyse_result code = check_segment<false>::apply(previous, current, turn, false);
if (code != analyse_continue)
{
return code;
@@ -279,15 +346,10 @@ public :
// Get the state (to determine it is within), we don't have
// to cover the on-segment case (covered above)
strategy.apply(turn.robust_point, previous, current, state);
#endif
}
}
}
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// It is nowhere outside, and not on segment, so it is within
return analyse_within;
#else
int const code = strategy.result(state);
if (code == 1)
{
@@ -300,21 +362,24 @@ public :
// Should normally not occur - on-segment is covered
return analyse_unknown;
#endif
}
};
class analyse_turn_wrt_piece
template <bool UseSideOfIntersection>
struct check_helper_segment {};
template <>
struct check_helper_segment<true>
{
template <typename Point, typename Turn>
static inline analyse_result check_helper_segment(Point const& s1,
static inline analyse_result apply(Point const& s1,
Point const& s2, Turn const& turn,
bool is_original,
Point const& offsetted)
{
boost::ignore_unused(offsetted);
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
boost::ignore_unused(is_original);
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
@@ -339,11 +404,9 @@ class analyse_turn_wrt_piece
if (geometry::covered_by(turn.robust_point, box))
{
// Points on helper-segments are considered as within
// Points on original boundary are processed differently
return is_original
? analyse_on_original_boundary
: analyse_within;
// Points on helper-segments (and not on its corners)
// are considered as within
return analyse_within;
}
// It is collinear but not on the segment. Because these
@@ -355,7 +418,20 @@ class analyse_turn_wrt_piece
// right of segment
return analyse_continue;
#else
}
};
template <>
struct check_helper_segment<false>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& s1,
Point const& s2, Turn const& turn,
bool is_original,
Point const& offsetted)
{
boost::ignore_unused(offsetted);
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
@@ -404,9 +480,12 @@ class analyse_turn_wrt_piece
// right of segment
return analyse_continue;
#endif
}
};
template <bool UseSideOfIntersection>
class analyse_turn_wrt_piece
{
template <typename Turn, typename Piece>
static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece)
{
@@ -423,6 +502,13 @@ class analyse_turn_wrt_piece
{
points[i] = piece.robust_ring[piece.offsetted_count + i];
}
// 3--offsetted outline--0
// | |
// left | | right
// | |
// 2===>==original===>===1
}
else if (helper_count == 3)
{
@@ -446,14 +532,20 @@ class analyse_turn_wrt_piece
{
return analyse_on_offsetted;
}
if (comparator(point, points[1]) || comparator(point, points[2]))
if (comparator(point, points[1]))
{
return analyse_on_original_boundary;
// On original, right corner
return piece.is_flat_end ? analyse_continue : analyse_on_original_boundary;
}
if (comparator(point, points[2]))
{
// On original, left corner
return piece.is_flat_start ? analyse_continue : analyse_on_original_boundary;
}
// Right side of the piece
analyse_result result
= check_helper_segment(points[0], points[1], turn,
= check_helper_segment<UseSideOfIntersection>::apply(points[0], points[1], turn,
false, points[0]);
if (result != analyse_continue)
{
@@ -461,7 +553,7 @@ class analyse_turn_wrt_piece
}
// Left side of the piece
result = check_helper_segment(points[2], points[3], turn,
result = check_helper_segment<UseSideOfIntersection>::apply(points[2], points[3], turn,
false, points[3]);
if (result != analyse_continue)
{
@@ -471,7 +563,7 @@ class analyse_turn_wrt_piece
if (! comparator(points[1], points[2]))
{
// Side of the piece at side of original geometry
result = check_helper_segment(points[1], points[2], turn,
result = check_helper_segment<UseSideOfIntersection>::apply(points[1], points[2], turn,
true, point);
if (result != analyse_continue)
{
@@ -518,7 +610,7 @@ class analyse_turn_wrt_piece
// w.r.t. specified direction, and prev points to a point smaller
// We now know if it is inside/outside
it_type prev = it - 1;
return check_segment(*prev, *it, turn, true);
return check_segment<UseSideOfIntersection>::apply(*prev, *it, turn, true);
}
return analyse_continue;
}
@@ -575,7 +667,7 @@ public :
// (on which any side or side-value would return 0)
if (! comparator(previous, current))
{
code = check_segment(previous, current, turn, false);
code = check_segment<UseSideOfIntersection>::apply(previous, current, turn, false);
if (code != analyse_continue)
{
return code;
@@ -588,45 +680,17 @@ public :
};
// Helper Structure, of which the apply method returns a side value in {-1, 0, 1}
template <bool UseSideOfIntersection>
struct turn_in_piece {};
template <typename Turns, typename Pieces>
class turn_in_piece_visitor
template <>
struct turn_in_piece<true>
{
Turns& m_turns; // because partition is currently operating on const input only
Pieces const& m_pieces; // to check for piece-type
template <typename Operation, typename Piece>
inline bool skip(Operation const& op, Piece const& piece) const
{
if (op.piece_index == piece.index)
{
return true;
}
Piece const& pc = m_pieces[op.piece_index];
if (pc.left_index == piece.index || pc.right_index == piece.index)
{
if (pc.type == strategy::buffer::buffered_flat_end)
{
// If it is a flat end, don't compare against its neighbor:
// it will always be located on one of the helper segments
return true;
}
if (pc.type == strategy::buffer::buffered_concave)
{
// If it is concave, the same applies: the IP will be
// located on one of the helper segments
return true;
}
}
return false;
}
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// NOTE: this function returns a side value in {-1, 0, 1}
private :
template <typename Turn, typename Piece>
static inline int turn_in_convex_piece(Turn const& turn,
Piece const& piece)
static inline int in_convex_piece(Turn const& turn, Piece const& piece)
{
typedef typename Turn::robust_point_type point_type;
typedef typename Piece::piece_robust_ring_type ring_type;
@@ -675,43 +739,119 @@ class turn_in_piece_visitor
}
return 1; // inside
}
#endif
public :
template <typename Turn, typename Piece, typename Strategy>
static inline int apply(Turn const& turn, Piece const& piece,
Strategy const& strategy)
{
if (piece.is_convex)
{
return in_convex_piece(turn, piece);
}
else
{
// side-of-intersection only supported for convex pieces
// Call point_in_geometry, a performance-bottleneck
// TODO: might be replaced by extending analysing piece
return detail::within::point_in_geometry(turn.robust_point,
piece.robust_ring, strategy);
}
}
};
template <>
struct turn_in_piece<false>
{
public :
template <typename Turn, typename Piece, typename Strategy>
static inline int apply(Turn const& turn, Piece const& piece,
Strategy const& strategy)
{
return detail::within::point_in_geometry(turn.robust_point,
piece.robust_ring, strategy);
}
};
template
<
typename CsTag,
typename Turns,
typename Pieces,
typename PointInGeometryStrategy
>
class turn_in_piece_visitor
{
Turns& m_turns; // because partition is currently operating on const input only
Pieces const& m_pieces; // to check for piece-type
PointInGeometryStrategy const& m_point_in_geometry_strategy;
template <typename Operation, typename Piece>
inline bool skip(Operation const& op, Piece const& piece) const
{
if (op.piece_index == piece.index)
{
return true;
}
Piece const& pc = m_pieces[op.piece_index];
if (pc.left_index == piece.index || pc.right_index == piece.index)
{
if (pc.type == strategy::buffer::buffered_flat_end)
{
// If it is a flat end, don't compare against its neighbor:
// it will always be located on one of the helper segments
return true;
}
if (pc.type == strategy::buffer::buffered_concave)
{
// If it is concave, the same applies: the IP will be
// located on one of the helper segments
return true;
}
}
return false;
}
public:
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces)
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces,
PointInGeometryStrategy const& strategy)
: m_turns(turns)
, m_pieces(pieces)
, m_point_in_geometry_strategy(strategy)
{}
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);
boost::ignore_unused(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,63 +873,51 @@ 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;
}
}
static const bool use_soi = use_side_of_intersection<CsTag>::value;
boost::ignore_unused(use_soi);
analyse_result analyse_code =
piece.type == geometry::strategy::buffer::buffered_point
? analyse_turn_wrt_point_piece::apply(turn, piece)
: analyse_turn_wrt_piece::apply(turn, piece);
? analyse_turn_wrt_point_piece<use_soi>::apply(turn, piece)
: analyse_turn_wrt_piece<use_soi>::apply(turn, piece);
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;
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
return true;
case analyse_near_offsetted :
mutable_turn.count_within_near_offsetted++;
return;
#endif
return true;
default :
break;
}
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// We don't know (yet)
int geometry_code = 0;
if (piece.is_convex)
{
geometry_code = turn_in_convex_piece(turn, piece);
}
else
{
// TODO: this point_in_geometry is a performance-bottleneck here and
// will be replaced completely by extending analyse_piece functionality
geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
}
#else
int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
#endif
int const geometry_code = turn_in_piece<use_soi>::apply(turn, piece,
m_point_in_geometry_strategy);
if (geometry_code == 1)
{
mutable_turn.count_within++;
}
return true;
}
};