update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -3,8 +3,8 @@
// 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.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -15,7 +15,9 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/throw_exception.hpp>
#include <boost/geometry/core/closure.hpp>
@@ -85,22 +87,15 @@ template
typename Geometry2,
typename RingCollection,
typename OutputIterator,
typename AreaStrategy
typename Strategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
OutputIterator out,
AreaStrategy const& area_strategy,
Strategy const& strategy,
add_rings_error_handling error_handling = add_rings_ignore_unordered)
{
typedef typename SelectionMap::const_iterator iterator;
typedef typename AreaStrategy::template result_type
<
GeometryOut
>::type area_type;
area_type const zero = 0;
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
<
geometry::closure
@@ -113,29 +108,23 @@ inline OutputIterator add_rings(SelectionMap const& map,
>::value;
for (iterator it = boost::begin(map);
it != boost::end(map);
++it)
for (auto const& pair : map)
{
if (! it->second.discarded
&& it->second.parent.source_index == -1)
if (! pair.second.discarded
&& pair.second.parent.source_index == -1)
{
GeometryOut result;
convert_and_add(result, geometry1, geometry2, collection,
it->first, it->second.reversed, false);
pair.first, pair.second.reversed, false);
// Add children
for (typename std::vector<ring_identifier>::const_iterator child_it
= it->second.children.begin();
child_it != it->second.children.end();
++child_it)
for (auto const& child : pair.second.children)
{
iterator mit = map.find(*child_it);
if (mit != map.end()
&& ! mit->second.discarded)
auto mit = map.find(child);
if (mit != map.end() && ! mit->second.discarded)
{
convert_and_add(result, geometry1, geometry2, collection,
*child_it, mit->second.reversed, true);
child, mit->second.reversed, true);
}
}
@@ -144,7 +133,9 @@ inline OutputIterator add_rings(SelectionMap const& map,
// everything is figured out yet (sum of positive/negative rings)
if (geometry::num_points(result) >= min_num_points)
{
area_type const area = geometry::area(result, area_strategy);
typedef typename geometry::area_result<GeometryOut, Strategy>::type area_type;
area_type const area = geometry::area(result, strategy);
area_type const zero = 0;
// Ignore if area is 0
if (! math::equals(area, zero))
{
@@ -172,16 +163,16 @@ template
typename Geometry,
typename RingCollection,
typename OutputIterator,
typename AreaStrategy
typename Strategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry const& geometry,
RingCollection const& collection,
OutputIterator out,
AreaStrategy const& area_strategy)
Strategy const& strategy)
{
Geometry empty;
return add_rings<GeometryOut>(map, geometry, empty, collection, out, area_strategy);
return add_rings<GeometryOut>(map, geometry, empty, collection, out, strategy);
}

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2018-2020.
// Modifications copyright (c) 2018-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -40,9 +40,9 @@ inline void append_with_duplicates(Range& range, Point const& point)
geometry::append(range, point);
}
template <typename Range, typename Point, typename EqPPStrategy>
template <typename Range, typename Point, typename Strategy>
inline void append_no_duplicates(Range& range, Point const& point,
EqPPStrategy const& strategy)
Strategy const& strategy)
{
if ( boost::empty(range)
|| ! geometry::detail::equals::equals_point_point(geometry::range::back(range),

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2020.
// Modifications copyright (c) 2014-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -14,10 +14,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
#include <boost/range.hpp>
#include <type_traits>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/static_assert.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
@@ -36,11 +42,11 @@ namespace detail { namespace overlay
{
// TODO: move this / rename this
template <typename Point1, typename Point2, typename EqualsStrategy, typename RobustPolicy>
template <typename Point1, typename Point2, typename Strategy, typename RobustPolicy>
inline bool points_equal_or_close(Point1 const& point1,
Point2 const& point2,
EqualsStrategy const& strategy,
RobustPolicy const& robust_policy)
Point2 const& point2,
Strategy const& strategy,
RobustPolicy const& robust_policy)
{
if (detail::equals::equals_point_point(point1, point2, strategy))
{
@@ -64,7 +70,7 @@ inline bool points_equal_or_close(Point1 const& point1,
geometry::recalculate(point2_rob, point2, robust_policy);
// Only if this is the case the same strategy can be used.
BOOST_STATIC_ASSERT((boost::is_same
BOOST_STATIC_ASSERT((std::is_same
<
typename geometry::cs_tag<Point1>::type,
typename geometry::cs_tag<robust_point_type>::type
@@ -74,10 +80,10 @@ inline bool points_equal_or_close(Point1 const& point1,
}
template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
template <typename Range, typename Point, typename Strategy, typename RobustPolicy>
inline void append_no_dups_or_spikes(Range& range, Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
Strategy const& strategy,
RobustPolicy const& robust_policy)
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
std::cout << " add: ("
@@ -88,14 +94,22 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
// for geometries >= 3 points.
// So we have to check the first potential duplicate differently
if ( boost::size(range) == 1
&& points_equal_or_close(*(boost::begin(range)), point,
strategy.get_equals_point_point_strategy(),
&& points_equal_or_close(*(boost::begin(range)), point, strategy,
robust_policy) )
{
return;
}
traits::push_back<Range>::apply(range, point);
auto append = [](auto& r, const auto& p)
{
using point_t = typename boost::range_value<Range>::type;
point_t rp;
geometry::detail::conversion::convert_point_to_point(p, rp);
traits::push_back<Range>::apply(r, std::move(rp));
};
append(range, point);
// If a point is equal, or forming a spike, remove the pen-ultimate point
// because this one caused the spike.
@@ -106,19 +120,19 @@ 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,
strategy.side(), // TODO: Pass strategy?
robust_policy))
{
// Use the Concept/traits, so resize and append again
traits::resize<Range>::apply(range, boost::size(range) - 2);
traits::push_back<Range>::apply(range, point);
append(range, point);
}
}
template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
template <typename Range, typename Point, typename Strategy, typename RobustPolicy>
inline void append_no_collinear(Range& range, Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
Strategy const& strategy,
RobustPolicy const& robust_policy)
{
// Stricter version, not allowing any point in a linear row
// (spike, continuation or same point)
@@ -128,7 +142,7 @@ inline void append_no_collinear(Range& range, Point const& point,
// So we have to check the first potential duplicate differently
if ( boost::size(range) == 1
&& points_equal_or_close(*(boost::begin(range)), point,
strategy.get_equals_point_point_strategy(),
strategy,
robust_policy) )
{
return;
@@ -145,7 +159,7 @@ inline void append_no_collinear(Range& range, Point const& point,
&& point_is_collinear(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
strategy,
strategy.side(), // TODO: Pass strategy?
robust_policy))
{
// Use the Concept/traits, so resize and append again
@@ -154,10 +168,10 @@ inline void append_no_collinear(Range& range, Point const& point,
}
}
template <typename Range, typename SideStrategy, typename RobustPolicy>
template <typename Range, typename Strategy, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
Strategy const& strategy,
RobustPolicy const& robust_policy)
{
std::size_t const minsize
= core_detail::closure::minimum_ring_size
@@ -170,7 +184,6 @@ inline void clean_closing_dups_and_spikes(Range& range,
return;
}
typedef typename boost::range_iterator<Range>::type iterator_type;
static bool const closed = geometry::closure<Range>::value == geometry::closed;
// TODO: the following algorithm could be rewritten to first look for spikes
@@ -180,9 +193,9 @@ inline void clean_closing_dups_and_spikes(Range& range,
do
{
found = false;
iterator_type first = boost::begin(range);
iterator_type second = first + 1;
iterator_type ultimate = boost::end(range) - 1;
auto first = boost::begin(range);
auto second = first + 1;
auto ultimate = boost::end(range) - 1;
if (BOOST_GEOMETRY_CONDITION(closed))
{
ultimate--;
@@ -190,7 +203,9 @@ 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 collinear w.r.t. the last segment)
if (point_is_collinear(*second, *ultimate, *first, strategy, robust_policy))
if (point_is_collinear(*second, *ultimate, *first,
strategy.side(), // TODO: Pass strategy?
robust_policy))
{
range::erase(range, first);
if (BOOST_GEOMETRY_CONDITION(closed))

View File

@@ -0,0 +1,49 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2021 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_APPROXIMATELY_EQUALS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPROXIMATELY_EQUALS_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template <typename Point1, typename Point2, typename E>
inline bool approximately_equals(Point1 const& a, Point2 const& b,
E const& epsilon_multiplier)
{
using coor_t = typename select_coordinate_type<Point1, Point2>::type;
using calc_t = typename geometry::select_most_precise<coor_t, E>::type;
calc_t const& a0 = geometry::get<0>(a);
calc_t const& b0 = geometry::get<0>(b);
calc_t const& a1 = geometry::get<1>(a);
calc_t const& b1 = geometry::get<1>(b);
math::detail::equals_factor_policy<calc_t> policy(a0, b0, a1, b1);
policy.multiply_epsilon(epsilon_multiplier);
return math::detail::equals_by_policy(a0, b0, policy)
&& math::detail::equals_by_policy(a1, b1, policy);
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPROXIMATELY_EQUALS_HPP

View File

@@ -3,8 +3,9 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2023.
// Modifications copyright (c) 2017-2023 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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,
@@ -14,17 +15,23 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/area_result.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
namespace boost { namespace geometry
{
@@ -125,26 +132,42 @@ struct ring_info_helper
};
template <typename Strategy>
struct ring_info_helper_get_box
{
ring_info_helper_get_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename InputItem>
static inline void apply(Box& total, InputItem const& item)
inline void apply(Box& total, InputItem const& item) const
{
geometry::expand(total, item.envelope);
assert_coordinate_type_equal(total, item.envelope);
geometry::expand(total, item.envelope, m_strategy);
}
Strategy const& m_strategy;
};
template <typename DisjointBoxBoxStrategy>
struct ring_info_helper_ovelaps_box
template <typename Strategy>
struct ring_info_helper_overlaps_box
{
ring_info_helper_overlaps_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename InputItem>
static inline bool apply(Box const& box, InputItem const& item)
inline bool apply(Box const& box, InputItem const& item) const
{
assert_coordinate_type_equal(box, item.envelope);
return ! geometry::detail::disjoint::disjoint_box_box(
box, item.envelope, DisjointBoxBoxStrategy());
box, item.envelope, m_strategy);
}
Strategy const& m_strategy;
};
// Segments intersection Strategy
template
<
typename Geometry1,
@@ -190,7 +213,7 @@ struct assign_visitor
{
ring_info_type& inner_in_map = m_ring_map[inner.id];
if (geometry::covered_by(inner_in_map.point, outer.envelope)
if (geometry::covered_by(inner_in_map.point, outer.envelope, m_strategy)
&& within_selected_input(inner_in_map, inner.id, outer.id,
m_geometry1, m_geometry2, m_collection,
m_strategy)
@@ -237,44 +260,37 @@ 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
typedef typename geometry::area_result
<
point_type
>::type::template result_type<point_type>::type area_result_type;
typedef typename RingMap::iterator map_iterator_type;
point_type, Strategy // TODO: point_type is technically incorrect
>::type area_result_type;
{
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;
std::size_t count_total = ring_map.size();
std::size_t count_positive = 0;
std::size_t index_positive = 0; // only used if count_positive>0
std::size_t index = 0;
// Copy to vector (with new approach this might be obsolete as well, using the map directly)
vector_type vector(count_total);
// Copy to vector (this might be obsolete, using the map directly)
using helper = ring_info_helper<point_type, area_result_type>;
std::vector<helper> vector(count_total);
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it, ++index)
for_each_with_index(ring_map, [&](std::size_t index, auto const& pair)
{
vector[index] = helper(it->first, it->second.get_area());
vector[index] = helper(pair.first, pair.second.get_area());
helper& item = vector[index];
switch(it->first.source_index)
switch(pair.first.source_index)
{
case 0 :
geometry::envelope(get_ring<tag1>::apply(it->first, geometry1),
item.envelope, strategy.get_envelope_strategy());
geometry::envelope(get_ring<tag1>::apply(pair.first, geometry1),
item.envelope, strategy);
break;
case 1 :
geometry::envelope(get_ring<tag2>::apply(it->first, geometry2),
item.envelope, strategy.get_envelope_strategy());
geometry::envelope(get_ring<tag2>::apply(pair.first, geometry2),
item.envelope, strategy);
break;
case 2 :
geometry::envelope(get_ring<void>::apply(it->first, collection),
item.envelope, strategy.get_envelope_strategy());
geometry::envelope(get_ring<void>::apply(pair.first, collection),
item.envelope, strategy);
break;
}
@@ -286,7 +302,7 @@ inline void assign_parents(Geometry1 const& geometry1,
count_positive++;
index_positive = index;
}
}
});
if (! check_for_orientation)
{
@@ -307,17 +323,15 @@ inline void assign_parents(Geometry1 const& geometry1,
// located outside the outer ring, this cannot be done
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
index = 0;
for (vector_iterator_type it = boost::begin(vector);
it != boost::end(vector); ++it, ++index)
for_each_with_index(vector, [&](std::size_t index, auto const& item)
{
if (index != index_positive)
{
ring_info_type& inner = ring_map[it->id];
ring_info_type& inner = ring_map[item.id];
inner.parent = id_of_positive;
outer.children.push_back(it->id);
outer.children.push_back(item.id);
}
}
});
return;
}
}
@@ -329,24 +343,19 @@ inline void assign_parents(Geometry1 const& geometry1,
Strategy
> visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation);
typedef ring_info_helper_ovelaps_box
<
typename Strategy::disjoint_box_box_strategy_type
> overlaps_box_type;
geometry::partition
<
box_type
>::apply(vector, visitor, ring_info_helper_get_box(),
overlaps_box_type());
>::apply(vector, visitor,
ring_info_helper_get_box<Strategy>(strategy),
ring_info_helper_overlaps_box<Strategy>(strategy));
}
if (check_for_orientation)
{
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it)
for (auto& pair : ring_map)
{
ring_info_type& info = it->second;
ring_info_type& info = pair.second;
if (geometry::math::equals(info.get_area(), 0))
{
info.discarded = true;
@@ -383,12 +392,11 @@ inline void assign_parents(Geometry1 const& geometry1,
}
// Assign childlist
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it)
for (auto& pair : ring_map)
{
if (it->second.parent.source_index >= 0)
if (pair.second.parent.source_index >= 0)
{
ring_map[it->second.parent].children.push_back(it->first);
ring_map[pair.second.parent].children.push_back(pair.first);
}
}
}

View File

@@ -2,8 +2,8 @@
// 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.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020, 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,7 +16,9 @@
#include <cstddef>
#include <string>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -36,21 +38,11 @@ namespace detail { namespace overlay
template <typename Turns>
inline void clear_visit_info(Turns& turns)
{
typedef typename boost::range_value<Turns>::type tp_type;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
for (auto& turn : turns)
{
for (typename boost::range_iterator
<
typename tp_type::container_type
>::type op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
++op_it)
for (auto& op : turn.operations)
{
op_it->visited.clear();
op.visited.clear();
}
}
}

View File

@@ -26,7 +26,6 @@
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
namespace boost { namespace geometry
@@ -128,37 +127,30 @@ inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
bool error = false;
int index = 0;
std::vector<meta_turn<turn_point_type> > meta_turns;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
++it, ++index)
for_each_with_index(turn_points, [&](std::size_t index, auto const& point)
{
meta_turns.push_back(meta_turn<turn_point_type>(index, *it));
}
meta_turns.push_back(meta_turn<turn_point_type>(index, point));
});
int cycle = 0;
for (typename boost::range_iterator<std::vector<meta_turn<turn_point_type> > > ::type
it = boost::begin(meta_turns);
it != boost::end(meta_turns);
++it)
for (auto& meta_turn : meta_turns)
{
if (! (it->turn->blocked() || it->turn->discarded))
if (! (meta_turn.turn->blocked() || meta_turn.turn->discarded))
{
for (int i = 0 ; i < 2; i++)
{
if (! it->handled[i]
&& it->turn->operations[i].operation == for_operation)
if (! meta_turn.handled[i]
&& meta_turn.turn->operations[i].operation == for_operation)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "CYCLE " << cycle << std::endl;
#endif
it->handled[i] = true;
check_detailed(meta_turns, *it, i, cycle++, it->index, for_operation, error);
meta_turn.handled[i] = true;
check_detailed(meta_turns, meta_turn, i, cycle++, meta_turn.index, for_operation, error);
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout <<" END CYCLE " << it->index << std::endl;
std::cout <<" END CYCLE " << meta_turn.index << std::endl;
#endif
}
}

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015, 2018.
// Modifications copyright (c) 2015-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2020.
// Modifications copyright (c) 2015-2020 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
@@ -15,7 +15,9 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/empty.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
@@ -195,9 +197,8 @@ OutputIterator clip_range_with_box(Box const& b, Range const& range,
OutputLinestring line_out;
typedef typename boost::range_iterator<Range const>::type iterator_type;
iterator_type vertex = boost::begin(range);
for(iterator_type previous = vertex++;
auto vertex = boost::begin(range);
for (auto previous = vertex++;
vertex != boost::end(range);
++previous, ++vertex)
{

View File

@@ -0,0 +1,232 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2020-2023.
// Modifications copyright (c) 2020-2023 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_EXITS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_EXITS_HPP
#include <cstddef>
#include <set>
#include <vector>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/util/condition.hpp>
#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \
|| defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \
|| defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
# include <string>
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/io/wkt/wkt.hpp>
#endif
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
// Structure to check relatively simple cluster cases
template <overlay_type OverlayType,
typename Turns,
typename Sbs>
struct cluster_exits
{
private :
static const operation_type target_operation = operation_from_overlay<OverlayType>::value;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
struct linked_turn_op_info
{
explicit linked_turn_op_info(signed_size_type ti = -1, int oi = -1,
signed_size_type nti = -1)
: turn_index(ti)
, op_index(oi)
, next_turn_index(nti)
, rank_index(-1)
{}
signed_size_type turn_index;
int op_index;
signed_size_type next_turn_index;
signed_size_type rank_index;
};
inline signed_size_type get_rank(Sbs const& sbs,
linked_turn_op_info const& info) const
{
for (auto const& rp : sbs.m_ranked_points)
{
if (rp.turn_index == info.turn_index
&& rp.operation_index == info.op_index
&& rp.direction == sort_by_side::dir_to)
{
return rp.rank;
}
}
return -1;
}
std::set<signed_size_type> const& m_ids;
std::vector<linked_turn_op_info> possibilities;
std::vector<linked_turn_op_info> blocked;
bool m_valid;
bool collect(Turns const& turns)
{
for (auto cluster_turn_index : m_ids)
{
turn_type const& cluster_turn = turns[cluster_turn_index];
if (cluster_turn.discarded)
{
continue;
}
if (cluster_turn.both(target_operation))
{
// Not (yet) supported, can be cluster of u/u turns
return false;
}
for (int i = 0; i < 2; i++)
{
turn_operation_type const& op = cluster_turn.operations[i];
turn_operation_type const& other_op = cluster_turn.operations[1 - i];
signed_size_type const ni = op.enriched.get_next_turn_index();
if (op.operation == target_operation
|| op.operation == operation_continue)
{
if (ni == cluster_turn_index)
{
// Not (yet) supported, traveling to itself, can be
// hole
return false;
}
possibilities.push_back(
linked_turn_op_info(cluster_turn_index, i, ni));
}
else if (op.operation == operation_blocked
&& ! (ni == other_op.enriched.get_next_turn_index())
&& m_ids.count(ni) == 0)
{
// Points to turn, not part of this cluster,
// and that way is blocked. But if the other operation
// points at the same turn, it is still fine.
blocked.push_back(
linked_turn_op_info(cluster_turn_index, i, ni));
}
}
}
return true;
}
bool check_blocked(Sbs const& sbs)
{
if (blocked.empty())
{
return true;
}
for (auto& info : possibilities)
{
info.rank_index = get_rank(sbs, info);
}
for (auto& info : blocked)
{
info.rank_index = get_rank(sbs, info);
}
for (auto const& lti : possibilities)
{
for (auto const& blti : blocked)
{
if (blti.next_turn_index == lti.next_turn_index
&& blti.rank_index == lti.rank_index)
{
return false;
}
}
}
return true;
}
public :
cluster_exits(Turns const& turns,
std::set<signed_size_type> const& ids,
Sbs const& sbs)
: m_ids(ids)
, m_valid(collect(turns) && check_blocked(sbs))
{
}
inline bool apply(signed_size_type& turn_index,
int& op_index,
bool first_run = true) const
{
if (! m_valid)
{
return false;
}
// Traversal can either enter the cluster in the first turn,
// or it can start halfway.
// If there is one (and only one) possibility pointing outside
// the cluster, take that one.
linked_turn_op_info target;
for (auto const& lti : possibilities)
{
if (m_ids.count(lti.next_turn_index) == 0)
{
if (target.turn_index >= 0
&& target.next_turn_index != lti.next_turn_index)
{
// Points to different target
return false;
}
if (first_run
&& BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer)
&& target.turn_index >= 0)
{
// Target already assigned, so there are more targets
// or more ways to the same target
return false;
}
target = lti;
}
}
if (target.turn_index < 0)
{
return false;
}
turn_index = target.turn_index;
op_index = target.op_index;
return true;
}
};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_EXITS_HPP

View File

@@ -0,0 +1,107 @@
// Boost.Geometry
// Copyright (c) 2023 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_COLOCATE_CLUSTERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
// Default implementation, using the first point for all turns in the cluster.
template
<
typename Point,
typename CoordinateType = typename geometry::coordinate_type<Point>::type,
typename CsTag = typename geometry::cs_tag<Point>::type,
bool IsIntegral = std::is_integral<CoordinateType>::value
>
struct cluster_colocator
{
template <typename TurnIndices, typename Turns>
static inline void apply(TurnIndices const& indices, Turns& turns)
{
// This approach works for all but one testcase (rt_p13)
// The problem is fill_sbs, which uses sides and these sides might change slightly
// depending on the exact location of the cluster.
// Using the centroid is, on the average, a safer choice for sides.
// Alternatively fill_sbs could be revised, but that requires a lot of work
// and is outside current scope.
// Integer coordinates are always colocated already and do not need centroid calculation.
// Geographic/spherical coordinates might (in extremely rare cases) cross the date line
// and therefore the first point is taken for them as well.
auto it = indices.begin();
auto const& first_point = turns[*it].point;
for (++it; it != indices.end(); ++it)
{
turns[*it].point = first_point;
}
}
};
// Specialization for non-integral cartesian coordinates, calculating
// the centroid of the points of the turns in the cluster.
template <typename Point, typename CoordinateType>
struct cluster_colocator<Point, CoordinateType, geometry::cartesian_tag, false>
{
template <typename TurnIndices, typename Turns>
static inline void apply(TurnIndices const& indices, Turns& turns)
{
CoordinateType centroid_0 = 0;
CoordinateType centroid_1 = 0;
for (const auto& index : indices)
{
centroid_0 += geometry::get<0>(turns[index].point);
centroid_1 += geometry::get<1>(turns[index].point);
}
centroid_0 /= indices.size();
centroid_1 /= indices.size();
for (const auto& index : indices)
{
geometry::set<0>(turns[index].point, centroid_0);
geometry::set<1>(turns[index].point, centroid_1);
}
}
};
// Moves intersection points per cluster such that they are identical.
// Because clusters are intersection close together, and
// handled as one location. Then they should also have one location.
// It is necessary to avoid artefacts and invalidities.
template <typename Clusters, typename Turns>
inline void colocate_clusters(Clusters const& clusters, Turns& turns)
{
for (auto const& pair : clusters)
{
auto const& indices = pair.second.turn_indices;
if (indices.size() < 2)
{
// Defensive check
continue;
}
using point_t = decltype(turns[*indices.begin()].point);
cluster_colocator<point_t>::apply(indices, turns);
}
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP

View File

@@ -2,9 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, Oracle and/or its affiliates.
// This file was modified by Oracle on 2018-2020.
// Modifications copyright (c) 2018-2020, 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,
@@ -14,16 +13,15 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
#include <boost/mpl/assert.hpp>
#include <boost/range/algorithm/reverse.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
@@ -37,11 +35,9 @@ namespace detail { namespace overlay
template<typename Tag>
struct convert_ring
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TAG
, (types<Tag>)
);
BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
"Not or not yet implemented for this geometry Tag.",
Tag);
};
template<>
@@ -90,6 +86,7 @@ struct convert_ring<polygon_tag>
if (geometry::num_points(source) >= min_num_points)
{
// TODO: resize and .size() and .back() should not be called here
interior_rings(destination).resize(
interior_rings(destination).size() + 1);
geometry::convert(source, interior_rings(destination).back());

View File

@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2020-2021.
// Modifications copyright (c) 2020-2021, 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
@@ -10,22 +15,24 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
#include <boost/array.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <array>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
@@ -36,38 +43,40 @@ namespace boost { namespace geometry
namespace detail { namespace copy_segments
{
inline signed_size_type circular_offset(signed_size_type segment_count, signed_size_type index,
signed_size_type offset)
{
signed_size_type result = (index + offset) % segment_count;
if (result < 0)
{
result += segment_count;
}
return result;
}
template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point_range
{
static inline bool apply(Range const& range,
SegmentIdentifier const& seg_id, int offset,
SegmentIdentifier const& seg_id, signed_size_type offset,
PointOut& point)
{
typedef typename closeable_view
<
Range const,
closure<Range>::value
>::type cview_type;
using view_type = detail::closed_clockwise_view
<
Range const,
closure<Range>::value,
Reverse ? counterclockwise : clockwise
>;
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
view_type view(range);
cview_type cview(range);
rview_type view(cview);
std::size_t const segment_count = boost::size(view) - 1;
signed_size_type const target = circular_offset(segment_count, seg_id.segment_index, offset);
BOOST_GEOMETRY_ASSERT(target >= 0
&& std::size_t(target) < boost::size(view));
typedef typename boost::range_iterator<rview_type>::type iterator;
geometry::ever_circling_iterator<iterator> it(boost::begin(view), boost::end(view),
boost::begin(view) + seg_id.segment_index, true);
geometry::convert(range::at(view, target), point);
for (signed_size_type i = 0; i < offset; ++i, ++it)
{
}
geometry::convert(*it, point);
return true;
}
};
@@ -77,7 +86,7 @@ template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename P
struct copy_segment_point_polygon
{
static inline bool apply(Polygon const& polygon,
SegmentIdentifier const& seg_id, int offset,
SegmentIdentifier const& seg_id, signed_size_type offset,
PointOut& point)
{
// Call ring-version with the right ring
@@ -103,18 +112,17 @@ template <typename Box, bool Reverse, typename SegmentIdentifier, typename Point
struct copy_segment_point_box
{
static inline bool apply(Box const& box,
SegmentIdentifier const& seg_id, int offset,
SegmentIdentifier const& seg_id, signed_size_type offset,
PointOut& point)
{
signed_size_type index = seg_id.segment_index;
for (int i = 0; i < offset; i++)
{
index++;
}
boost::array<typename point_type<Box>::type, 4> bp;
std::array<typename point_type<Box>::type, 4> bp;
assign_box_corners_oriented<Reverse>(box, bp);
point = bp[index % 4];
signed_size_type const target = circular_offset(4, seg_id.segment_index, offset);
BOOST_GEOMETRY_ASSERT(target >= 0
&& std::size_t(target) < bp.size());
point = bp[target];
return true;
}
};
@@ -130,15 +138,11 @@ template
struct copy_segment_point_multi
{
static inline bool apply(MultiGeometry const& multi,
SegmentIdentifier const& seg_id, int offset,
SegmentIdentifier const& seg_id, signed_size_type offset,
PointOut& point)
{
BOOST_GEOMETRY_ASSERT
(
seg_id.multi_index >= 0
&& seg_id.multi_index < int(boost::size(multi))
);
BOOST_GEOMETRY_ASSERT(seg_id.multi_index >= 0
&& std::size_t(seg_id.multi_index) < boost::size(multi));
// Call the single-version
return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, offset, point);
@@ -165,11 +169,9 @@ template
>
struct copy_segment_point
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<GeometryIn>)
);
BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
"Not or not yet implemented for this Geometry type.",
Tag, GeometryIn);
};
@@ -273,16 +275,13 @@ struct copy_segment_point
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Helper function, copies a point from a segment
\ingroup overlay
*/
template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
inline bool copy_segment_point(Geometry const& geometry,
SegmentIdentifier const& seg_id, int offset,
SegmentIdentifier const& seg_id, signed_size_type offset,
PointOut& point_out)
{
concepts::check<Geometry const>();
@@ -311,7 +310,7 @@ template
typename PointOut
>
inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
SegmentIdentifier const& seg_id, int offset,
SegmentIdentifier const& seg_id, signed_size_type offset,
PointOut& point_out)
{
concepts::check<Geometry1 const>();
@@ -394,7 +393,6 @@ inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geo
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP

View File

@@ -1,10 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021 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
@@ -16,12 +16,13 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
#include <array>
#include <type_traits>
#include <vector>
#include <boost/array.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
@@ -41,8 +42,7 @@
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
@@ -61,35 +61,28 @@ struct copy_segments_ring
<
typename Ring,
typename SegmentIdentifier,
typename SideStrategy,
typename Strategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
using view_type = detail::closed_clockwise_view
<
Ring const,
closure<Ring>::value,
Reverse ? counterclockwise : clockwise
>;
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
using iterator = typename boost::range_iterator<view_type const>::type;
using ec_iterator = geometry::ever_circling_iterator<iterator>;
typedef typename boost::range_iterator<rview_type const>::type iterator;
typedef geometry::ever_circling_iterator<iterator> ec_iterator;
cview_type cview(ring);
rview_type view(cview);
view_type view(ring);
// The problem: sometimes we want to from "3" to "2"
// -> end = "3" -> end == begin
@@ -125,12 +118,12 @@ class copy_segments_linestring
{
private:
// remove spikes
template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
template <typename RangeOut, typename Point, typename Strategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
SideStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
boost::true_type const&)
std::true_type const&)
{
detail::overlay::append_no_dups_or_spikes(current_output, point,
strategy,
@@ -138,14 +131,14 @@ private:
}
// keep spikes
template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
template <typename RangeOut, typename Point, typename Strategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
SideStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const&,
boost::false_type const&)
std::false_type const&)
{
detail::overlay::append_no_duplicates(current_output, point, strategy.get_equals_point_point_strategy());
detail::overlay::append_no_duplicates(current_output, point, strategy);
}
public:
@@ -175,14 +168,11 @@ public:
}
signed_size_type const count = to_index - from_index + 1;
typename boost::range_iterator<LineString const>::type
it = boost::begin(ls) + from_index;
auto it = boost::begin(ls) + from_index;
for (signed_size_type i = 0; i < count; ++i, ++it)
{
append_to_output(current_output, *it, strategy, robust_policy,
boost::integral_constant<bool, RemoveSpikes>());
std::integral_constant<bool, RemoveSpikes>());
}
}
};
@@ -246,7 +236,7 @@ struct copy_segments_box
: 5 - index + to_index + 1;
// Create array of points, the fifth one closes it
boost::array<typename point_type<Box>::type, 5> bp;
std::array<typename point_type<Box>::type, 5> bp;
assign_box_corners_oriented<Reverse>(box, bp);
bp[4] = bp[0];

View File

@@ -28,6 +28,7 @@ inline char method_char(detail::overlay::method_type const& method)
case method_touch_interior : return 'm';
case method_collinear : return 'c';
case method_equal : return 'e';
case method_start : return 's';
case method_error : return '!';
default : return '?';
}

View File

@@ -0,0 +1,160 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2021 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2023.
// Modifications copyright (c) 2023 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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_DISCARD_DUPLICATE_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISCARD_DUPLICATE_TURNS_HPP
#include <map>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
inline bool same_multi_and_ring_id(segment_identifier const& first,
segment_identifier const& second)
{
return first.ring_index == second.ring_index
&& first.multi_index == second.multi_index;
}
template <typename Geometry0, typename Geometry1>
inline bool is_consecutive(segment_identifier const& first,
segment_identifier const& second,
Geometry0 const& geometry0,
Geometry1 const& geometry1)
{
if (first.source_index == second.source_index
&& first.ring_index == second.ring_index
&& first.multi_index == second.multi_index)
{
// If the segment distance is 1, there are no segments in between
// and the segments are consecutive.
signed_size_type const sd = first.source_index == 0
? segment_distance(geometry0, first, second)
: segment_distance(geometry1, first, second);
return sd <= 1;
}
return false;
}
// Returns true if two turns correspond to each other in the sense that one has
// "method_start" and the other has "method_touch" or "method_interior" at that
// same point (but with next segment)
template <typename Turn, typename Geometry0, typename Geometry1>
inline bool corresponding_turn(Turn const& turn, Turn const& start_turn,
Geometry0 const& geometry0,
Geometry1 const& geometry1)
{
std::size_t count = 0;
for (std::size_t i = 0; i < 2; i++)
{
for (std::size_t j = 0; j < 2; j++)
{
if (same_multi_and_ring_id(turn.operations[i].seg_id,
start_turn.operations[j].seg_id))
{
// Verify if all operations are consecutive
if (is_consecutive(turn.operations[i].seg_id,
start_turn.operations[j].seg_id,
geometry0, geometry1)
&& is_consecutive(turn.operations[1 - i].seg_id,
start_turn.operations[1 - j].seg_id,
geometry0, geometry1))
{
count++;
}
}
}
}
// An intersection is located on exactly two rings
// The corresponding turn, if any, should be located on the same two rings.
return count == 2;
}
template <typename Turns, typename Geometry0, typename Geometry1>
inline void discard_duplicate_start_turns(Turns& turns,
Geometry0 const& geometry0,
Geometry1 const& geometry1)
{
// Start turns are generated, in case the previous turn is missed.
// But often it is not missed, and then it should be deleted.
// This is how it can be
// (in float, collinear, points far apart due to floating point precision)
// [m, i s:0, v:6 1/1 (1) // u s:1, v:5 pnt (2.54044, 3.12623)]
// [s, i s:0, v:7 0/1 (0) // u s:1, v:5 pnt (2.70711, 3.29289)]
using multi_and_ring_id_type = std::pair<signed_size_type, signed_size_type>;
auto adapt_id = [](segment_identifier const& seg_id)
{
return multi_and_ring_id_type{seg_id.multi_index, seg_id.ring_index};
};
// 1 Build map of start turns (multi/ring-id -> turn indices)
std::map<multi_and_ring_id_type, std::vector<std::size_t>> start_turns_per_segment;
std::size_t index = 0;
for (auto const& turn : turns)
{
if (turn.method == method_start)
{
for (const auto& op : turn.operations)
{
start_turns_per_segment[adapt_id(op.seg_id)].push_back(index);
}
}
index++;
}
// 2: Verify all other turns if they are present in the map, and if so,
// if they have the other turns as corresponding
for (auto const& turn : turns)
{
// Any turn which "crosses" does not have a corresponding turn.
// Also avoid comparing "start" with itself.
if (turn.method != method_crosses && turn.method != method_start)
{
for (const auto& op : turn.operations)
{
auto it = start_turns_per_segment.find(adapt_id(op.seg_id));
if (it != start_turns_per_segment.end())
{
for (std::size_t const& i : it->second)
{
if (corresponding_turn(turn, turns[i],
geometry0, geometry1))
{
turns[i].discarded = true;
}
}
}
}
}
index++;
}
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISCARD_DUPLICATE_TURNS_HPP

View File

@@ -3,6 +3,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020 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)
@@ -25,16 +29,16 @@ template <order_selector Selector, bool Reverse = false>
struct do_reverse {};
template <>
struct do_reverse<clockwise, false> : boost::false_type {};
struct do_reverse<clockwise, false> : std::false_type {};
template <>
struct do_reverse<clockwise, true> : boost::true_type {};
struct do_reverse<clockwise, true> : std::true_type {};
template <>
struct do_reverse<counterclockwise, false> : boost::true_type {};
struct do_reverse<counterclockwise, false> : std::true_type {};
template <>
struct do_reverse<counterclockwise, true> : boost::false_type {};
struct do_reverse<counterclockwise, true> : std::false_type {};
}} // namespace detail::overlay

View File

@@ -3,9 +3,8 @@
// 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.
// This file was modified by Oracle on 2017-2021.
// Modifications copyright (c) 2017-2020 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,
@@ -30,15 +29,19 @@
#endif
#endif
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.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/policies/robustness/robust_type.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
@@ -53,9 +56,9 @@ namespace detail { namespace overlay
{
template <typename Turns>
struct discarded_turn
struct discarded_indexed_turn
{
discarded_turn(Turns const& turns)
discarded_indexed_turn(Turns const& turns)
: m_turns(turns)
{}
@@ -80,24 +83,24 @@ template
typename Turns,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename SideStrategy
typename Strategy
>
inline void enrich_sort(Operations& operations,
Turns const& turns,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
SideStrategy const& strategy)
Strategy const& strategy)
{
std::sort(boost::begin(operations),
boost::end(operations),
less_by_segment_ratio
std::sort(std::begin(operations),
std::end(operations),
less_by_segment_ratio
<
Turns,
typename boost::range_value<Operations>::type,
Geometry1, Geometry2,
RobustPolicy,
SideStrategy,
Strategy,
Reverse1, Reverse2
>(turns, geometry1, geometry2, robust_policy, strategy));
}
@@ -107,93 +110,83 @@ template <typename Operations, typename Turns>
inline void enrich_assign(Operations& operations, Turns& turns,
bool check_turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef typename boost::range_iterator<Operations>::type iterator_type;
if (operations.size() > 0)
if (operations.empty())
{
// Assign travel-to-vertex/ip index for each turning point.
// Iterator "next" is circular
return;
}
geometry::ever_circling_range_iterator<Operations const> next(operations);
++next;
// Assign travel-to-vertex/ip index for each turning point.
// Iterator "next" is circular
for (iterator_type it = boost::begin(operations);
it != boost::end(operations); ++it)
geometry::ever_circling_range_iterator<Operations const> next(operations);
++next;
for (auto const& indexed : operations)
{
auto& turn = turns[indexed.turn_index];
auto& op = turn.operations[indexed.operation_index];
if (check_turns && indexed.turn_index == next->turn_index)
{
turn_type& turn = turns[it->turn_index];
op_type& op = turn.operations[it->operation_index];
// Normal behaviour: next points at next turn, increase next.
// For dissolve this should not be done, turn_index is often
// the same for two consecutive operations
++next;
}
if (check_turns && it->turn_index == next->turn_index)
{
// Normal behaviour: next points at next turn, increase next.
// For dissolve this should not be done, turn_index is often
// the same for two consecutive operations
++next;
}
// Cluster behaviour: next should point after cluster, unless
// their seg_ids are not the same
// (For dissolve, this is still to be examined - TODO)
while (turn.is_clustered()
&& indexed.turn_index != next->turn_index
&& turn.cluster_id == turns[next->turn_index].cluster_id
&& op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id)
{
++next;
}
// Cluster behaviour: next should point after cluster, unless
// their seg_ids are not the same
// (For dissolve, this is still to be examined - TODO)
while (turn.is_clustered()
&& it->turn_index != next->turn_index
&& turn.cluster_id == turns[next->turn_index].cluster_id
&& op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id)
{
++next;
}
auto const& next_turn = turns[next->turn_index];
auto const& next_op = next_turn.operations[next->operation_index];
turn_type const& next_turn = turns[next->turn_index];
op_type const& next_op = next_turn.operations[next->operation_index];
op.enriched.travels_to_ip_index
= static_cast<signed_size_type>(next->turn_index);
op.enriched.travels_to_vertex_index
= next->subject->seg_id.segment_index;
op.enriched.travels_to_ip_index
= static_cast<signed_size_type>(next->turn_index);
op.enriched.travels_to_vertex_index
= next->subject->seg_id.segment_index;
if (op.seg_id.segment_index == next_op.seg_id.segment_index
&& op.fraction < next_op.fraction)
{
// Next turn is located further on same segment
// assign next_ip_index
// (this is one not circular therefore fraction is considered)
op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index);
}
if (op.seg_id.segment_index == next_op.seg_id.segment_index
&& op.fraction < next_op.fraction)
{
// Next turn is located further on same segment
// assign next_ip_index
// (this is one not circular therefore fraction is considered)
op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index);
}
if (! check_turns)
{
++next;
}
if (! check_turns)
{
++next;
}
}
// DEBUG
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
for (auto const& indexed_op : operations)
{
for (iterator_type it = boost::begin(operations);
it != boost::end(operations);
++it)
{
op_type const& op = turns[it->turn_index]
.operations[it->operation_index];
auto const& op = turns[indexed_op.turn_index].operations[indexed_op.operation_index];
std::cout << it->turn_index
<< " cl=" << turns[it->turn_index].cluster_id
<< " meth=" << method_char(turns[it->turn_index].method)
<< " seg=" << op.seg_id
<< " dst=" << op.fraction // needs define
<< " op=" << operation_char(turns[it->turn_index].operations[0].operation)
<< operation_char(turns[it->turn_index].operations[1].operation)
<< " (" << operation_char(op.operation) << ")"
<< " nxt=" << op.enriched.next_ip_index
<< " / " << op.enriched.travels_to_ip_index
<< " [vx " << op.enriched.travels_to_vertex_index << "]"
<< std::boolalpha << turns[it->turn_index].discarded
<< std::endl;
;
}
std::cout << indexed_op.turn_index
<< " cl=" << turns[indexed_op.turn_index].cluster_id
<< " meth=" << method_char(turns[indexed_op.turn_index].method)
<< " seg=" << op.seg_id
<< " dst=" << op.fraction // needs define
<< " op=" << operation_char(turns[indexed_op.turn_index].operations[0].operation)
<< operation_char(turns[indexed_op.turn_index].operations[1].operation)
<< " (" << operation_char(op.operation) << ")"
<< " nxt=" << op.enriched.next_ip_index
<< " / " << op.enriched.travels_to_ip_index
<< " [vx " << op.enriched.travels_to_vertex_index << "]"
<< (turns[indexed_op.turn_index].discarded ? " discarded" : "")
<< std::endl;
}
#endif
// END DEBUG
@@ -203,47 +196,37 @@ inline void enrich_assign(Operations& operations, Turns& turns,
template <typename Operations, typename Turns>
inline void enrich_adapt(Operations& operations, Turns& turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef typename boost::range_value<Operations>::type indexed_turn_type;
// Operations is a vector of indexed_turn_operation<>
// If it is empty, or contains one or two items, it makes no sense
if (operations.size() < 3)
{
// If it is empty, or contains one or two turns, it makes no sense
return;
}
// Operations is a vector of indexed_turn_operation<>
// Last index:
std::size_t const x = operations.size() - 1;
bool next_phase = false;
std::size_t previous_index = operations.size() - 1;
for (std::size_t i = 0; i < operations.size(); i++)
for_each_with_index(operations, [&](std::size_t index, auto const& indexed)
{
indexed_turn_type const& indexed = operations[i];
auto& turn = turns[indexed.turn_index];
auto& op = turn.operations[indexed.operation_index];
turn_type& turn = turns[indexed.turn_index];
op_type& op = turn.operations[indexed.operation_index];
// Previous/next index
std::size_t const p = i > 0 ? i - 1 : x;
std::size_t const n = i < x ? i + 1 : 0;
turn_type const& next_turn = turns[operations[n].turn_index];
op_type const& next_op = next_turn.operations[operations[n].operation_index];
std::size_t const next_index = index + 1 < operations.size() ? index + 1 : 0;
auto const& next_turn = turns[operations[next_index].turn_index];
auto const& next_op = next_turn.operations[operations[next_index].operation_index];
if (op.seg_id.segment_index == next_op.seg_id.segment_index)
{
turn_type const& prev_turn = turns[operations[p].turn_index];
op_type const& prev_op = prev_turn.operations[operations[p].operation_index];
auto const& prev_turn = turns[operations[previous_index].turn_index];
auto const& prev_op = prev_turn.operations[operations[previous_index].operation_index];
if (op.seg_id.segment_index == prev_op.seg_id.segment_index)
{
op.enriched.startable = false;
next_phase = true;
}
}
}
previous_index = index;
});
if (! next_phase)
{
@@ -252,12 +235,8 @@ inline void enrich_adapt(Operations& operations, Turns& turns)
// Discard turns which are both non-startable
next_phase = false;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
for (auto& turn : turns)
{
turn_type& turn = *it;
if (! turn.operations[0].enriched.startable
&& ! turn.operations[1].enriched.startable)
{
@@ -272,53 +251,50 @@ inline void enrich_adapt(Operations& operations, Turns& turns)
}
// Remove discarded turns from operations to avoid having them as next turn
discarded_turn<Turns> const predicate(turns);
operations.erase(std::remove_if(boost::begin(operations),
boost::end(operations), predicate), boost::end(operations));
discarded_indexed_turn<Turns> const predicate(turns);
operations.erase(std::remove_if(std::begin(operations),
std::end(operations), predicate), std::end(operations));
}
template <typename Turns, typename MappedVector>
inline void create_map(Turns const& turns, MappedVector& mapped_vector)
struct enriched_map_default_include_policy
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::container_type container_type;
typedef typename MappedVector::mapped_type mapped_type;
typedef typename boost::range_value<mapped_type>::type indexed_type;
std::size_t index = 0;
for (typename boost::range_iterator<Turns const>::type
it = boost::begin(turns);
it != boost::end(turns);
++it, ++index)
template <typename Operation>
static inline bool include(Operation const& )
{
// Add all (non discarded) operations on this ring
// Blocked operations or uu on clusters (for intersection)
// should be included, to block potential paths in clusters
turn_type const& turn = *it;
if (turn.discarded)
{
continue;
}
std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(turn.operations);
op_it != boost::end(turn.operations);
++op_it, ++op_index)
{
ring_identifier const ring_id
(
op_it->seg_id.source_index,
op_it->seg_id.multi_index,
op_it->seg_id.ring_index
);
mapped_vector[ring_id].push_back
(
indexed_type(index, op_index, *op_it,
it->operations[1 - op_index].seg_id)
);
}
// By default include all operations
return true;
}
};
// Add all (non discarded) operations on this ring
// Blocked operations or uu on clusters (for intersection)
// should be included, to block potential paths in clusters
template <typename Turns, typename MappedVector, typename IncludePolicy>
inline void create_map(Turns const& turns, MappedVector& mapped_vector,
IncludePolicy const& include_policy)
{
for_each_with_index(turns, [&](std::size_t index, auto const& turn)
{
if (! turn.discarded)
{
for_each_with_index(turn.operations, [&](std::size_t op_index, auto const& op)
{
if (include_policy.include(op.operation))
{
ring_identifier const ring_id
(
op.seg_id.source_index,
op.seg_id.multi_index,
op.seg_id.ring_index
);
mapped_vector[ring_id].emplace_back
(
index, op_index, op, turn.operations[1 - op_index].seg_id
);
}
});
}
});
}
template <typename Point1, typename Point2>
@@ -327,7 +303,7 @@ inline typename geometry::coordinate_type<Point1>::type
{
// TODO: use comparable distance for point-point instead - but that
// causes currently cycling include problems
typedef typename geometry::coordinate_type<Point1>::type ctype;
using ctype = typename geometry::coordinate_type<Point1>::type;
ctype const dx = get<0>(a) - get<0>(b);
ctype const dy = get<1>(a) - get<1>(b);
return dx * dx + dy * dy;
@@ -336,30 +312,24 @@ inline typename geometry::coordinate_type<Point1>::type
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)
for (auto& turn : turns)
{
turn_type& turn = *it;
auto& op0 = turn.operations[0];
auto& op1 = turn.operations[1];
op_type& op0 = turn.operations[0];
op_type& op1 = turn.operations[1];
static decltype(op0.remaining_distance) const zero_distance = 0;
if (op0.remaining_distance != 0
|| op1.remaining_distance != 0)
if (op0.remaining_distance != zero_distance
|| op1.remaining_distance != zero_distance)
{
continue;
}
signed_size_type const to_index0 = op0.enriched.get_next_turn_index();
signed_size_type const to_index1 = op1.enriched.get_next_turn_index();
auto const to_index0 = op0.enriched.get_next_turn_index();
auto const to_index1 = op1.enriched.get_next_turn_index();
if (to_index0 >= 0
&& to_index1 >= 0
&& to_index0 != to_index1)
&& 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);
@@ -381,13 +351,13 @@ inline void calculate_remaining_distance(Turns& turns)
\tparam Clusters type of cluster container
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam SideStrategy side strategy type
\tparam PointInGeometryStrategy point in geometry strategy type
\param turns container containing intersection points
\param clusters container containing clusters
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param robust_policy policy to handle robustness issues
\param strategy strategy
\param strategy point in geometry strategy
*/
template
<
@@ -397,48 +367,48 @@ template
typename Clusters,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename SideStrategy
typename IntersectionStrategy
>
inline void enrich_intersection_points(Turns& turns,
Clusters& clusters,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
SideStrategy const& strategy)
IntersectionStrategy const& strategy)
{
static const detail::overlay::operation_type target_operation
constexpr detail::overlay::operation_type target_operation
= detail::overlay::operation_from_overlay<OverlayType>::value;
static const detail::overlay::operation_type opposite_operation
constexpr detail::overlay::operation_type opposite_operation
= target_operation == detail::overlay::operation_union
? detail::overlay::operation_intersection
: detail::overlay::operation_union;
static const bool is_dissolve = OverlayType == overlay_dissolve;
constexpr bool is_dissolve = OverlayType == overlay_dissolve;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef detail::overlay::indexed_turn_operation
using turn_type = typename boost::range_value<Turns>::type;
using indexed_turn_operation = detail::overlay::indexed_turn_operation
<
op_type
> indexed_turn_operation;
typename turn_type::turn_operation_type
> ;
typedef std::map
using mapped_vector_type = std::map
<
ring_identifier,
std::vector<indexed_turn_operation>
> mapped_vector_type;
>;
// From here on, turn indexes are used (in clusters, next_index, etc)
// and turns may not be DELETED - they may only be flagged as discarded
discard_duplicate_start_turns(turns, geometry1, geometry2);
bool has_cc = false;
bool const has_colocations
= detail::overlay::handle_colocations<Reverse1, Reverse2, OverlayType>(turns,
clusters, geometry1, geometry2);
= detail::overlay::handle_colocations
<
Reverse1, Reverse2, OverlayType, Geometry1, Geometry2
>(turns, clusters, robust_policy);
// Discard turns not part of target overlay
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
for (auto& turn : turns)
{
turn_type& turn = *it;
if (turn.both(detail::overlay::operation_none)
|| turn.both(opposite_operation)
|| turn.both(detail::overlay::operation_blocked)
@@ -474,52 +444,36 @@ inline void enrich_intersection_points(Turns& turns,
<
OverlayType,
target_operation
>::apply(turns, clusters, geometry1, geometry2);
>::apply(turns, clusters, geometry1, geometry2,
strategy);
detail::overlay::discard_open_turns
<
OverlayType,
target_operation
>::apply(turns, clusters, geometry1, geometry2);
>::apply(turns, clusters, geometry1, geometry2,
strategy);
}
// 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, mapped_vector);
detail::overlay::create_map(turns, mapped_vector,
detail::overlay::enriched_map_default_include_policy());
// No const-iterator; contents of mapped copy is temporary,
// and changed by enrich
for (typename mapped_vector_type::iterator mit
= mapped_vector.begin();
mit != mapped_vector.end();
++mit)
for (auto& pair : mapped_vector)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-sort Ring "
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<Reverse1, Reverse2>(
mit->second, turns,
pair.second, turns,
geometry1, geometry2,
robust_policy, strategy);
}
for (typename mapped_vector_type::iterator mit
= mapped_vector.begin();
mit != mapped_vector.end();
++mit)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-assign Ring "
<< mit->first << std::endl;
#endif
if (is_dissolve)
std::cout << "ENRICH-sort Ring " << pair.first << std::endl;
for (auto const& op : pair.second)
{
detail::overlay::enrich_adapt(mit->second, turns);
std::cout << op.turn_index << " " << op.operation_index << std::endl;
}
detail::overlay::enrich_assign(mit->second, turns, ! is_dissolve);
#endif
}
if (has_colocations)
@@ -532,11 +486,26 @@ inline void enrich_intersection_points(Turns& turns,
Reverse2,
OverlayType
>(clusters, turns, target_operation,
geometry1, geometry2, strategy);
geometry1, geometry2, strategy.side()); // TODO: pass strategy
detail::overlay::cleanup_clusters(turns, clusters);
}
// After cleaning up clusters assign the next turns
for (auto& pair : mapped_vector)
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << "ENRICH-assign Ring " << pair.first << std::endl;
#endif
if (is_dissolve)
{
detail::overlay::enrich_adapt(pair.second, turns);
}
detail::overlay::enrich_assign(pair.second, turns, ! is_dissolve);
}
if (has_cc)
{
detail::overlay::calculate_remaining_distance(turns);

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2022.
// Modifications copyright (c) 2014-2022 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
@@ -16,19 +16,23 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
#include <cstddef>
#include <type_traits>
#include <boost/range.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
#include <boost/geometry/algorithms/detail/tupled_output.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/util/condition.hpp>
namespace boost { namespace geometry
{
@@ -42,7 +46,7 @@ namespace following
{
template <typename Turn, typename Operation>
static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
{
// (Blocked means: blocked for polygon/polygon intersection, because
// they are reversed. But for polygon/line it is similar to continue)
@@ -58,11 +62,11 @@ template
typename Operation,
typename LineString,
typename Polygon,
typename PtInPolyStrategy
typename Strategy
>
static inline bool last_covered_by(Turn const& /*turn*/, Operation const& op,
inline bool last_covered_by(Turn const& /*turn*/, Operation const& op,
LineString const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
Strategy const& strategy)
{
return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
}
@@ -74,18 +78,20 @@ template
typename Operation,
typename LineString,
typename Polygon,
typename PtInPolyStrategy
typename Strategy
>
static inline bool is_leaving(Turn const& turn, Operation const& op,
inline bool is_leaving(Turn const& turn, Operation const& op,
bool entered, bool first,
LineString const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
Strategy const& strategy)
{
if (op.operation == operation_union)
{
return entered
|| turn.method == method_crosses
|| (first && last_covered_by(turn, op, linestring, polygon, strategy))
|| (first
&& op.position != position_front
&& last_covered_by(turn, op, linestring, polygon, strategy))
;
}
return false;
@@ -98,12 +104,12 @@ template
typename Operation,
typename LineString,
typename Polygon,
typename PtInPolyStrategy
typename Strategy
>
static inline bool is_staying_inside(Turn const& turn, Operation const& op,
inline bool is_staying_inside(Turn const& turn, Operation const& op,
bool entered, bool first,
LineString const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
Strategy const& strategy)
{
if (turn.method == method_crosses)
{
@@ -126,11 +132,11 @@ template
typename Operation,
typename Linestring,
typename Polygon,
typename PtInPolyStrategy
typename Strategy
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
inline bool was_entered(Turn const& turn, Operation const& op, bool first,
Linestring const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
Strategy const& strategy)
{
if (first && (turn.method == method_collinear || turn.method == method_equal))
{
@@ -139,13 +145,68 @@ static inline bool was_entered(Turn const& turn, Operation const& op, bool first
return false;
}
template
<
typename Turn,
typename Operation
>
inline bool is_touching(Turn const& turn, Operation const& op,
bool entered)
{
return (op.operation == operation_union || op.operation == operation_blocked)
&& (turn.method == method_touch || turn.method == method_touch_interior)
&& !entered
&& !op.is_collinear;
}
template
<
typename GeometryOut,
typename Tag = typename geometry::tag<GeometryOut>::type
>
struct add_isolated_point
{};
template <typename LineStringOut>
struct add_isolated_point<LineStringOut, linestring_tag>
{
template <typename Point, typename OutputIterator>
static inline void apply(Point const& point, OutputIterator& out)
{
LineStringOut isolated_point_ls;
geometry::append(isolated_point_ls, point);
#ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
geometry::append(isolated_point_ls, point);
#endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
*out++ = isolated_point_ls;
}
};
template <typename PointOut>
struct add_isolated_point<PointOut, point_tag>
{
template <typename Point, typename OutputIterator>
static inline void apply(Point const& point, OutputIterator& out)
{
PointOut isolated_point;
geometry::detail::conversion::convert_point_to_point(point, isolated_point);
*out++ = isolated_point;
}
};
// Template specialization structure to call the right actions for the right type
template <overlay_type OverlayType, bool RemoveSpikes = true>
struct action_selector
{
// If you get here the overlay type is not intersection or difference
// BOOST_MPL_ASSERT(false);
BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
"If you get here the overlay type is not intersection or difference.",
std::integral_constant<overlay_type, OverlayType>);
};
// Specialization for intersection, containing the implementation
@@ -173,7 +234,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
{
// On enter, append the intersection point and remember starting point
// TODO: we don't check on spikes for linestrings (?). Consider this.
detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
detail::overlay::append_no_duplicates(current_piece, point, strategy);
segment_id = operation.seg_id;
}
@@ -202,7 +263,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
<
false, RemoveSpikes
>::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
detail::overlay::append_no_duplicates(current_piece, point, strategy);
if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
@@ -213,26 +274,14 @@ struct action_selector<overlay_intersection, RemoveSpikes>
template
<
typename OutputIterator,
typename LineStringOut,
typename LineString,
typename LineStringOrPointOut,
typename Point,
typename Operation
typename OutputIterator
>
static inline void isolated_point(LineStringOut&,
LineString const&,
segment_identifier&,
signed_size_type, Point const& point,
Operation const& , OutputIterator& out)
static inline void isolated_point(Point const& point,
OutputIterator& out)
{
LineStringOut isolated_point_ls;
geometry::append(isolated_point_ls, point);
#ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
geometry::append(isolated_point_ls, point);
#endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
*out++ = isolated_point_ls;
add_isolated_point<LineStringOrPointOut>::apply(point, out);
}
static inline bool is_entered(bool entered)
@@ -301,17 +350,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
template
<
typename OutputIterator,
typename LineStringOut,
typename LineString,
typename LineStringOrPointOut,
typename Point,
typename Operation
typename OutputIterator
>
static inline void isolated_point(LineStringOut&,
LineString const&,
segment_identifier&,
signed_size_type, Point const&,
Operation const&, OutputIterator&)
static inline void isolated_point(Point const&,
OutputIterator const&)
{
}
@@ -327,7 +371,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
};
}
} // namespace following
/*!
\brief Follows a linestring from intersection point to intersection point, outputting which
@@ -336,64 +380,23 @@ struct action_selector<overlay_difference, RemoveSpikes>
*/
template
<
typename LineStringOut,
typename GeometryOut,
typename LineString,
typename Polygon,
overlay_type OverlayType,
bool RemoveSpikes = true
bool RemoveSpikes,
bool FollowIsolatedPoints
>
class follow
{
#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
template <typename Turn>
struct sort_on_segment
{
// In case of turn point at the same location, we want to have continue/blocked LAST
// because that should be followed (intersection) or skipped (difference).
inline int operation_order(Turn const& turn) const
{
operation_type const& operation = turn.operations[0].operation;
switch(operation)
{
case operation_opposite : return 0;
case operation_none : return 0;
case operation_union : return 1;
case operation_intersection : return 2;
case operation_blocked : return 3;
case operation_continue : return 4;
}
return -1;
};
inline bool use_operation(Turn const& left, Turn const& right) const
{
// If they are the same, OK.
return operation_order(left) < operation_order(right);
}
inline bool use_distance(Turn const& left, Turn const& right) const
{
return left.operations[0].fraction == right.operations[0].fraction
? use_operation(left, right)
: left.operations[0].fraction < right.operations[0].fraction
;
}
inline bool operator()(Turn const& left, Turn const& right) const
{
segment_identifier const& sl = left.operations[0].seg_id;
segment_identifier const& sr = right.operations[0].seg_id;
return sl == sr
? use_distance(left, right)
: sl < sr
;
}
};
#endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
typedef geometry::detail::output_geometry_access
<
GeometryOut, linestring_tag, linestring_tag
> linear;
typedef geometry::detail::output_geometry_access
<
GeometryOut, point_tag, linestring_tag
> pointlike;
public :
@@ -419,75 +422,72 @@ public :
OutputIterator out,
Strategy const& strategy)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename boost::range_iterator
<
typename turn_type::container_type
>::type turn_operation_iterator_type;
typedef following::action_selector<OverlayType, 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)
// sort turns by Linear seg_id, then by fraction, then
// for same ring id: x, u, i, c
// for different ring id: c, i, u, x
#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
#else
typedef relate::turns::less<0, relate::turns::less_op_linear_areal_single<0> > turn_less;
typedef relate::turns::less
<
0, relate::turns::less_op_linear_areal_single<0>, Strategy
> turn_less;
std::sort(boost::begin(turns), boost::end(turns), turn_less());
#endif
LineStringOut current_piece;
typename linear::type current_piece;
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
// Iterate through all intersection points (they are ordered along the line)
bool entered = false;
bool first = true;
for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
for (auto const& turn : turns)
{
turn_operation_iterator_type iit = boost::begin(it->operations);
auto const& op = turn.operations[0];
if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
if (following::was_entered(turn, op, first, linestring, polygon, strategy))
{
debug_traverse(*it, *iit, "-> Was entered");
debug_traverse(turn, op, "-> Was entered");
entered = true;
}
if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
if (following::is_staying_inside(turn, op, entered, first, linestring, polygon, strategy))
{
debug_traverse(*it, *iit, "-> Staying inside");
debug_traverse(turn, op, "-> Staying inside");
entered = true;
}
else if (following::is_entering(*it, *iit))
else if (following::is_entering(turn, op))
{
debug_traverse(*it, *iit, "-> Entering");
debug_traverse(turn, op, "-> Entering");
entered = true;
action::enter(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
op.seg_id.segment_index, turn.point, op,
strategy, robust_policy,
out);
linear::get(out));
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
else if (following::is_leaving(turn, op, entered, first, linestring, polygon, strategy))
{
debug_traverse(*it, *iit, "-> Leaving");
debug_traverse(turn, op, "-> Leaving");
entered = false;
action::leave(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
op.seg_id.segment_index, turn.point, op,
strategy, robust_policy,
out);
linear::get(out));
}
else if (BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints)
&& following::is_touching(turn, op, entered))
{
debug_traverse(turn, op, "-> Isolated point");
action::template isolated_point
<
typename pointlike::type
>(turn.point, pointlike::get(out));
}
first = false;
}
@@ -504,10 +504,20 @@ public :
}
// Output the last one, if applicable
if (::boost::size(current_piece) > 1)
std::size_t current_piece_size = ::boost::size(current_piece);
if (current_piece_size > 1)
{
*out++ = current_piece;
*linear::get(out)++ = current_piece;
}
else if (BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints)
&& current_piece_size == 1)
{
action::template isolated_point
<
typename pointlike::type
>(range::front(current_piece), pointlike::get(out));
}
return out;
}

View File

@@ -2,7 +2,7 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2014-2020, 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
@@ -18,7 +18,10 @@
#include <algorithm>
#include <iterator>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/throw_exception.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -34,9 +37,12 @@
#include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
#include <boost/geometry/algorithms/detail/tupled_output.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/util/condition.hpp>
namespace boost { namespace geometry
{
@@ -68,7 +74,7 @@ static inline bool is_entering(Turn const& turn,
template <typename Turn, typename Operation>
static inline bool is_staying_inside(Turn const& turn,
Operation const& operation,
Operation const& operation,
bool entered)
{
if ( !entered )
@@ -161,29 +167,36 @@ static inline bool is_isolated_point(Turn const& turn,
// GeometryOut - linestring or tuple of at least point and linestring
template
<
typename LinestringOut,
typename GeometryOut,
typename Linestring,
typename Linear,
overlay_type OverlayType,
bool FollowIsolatedPoints,
bool FollowContinueTurns
>
class follow_linestring_linear_linestring
class follow_linestring_linear
{
protected:
// allow spikes (false indicates: do not remove spikes)
typedef following::action_selector<OverlayType, false> action;
typedef geometry::detail::output_geometry_access
<
GeometryOut, linestring_tag, linestring_tag
> linear;
typedef geometry::detail::output_geometry_access
<
GeometryOut, point_tag, linestring_tag
> pointlike;
template
<
typename TurnIterator,
typename TurnOperationIterator,
typename LinestringOut,
typename SegmentIdentifier,
typename OutputIterator,
typename SideStrategy
@@ -209,10 +222,12 @@ protected:
entered = true;
if ( enter_count == 0 )
{
action::enter(current_piece, linestring,
action::enter(current_piece,
linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, strategy, robust_policy, oit);
it->point, *op_it, strategy, robust_policy,
linear::get(oit));
}
++enter_count;
}
@@ -224,23 +239,25 @@ protected:
if ( enter_count == 0 )
{
entered = false;
action::leave(current_piece, linestring,
action::leave(current_piece,
linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, strategy, robust_policy, oit);
it->point, *op_it, strategy, robust_policy,
linear::get(oit));
}
}
else if ( FollowIsolatedPoints
else if ( BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints)
&& is_isolated_point(*it, *op_it, entered) )
{
detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
action::isolated_point(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, oit);
action::template isolated_point
<
typename pointlike::type
>(it->point, pointlike::get(oit));
}
else if ( FollowContinueTurns
else if ( BOOST_GEOMETRY_CONDITION(FollowContinueTurns)
&& is_staying_inside(*it, *op_it, entered) )
{
detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
@@ -253,6 +270,7 @@ protected:
template
<
typename SegmentIdentifier,
typename LinestringOut,
typename OutputIterator,
typename SideStrategy
>
@@ -283,7 +301,7 @@ protected:
// Output the last one, if applicable
if (::boost::size(current_piece) > 1)
{
*oit++ = current_piece;
*linear::get(oit)++ = current_piece;
}
return oit;
@@ -300,7 +318,7 @@ public:
// Iterate through all intersection points (they are
// ordered along the each line)
LinestringOut current_piece;
typename linear::type current_piece;
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
bool entered = false;
@@ -309,21 +327,17 @@ public:
for (TurnIterator it = first; it != beyond; ++it)
{
oit = process_turn(it, boost::begin(it->operations),
entered, enter_count,
entered, enter_count,
linestring,
current_piece, current_segment_id,
oit,
strategy);
}
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
if (enter_count != 0)
{
BOOST_THROW_EXCEPTION(inconsistent_turns_exception());
return oit;
}
#else
BOOST_GEOMETRY_ASSERT(enter_count == 0);
#endif
return process_end(entered, linestring,
current_segment_id, current_piece,
@@ -344,8 +358,8 @@ template
bool FollowIsolatedPoints,
bool FollowContinueTurns
>
class follow_multilinestring_linear_linestring
: follow_linestring_linear_linestring
class follow_multilinestring_linear
: follow_linestring_linear
<
LinestringOut,
typename boost::range_value<MultiLinestring>::type,
@@ -358,7 +372,7 @@ class follow_multilinestring_linear_linestring
protected:
typedef typename boost::range_value<MultiLinestring>::type Linestring;
typedef follow_linestring_linear_linestring
typedef follow_linestring_linear
<
LinestringOut, Linestring, Linear,
OverlayType, FollowIsolatedPoints, FollowContinueTurns
@@ -492,11 +506,10 @@ template
overlay_type OverlayType,
bool FollowIsolatedPoints,
bool FollowContinueTurns,
typename TagOut = typename tag<LinestringOut>::type,
typename TagIn1 = typename tag<Geometry1>::type
>
struct follow
: not_implemented<LinestringOut, Geometry1>
: not_implemented<Geometry1>
{};
@@ -514,8 +527,8 @@ struct follow
<
LinestringOut, Linestring, Linear,
OverlayType, FollowIsolatedPoints, FollowContinueTurns,
linestring_tag, linestring_tag
> : follow_linestring_linear_linestring
linestring_tag
> : follow_linestring_linear
<
LinestringOut, Linestring, Linear,
OverlayType, FollowIsolatedPoints, FollowContinueTurns
@@ -536,8 +549,8 @@ struct follow
<
LinestringOut, MultiLinestring, Linear,
OverlayType, FollowIsolatedPoints, FollowContinueTurns,
linestring_tag, multi_linestring_tag
> : follow_multilinestring_linear_linestring
multi_linestring_tag
> : follow_multilinestring_linear
<
LinestringOut, MultiLinestring, Linear,
OverlayType, FollowIsolatedPoints, FollowContinueTurns

View File

@@ -0,0 +1,228 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2021 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_CLUSTERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_CLUSTERS_HPP
#include <algorithm>
#include <map>
#include <vector>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/algorithms/detail/overlay/approximately_equals.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/policies/robustness/rescale_policy_tags.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/util/math.hpp>
#define BOOST_GEOMETRY_USE_RESCALING_IN_GET_CLUSTERS
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
template <typename Tag = no_rescale_policy_tag, bool Integral = false>
struct sweep_equal_policy
{
private:
template <typename T>
static inline T threshold()
{
// Points within some epsilons are considered as equal.
return T(100);
}
public:
// Returns true if point are considered equal (within an epsilon)
template <typename P>
static inline bool equals(P const& p1, P const& p2)
{
using coor_t = typename coordinate_type<P>::type;
return approximately_equals(p1, p2, threshold<coor_t>());
}
template <typename T>
static inline bool exceeds(T value)
{
// This threshold is an arbitrary value
// as long as it is bigger than the used value above
T const limit = T(1) / threshold<T>();
return value > limit;
}
};
template <>
struct sweep_equal_policy<no_rescale_policy_tag, true>
{
template <typename P>
static inline bool equals(P const& p1, P const& p2)
{
return geometry::get<0>(p1) == geometry::get<0>(p2)
&& geometry::get<1>(p1) == geometry::get<1>(p2);
}
template <typename T>
static inline bool exceeds(T value)
{
return value > 0;
}
};
#ifdef BOOST_GEOMETRY_USE_RESCALING_IN_GET_CLUSTERS
template <>
struct sweep_equal_policy<rescale_policy_tag, true>
{
template <typename P>
static inline bool equals(P const& p1, P const& p2)
{
// Neighbouring cells in the "integer grid" are considered as equal
return math::abs(geometry::get<0>(p1) - geometry::get<0>(p2)) <= 1
&& math::abs(geometry::get<1>(p1) - geometry::get<1>(p2)) <= 1;
}
template <typename T>
static inline bool exceeds(T value)
{
return value > 1;
}
};
#endif
template <typename Point>
struct turn_with_point
{
std::size_t turn_index;
Point pnt;
};
template <typename Cluster, typename Point>
struct cluster_with_point
{
Cluster cluster;
Point pnt;
};
// Use a sweep algorithm to detect clusters
template
<
typename Turns,
typename Clusters,
typename RobustPolicy
>
inline void get_clusters(Turns& turns, Clusters& clusters,
RobustPolicy const& robust_policy)
{
using turn_type = typename boost::range_value<Turns>::type;
using cluster_type = typename Clusters::mapped_type;
#ifdef BOOST_GEOMETRY_USE_RESCALING_IN_GET_CLUSTERS
// For now still use robust points for rescaled, otherwise points do not match
using point_type = typename geometry::robust_point_type
<
typename turn_type::point_type,
RobustPolicy
>::type;
#else
using point_type = typename turn_type::point_type;
#endif
sweep_equal_policy
<
typename rescale_policy_type<RobustPolicy>::type,
std::is_integral<typename coordinate_type<point_type>::type>::value
> equal_policy;
std::vector<turn_with_point<point_type>> points;
std::size_t turn_index = 0;
for (auto const& turn : turns)
{
if (! turn.discarded)
{
#ifdef BOOST_GEOMETRY_USE_RESCALING_IN_GET_CLUSTERS
point_type pnt;
geometry::recalculate(pnt, turn.point, robust_policy);
points.push_back({turn_index, pnt});
#else
points.push_back({turn_index, turn.point});
#endif
}
turn_index++;
}
// Sort the points from top to bottom
std::sort(points.begin(), points.end(), [](auto const& e1, auto const& e2)
{
return geometry::get<1>(e1.pnt) > geometry::get<1>(e2.pnt);
});
// The output vector will be sorted from bottom too
std::vector<cluster_with_point<cluster_type, point_type>> clustered_points;
// Compare points with each other. Performance is O(n log(n)) because of the sorting.
for (auto it1 = points.begin(); it1 != points.end(); ++it1)
{
// Inner loop, iterates until it exceeds coordinates in y-direction
for (auto it2 = it1 + 1; it2 != points.end(); ++it2)
{
auto const d = geometry::get<1>(it1->pnt) - geometry::get<1>(it2->pnt);
if (equal_policy.exceeds(d))
{
// Points at this y-coordinate or below cannot be equal
break;
}
if (equal_policy.equals(it1->pnt, it2->pnt))
{
std::size_t cindex = 0;
// Most recent clusters (with this y-value) are at the bottom
// therefore we can stop as soon as the y-value is out of reach (TODO)
bool found = false;
for (auto cit = clustered_points.begin();
cit != clustered_points.end(); ++cit)
{
found = equal_policy.equals(cit->pnt, it1->pnt);
if (found)
{
break;
}
cindex++;
}
// Add new cluster
if (! found)
{
cindex = clustered_points.size();
cluster_type newcluster;
clustered_points.push_back({newcluster, it1->pnt});
}
clustered_points[cindex].cluster.turn_indices.insert(it1->turn_index);
clustered_points[cindex].cluster.turn_indices.insert(it2->turn_index);
}
}
}
// Convert to map
signed_size_type cluster_id = 1;
for (auto& trace : clustered_points)
{
clusters[cluster_id++] = trace.cluster;
}
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_CLUSTERS_HPP

View File

@@ -0,0 +1,152 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2019-2021 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2022.
// Modifications copyright (c) 2022 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_GET_DISTANCE_MEASURE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_DISTANCE_MEASURE_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <cmath>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename T>
struct distance_measure
{
T measure;
distance_measure()
: measure(T())
{}
// Returns true if the distance measure is absolutely zero
bool is_zero() const
{
return ! is_positive() && ! is_negative();
}
// Returns true if the distance measure is positive. Distance measure
// algorithm returns positive value if it is located on the left side.
bool is_positive() const { return measure > T(0); }
// Returns true if the distance measure is negative. Distance measure
// algorithm returns negative value if it is located on the right side.
bool is_negative() const { return measure < T(0); }
};
} // detail
namespace detail_dispatch
{
// TODO: this is effectively a strategy, but for internal usage.
// It might be moved to the strategies folder.
template <typename CalculationType, typename CsTag>
struct get_distance_measure
: not_implemented<CsTag>
{};
template <typename CalculationType>
struct get_distance_measure<CalculationType, spherical_tag>
{
// By default the distance measure is zero, no side difference
using result_type = detail::distance_measure<CalculationType>;
template <typename SegmentPoint, typename Point>
static result_type apply(SegmentPoint const& , SegmentPoint const& ,
Point const& )
{
const result_type result;
return result;
}
};
template <typename CalculationType>
struct get_distance_measure<CalculationType, geographic_tag>
: get_distance_measure<CalculationType, spherical_tag>
{};
template <typename CalculationType>
struct get_distance_measure<CalculationType, cartesian_tag>
{
using result_type = detail::distance_measure<CalculationType>;
template <typename SegmentPoint, typename Point>
static result_type apply(SegmentPoint const& p1, SegmentPoint const& p2,
Point const& p)
{
// Get the distance measure / side value
// It is not a real distance and purpose is
// to detect small differences in collinearity
auto const line = detail::make::make_infinite_line<CalculationType>(p1, p2);
result_type result;
result.measure = arithmetic::side_value(line, p);
return result;
}
};
} // namespace detail_dispatch
namespace detail
{
// Returns a (often very tiny) value to indicate its side, and distance,
// 0 (absolutely 0, not even an epsilon) means collinear. Like side,
// a negative means that p is to the right of p1-p2. And a positive value
// means that p is to the left of p1-p2.
template <typename SegmentPoint, typename Point, typename Strategies>
inline auto get_distance_measure(SegmentPoint const& p1, SegmentPoint const& p2, Point const& p,
Strategies const&)
{
using calc_t = typename select_coordinate_type<SegmentPoint, Point>::type;
// Verify equality, without using a tolerance
// (so don't use equals or equals_point_point)
// because it is about very tiny differences.
auto identical = [](const auto& point1, const auto& point2)
{
return geometry::get<0>(point1) == geometry::get<0>(point2)
&& geometry::get<1>(point1) == geometry::get<1>(point2);
};
if (identical(p1, p) || identical(p2, p))
{
detail::distance_measure<calc_t> const result;
return result;
}
return detail_dispatch::get_distance_measure
<
calc_t,
typename Strategies::cs_tag
>::apply(p1, p2, p);
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_DISTANCE_MEASURE_HPP

View File

@@ -2,8 +2,8 @@
// 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.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -16,17 +16,16 @@
#include <cstddef>
#include <type_traits>
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/policies/robustness/rescale_policy_tags.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
namespace boost { namespace geometry
{
@@ -56,45 +55,25 @@ struct get_turn_without_info
UniqueSubRange2 const& range_q,
TurnInfo const& ,
Strategy const& strategy,
RobustPolicy const& robust_policy,
RobustPolicy const& ,
OutputIterator out)
{
// Make sure this is only called with no rescaling
BOOST_STATIC_ASSERT((std::is_same
<
no_rescale_policy_tag,
typename rescale_policy_type<RobustPolicy>::type
>::value));
typedef typename TurnInfo::point_type turn_point_type;
typedef policies::relate::segments_intersection_points
<
segment_intersection_points
<
turn_point_type,
typename geometry::segment_ratio_type
<
turn_point_type, RobustPolicy
>::type
>
segment_intersection_points<turn_point_type>
> policy_type;
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
Point1 const& pi = range_p.at(0);
Point1 const& pj = range_p.at(1);
Point2 const& qi = range_q.at(0);
Point2 const& qj = range_q.at(1);
segment_type1 p1(pi, pj);
segment_type2 q1(qi, qj);
typedef typename geometry::robust_point_type
<
Point1, RobustPolicy
>::type robust_point_type;
robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
geometry::recalculate(pi_rob, pi, robust_policy);
geometry::recalculate(pj_rob, pj, robust_policy);
geometry::recalculate(qi_rob, qi, robust_policy);
geometry::recalculate(qj_rob, qj, robust_policy);
typename policy_type::return_type result
= strategy.apply(p1, q1, policy_type(), robust_policy,
pi_rob, pj_rob, qi_rob, qj_rob);
typename policy_type::return_type const result
= strategy.relate().apply(range_p, range_q, policy_type());
for (std::size_t i = 0; i < result.count; i++)
{
@@ -138,7 +117,7 @@ inline void get_intersection_points(Geometry1 const& geometry1,
detail::get_turns::no_interrupt_policy interrupt_policy;
boost::mpl::if_c
std::conditional_t
<
reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::get_turns_reversed
@@ -157,12 +136,11 @@ inline void get_intersection_points(Geometry1 const& geometry1,
false, false,
TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
strategy,
robust_policy,
turns, interrupt_policy);
>::apply(0, geometry1,
1, geometry2,
strategy,
robust_policy,
turns, interrupt_policy);
}

View File

@@ -2,6 +2,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020 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,7 +14,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
#include <boost/range.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
@@ -18,6 +23,8 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
@@ -49,8 +56,6 @@ struct get_ring<void>
};
template<>
struct get_ring<ring_tag>
{
@@ -112,6 +117,49 @@ struct get_ring<multi_polygon_tag>
}
};
// Returns the number of segments on a ring (regardless whether the ring is open or closed)
template <typename Geometry>
inline signed_size_type segment_count_on_ring(Geometry const& geometry,
ring_identifier const& ring_id)
{
using tag = typename geometry::tag<Geometry>::type;
// A closed polygon, a triangle of 4 points, including starting point,
// contains 3 segments. So handle as if it is closed, and subtract one.
return geometry::num_points(detail::overlay::get_ring<tag>::apply(ring_id, geometry), true) - 1;
}
// Returns the number of segments on a ring (regardless whether the ring is open or closed)
template <typename Geometry>
inline signed_size_type segment_count_on_ring(Geometry const& geometry,
segment_identifier const& seg_id)
{
return segment_count_on_ring(geometry, ring_identifier(0, seg_id.multi_index, seg_id.ring_index));
}
// Returns the distance between the second and the first segment identifier (second-first)
// It supports circular behavior and for this it is necessary to pass the geometry.
// It will not report negative values
template <typename Geometry>
inline signed_size_type segment_distance(Geometry const& geometry,
segment_identifier const& first, segment_identifier const& second)
{
// It is an internal function, make sure the preconditions are met
BOOST_ASSERT(second.source_index == first.source_index);
BOOST_ASSERT(second.multi_index == first.multi_index);
BOOST_ASSERT(second.ring_index == first.ring_index);
signed_size_type const result = second.segment_index - first.segment_index;
if (second.segment_index >= first.segment_index)
{
return result;
}
// Take wrap into account, counting segments on the ring (passing any of the ids is fine).
// Suppose point_count=10 (10 points, 9 segments), first.seg_id=7, second.seg_id=2,
// then distance=9-7+2=4, being segments 7,8,0,1
return segment_count_on_ring(geometry, first) + result;
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2013, 2014, 2017, 2018.
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2020.
// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -55,7 +55,7 @@ namespace detail { namespace overlay {
// <----|
// |-------> 2 0 0 1 -1 F and i/i x/u
// |-------> 2 0 0 -1 1 F symetric i/i u/x
// |-------> 2 0 0 -1 1 F symmetric i/i u/x
// |------->
//
// |-------> 2 0 0 -1 -1 T i/u u/i
@@ -74,7 +74,7 @@ namespace detail { namespace overlay {
// <-----|
//
// |-----> 1 -1 0 -1 0 F and u/x
// |-----> 1 0 -1 0 -1 F symetric x/u
// |-----> 1 0 -1 0 -1 F symmetric x/u
// |----->
// D0 or D1 != 0
@@ -82,7 +82,7 @@ namespace detail { namespace overlay {
// ^
// |
// + 1 -1 1 -1 1 F and u/x (P is vertical)
// |--------> 1 1 -1 1 -1 F symetric x/u (P is horizontal)
// |--------> 1 1 -1 1 -1 F symmetric x/u (P is horizontal)
// ^
// |
// +
@@ -111,23 +111,27 @@ namespace detail { namespace overlay {
class linear_intersections
{
public:
template <typename Point1, typename Point2, typename IntersectionResult, typename EqPPStrategy>
template
<
typename Point1, typename Point2, typename IntersectionResult,
typename Strategy
>
linear_intersections(Point1 const& pi,
Point2 const& qi,
IntersectionResult const& result,
bool is_p_last, bool is_q_last,
EqPPStrategy const& strategy)
Strategy const& strategy)
{
int arrival_a = result.template get<1>().arrival[0];
int arrival_b = result.template get<1>().arrival[1];
bool same_dirs = result.template get<1>().dir_a == 0
&& result.template get<1>().dir_b == 0;
int arrival_a = result.direction.arrival[0];
int arrival_b = result.direction.arrival[1];
bool same_dirs = result.direction.dir_a == 0
&& result.direction.dir_b == 0;
if ( same_dirs )
{
if ( result.template get<0>().count == 2 )
if ( result.intersection_points.count == 2 )
{
if ( ! result.template get<1>().opposite )
if ( ! result.direction.opposite )
{
ips[0].p_operation = operation_intersection;
ips[0].q_operation = operation_intersection;
@@ -136,10 +140,10 @@ public:
ips[0].is_pi
= equals::equals_point_point(
pi, result.template get<0>().intersections[0], strategy);
pi, result.intersection_points.intersections[0], strategy);
ips[0].is_qi
= equals::equals_point_point(
qi, result.template get<0>().intersections[0], strategy);
qi, result.intersection_points.intersections[0], strategy);
ips[1].is_pj = arrival_a != -1;
ips[1].is_qj = arrival_b != -1;
}
@@ -158,7 +162,7 @@ public:
}
else
{
BOOST_GEOMETRY_ASSERT(result.template get<0>().count == 1);
BOOST_GEOMETRY_ASSERT(result.intersection_points.count == 1);
ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
@@ -197,7 +201,7 @@ public:
BOOST_STATIC_ASSERT(I < 2);
return ips[I];
}
private:
// only if collinear (same_dirs)
@@ -237,7 +241,7 @@ struct get_turn_info_for_endpoint
typename TurnInfo,
typename IntersectionInfo,
typename OutputIterator,
typename EqPPStrategy
typename Strategy
>
static inline bool apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
@@ -245,7 +249,7 @@ struct get_turn_info_for_endpoint
IntersectionInfo const& inters,
method_type /*method*/,
OutputIterator out,
EqPPStrategy const& strategy)
Strategy const& strategy)
{
std::size_t ip_count = inters.i_info().count;
// no intersection points
@@ -283,7 +287,7 @@ struct get_turn_info_for_endpoint
if ( intersections.template get<1>().p_operation == operation_none )
return result_ignore_ip0;
bool append1_last
= analyse_segment_and_assign_ip(range_p, range_q,
intersections.template get<1>(),
@@ -398,8 +402,7 @@ struct get_turn_info_for_endpoint
{
boost::ignore_unused(ip_index, tp_model);
typename IntersectionInfo::side_strategy_type const& sides
= inters.get_side_strategy();
auto const strategy = inters.strategy();
if ( !first2 && !last2 )
{
@@ -409,8 +412,8 @@ struct get_turn_info_for_endpoint
// may this give false positives for INTs?
typename IntersectionResult::point_type const&
inters_pt = inters.i_info().intersections[ip_index];
BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt, strategy));
BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt, strategy));
#endif
if ( ip_i2 )
{
@@ -421,6 +424,7 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
auto const sides = strategy.side();
int const side_pj_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(1));
int const side_pj_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(1));
int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2));
@@ -432,7 +436,7 @@ struct get_turn_info_for_endpoint
if ( operations_both(operations, operation_continue) )
{
if ( op1 != operation_union
if ( op1 != operation_union
|| op2 != operation_union
|| ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
{
@@ -460,8 +464,8 @@ struct get_turn_info_for_endpoint
// may this give false positives for INTs?
typename IntersectionResult::point_type const&
inters_pt = inters.i_info().intersections[ip_index];
BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt, strategy));
BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt, strategy));
#endif
if ( ip_i2 )
{
@@ -472,6 +476,7 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
auto const sides = strategy.side();
int const side_pi_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(0));
int const side_pi_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(0));
int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2));
@@ -539,22 +544,22 @@ struct get_turn_info_for_endpoint
OutputIterator out)
{
TurnInfo tp = tp_model;
//geometry::convert(ip, tp.point);
//tp.method = method;
base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index);
base_turn_handler::assign_point(tp, method, result.intersection_points, ip_index);
tp.operations[0].operation = op0;
tp.operations[1].operation = op1;
tp.operations[0].position = pos0;
tp.operations[1].position = pos1;
if ( result.template get<0>().count > 1 )
if ( result.intersection_points.count > 1 )
{
// NOTE: is_collinear is NOT set for the first endpoint
// for which there is no preceding segment
//BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
//BOOST_GEOMETRY_ASSERT( result.direction.dir_a == 0 && result.direction.dir_b == 0 );
if ( ! is_p_first_ip )
{
tp.operations[0].is_collinear = op0 != operation_intersection
@@ -567,7 +572,7 @@ struct get_turn_info_for_endpoint
|| is_q_spike;
}
}
else //if ( result.template get<0>().count == 1 )
else //if ( result.intersection_points.count == 1 )
{
if ( op0 == operation_blocked && op1 == operation_intersection )
{

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018.
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2020.
// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -18,11 +18,8 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/geometries/segment.hpp> // referring_segment
#include <boost/geometry/policies/relate/direction.hpp>
#include <boost/geometry/policies/relate/intersection_points.hpp>
#include <boost/geometry/policies/relate/tupled.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/relate/intersection_policy.hpp>
#include <boost/geometry/policies/robustness/rescale_policy_tags.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
namespace boost { namespace geometry {
@@ -47,20 +44,18 @@ struct turn_operation_linear
template
<
typename TurnPointCSTag,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename SideStrategy
typename Strategy
>
struct side_calculator
{
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
typedef decltype(std::declval<Strategy>().side()) side_strategy_type;
inline side_calculator(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
SideStrategy const& side_strategy)
: m_side_strategy(side_strategy)
Strategy const& strategy)
: m_side_strategy(strategy.side())
, m_range_p(range_p)
, m_range_q(range_q)
{}
@@ -79,17 +74,16 @@ struct side_calculator
inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); }
inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); }
inline point1_type const& get_pi() const { return m_range_p.at(0); }
inline point1_type const& get_pj() const { return m_range_p.at(1); }
inline point1_type const& get_pk() const { return m_range_p.at(2); }
inline auto const& get_pi() const { return m_range_p.at(0); }
inline auto const& get_pj() const { return m_range_p.at(1); }
inline auto const& get_pk() const { return m_range_p.at(2); }
inline point2_type const& get_qi() const { return m_range_q.at(0); }
inline point2_type const& get_qj() const { return m_range_q.at(1); }
inline point2_type const& get_qk() const { return m_range_q.at(2); }
inline auto const& get_qi() const { return m_range_q.at(0); }
inline auto const& get_qj() const { return m_range_q.at(1); }
inline auto const& get_qk() const { return m_range_q.at(2); }
// Used side-strategy, owned by the calculator,
// created from .get_side_strategy()
SideStrategy m_side_strategy;
// Used side-strategy, owned by the calculator
side_strategy_type m_side_strategy;
// Used ranges - owned by get_turns or (for robust points) by intersection_info_base
UniqueSubRange1 const& m_range_p;
@@ -153,18 +147,20 @@ template
typename UniqueSubRange1, typename UniqueSubRange2,
typename RobustPolicy
>
struct robust_points
struct robust_point_calculator
{
typedef typename geometry::robust_point_type
<
typename UniqueSubRange1::point_type, RobustPolicy
>::type robust_point1_type;
typedef typename geometry::robust_point_type
<
typename UniqueSubRange2::point_type, RobustPolicy
>::type robust_point2_type;
typedef robust_point1_type robust_point2_type;
inline robust_points(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
RobustPolicy const& robust_policy)
inline robust_point_calculator(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
RobustPolicy const& robust_policy)
: m_robust_policy(robust_policy)
, m_range_p(range_p)
, m_range_q(range_q)
@@ -214,139 +210,182 @@ private :
mutable bool m_qk_retrieved;
};
// Default version (empty - specialized below)
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy>
class intersection_info_base
: private robust_points<UniqueSubRange1, UniqueSubRange2, RobustPolicy>
typename TurnPoint, typename UmbrellaStrategy,
typename RobustPolicy,
typename Tag = typename rescale_policy_type<RobustPolicy>::type
>
class intersection_info_base {};
// Version with rescaling, having robust points
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint, typename UmbrellaStrategy,
typename RobustPolicy
>
class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, UmbrellaStrategy, RobustPolicy, rescale_policy_tag>
{
typedef robust_points<UniqueSubRange1, UniqueSubRange2, RobustPolicy> base;
typedef robust_point_calculator
<
UniqueSubRange1, UniqueSubRange2,
RobustPolicy
>
robust_calc_type;
public:
typedef typename base::robust_point1_type robust_point1_type;
typedef typename base::robust_point2_type robust_point2_type;
typedef segment_intersection_points
<
TurnPoint,
geometry::segment_ratio<boost::long_long_type>
> intersection_point_type;
typedef policies::relate::segments_intersection_policy
<
intersection_point_type
> intersection_policy_type;
typedef typename intersection_policy_type::return_type result_type;
typedef typename robust_calc_type::robust_point1_type robust_point1_type;
typedef typename robust_calc_type::robust_point2_type robust_point2_type;
typedef robust_subrange_adapter<robust_point1_type, UniqueSubRange1, RobustPolicy> robust_subrange1;
typedef robust_subrange_adapter<robust_point2_type, UniqueSubRange2, RobustPolicy> robust_subrange2;
typedef typename cs_tag<TurnPoint>::type cs_tag;
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef side_calculator<cs_tag, robust_subrange1, robust_subrange2,
side_strategy_type> side_calculator_type;
typedef side_calculator
<
robust_subrange1, robust_subrange2, UmbrellaStrategy
> side_calculator_type;
typedef side_calculator
<
cs_tag, robust_subrange2, robust_subrange1,
side_strategy_type
robust_subrange2, robust_subrange1, UmbrellaStrategy
> robust_swapped_side_calculator_type;
intersection_info_base(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
IntersectionStrategy const& intersection_strategy,
UmbrellaStrategy const& umbrella_strategy,
RobustPolicy const& robust_policy)
: base(range_p, range_q, robust_policy)
, m_range_p(range_p)
: m_range_p(range_p)
, m_range_q(range_q)
, m_robust_range_p(range_p, base::m_rpi, base::m_rpj, robust_policy)
, m_robust_range_q(range_q, base::m_rqi, base::m_rqj, robust_policy)
, m_side_calc(m_robust_range_p, m_robust_range_q,
intersection_strategy.get_side_strategy())
, m_robust_calc(range_p, range_q, robust_policy)
, m_robust_range_p(range_p, m_robust_calc.m_rpi, m_robust_calc.m_rpj, robust_policy)
, m_robust_range_q(range_q, m_robust_calc.m_rqi, m_robust_calc.m_rqj, robust_policy)
, m_side_calc(m_robust_range_p, m_robust_range_q, umbrella_strategy)
, m_swapped_side_calc(m_robust_range_q, m_robust_range_p, umbrella_strategy)
, m_result(umbrella_strategy.relate().apply(range_p, range_q,
intersection_policy_type(),
m_robust_range_p, m_robust_range_q))
{}
inline typename UniqueSubRange1::point_type const& pi() const { return m_range_p.at(0); }
inline typename UniqueSubRange2::point_type const& qi() const { return m_range_q.at(0); }
inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
inline robust_point1_type const& rpi() const { return base::m_rpi; }
inline robust_point1_type const& rpj() const { return base::m_rpj; }
inline robust_point1_type const& rpk() const { return base::get_rpk(); }
inline robust_point1_type const& rpi() const { return m_robust_calc.m_rpi; }
inline robust_point1_type const& rpj() const { return m_robust_calc.m_rpj; }
inline robust_point1_type const& rpk() const { return m_robust_calc.get_rpk(); }
inline robust_point2_type const& rqi() const { return base::m_rqi; }
inline robust_point2_type const& rqj() const { return base::m_rqj; }
inline robust_point2_type const& rqk() const { return base::get_rqk(); }
inline robust_point2_type const& rqi() const { return m_robust_calc.m_rqi; }
inline robust_point2_type const& rqj() const { return m_robust_calc.m_rqj; }
inline robust_point2_type const& rqk() const { return m_robust_calc.get_rqk(); }
inline side_calculator_type const& sides() const { return m_side_calc; }
robust_swapped_side_calculator_type get_swapped_sides() const
inline robust_swapped_side_calculator_type const& swapped_sides() const
{
robust_swapped_side_calculator_type result(
m_robust_range_q, m_robust_range_p,
m_side_calc.m_side_strategy);
return result;
return m_swapped_side_calc;
}
private :
// Owned by get_turns
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
private :
// Owned by this class
robust_calc_type m_robust_calc;
robust_subrange1 m_robust_range_p;
robust_subrange2 m_robust_range_q;
side_calculator_type m_side_calc;
robust_swapped_side_calculator_type m_swapped_side_calc;
protected :
result_type m_result;
};
// Version without rescaling
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint, typename IntersectionStrategy
typename TurnPoint, typename UmbrellaStrategy,
typename RobustPolicy
>
class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, IntersectionStrategy, detail::no_rescale_policy>
TurnPoint, UmbrellaStrategy, RobustPolicy, no_rescale_policy_tag>
{
public:
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
typedef typename UniqueSubRange1::point_type robust_point1_type;
typedef typename UniqueSubRange2::point_type robust_point2_type;
typedef segment_intersection_points<TurnPoint> intersection_point_type;
typedef policies::relate::segments_intersection_policy
<
intersection_point_type
> intersection_policy_type;
typedef typename cs_tag<TurnPoint>::type cs_tag;
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef side_calculator<cs_tag, UniqueSubRange1, UniqueSubRange2, side_strategy_type> side_calculator_type;
typedef typename intersection_policy_type::return_type result_type;
typedef side_calculator
<
cs_tag, UniqueSubRange2, UniqueSubRange1,
side_strategy_type
UniqueSubRange1, UniqueSubRange2, UmbrellaStrategy
> side_calculator_type;
typedef side_calculator
<
UniqueSubRange2, UniqueSubRange1, UmbrellaStrategy
> swapped_side_calculator_type;
intersection_info_base(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
IntersectionStrategy const& intersection_strategy,
no_rescale_policy const& /*robust_policy*/)
UmbrellaStrategy const& umbrella_strategy,
no_rescale_policy const& )
: m_range_p(range_p)
, m_range_q(range_q)
, m_side_calc(range_p, range_q,
intersection_strategy.get_side_strategy())
, m_side_calc(range_p, range_q, umbrella_strategy)
, m_swapped_side_calc(range_q, range_p, umbrella_strategy)
, m_result(umbrella_strategy.relate()
.apply(range_p, range_q, intersection_policy_type()))
{}
inline point1_type const& rpi() const { return m_side_calc.get_pi(); }
inline point1_type const& rpj() const { return m_side_calc.get_pj(); }
inline point1_type const& rpk() const { return m_side_calc.get_pk(); }
inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
inline point2_type const& rqi() const { return m_side_calc.get_qi(); }
inline point2_type const& rqj() const { return m_side_calc.get_qj(); }
inline point2_type const& rqk() const { return m_side_calc.get_qk(); }
inline auto const& rpi() const { return m_side_calc.get_pi(); }
inline auto const& rpj() const { return m_side_calc.get_pj(); }
inline auto const& rpk() const { return m_side_calc.get_pk(); }
inline auto const& rqi() const { return m_side_calc.get_qi(); }
inline auto const& rqj() const { return m_side_calc.get_qj(); }
inline auto const& rqk() const { return m_side_calc.get_qk(); }
inline side_calculator_type const& sides() const { return m_side_calc; }
swapped_side_calculator_type get_swapped_sides() const
inline swapped_side_calculator_type const& swapped_sides() const
{
swapped_side_calculator_type result(
m_range_q, m_range_p,
m_side_calc.m_side_strategy);
return result;
return m_swapped_side_calc;
}
protected :
private :
// Owned by get_turns
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
private :
// Owned here, passed by .get_side_strategy()
// Owned by this class
side_calculator_type m_side_calc;
swapped_side_calculator_type m_swapped_side_calc;
protected :
result_type m_result;
};
@@ -354,80 +393,43 @@ template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint,
typename IntersectionStrategy,
typename UmbrellaStrategy,
typename RobustPolicy
>
class intersection_info
: public intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, IntersectionStrategy, RobustPolicy>
TurnPoint, UmbrellaStrategy, RobustPolicy>
{
typedef intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, IntersectionStrategy, RobustPolicy> base;
TurnPoint, UmbrellaStrategy, RobustPolicy> base;
public:
typedef segment_intersection_points
<
TurnPoint,
typename geometry::segment_ratio_type
<
TurnPoint, RobustPolicy
>::type
> intersection_point_type;
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
typedef typename UmbrellaStrategy::cs_tag cs_tag;
// NOTE: formerly defined in intersection_strategies
typedef policies::relate::segments_tupled
<
policies::relate::segments_intersection_points
<
intersection_point_type
>,
policies::relate::segments_direction
> intersection_policy_type;
typedef IntersectionStrategy intersection_strategy_type;
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef model::referring_segment<point1_type const> segment_type1;
typedef model::referring_segment<point2_type const> segment_type2;
typedef typename base::side_calculator_type side_calculator_type;
typedef typename intersection_policy_type::return_type result_type;
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
typedef typename base::result_type result_type;
typedef typename result_type::intersection_points_type i_info_type;
typedef typename result_type::direction_type d_info_type;
intersection_info(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
IntersectionStrategy const& intersection_strategy,
UmbrellaStrategy const& umbrella_strategy,
RobustPolicy const& robust_policy)
: base(range_p, range_q,
intersection_strategy, robust_policy)
, m_result(intersection_strategy.apply(
segment_type1(range_p.at(0), range_p.at(1)),
segment_type2(range_q.at(0), range_q.at(1)),
intersection_policy_type(),
robust_policy,
base::rpi(), base::rpj(),
base::rqi(), base::rqj()))
, m_intersection_strategy(intersection_strategy)
: base(range_p, range_q, umbrella_strategy, robust_policy)
, m_umbrella_strategy(umbrella_strategy)
, m_robust_policy(robust_policy)
{}
inline result_type const& result() const { return m_result; }
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
inline side_strategy_type get_side_strategy() const
{
return m_intersection_strategy.get_side_strategy();
}
inline result_type const& result() const { return base::m_result; }
inline i_info_type const& i_info() const { return base::m_result.intersection_points; }
inline d_info_type const& d_info() const { return base::m_result.direction; }
// TODO: it's more like is_spike_ip_p
inline bool is_spike_p() const
{
if (base::m_range_p.is_last_segment())
if (base::p_is_last_segment())
{
return false;
}
@@ -442,7 +444,7 @@ public:
}
// TODO: why is q used to determine spike property in p?
bool const has_qk = ! base::m_range_q.is_last_segment();
bool const has_qk = ! base::q_is_last_segment();
int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0;
int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0;
@@ -452,7 +454,7 @@ public:
{
// qk is collinear with both p1 and p2,
// verify if pk goes backwards w.r.t. pi/pj
return direction_code(base::rpi(), base::rpj(), base::rpk()) == -1;
return direction_code<cs_tag>(base::rpi(), base::rpj(), base::rpk()) == -1;
}
// qk is at opposite side of p1/p2, therefore
@@ -460,13 +462,13 @@ public:
return true;
}
}
return false;
}
inline bool is_spike_q() const
{
if (base::m_range_q.is_last_segment())
if (base::q_is_last_segment())
{
return false;
}
@@ -480,24 +482,29 @@ public:
}
// TODO: why is p used to determine spike property in q?
bool const has_pk = ! base::m_range_p.is_last_segment();
bool const has_pk = ! base::p_is_last_segment();
int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0;
int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0;
if (pk_q1 == -pk_q2)
{
if (pk_q1 == 0)
{
return direction_code(base::rqi(), base::rqj(), base::rqk()) == -1;
return direction_code<cs_tag>(base::rqi(), base::rqj(), base::rqk()) == -1;
}
return true;
}
}
return false;
}
UmbrellaStrategy const& strategy() const
{
return m_umbrella_strategy;
}
private:
template <std::size_t OpId>
bool is_ip_j() const
@@ -522,8 +529,7 @@ private:
}
}
result_type m_result;
IntersectionStrategy const& m_intersection_strategy;
UmbrellaStrategy const& m_umbrella_strategy;
RobustPolicy const& m_robust_policy;
};

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018.
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2020.
// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -44,7 +44,7 @@ struct get_turn_info_linear_areal
typename UniqueSubRange1,
typename UniqueSubRange2,
typename TurnInfo,
typename IntersectionStrategy,
typename UmbrellaStrategy,
typename RobustPolicy,
typename OutputIterator
>
@@ -52,7 +52,7 @@ struct get_turn_info_linear_areal
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo const& tp_model,
IntersectionStrategy const& strategy,
UmbrellaStrategy const& umbrella_strategy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
@@ -60,11 +60,11 @@ struct get_turn_info_linear_areal
<
UniqueSubRange1, UniqueSubRange2,
typename TurnInfo::point_type,
IntersectionStrategy,
UmbrellaStrategy,
RobustPolicy
> inters_info;
inters_info inters(range_p, range_q, strategy, robust_policy);
inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
char const method = inters.d_info().how;
@@ -79,7 +79,7 @@ struct get_turn_info_linear_areal
case 's' : // starts from the middle
get_turn_info_for_endpoint<true, true>(range_p, range_q,
tp_model, inters, method_none, out,
strategy.get_point_in_point_strategy());
umbrella_strategy);
break;
case 'd' : // disjoint: never do anything
@@ -89,30 +89,27 @@ struct get_turn_info_linear_areal
{
if ( get_turn_info_for_endpoint<false, true>(range_p, range_q,
tp_model, inters, method_touch_interior, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
else
{
typedef touch_interior
<
TurnInfo
> policy;
using handler = touch_interior<TurnInfo, verify_policy_la>;
// If Q (1) arrives (1)
if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(range_p, range_q, tp,
handler::template apply<0>(range_p, range_q, tp,
inters.i_info(), inters.d_info(),
inters.sides());
inters.sides(), umbrella_strategy);
}
else
{
// Swap p/q
policy::template apply<1>(range_q, range_p,
handler::template apply<1>(range_q, range_p,
tp, inters.i_info(), inters.d_info(),
inters.get_swapped_sides());
inters.swapped_sides(), umbrella_strategy);
}
if ( tp.operations[1].operation == operation_blocked )
@@ -123,12 +120,12 @@ struct get_turn_info_linear_areal
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
// this function assumes that 'u' must be set for a spike
calculate_spike_operation(tp.operations[0].operation,
inters,
strategy.get_point_in_point_strategy());
umbrella_strategy);
*out++ = tp;
}
}
@@ -147,14 +144,16 @@ struct get_turn_info_linear_areal
// Both touch (both arrive there)
if ( get_turn_info_for_endpoint<false, true>(range_p, range_q,
tp_model, inters, method_touch, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
else
else
{
touch<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
using handler = touch<TurnInfo, verify_policy_la>;
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(),
umbrella_strategy);
if ( tp.operations[1].operation == operation_blocked )
{
@@ -179,7 +178,7 @@ struct get_turn_info_linear_areal
}
else
{
tp.operations[0].operation = operation_union;
tp.operations[0].operation = operation_union;
}
}
}
@@ -220,7 +219,7 @@ struct get_turn_info_linear_areal
bool ignore_spike
= calculate_spike_operation(tp.operations[0].operation,
inters,
strategy.get_point_in_point_strategy());
umbrella_strategy);
if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ignore_spike
@@ -236,7 +235,7 @@ struct get_turn_info_linear_areal
{
if ( get_turn_info_for_endpoint<true, true>(range_p, range_q,
tp_model, inters, method_equal, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
@@ -248,8 +247,10 @@ struct get_turn_info_linear_areal
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
using handler = equal<TurnInfo, verify_policy_la>;
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(),
umbrella_strategy);
turn_transformer_ec<false> transformer(method_touch);
transformer(tp);
@@ -280,7 +281,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<true, true>(
range_p, range_q,
tp_model, inters, method_collinear, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
@@ -296,16 +297,19 @@ struct get_turn_info_linear_areal
if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
using handler = equal<TurnInfo, verify_policy_la>;
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(),
umbrella_strategy);
method_replace = method_touch;
version = append_equal;
}
else
{
collinear<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
using handler = collinear<TurnInfo, verify_policy_la>;
handler::apply(range_p, range_q, tp, inters.i_info(),
inters.d_info(), inters.sides());
//method_replace = method_touch_interior;
//version = append_collinear;
@@ -359,13 +363,13 @@ struct get_turn_info_linear_areal
if ( range_p.is_first_segment()
&& equals::equals_point_point(range_p.at(0), tp.point,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
tp.operations[0].position = position_front;
}
else if ( range_p.is_last_segment()
&& equals::equals_point_point(range_p.at(1), tp.point,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
tp.operations[0].position = position_back;
}
@@ -392,10 +396,10 @@ struct get_turn_info_linear_areal
template <typename Operation,
typename IntersectionInfo,
typename EqPPStrategy>
typename Strategy>
static inline bool calculate_spike_operation(Operation & op,
IntersectionInfo const& inters,
EqPPStrategy const& strategy)
Strategy const& strategy)
{
bool is_p_spike = ( op == operation_union || op == operation_intersection )
&& inters.is_spike_p();
@@ -403,7 +407,7 @@ struct get_turn_info_linear_areal
if ( is_p_spike )
{
int const pk_q1 = inters.sides().pk_wrt_q1();
bool going_in = pk_q1 < 0; // Pk on the right
bool going_out = pk_q1 > 0; // Pk on the left
@@ -411,11 +415,11 @@ struct get_turn_info_linear_areal
// special cases
if ( qk_q1 < 0 ) // Q turning R
{
{
// spike on the edge point
// if it's already known that the spike is going out this musn't be checked
if ( ! going_out
&& detail::equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) )
&& equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) )
{
int const pk_q2 = inters.sides().pk_wrt_q2();
going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both
@@ -427,7 +431,7 @@ struct get_turn_info_linear_areal
// spike on the edge point
// if it's already known that the spike is going in this musn't be checked
if ( ! going_in
&& detail::equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) )
&& equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) )
{
int const pk_q2 = inters.sides().pk_wrt_q2();
going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them
@@ -524,7 +528,7 @@ struct get_turn_info_linear_areal
|| tp.operations[0].operation == operation_intersection ) : // i ???
true )
&& inters.is_spike_p();
// TODO: throw an exception for spike in Areal?
/*bool is_q_spike = ( ( Version == append_touches
&& tp.operations[1].operation == operation_continue )
@@ -671,7 +675,7 @@ struct get_turn_info_linear_areal
// possible to define a spike on an endpoint. Areal geometries must
// NOT have spikes at all. One thing that could be done is to throw
// an exception when spike is detected in Areal geometry.
template <bool EnableFirst,
bool EnableLast,
typename UniqueSubRange1,
@@ -679,7 +683,7 @@ struct get_turn_info_linear_areal
typename TurnInfo,
typename IntersectionInfo,
typename OutputIterator,
typename EqPPStrategy>
typename Strategy>
static inline bool get_turn_info_for_endpoint(
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
@@ -687,7 +691,7 @@ struct get_turn_info_linear_areal
IntersectionInfo const& inters,
method_type /*method*/,
OutputIterator out,
EqPPStrategy const& strategy)
Strategy const& strategy)
{
namespace ov = overlay;
typedef ov::get_turn_info_for_endpoint<EnableFirst, EnableLast> get_info_e;
@@ -705,9 +709,6 @@ struct get_turn_info_linear_areal
return false;
}
typename IntersectionInfo::side_strategy_type const& sides
= inters.get_side_strategy();
linear_intersections intersections(range_p.at(0),
range_q.at(0),
inters.result(),
@@ -738,6 +739,8 @@ struct get_turn_info_linear_areal
}
else
{
auto const sides = strategy.side();
// pi is the intersection point at qj or in the middle of q1
// so consider segments
// 1. pi at qj: qi-qj-pj and qi-qj-qk
@@ -798,7 +801,7 @@ struct get_turn_info_linear_areal
&& ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication
{
TurnInfo tp = tp_model;
if ( inters.i_info().count > 1 )
{
//BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
@@ -807,6 +810,8 @@ struct get_turn_info_linear_areal
}
else //if ( result.template get<0>().count == 1 )
{
auto const sides = strategy.side();
// pj is the intersection point at qj or in the middle of q1
// so consider segments
// 1. pj at qj: qi-qj-pi and qi-qj-qk
@@ -822,7 +827,7 @@ struct get_turn_info_linear_areal
{
side_pi_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(0)); // pi wrt q2
side_pi_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1
side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1
side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1
}
// 2. ip0 or pj in the middle of q1
else
@@ -848,7 +853,7 @@ struct get_turn_info_linear_areal
tp.operations[0].operation = operation_blocked;
tp.operations[0].position = position_back;
tp.operations[1].position = position_middle;
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
unsigned int ip_index = ip_count > 1 ? 1 : 0;
@@ -863,14 +868,6 @@ struct get_turn_info_linear_areal
// don't ignore anything for now
return false;
}
template <typename Point1, typename Point2, typename IntersectionStrategy>
static inline bool equals_point_point(Point1 const& point1, Point2 const& point2,
IntersectionStrategy const& strategy)
{
return detail::equals::equals_point_point(point1, point2,
strategy.get_point_in_point_strategy());
}
};
}} // namespace detail::overlay

View File

@@ -39,7 +39,7 @@ struct get_turn_info_linear_linear
typename UniqueSubRange1,
typename UniqueSubRange2,
typename TurnInfo,
typename IntersectionStrategy,
typename UmbrellaStrategy,
typename RobustPolicy,
typename OutputIterator
>
@@ -47,7 +47,7 @@ struct get_turn_info_linear_linear
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo const& tp_model,
IntersectionStrategy const& strategy,
UmbrellaStrategy const& umbrella_strategy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
@@ -55,11 +55,11 @@ struct get_turn_info_linear_linear
<
UniqueSubRange1, UniqueSubRange2,
typename TurnInfo::point_type,
IntersectionStrategy,
UmbrellaStrategy,
RobustPolicy
> inters_info;
inters_info inters(range_p, range_q, strategy, robust_policy);
inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
char const method = inters.d_info().how;
@@ -75,7 +75,7 @@ struct get_turn_info_linear_linear
get_turn_info_for_endpoint<true, true>
::apply(range_p, range_q,
tp_model, inters, method_none, out,
strategy.get_point_in_point_strategy());
umbrella_strategy);
break;
case 'd' : // disjoint: never do anything
@@ -83,35 +83,34 @@ struct get_turn_info_linear_linear
case 'm' :
{
using handler = touch_interior<TurnInfo, verify_policy_ll>;
if ( get_turn_info_for_endpoint<false, true>
::apply(range_p, range_q,
tp_model, inters, method_touch_interior, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
else
{
typedef touch_interior
<
TurnInfo
> policy;
// If Q (1) arrives (1)
if ( inters.d_info().arrival[1] == 1)
{
policy::template apply<0>(range_p, range_q, tp,
handler::template apply<0>(range_p, range_q, tp,
inters.i_info(), inters.d_info(),
inters.sides());
inters.sides(),
umbrella_strategy);
}
else
{
// Swap p/q
policy::template apply<1>(range_q, range_p, tp,
handler::template apply<1>(range_q, range_p, tp,
inters.i_info(), inters.d_info(),
inters.get_swapped_sides());
inters.swapped_sides(),
umbrella_strategy);
}
if ( tp.operations[0].operation == operation_blocked )
{
tp.operations[1].is_collinear = true;
@@ -124,7 +123,7 @@ struct get_turn_info_linear_linear
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
*out++ = tp;
}
}
@@ -140,18 +139,22 @@ struct get_turn_info_linear_linear
break;
case 't' :
{
using handler = touch<TurnInfo, verify_policy_ll>;
// Both touch (both arrive there)
if ( get_turn_info_for_endpoint<false, true>
::apply(range_p, range_q,
tp_model, inters, method_touch, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
else
else
{
touch<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(),
inters.sides(),
umbrella_strategy);
// workarounds for touch<> not taking spikes into account starts here
// those was discovered empirically
@@ -166,7 +169,7 @@ struct get_turn_info_linear_linear
if ( inters.is_spike_p() && inters.is_spike_q() )
{
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_union;
tp.operations[1].operation = operation_union;
}
else
{
@@ -185,7 +188,7 @@ struct get_turn_info_linear_linear
}
else
{
tp.operations[0].operation = operation_union;
tp.operations[0].operation = operation_union;
}
}
else
@@ -204,7 +207,7 @@ struct get_turn_info_linear_linear
}
else
{
tp.operations[1].operation = operation_union;
tp.operations[1].operation = operation_union;
}
}
else
@@ -220,7 +223,7 @@ struct get_turn_info_linear_linear
&& inters.is_spike_p() )
{
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_union;
tp.operations[1].operation = operation_union;
}
}
else if ( tp.operations[0].operation == operation_none
@@ -271,10 +274,12 @@ struct get_turn_info_linear_linear
break;
case 'e':
{
using handler = equal<TurnInfo, verify_policy_ll>;
if ( get_turn_info_for_endpoint<true, true>
::apply(range_p, range_q,
tp_model, inters, method_equal, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
@@ -287,8 +292,9 @@ struct get_turn_info_linear_linear
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(),
umbrella_strategy);
operation_type spike_op
= ( tp.operations[0].operation != operation_continue
@@ -328,7 +334,7 @@ struct get_turn_info_linear_linear
if ( get_turn_info_for_endpoint<true, true>
::apply(range_p, range_q,
tp_model, inters, method_collinear, out,
strategy.get_point_in_point_strategy()) )
umbrella_strategy) )
{
// do nothing
}
@@ -346,8 +352,11 @@ struct get_turn_info_linear_linear
if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
using handler = equal<TurnInfo, verify_policy_ll>;
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides(),
umbrella_strategy);
method_replace = method_touch;
if ( tp.operations[0].operation != operation_continue
@@ -358,8 +367,10 @@ struct get_turn_info_linear_linear
}
else
{
collinear<TurnInfo>::apply(range_p, range_q,
tp, inters.i_info(), inters.d_info(), inters.sides());
using handler = collinear<TurnInfo, verify_policy_ll>;
handler::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(),
inters.sides());
//method_replace = method_touch_interior;
//spike_op = operation_continue;
@@ -368,7 +379,7 @@ struct get_turn_info_linear_linear
// transform turn
turn_transformer_ec transformer(method_replace);
transformer(tp);
// conditionally handle spikes
if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ! append_collinear_spikes(tp, inters,
@@ -410,29 +421,26 @@ struct get_turn_info_linear_linear
// degenerate points
if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) )
{
typedef typename IntersectionStrategy::point_in_point_strategy_type
equals_strategy_type;
only_convert::apply(tp, inters.i_info());
// if any, only one of those should be true
if ( range_p.is_first_segment()
&& equals::equals_point_point(range_p.at(0), tp.point, equals_strategy_type()) )
&& equals::equals_point_point(range_p.at(0), tp.point, umbrella_strategy) )
{
tp.operations[0].position = position_front;
}
else if ( range_p.is_last_segment()
&& equals::equals_point_point(range_p.at(1), tp.point, equals_strategy_type()) )
&& equals::equals_point_point(range_p.at(1), tp.point, umbrella_strategy) )
{
tp.operations[0].position = position_back;
}
else if ( range_q.is_first_segment()
&& equals::equals_point_point(range_q.at(0), tp.point, equals_strategy_type()) )
&& equals::equals_point_point(range_q.at(0), tp.point, umbrella_strategy) )
{
tp.operations[1].position = position_front;
}
else if ( range_q.is_last_segment()
&& equals::equals_point_point(range_q.at(1), tp.point, equals_strategy_type()) )
&& equals::equals_point_point(range_q.at(1), tp.point, umbrella_strategy) )
{
tp.operations[1].position = position_back;
}
@@ -516,7 +524,7 @@ struct get_turn_info_linear_linear
return true;
}
return false;
}
@@ -559,9 +567,9 @@ struct get_turn_info_linear_linear
{
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = false;
BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1);
base_turn_handler::assign_point(tp, method_touch_interior,
inters.i_info(), 1);
}
@@ -590,7 +598,7 @@ struct get_turn_info_linear_linear
{
tp.operations[0].is_collinear = false;
tp.operations[1].is_collinear = true;
BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0);
base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
@@ -605,7 +613,7 @@ struct get_turn_info_linear_linear
res = true;
}
return res;
}

View File

@@ -1,11 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2016, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// Copyright (c) 2014-2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021 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,15 +15,29 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
#include <array>
#include <cstddef>
#include <map>
#include <boost/array.hpp>
#include <boost/concept_check.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -35,14 +48,8 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
@@ -50,22 +57,11 @@
#include <boost/geometry/strategies/intersection_strategies.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/type_traits.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
# include <sstream>
@@ -108,26 +104,27 @@ template
typename Section,
typename Point,
typename CircularIterator,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy
>
struct unique_sub_range_from_section
{
typedef Point point_type;
using point_type = Point;
unique_sub_range_from_section(Section const& section, signed_size_type index,
CircularIterator circular_iterator,
Point const& previous, Point const& current,
Strategy const& strategy,
RobustPolicy const& robust_policy)
: m_section(section)
, m_index(index)
, m_previous_point(previous)
, m_current_point(current)
, m_circular_iterator(circular_iterator)
, m_point_retrieved(false)
, m_robust_policy(robust_policy)
{
}
: m_section(section)
, m_index(index)
, m_previous_point(previous)
, m_current_point(current)
, m_circular_iterator(circular_iterator)
, m_next_point_retrieved(false)
, m_strategy(strategy)
, m_robust_policy(robust_policy)
{}
inline bool is_first_segment() const
{
@@ -159,19 +156,18 @@ struct unique_sub_range_from_section
private :
inline Point const& get_next_point() const
{
if (! m_point_retrieved)
if (! m_next_point_retrieved)
{
advance_to_non_duplicate_next(m_current_point, m_circular_iterator);
m_point = *m_circular_iterator;
m_point_retrieved = true;
m_next_point_retrieved = true;
}
return m_point;
return *m_circular_iterator;
}
inline void advance_to_non_duplicate_next(Point const& current, CircularIterator& circular_iterator) const
{
typedef typename IntersectionStrategy::point_in_point_strategy_type disjoint_strategy_type;
typedef typename robust_point_type<Point, RobustPolicy>::type robust_point_type;
using box_point_type = typename geometry::point_type<typename Section::box_type>::type;
using robust_point_type = typename robust_point_type<box_point_type, RobustPolicy>::type;
robust_point_type current_robust_point;
robust_point_type next_robust_point;
geometry::recalculate(current_robust_point, current, m_robust_policy);
@@ -187,12 +183,9 @@ private :
// So advance to the "non duplicate next"
// (the check is defensive, to avoid endless loops)
std::size_t check = 0;
while(! detail::disjoint::disjoint_point_point
(
current_robust_point, next_robust_point,
disjoint_strategy_type()
)
&& check++ < m_section.range_count)
while (! detail::disjoint::disjoint_point_point(
current_robust_point, next_robust_point, m_strategy)
&& check++ < m_section.range_count)
{
circular_iterator++;
geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy);
@@ -204,12 +197,11 @@ private :
Point const& m_previous_point;
Point const& m_current_point;
mutable CircularIterator m_circular_iterator;
mutable Point m_point;
mutable bool m_point_retrieved;
mutable bool m_next_point_retrieved;
Strategy m_strategy;
RobustPolicy m_robust_policy;
};
template
<
typename Geometry1, typename Geometry2,
@@ -219,40 +211,24 @@ template
>
class get_turns_in_sections
{
typedef typename closeable_view
using range1_view = detail::closed_clockwise_view
<
typename range_type<Geometry1>::type const,
closure<Geometry1>::value
>::type cview_type1;
typedef typename closeable_view
typename ring_type<Geometry1>::type const,
geometry::closure<Geometry1>::value,
Reverse1 ? counterclockwise : clockwise
>;
using range2_view = detail::closed_clockwise_view
<
typename range_type<Geometry2>::type const,
closure<Geometry2>::value
>::type cview_type2;
typename ring_type<Geometry2>::type const,
geometry::closure<Geometry2>::value,
Reverse2 ? counterclockwise : clockwise
>;
typedef typename reversible_view
<
cview_type1 const,
Reverse1 ? iterate_reverse : iterate_forward
>::type view_type1;
typedef typename reversible_view
<
cview_type2 const,
Reverse2 ? iterate_reverse : iterate_forward
>::type view_type2;
using range1_iterator = typename boost::range_iterator<range1_view const>::type;
using range2_iterator = typename boost::range_iterator<range2_view const>::type;
typedef typename boost::range_iterator
<
view_type1 const
>::type range1_iterator;
typedef typename boost::range_iterator
<
view_type2 const
>::type range2_iterator;
typedef ever_circling_iterator<range1_iterator> circular1_iterator;
typedef ever_circling_iterator<range2_iterator> circular2_iterator;
using circular1_iterator = ever_circling_iterator<range1_iterator>;
using circular2_iterator = ever_circling_iterator<range2_iterator>;
template <typename Geometry, typename Section>
static inline bool adjacent(Section const& section,
@@ -268,15 +244,7 @@ class get_turns_in_sections
boost::ignore_unused(n, index1, index2);
return boost::is_same
<
typename tag_cast
<
typename geometry::tag<Geometry>::type,
areal_tag
>::type,
areal_tag
>::value
return util::is_areal<Geometry>::value
&& index1 == 0
&& index2 >= n - 2
;
@@ -285,29 +253,20 @@ class get_turns_in_sections
public :
// Returns true if terminated, false if interrupted
template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
bool skip_larger, bool skip_adjacent,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
boost::ignore_unused(interrupt_policy);
static bool const areal1 = boost::is_same
<
typename tag_cast<typename tag<Geometry1>::type, areal_tag>::type,
areal_tag
>::type::value;
static bool const areal2 = boost::is_same
<
typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
areal_tag
>::type::value;
static bool const areal1 = util::is_areal<Geometry1>::value;
static bool const areal2 = util::is_areal<Geometry2>::value;
if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
|| (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
@@ -319,10 +278,8 @@ public :
return true;
}
cview_type1 cview1(range_by_section(geometry1, sec1));
cview_type2 cview2(range_by_section(geometry2, sec2));
view_type1 view1(cview1);
view_type2 view2(cview2);
range1_view const view1(range_by_section(geometry1, sec1));
range2_view const view2(range_by_section(geometry2, sec2));
range1_iterator begin_range_1 = boost::begin(view1);
range1_iterator end_range_1 = boost::end(view1);
@@ -342,7 +299,7 @@ public :
// We need a circular iterator because it might run through the closing point.
// One circle is actually enough but this one is just convenient.
ever_circling_iterator<range1_iterator> next1(begin_range_1, end_range_1, it1, true);
circular1_iterator next1(begin_range_1, end_range_1, it1, true);
next1++;
// Walk through section and stop if we exceed the other box
@@ -355,11 +312,11 @@ public :
unique_sub_range_from_section
<
areal1, Section1, point1_type, circular1_iterator,
IntersectionStrategy, RobustPolicy
Strategy, RobustPolicy
> unique_sub_range1(sec1, index1,
circular1_iterator(begin_range_1, end_range_1, next1, true),
*prev1, *it1,
robust_policy);
strategy, robust_policy);
signed_size_type index2 = sec2.begin_index;
signed_size_type ndi2 = sec2.non_duplicate_index;
@@ -368,7 +325,7 @@ public :
get_start_point_iterator(sec2, view2, prev2, it2, end2,
index2, ndi2, dir2, sec1.bounding_box, robust_policy);
ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
circular2_iterator next2(begin_range_2, end_range_2, it2, true);
next2++;
for (prev2 = it2++, next2++;
@@ -408,11 +365,11 @@ public :
unique_sub_range_from_section
<
areal2, Section2, point2_type, circular2_iterator,
IntersectionStrategy, RobustPolicy
Strategy, RobustPolicy
> unique_sub_range2(sec2, index2,
circular2_iterator(begin_range_2, end_range_2, next2),
*prev2, *it2,
robust_policy);
strategy, robust_policy);
typedef typename boost::range_value<Turns>::type turn_info;
@@ -427,7 +384,7 @@ public :
std::size_t const size_before = boost::size(turns);
TurnPolicy::apply(unique_sub_range1, unique_sub_range2,
ti, intersection_strategy, robust_policy,
ti, strategy, robust_policy,
std::back_inserter(turns));
if (InterruptPolicy::enabled)
@@ -449,8 +406,6 @@ public :
private :
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
typedef typename model::referring_segment<point1_type const> segment1_type;
typedef typename model::referring_segment<point2_type const> segment2_type;
// It is NOT possible to have section-iterators here
// because of the logistics of "index" (the section-iterator automatically
@@ -484,7 +439,7 @@ template
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename TurnPolicy,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
@@ -495,20 +450,20 @@ struct section_visitor
Geometry1 const& m_geometry1;
int m_source_id2;
Geometry2 const& m_geometry2;
IntersectionStrategy const& m_intersection_strategy;
Strategy const& m_strategy;
RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
section_visitor(int id1, Geometry1 const& g1,
int id2, Geometry2 const& g2,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& ip)
: m_source_id1(id1), m_geometry1(g1)
, m_source_id2(id2), m_geometry2(g2)
, m_intersection_strategy(intersection_strategy)
, m_strategy(strategy)
, m_rescale_policy(robust_policy)
, m_turns(turns)
, m_interrupt_policy(ip)
@@ -519,7 +474,7 @@ struct section_visitor
{
if (! detail::disjoint::disjoint_box_box(sec1.bounding_box,
sec2.bounding_box,
m_intersection_strategy.get_disjoint_box_box_strategy()))
m_strategy) )
{
// false if interrupted
return get_turns_in_sections
@@ -532,7 +487,7 @@ struct section_visitor
>::apply(m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
false, false,
m_intersection_strategy,
m_strategy,
m_rescale_policy,
m_turns, m_interrupt_policy);
}
@@ -551,11 +506,11 @@ class get_turns_generic
{
public:
template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& geometry1,
int source_id2, Geometry2 const& geometry2,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
@@ -574,17 +529,12 @@ public:
typedef geometry::sections<box_type, 2> sections_type;
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();
typename IntersectionStrategy::expand_strategy_type const
expand_strategy = intersection_strategy.get_expand_strategy();
typedef std::integer_sequence<std::size_t, 0, 1> dimensions;
geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
sec1, envelope_strategy, expand_strategy, 0);
sec1, strategy, 0);
geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
sec2, envelope_strategy, expand_strategy, 1);
sec2, strategy, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
@@ -592,27 +542,17 @@ public:
Geometry1, Geometry2,
Reverse1, Reverse2,
TurnPolicy,
IntersectionStrategy, RobustPolicy,
Strategy, RobustPolicy,
Turns, InterruptPolicy
> visitor(source_id1, geometry1, source_id2, geometry2,
intersection_strategy, robust_policy,
turns, interrupt_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;
strategy, robust_policy, turns, interrupt_policy);
geometry::partition
<
box_type
>::apply(sec1, sec2, visitor,
get_section_box_type(),
overlaps_section_box_type());
detail::section::get_section_box<Strategy>(strategy),
detail::section::overlaps_section_box<Strategy>(strategy));
}
};
@@ -628,24 +568,16 @@ struct get_turns_cs
{
typedef typename geometry::point_type<Range>::type range_point_type;
typedef typename geometry::point_type<Box>::type box_point_type;
typedef boost::array<box_point_type, 4> box_array;
typedef std::array<box_point_type, 4> box_array;
typedef typename closeable_view
using view_type = detail::closed_clockwise_view
<
Range const,
closure<Range>::value
>::type cview_type;
geometry::closure<Range>::value,
ReverseRange ? counterclockwise : clockwise
>;
typedef typename reversible_view
<
cview_type const,
ReverseRange ? iterate_reverse : iterate_forward
>::type view_type;
typedef typename boost::range_iterator
<
view_type const
>::type iterator_type;
using iterator_type = typename boost::range_iterator<view_type const>::type;
struct unique_sub_range_from_box_policy
{
@@ -731,8 +663,7 @@ struct get_turns_cs
box_array box_points;
assign_box_corners_oriented<ReverseBox>(box, box_points);
cview_type cview(range);
view_type view(cview);
view_type const view(range);
// TODO: in this code, possible duplicate points are not yet taken
// into account (not in the iterator, nor in the retrieve policy)
@@ -909,10 +840,8 @@ struct get_turns_polygon_cs
signed_size_type i = 0;
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
auto const& rings = interior_rings(polygon);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
{
intersector_type::apply(
source_id1, *it,
@@ -944,15 +873,8 @@ struct get_turns_multi_polygon_cs
Turns& turns,
InterruptPolicy& interrupt_policy)
{
typedef typename boost::range_iterator
<
Multi const
>::type iterator_type;
signed_size_type i = 0;
for (iterator_type it = boost::begin(multi);
it != boost::end(multi);
++it, ++i)
for (auto it = boost::begin(multi); it != boost::end(multi); ++it, ++i)
{
// Call its single version
get_turns_polygon_cs
@@ -993,24 +915,24 @@ struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear
: overlay::get_turn_info_linear_areal<AssignPolicy>
{};
template <typename Geometry1, typename Geometry2, typename SegmentRatio,
template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio,
typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
struct turn_operation_type
{
typedef overlay::turn_operation<typename point_type<Geometry1>::type, SegmentRatio> type;
using type = overlay::turn_operation<Point, SegmentRatio>;
};
template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, Point, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
{
typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type;
using type = overlay::turn_operation_linear<Point, SegmentRatio>;
};
template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
template <typename Geometry1, typename Geometry2, typename Point, typename SegmentRatio, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, Point, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
{
typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type;
using type = overlay::turn_operation_linear<Point, SegmentRatio>;
};
}} // namespace detail::get_turns
@@ -1114,10 +1036,10 @@ template
>
struct get_turns_reversed
{
template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(int source_id1, Geometry1 const& g1,
int source_id2, Geometry2 const& g2,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
@@ -1129,7 +1051,7 @@ struct get_turns_reversed
Reverse2, Reverse1,
TurnPolicy
>::apply(source_id2, g2, source_id1, g1,
intersection_strategy, robust_policy,
strategy, robust_policy,
turns, interrupt_policy);
}
};
@@ -1160,14 +1082,14 @@ template
typename AssignPolicy,
typename Geometry1,
typename Geometry2,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void get_turns(Geometry1 const& geometry1,
Geometry2 const& geometry2,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
@@ -1177,7 +1099,7 @@ inline void get_turns(Geometry1 const& geometry1,
typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
//typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
boost::mpl::if_c
std::conditional_t
<
reverse_dispatch<Geometry1, Geometry2>::type::value,
dispatch::get_turns_reversed
@@ -1196,11 +1118,11 @@ inline void get_turns(Geometry1 const& geometry1,
Reverse1, Reverse2,
TurnPolicy
>
>::type::apply(0, geometry1,
1, geometry2,
intersection_strategy,
robust_policy,
turns, interrupt_policy);
>::apply(0, geometry1,
1, geometry2,
strategy,
robust_policy,
turns, interrupt_policy);
}
#if defined(_MSC_VER)

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2015 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-2020.
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -21,15 +21,21 @@
#include <vector>
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/colocate_clusters.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_clusters.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.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/sort_by_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/util/condition.hpp>
@@ -47,306 +53,22 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename SegmentRatio>
struct segment_fraction
{
segment_identifier seg_id;
SegmentRatio fraction;
segment_fraction(segment_identifier const& id, SegmentRatio const& fr)
: seg_id(id)
, fraction(fr)
{}
segment_fraction()
{}
bool operator<(segment_fraction<SegmentRatio> const& other) const
{
return seg_id == other.seg_id
? fraction < other.fraction
: seg_id < other.seg_id;
}
};
struct turn_operation_index
{
turn_operation_index(signed_size_type ti = -1,
signed_size_type oi = -1)
: turn_index(ti)
, op_index(oi)
{}
signed_size_type turn_index;
signed_size_type op_index; // only 0,1
};
template <typename Turns>
struct less_by_fraction_and_type
{
inline less_by_fraction_and_type(Turns const& turns)
: m_turns(turns)
{
}
inline bool operator()(turn_operation_index const& left,
turn_operation_index const& right) const
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
turn_type const& left_turn = m_turns[left.turn_index];
turn_type const& right_turn = m_turns[right.turn_index];
turn_operation_type const& left_op
= left_turn.operations[left.op_index];
turn_operation_type const& right_op
= right_turn.operations[right.op_index];
if (! (left_op.fraction == right_op.fraction))
{
return left_op.fraction < right_op.fraction;
}
// Order xx first - used to discard any following colocated turn
bool const left_both_xx = left_turn.both(operation_blocked);
bool const right_both_xx = right_turn.both(operation_blocked);
if (left_both_xx && ! right_both_xx)
{
return true;
}
if (! left_both_xx && right_both_xx)
{
return false;
}
bool const left_both_uu = left_turn.both(operation_union);
bool const right_both_uu = right_turn.both(operation_union);
if (left_both_uu && ! right_both_uu)
{
return true;
}
if (! left_both_uu && right_both_uu)
{
return false;
}
turn_operation_type const& left_other_op
= left_turn.operations[1 - left.op_index];
turn_operation_type const& right_other_op
= right_turn.operations[1 - right.op_index];
// Fraction is the same, now sort on ring id, first outer ring,
// then interior rings
return left_other_op.seg_id < right_other_op.seg_id;
}
private:
Turns const& m_turns;
};
template <typename Operation, typename ClusterPerSegment>
inline signed_size_type get_cluster_id(Operation const& op, ClusterPerSegment const& cluster_per_segment)
{
typedef typename ClusterPerSegment::key_type segment_fraction_type;
segment_fraction_type seg_frac(op.seg_id, op.fraction);
typename ClusterPerSegment::const_iterator it
= cluster_per_segment.find(seg_frac);
if (it == cluster_per_segment.end())
{
return -1;
}
return it->second;
}
template <typename Operation, typename ClusterPerSegment>
inline void add_cluster_id(Operation const& op,
ClusterPerSegment& cluster_per_segment, signed_size_type id)
{
typedef typename ClusterPerSegment::key_type segment_fraction_type;
segment_fraction_type seg_frac(op.seg_id, op.fraction);
cluster_per_segment[seg_frac] = id;
}
template <typename Turn, typename ClusterPerSegment>
inline signed_size_type add_turn_to_cluster(Turn const& turn,
ClusterPerSegment& cluster_per_segment, signed_size_type& cluster_id)
{
signed_size_type cid0 = get_cluster_id(turn.operations[0], cluster_per_segment);
signed_size_type cid1 = get_cluster_id(turn.operations[1], cluster_per_segment);
if (cid0 == -1 && cid1 == -1)
{
// Because of this, first cluster ID will be 1
++cluster_id;
add_cluster_id(turn.operations[0], cluster_per_segment, cluster_id);
add_cluster_id(turn.operations[1], cluster_per_segment, cluster_id);
return cluster_id;
}
else if (cid0 == -1 && cid1 != -1)
{
add_cluster_id(turn.operations[0], cluster_per_segment, cid1);
return cid1;
}
else if (cid0 != -1 && cid1 == -1)
{
add_cluster_id(turn.operations[1], cluster_per_segment, cid0);
return cid0;
}
else if (cid0 == cid1)
{
// Both already added to same cluster, no action
return cid0;
}
// Both operations.seg_id/fraction were already part of any cluster, and
// these clusters are not the same. Merge of two clusters is necessary
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
std::cout << " TODO: merge " << cid0 << " and " << cid1 << std::endl;
#endif
return cid0;
}
template
<
typename Turns,
typename ClusterPerSegment,
typename Operations,
typename Geometry1,
typename Geometry2
>
inline void handle_colocation_cluster(Turns& turns,
signed_size_type& cluster_id,
ClusterPerSegment& cluster_per_segment,
Operations const& operations,
Geometry1 const& /*geometry1*/, Geometry2 const& /*geometry2*/)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
std::vector<turn_operation_index>::const_iterator vit = operations.begin();
turn_operation_index ref_toi = *vit;
signed_size_type ref_id = -1;
for (++vit; vit != operations.end(); ++vit)
{
turn_type& ref_turn = turns[ref_toi.turn_index];
turn_operation_type const& ref_op
= ref_turn.operations[ref_toi.op_index];
turn_operation_index const& toi = *vit;
turn_type& turn = turns[toi.turn_index];
turn_operation_type const& op = turn.operations[toi.op_index];
BOOST_ASSERT(ref_op.seg_id == op.seg_id);
if (ref_op.fraction == op.fraction)
{
turn_operation_type const& other_op = turn.operations[1 - toi.op_index];
if (ref_id == -1)
{
ref_id = add_turn_to_cluster(ref_turn, cluster_per_segment, cluster_id);
}
BOOST_ASSERT(ref_id != -1);
// ref_turn (both operations) are already added to cluster,
// so also "op" is already added to cluster,
// We only need to add other_op
signed_size_type id = get_cluster_id(other_op, cluster_per_segment);
if (id != -1 && id != ref_id)
{
}
else if (id == -1)
{
// Add to same cluster
add_cluster_id(other_op, cluster_per_segment, ref_id);
id = ref_id;
}
}
else
{
// Not on same fraction on this segment
// assign for next
ref_toi = toi;
ref_id = -1;
}
}
}
template
<
typename Turns,
typename Clusters,
typename ClusterPerSegment
>
inline void assign_cluster_to_turns(Turns& turns,
Clusters& clusters,
ClusterPerSegment const& cluster_per_segment)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
typedef typename ClusterPerSegment::key_type segment_fraction_type;
signed_size_type turn_index = 0;
for (typename boost::range_iterator<Turns>::type it = turns.begin();
it != turns.end(); ++it, ++turn_index)
{
turn_type& turn = *it;
if (turn.discarded)
{
// They were processed (to create proper map) but will not be added
// This might leave a cluster with only 1 turn, which will be fixed
// afterwards
continue;
}
for (int i = 0; i < 2; i++)
{
turn_operation_type const& op = turn.operations[i];
segment_fraction_type seg_frac(op.seg_id, op.fraction);
typename ClusterPerSegment::const_iterator cit = cluster_per_segment.find(seg_frac);
if (cit != cluster_per_segment.end())
{
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
if (turn.is_clustered()
&& turn.cluster_id != cit->second)
{
std::cout << " CONFLICT " << std::endl;
}
#endif
turn.cluster_id = cit->second;
clusters[turn.cluster_id].turn_indices.insert(turn_index);
}
}
}
}
// Removes clusters which have only one point left, or are empty.
template <typename Turns, typename Clusters>
inline void remove_clusters(Turns& turns, Clusters& clusters)
{
typename Clusters::iterator it = clusters.begin();
auto it = clusters.begin();
while (it != clusters.end())
{
// Hold iterator and increase. We can erase cit, this keeps the
// iterator valid (cf The standard associative-container erase idiom)
typename Clusters::iterator current_it = it;
auto current_it = it;
++it;
std::set<signed_size_type> const& turn_indices
= current_it->second.turn_indices;
auto const& turn_indices = current_it->second.turn_indices;
if (turn_indices.size() == 1)
{
signed_size_type const turn_index = *turn_indices.begin();
auto const turn_index = *turn_indices.begin();
turns[turn_index].cluster_id = -1;
clusters.erase(current_it);
}
@@ -357,36 +79,35 @@ 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)
for (auto& pair : clusters)
{
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 */)
auto& cinfo = pair.second;
auto& indices = cinfo.turn_indices;
for (auto sit = indices.begin(); sit != indices.end(); /* no increment */)
{
std::set<signed_size_type>::iterator current_it = sit;
auto current_it = sit;
++sit;
signed_size_type const turn_index = *current_it;
auto const turn_index = *current_it;
if (turns[turn_index].discarded)
{
ids.erase(current_it);
indices.erase(current_it);
}
}
}
remove_clusters(turns, clusters);
colocate_clusters(clusters, turns);
}
template <typename Turn, typename IdSet>
inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id)
template <typename Turn, typename IndexSet>
inline void discard_colocated_turn(Turn& turn, IndexSet& indices, signed_size_type index)
{
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);
indices.insert(index);
}
template <bool Reverse>
@@ -446,22 +167,17 @@ template
>
inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
{
typedef std::set<signed_size_type>::const_iterator set_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
std::set<signed_size_type> indices_to_remove;
std::set<signed_size_type> ids_to_remove;
for (typename Clusters::iterator cit = clusters.begin();
cit != clusters.end(); ++cit)
for (auto& pair : clusters)
{
cluster_info& cinfo = cit->second;
std::set<signed_size_type>& ids = cinfo.turn_indices;
cluster_info& cinfo = pair.second;
ids_to_remove.clear();
indices_to_remove.clear();
for (set_iterator it = ids.begin(); it != ids.end(); ++it)
for (auto index : cinfo.turn_indices)
{
turn_type& turn = turns[*it];
auto& turn = turns[index];
segment_identifier const& seg_0 = turn.operations[0].seg_id;
segment_identifier const& seg_1 = turn.operations[1].seg_id;
@@ -472,34 +188,33 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
continue;
}
for (set_iterator int_it = ids.begin(); int_it != ids.end(); ++int_it)
for (auto interior_index : cinfo.turn_indices)
{
if (*it == *int_it)
if (index == interior_index)
{
continue;
}
// Turn with, possibly, an interior ring involved
turn_type& int_turn = turns[*int_it];
segment_identifier const& int_seg_0 = int_turn.operations[0].seg_id;
segment_identifier const& int_seg_1 = int_turn.operations[1].seg_id;
auto& interior_turn = turns[interior_index];
segment_identifier const& int_seg_0 = interior_turn.operations[0].seg_id;
segment_identifier const& int_seg_1 = interior_turn.operations[1].seg_id;
if (is_ie_turn<Reverse0, Reverse1>(seg_0, seg_1, int_seg_0, int_seg_1))
{
discard_ie_turn(int_turn, ids_to_remove, *int_it);
discard_colocated_turn(interior_turn, indices_to_remove, interior_index);
}
if (is_ie_turn<Reverse1, Reverse0>(seg_1, seg_0, int_seg_1, int_seg_0))
{
discard_ie_turn(int_turn, ids_to_remove, *int_it);
discard_colocated_turn(interior_turn, indices_to_remove, interior_index);
}
}
}
// Erase from the ids (which cannot be done above)
for (set_iterator sit = ids_to_remove.begin();
sit != ids_to_remove.end(); ++sit)
// Erase from the indices (which cannot be done above)
for (auto index : indices_to_remove)
{
ids.erase(*sit);
cinfo.turn_indices.erase(index);
}
}
}
@@ -512,19 +227,14 @@ template
>
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)
for (auto const& pair : clusters)
{
cluster_info const& cinfo = cit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
cluster_info const& cinfo = pair.second;
bool both_target = false;
for (set_iterator it = ids.begin(); it != ids.end(); ++it)
for (auto index : cinfo.turn_indices)
{
turn_type const& turn = turns[*it];
auto const& turn = turns[index];
if (turn.both(operation_from_overlay<OverlayType>::value))
{
both_target = true;
@@ -534,14 +244,10 @@ inline void set_colocation(Turns& turns, Clusters const& clusters)
if (both_target)
{
for (set_iterator it = ids.begin(); it != ids.end(); ++it)
for (auto index : cinfo.turn_indices)
{
turn_type& turn = turns[*it];
if (both_target)
{
turn.has_colocated_both = true;
}
auto& turn = turns[index];
turn.has_colocated_both = true;
}
}
}
@@ -559,7 +265,7 @@ inline void check_colocation(bool& has_blocked,
has_blocked = false;
typename Clusters::const_iterator mit = clusters.find(cluster_id);
auto mit = clusters.find(cluster_id);
if (mit == clusters.end())
{
return;
@@ -567,11 +273,9 @@ inline void check_colocation(bool& has_blocked,
cluster_info const& cinfo = mit->second;
for (std::set<signed_size_type>::const_iterator it
= cinfo.turn_indices.begin();
it != cinfo.turn_indices.end(); ++it)
for (auto index : cinfo.turn_indices)
{
turn_type const& turn = turns[*it];
turn_type const& turn = turns[index];
if (turn.any_blocked())
{
has_blocked = true;
@@ -579,6 +283,25 @@ inline void check_colocation(bool& has_blocked,
}
}
template
<
typename Turns,
typename Clusters
>
inline void assign_cluster_ids(Turns& turns, Clusters const& clusters)
{
for (auto& turn : turns)
{
turn.cluster_id = -1;
}
for (auto const& kv : clusters)
{
for (const auto& index : kv.second.turn_indices)
{
turns[index].cluster_id = kv.first;
}
}
}
// Checks colocated turns and flags combinations of uu/other, possibly a
// combination of a ring touching another geometry's interior ring which is
@@ -591,93 +314,28 @@ template
<
bool Reverse1, bool Reverse2,
overlay_type OverlayType,
typename Geometry0,
typename Geometry1,
typename Turns,
typename Clusters,
typename Geometry1,
typename Geometry2
typename RobustPolicy
>
inline bool handle_colocations(Turns& turns, Clusters& clusters,
Geometry1 const& geometry1, Geometry2 const& geometry2)
RobustPolicy const& robust_policy)
{
static const detail::overlay::operation_type target_operation
= detail::overlay::operation_from_overlay<OverlayType>::value;
typedef std::map
<
segment_identifier,
std::vector<turn_operation_index>
> map_type;
// Create and fill map on segment-identifier Map is sorted on seg_id,
// meaning it is sorted on ring_identifier too. This means that exterior
// rings are handled first. If there is a colocation on the exterior ring,
// that information can be used for the interior ring too
map_type map;
get_clusters(turns, clusters, robust_policy);
signed_size_type index = 0;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it, ++index)
{
map[it->operations[0].seg_id].push_back(turn_operation_index(index, 0));
map[it->operations[1].seg_id].push_back(turn_operation_index(index, 1));
}
// Check if there are multiple turns on one or more segments,
// if not then nothing is to be done
bool colocations = 0;
for (typename map_type::const_iterator it = map.begin();
it != map.end();
++it)
{
if (it->second.size() > 1u)
{
colocations = true;
break;
}
}
if (! colocations)
if (clusters.empty())
{
return false;
}
// Sort all vectors, per same segment
less_by_fraction_and_type<Turns> less(turns);
for (typename map_type::iterator it = map.begin();
it != map.end(); ++it)
{
std::sort(it->second.begin(), it->second.end(), less);
}
assign_cluster_ids(turns, clusters);
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::segment_ratio_type segment_ratio_type;
typedef std::map
<
segment_fraction<segment_ratio_type>,
signed_size_type
> cluster_per_segment_type;
cluster_per_segment_type cluster_per_segment;
// Assign to zero, because of pre-increment later the cluster_id
// effectively starts with 1
// (and can later be negated to use uniquely with turn_index)
signed_size_type cluster_id = 0;
for (typename map_type::const_iterator it = map.begin();
it != map.end(); ++it)
{
if (it->second.size() > 1u)
{
handle_colocation_cluster(turns, cluster_id, cluster_per_segment,
it->second, geometry1, geometry2);
}
}
assign_cluster_to_turns(turns, clusters, cluster_per_segment);
// Get colocated information here and not later, to keep information
// Get colocated information here, and not later, to keep information
// on turns which are discarded afterwards
set_colocation<OverlayType>(turns, clusters);
@@ -685,36 +343,26 @@ inline bool handle_colocations(Turns& turns, Clusters& 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<Geometry0>::value>::value != Reverse1,
do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse2
>(turns, clusters);
}
// There might be clusters having only one turn, if the rest is discarded
// This is cleaned up later, after gathering the properties.
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
std::cout << "*** Colocations " << map.size() << std::endl;
for (typename map_type::const_iterator it = map.begin();
it != map.end(); ++it)
for (auto const& kv : map)
{
std::cout << it->first << std::endl;
for (std::vector<turn_operation_index>::const_iterator vit
= it->second.begin(); vit != it->second.end(); ++vit)
std::cout << kv.first << std::endl;
for (auto const& toi : kv.second)
{
turn_operation_index const& toi = *vit;
std::cout << geometry::wkt(turns[toi.turn_index].point)
<< std::boolalpha
<< " discarded=" << turns[toi.turn_index].discarded
<< " 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
<< " // " << operation_char(turns[toi.turn_index].operations[1].operation)
<< " " << turns[toi.turn_index].operations[1].seg_id
<< " " << turns[toi.turn_index].operations[1].fraction
<< std::endl;
detail::debug::debug_print_turn(turns[toi.turn_index]);
std::cout << std::endl;
}
}
#endif // DEBUG
#endif
return true;
}
@@ -733,9 +381,43 @@ struct is_turn_index
return indexed.turn_index == m_index;
}
std::size_t m_index;
signed_size_type m_index;
};
template
<
typename Sbs,
typename Point,
typename Turns,
typename Geometry1,
typename Geometry2
>
inline bool fill_sbs(Sbs& sbs, Point& turn_point,
cluster_info const& cinfo,
Turns const& turns,
Geometry1 const& geometry1, Geometry2 const& geometry2)
{
if (cinfo.turn_indices.empty())
{
return false;
}
bool first = true;
for (auto turn_index : cinfo.turn_indices)
{
auto const& turn = turns[turn_index];
if (first)
{
turn_point = turn.point;
}
for (int i = 0; i < 2; i++)
{
sbs.add(turn, turn.operations[i], turn_index, i, geometry1, geometry2, first);
first = false;
}
}
return true;
}
template
<
@@ -763,36 +445,17 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int>
> sbs_type;
for (typename Clusters::iterator mit = clusters.begin();
mit != clusters.end(); ++mit)
for (auto& pair : clusters)
{
cluster_info& cinfo = mit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
if (ids.empty())
cluster_info& cinfo = pair.second;
sbs_type sbs(strategy);
point_type turn_point; // should be all the same for all turns in cluster
if (! fill_sbs(sbs, turn_point, cinfo, turns, geometry1, geometry2))
{
continue;
}
sbs_type sbs(strategy);
point_type turn_point; // should be all the same for all turns in cluster
bool first = true;
for (std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
{
signed_size_type turn_index = *sit;
turn_type const& turn = turns[turn_index];
if (first)
{
turn_point = turn.point;
}
for (int i = 0; i < 2; i++)
{
turn_operation_type const& op = turn.operations[i];
sbs.add(op, turn_index, i, geometry1, geometry2, first);
first = false;
}
}
sbs.apply(turn_point);
sbs.find_open();
@@ -807,7 +470,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
// polygons
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
const typename sbs_type::rp& ranked = sbs.m_ranked_points[i];
typename sbs_type::rp const& ranked = sbs.m_ranked_points[i];
turn_type& turn = turns[ranked.turn_index];
turn_operation_type& op = turn.operations[ranked.operation_index];
@@ -832,10 +495,10 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
continue;
}
if (OverlayType != overlay_difference
if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_difference)
&& is_self_turn<OverlayType>(turn))
{
// Difference needs the self-turns, TODO: investigate
// TODO: investigate
continue;
}

View File

@@ -1,7 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2019-2022.
// Modifications copyright (c) 2019-2022 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
@@ -10,13 +15,15 @@
#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/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.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/overlay_type.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/within/implementation.hpp>
namespace boost { namespace geometry
{
@@ -28,15 +35,19 @@ namespace detail { namespace overlay
template <overlay_type OverlayType>
struct check_within
{
template <typename Turn, typename Geometry0, typename Geometry1>
template
<
typename Turn, typename Geometry0, typename Geometry1,
typename UmbrellaStrategy
>
static inline
bool apply(Turn const& turn, Geometry0 const& geometry0,
Geometry1 const& geometry1)
Geometry1 const& geometry1, UmbrellaStrategy const& strategy)
{
// Operations 0 and 1 have the same source index in self-turns
return turn.operations[0].seg_id.source_index == 0
? geometry::within(turn.point, geometry1)
: geometry::within(turn.point, geometry0);
? geometry::within(turn.point, geometry1, strategy)
: geometry::within(turn.point, geometry0, strategy);
}
};
@@ -44,24 +55,35 @@ struct check_within
template <>
struct check_within<overlay_difference>
{
template <typename Turn, typename Geometry0, typename Geometry1>
template
<
typename Turn, typename Geometry0, typename Geometry1,
typename UmbrellaStrategy
>
static inline
bool apply(Turn const& turn, Geometry0 const& geometry0,
Geometry1 const& geometry1)
Geometry1 const& geometry1, UmbrellaStrategy const& strategy)
{
// difference = intersection(a, reverse(b))
// therefore we should reverse the meaning of within for geometry1
return turn.operations[0].seg_id.source_index == 0
? ! geometry::covered_by(turn.point, geometry1)
: geometry::within(turn.point, geometry0);
? ! geometry::covered_by(turn.point, geometry1, strategy)
: geometry::within(turn.point, geometry0, strategy);
}
};
struct discard_turns
{
template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1>
template
<
typename Turns, typename Clusters,
typename Geometry0, typename Geometry1,
typename Strategy
>
static inline
void apply(Turns& , Clusters const& , Geometry0 const& , Geometry1 const& )
void apply(Turns& , Clusters const& ,
Geometry0 const& , Geometry1 const& ,
Strategy const& )
{}
};
@@ -72,25 +94,24 @@ struct discard_closed_turns : discard_turns {};
template <>
struct discard_closed_turns<overlay_union, operation_union>
{
template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1>
// Point in Geometry Strategy
template
<
typename Turns, typename Clusters,
typename Geometry0, typename Geometry1,
typename Strategy
>
static inline
void apply(Turns& turns, Clusters const& /*clusters*/,
Geometry0 const& geometry0, Geometry1 const& geometry1)
Geometry0 const& geometry0, Geometry1 const& geometry1,
Strategy const& strategy)
{
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)
for (auto& turn : turns)
{
turn_type& turn = *it;
if (! turn.discarded
&& is_self_turn<overlay_union>(turn)
&& check_within<overlay_union>::apply(turn,
geometry0, geometry1))
&& check_within<overlay_union>::apply(turn, geometry0,
geometry1, strategy))
{
// Turn is in the interior of other geometry
turn.discarded = true;
@@ -109,18 +130,16 @@ private :
bool is_self_cluster(signed_size_type cluster_id,
const Turns& turns, Clusters const& clusters)
{
typename Clusters::const_iterator cit = clusters.find(cluster_id);
auto cit = clusters.find(cluster_id);
if (cit == clusters.end())
{
return false;
}
cluster_info const& cinfo = cit->second;
for (std::set<signed_size_type>::const_iterator it
= cinfo.turn_indices.begin();
it != cinfo.turn_indices.end(); ++it)
for (auto index : cinfo.turn_indices)
{
if (! is_self_turn<OverlayType>(turns[*it]))
if (! is_self_turn<OverlayType>(turns[index]))
{
return false;
}
@@ -130,32 +149,31 @@ private :
}
template <typename Turns, typename Clusters,
typename Geometry0, typename Geometry1>
typename Geometry0, typename Geometry1, typename Strategy>
static inline
void discard_clusters(Turns& turns, Clusters const& clusters,
Geometry0 const& geometry0, Geometry1 const& geometry1)
Geometry0 const& geometry0, Geometry1 const& geometry1,
Strategy const& strategy)
{
for (typename Clusters::const_iterator cit = clusters.begin();
cit != clusters.end(); ++cit)
for (auto const& pair : clusters)
{
signed_size_type const cluster_id = cit->first;
signed_size_type const cluster_id = pair.first;
cluster_info const& cinfo = pair.second;
// If there are only self-turns in the cluster, the cluster should
// be located within the other geometry, for intersection
if (! cit->second.turn_indices.empty()
if (! cinfo.turn_indices.empty()
&& is_self_cluster(cluster_id, turns, clusters))
{
cluster_info const& cinfo = cit->second;
signed_size_type const index = *cinfo.turn_indices.begin();
if (! check_within<OverlayType>::apply(turns[index],
geometry0, geometry1))
signed_size_type const first_index = *cinfo.turn_indices.begin();
if (! check_within<OverlayType>::apply(turns[first_index],
geometry0, geometry1,
strategy))
{
// Discard all turns in cluster
for (std::set<signed_size_type>::const_iterator sit
= cinfo.turn_indices.begin();
sit != cinfo.turn_indices.end(); ++sit)
for (auto index : cinfo.turn_indices)
{
turns[*sit].discarded = true;
turns[index].discarded = true;
}
}
}
@@ -165,27 +183,22 @@ private :
public :
template <typename Turns, typename Clusters,
typename Geometry0, typename Geometry1>
typename Geometry0, typename Geometry1, typename Strategy>
static inline
void apply(Turns& turns, Clusters const& clusters,
Geometry0 const& geometry0, Geometry1 const& geometry1)
Geometry0 const& geometry0, Geometry1 const& geometry1,
Strategy const& strategy)
{
discard_clusters(turns, clusters, geometry0, geometry1);
discard_clusters(turns, clusters, geometry0, geometry1, strategy);
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)
for (auto& turn : turns)
{
turn_type& turn = *it;
// It is a ii self-turn
// Check if it is within the other geometry
if (! turn.discarded
&& is_self_turn<overlay_intersection>(turn)
&& ! check_within<OverlayType>::apply(turn, geometry0, geometry1))
&& ! check_within<OverlayType>::apply(turn, geometry0,
geometry1, strategy))
{
// It is not within another geometry, set it as non startable.
// It still might be traveled (#case_recursive_boxes_70)

View File

@@ -63,7 +63,7 @@ struct intersection_box_box
// Set dimensions of output coordinate
set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
return intersection_box_box<Dimension + 1, DimensionCount>
::apply(box1, box2, robust_policy, box_out, strategy);
}

View File

@@ -26,8 +26,7 @@ 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;
return turn.is_self();
}
};

View File

@@ -2,8 +2,8 @@
// 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.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -20,7 +20,8 @@
#include <set>
#include <vector>
#include <boost/range.hpp>
#include <boost/core/addressof.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
@@ -65,7 +66,7 @@ template
typename Indexed,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename SideStrategy,
typename Strategy,
bool Reverse1, bool Reverse2
>
struct less_by_segment_ratio
@@ -74,7 +75,7 @@ struct less_by_segment_ratio
, Geometry1 const& geometry1
, Geometry2 const& geometry2
, RobustPolicy const& robust_policy
, SideStrategy const& strategy)
, Strategy const& strategy)
: m_turns(turns)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
@@ -89,7 +90,7 @@ private :
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
RobustPolicy const& m_robust_policy;
SideStrategy const& m_strategy;
Strategy const& m_strategy;
typedef typename geometry::point_type<Geometry1>::type point_type;
@@ -114,8 +115,9 @@ private :
*right.other_seg_id,
si, sj);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
int const side_sj_p = m_strategy.apply(pi, pj, sj);
auto side_strategy = m_strategy.side();
int const side_rj_p = side_strategy.apply(pi, pj, rj);
int const side_sj_p = side_strategy.apply(pi, pj, sj);
// Put the one turning left (1; right == -1) as last
if (side_rj_p != side_sj_p)
@@ -123,8 +125,8 @@ private :
return side_rj_p < side_sj_p;
}
int const side_sj_r = m_strategy.apply(ri, rj, sj);
int const side_rj_s = m_strategy.apply(si, sj, rj);
int const side_sj_r = side_strategy.apply(ri, rj, sj);
int const side_rj_s = side_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
@@ -155,10 +157,8 @@ public :
return left.subject->fraction < right.subject->fraction;
}
typedef typename boost::range_value<Turns>::type turn_type;
turn_type const& left_turn = m_turns[left.turn_index];
turn_type const& right_turn = m_turns[right.turn_index];
auto const& left_turn = m_turns[left.turn_index];
auto const& right_turn = m_turns[right.turn_index];
// First check "real" intersection (crosses)
// -> distance zero due to precision, solve it by sorting

View File

@@ -1,13 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
// Copyright (c) 2014-2022, 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
@@ -15,7 +13,8 @@
#include <algorithm>
#include <vector>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -31,7 +30,7 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
namespace boost { namespace geometry
{
@@ -83,9 +82,7 @@ struct linear_linear_no_intersections
static inline OutputIterator apply(MultiLineString const& multilinestring,
OutputIterator oit)
{
for (typename boost::range_iterator<MultiLineString const>::type
it = boost::begin(multilinestring);
it != boost::end(multilinestring); ++it)
for (auto it = boost::begin(multilinestring); it != boost::end(multilinestring); ++it)
{
LineStringOut ls_out;
geometry::convert(*it, ls_out);
@@ -139,6 +136,7 @@ protected:
static bool const include_no_turn = false;
static bool const include_degenerate = EnableDegenerateTurns;
static bool const include_opposite = false;
static bool const include_start_turn = false;
};
@@ -147,13 +145,13 @@ protected:
typename Turns,
typename LinearGeometry1,
typename LinearGeometry2,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy
>
static inline void compute_turns(Turns& turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
IntersectionStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy)
{
turns.clear();
@@ -169,8 +167,7 @@ protected:
LinearGeometry1,
LinearGeometry2,
assign_policy
>,
RobustPolicy
>
>::apply(turns, linear1, linear2, interrupt_policy, strategy, robust_policy);
}
@@ -183,14 +180,14 @@ protected:
typename LinearGeometry1,
typename LinearGeometry2,
typename OutputIterator,
typename IntersectionStrategy
typename Strategy
>
static inline OutputIterator
sort_and_follow_turns(Turns& turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
OutputIterator oit,
IntersectionStrategy const& strategy)
Strategy const& strategy)
{
// remove turns that have no added value
turns::filter_continue_turns
@@ -207,7 +204,7 @@ protected:
turns::remove_duplicate_turns
<
Turns, EnableRemoveDuplicateTurns
>::apply(turns);
>::apply(turns, strategy);
return detail::overlay::following::linear::follow
<
@@ -218,7 +215,7 @@ protected:
FollowIsolatedPoints,
!EnableFilterContinueTurns || OverlayType == overlay_intersection
>::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
oit, strategy.get_side_strategy());
oit, strategy);
}
public:
@@ -237,13 +234,12 @@ public:
Linear1,
Linear2,
detail::get_turns::get_turn_info_type
<
Linear1,
Linear2,
assign_policy
>,
RobustPolicy
>::turn_info turn_info;
<
Linear1,
Linear2,
assign_policy
>
>::template turn_info_type<Strategy, RobustPolicy>::type turn_info;
typedef std::vector<turn_info> turns_container;

View File

@@ -2,6 +2,10 @@
// Copyright (c) 2017-2017 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020 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)
@@ -9,7 +13,8 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/size.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>

View File

@@ -3,9 +3,8 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2020.
// Modifications copyright (c) 2015-2020, 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
@@ -20,9 +19,9 @@
#include <deque>
#include <map>
#include <boost/range.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
@@ -104,10 +103,6 @@ template
>
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::turn_operation_type turn_operation_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
@@ -115,13 +110,8 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C
? operation_intersection
: operation_union;
for (typename boost::range_iterator<Turns const>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
for (auto const& turn : turns)
{
turn_type const& turn = *it;
bool cluster_checked = false;
bool has_blocked = false;
@@ -131,18 +121,9 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C
continue;
}
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(turn.operations);
op_it != boost::end(turn.operations);
++op_it)
for (auto const& op : turn.operations)
{
turn_operation_type const& op = *op_it;
ring_identifier const ring_id
(
op.seg_id.source_index,
op.seg_id.multi_index,
op.seg_id.ring_index
);
ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id);
if (! is_self_turn<OverlayType>(turn)
&& (
@@ -203,20 +184,13 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
Geometry2 const& geometry2,
OutputIterator out, Strategy const& strategy)
{
typedef std::deque
<
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
typedef typename geometry::point_type<Geometry1>::type point_type1;
typedef typename geometry::ring_type<GeometryOut>::type ring_type;
typedef std::deque<ring_type> ring_container_type;
typedef ring_properties
<
point_type1,
typename Strategy::template area_strategy
<
point_type1
>::type::template result_type<point_type1>::type
typename geometry::point_type<ring_type>::type,
typename geometry::area_result<ring_type, Strategy>::type
> properties;
// Silence warning C4127: conditional expression is constant
@@ -245,8 +219,7 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
ring_container_type rings;
assign_parents<OverlayType>(geometry1, geometry2, rings, all_of_one_of_them, strategy);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out,
strategy.template get_area_strategy<point_type1>());
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out, strategy);
}
@@ -287,14 +260,12 @@ struct overlay
typedef detail::overlay::traversal_turn_info
<
point_type,
typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
typename segment_ratio_type<point_type, RobustPolicy>::type
> turn_info;
typedef std::deque<turn_info> turn_container_type;
typedef std::deque
<
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
typedef typename geometry::ring_type<GeometryOut>::type ring_type;
typedef std::deque<ring_type> ring_container_type;
// Define the clusters, mapping cluster_id -> turns
typedef std::map
@@ -312,21 +283,26 @@ std::cout << "get turns" << std::endl;
geometry::get_turns
<
Reverse1, Reverse2,
detail::overlay::assign_null_policy
assign_policy_only_start_turns
>(geometry1, geometry2, strategy, robust_policy, turns, policy);
visitor.visit_turns(1, turns);
#if ! defined(BOOST_GEOMETRY_NO_SELF_TURNS)
if (needs_self_turns<Geometry1>::apply(geometry1))
if (! turns.empty() || OverlayType == overlay_dissolve)
{
self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
strategy, robust_policy, turns, policy, 0);
}
if (needs_self_turns<Geometry2>::apply(geometry2))
{
self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
strategy, robust_policy, turns, policy, 1);
// Calculate self turns if the output contains turns already,
// and if necessary (e.g.: multi-geometry, polygon with interior rings)
if (needs_self_turns<Geometry1>::apply(geometry1))
{
self_get_turn_points::self_turns<Reverse1, assign_policy_only_start_turns>(geometry1,
strategy, robust_policy, turns, policy, 0);
}
if (needs_self_turns<Geometry2>::apply(geometry2))
{
self_get_turn_points::self_turns<Reverse2, assign_policy_only_start_turns>(geometry2,
strategy, robust_policy, turns, policy, 1);
}
}
#endif
@@ -334,14 +310,12 @@ std::cout << "get turns" << std::endl;
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
typename Strategy::side_strategy_type side_strategy = strategy.get_side_strategy();
cluster_type clusters;
std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(turns,
clusters, geometry1, geometry2,
robust_policy,
side_strategy);
geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(
turns, clusters, geometry1, geometry2, robust_policy, strategy);
visitor.visit_turns(2, turns);
@@ -351,8 +325,8 @@ std::cout << "enrich" << std::endl;
std::cout << "traverse" << std::endl;
#endif
// Traverse through intersection/turn points and create rings of them.
// Note that these rings are always in clockwise order, even in CCW polygons,
// and are marked as "to be reversed" below
// These rings are always in clockwise order.
// In CCW polygons they are marked as "to be reversed" below.
ring_container_type rings;
traverse<Reverse1, Reverse2, Geometry1, Geometry2, OverlayType>::apply
(
@@ -368,12 +342,10 @@ std::cout << "traverse" << std::endl;
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
<
point_type,
typename area_strategy_type::template result_type<point_type>::type
typename geometry::area_result<ring_type, Strategy>::type
> properties;
// Select all rings which are NOT touched by any intersection point
@@ -382,15 +354,11 @@ std::cout << "traverse" << std::endl;
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)
for (auto const& ring : rings)
{
selected_ring_properties[id] = properties(*it, area_strategy);
selected_ring_properties[id] = properties(ring, strategy);
selected_ring_properties[id].reversed = ReverseOut;
id.multi_index++;
}
@@ -407,16 +375,19 @@ std::cout << "traverse" << std::endl;
// The result may be too big, so the area is negative. In this case either
// it can be returned or an exception can be thrown.
return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out,
area_strategy,
OverlayType == overlay_union ?
strategy,
#if defined(BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION)
OverlayType == overlay_union ?
add_rings_throw_if_reversed
: add_rings_ignore_unordered
#elif defined(BOOST_GEOMETRY_UNION_RETURN_INVALID)
OverlayType == overlay_union ?
add_rings_add_unordered
: add_rings_ignore_unordered
#else
add_rings_ignore_unordered
#endif
: add_rings_ignore_unordered);
);
}
template <typename RobustPolicy, typename OutputIterator, typename Strategy>

View File

@@ -0,0 +1,330 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2020, Oracle and/or its affiliates.
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_AREAL_HPP
#include <vector>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/not.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/point.hpp>
// TEMP
#include <boost/geometry/strategies/envelope/cartesian.hpp>
#include <boost/geometry/strategies/envelope/geographic.hpp>
#include <boost/geometry/strategies/envelope/spherical.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
// difference/intersection of multipoint-multipolygon
template
<
typename MultiPoint,
typename MultiPolygon,
typename PointOut,
overlay_type OverlayType,
typename Policy
>
class multipoint_multipolygon_point
{
private:
template <typename Strategy>
struct expand_box_point
{
explicit expand_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
inline void apply(Box& total, Point const& point) const
{
geometry::expand(total, point, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct expand_box_boxpair
{
explicit expand_box_boxpair(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box1, typename Box2, typename SizeT>
inline void apply(Box1& total, std::pair<Box2, SizeT> const& box_pair) const
{
geometry::expand(total, box_pair.first, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_point
{
explicit overlaps_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
inline bool apply(Box const& box, Point const& point) const
{
return ! geometry::disjoint(point, box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_boxpair
{
explicit overlaps_box_boxpair(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box1, typename Box2, typename SizeT>
inline bool apply(Box1 const& box, std::pair<Box2, SizeT> const& box_pair) const
{
return ! geometry::disjoint(box, box_pair.first, m_strategy);
}
Strategy const& m_strategy;
};
template <typename OutputIterator, typename Strategy>
class item_visitor_type
{
public:
item_visitor_type(MultiPolygon const& multipolygon,
OutputIterator& oit,
Strategy const& strategy)
: m_multipolygon(multipolygon)
, m_oit(oit)
, m_strategy(strategy)
{}
template <typename Point, typename Box, typename SizeT>
inline bool apply(Point const& item1, std::pair<Box, SizeT> const& item2)
{
action_selector_pl
<
PointOut, overlay_intersection
>::apply(item1,
Policy::apply(item1,
range::at(m_multipolygon,
item2.second),
m_strategy),
m_oit);
return true;
}
private:
MultiPolygon const& m_multipolygon;
OutputIterator& m_oit;
Strategy const& m_strategy;
};
template <typename Iterator, typename Box, typename SizeT, typename Strategy>
static inline void fill_box_pairs(Iterator first, Iterator last,
std::vector<std::pair<Box, SizeT> > & box_pairs,
Strategy const& strategy)
{
SizeT index = 0;
for (; first != last; ++first, ++index)
{
box_pairs.push_back(
std::make_pair(geometry::return_envelope<Box>(*first, strategy),
index));
}
}
template <typename OutputIterator, typename Strategy>
static inline OutputIterator get_common_points(MultiPoint const& multipoint,
MultiPolygon const& multipolygon,
OutputIterator oit,
Strategy const& strategy)
{
item_visitor_type<OutputIterator, Strategy> item_visitor(multipolygon, oit, strategy);
typedef geometry::model::point
<
typename geometry::coordinate_type<MultiPoint>::type,
geometry::dimension<MultiPoint>::value,
typename geometry::coordinate_system<MultiPoint>::type
> point_type;
typedef geometry::model::box<point_type> box_type;
typedef std::pair<box_type, std::size_t> box_pair;
std::vector<box_pair> box_pairs;
box_pairs.reserve(boost::size(multipolygon));
fill_box_pairs(boost::begin(multipolygon),
boost::end(multipolygon),
box_pairs, strategy);
geometry::partition
<
box_type
>::apply(multipoint, box_pairs, item_visitor,
expand_box_point<Strategy>(strategy),
overlaps_box_point<Strategy>(strategy),
expand_box_boxpair<Strategy>(strategy),
overlaps_box_boxpair<Strategy>(strategy));
return oit;
}
public:
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(MultiPoint const& multipoint,
MultiPolygon const& multipolygon,
RobustPolicy const& robust_policy,
OutputIterator oit,
Strategy const& strategy)
{
typedef std::vector
<
typename boost::range_value<MultiPoint>::type
> point_vector_type;
point_vector_type common_points;
// compute the common points
get_common_points(multipoint, multipolygon,
std::back_inserter(common_points),
strategy);
return multipoint_multipoint_point
<
MultiPoint, point_vector_type, PointOut, OverlayType
>::apply(multipoint, common_points, robust_policy, oit, strategy);
}
};
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DISPATCH
namespace detail_dispatch { namespace overlay
{
// dispatch struct for pointlike-areal difference/intersection computation
template
<
typename PointLike,
typename Areal,
typename PointOut,
overlay_type OverlayType,
typename Tag1,
typename Tag2
>
struct pointlike_areal_point
: not_implemented<PointLike, Areal, PointOut>
{};
template
<
typename Point,
typename Areal,
typename PointOut,
overlay_type OverlayType,
typename Tag2
>
struct pointlike_areal_point
<
Point, Areal, PointOut, OverlayType, point_tag, Tag2
> : detail::overlay::point_single_point
<
Point, Areal, PointOut, OverlayType,
detail::not_<detail::disjoint::reverse_covered_by>
>
{};
// TODO: Consider implementing Areal-specific version
// calculating envelope first in order to reject Points without
// calling disjoint for Rings and Polygons
template
<
typename MultiPoint,
typename Areal,
typename PointOut,
overlay_type OverlayType,
typename Tag2
>
struct pointlike_areal_point
<
MultiPoint, Areal, PointOut, OverlayType, multi_point_tag, Tag2
> : detail::overlay::multipoint_single_point
<
MultiPoint, Areal, PointOut, OverlayType,
detail::not_<detail::disjoint::reverse_covered_by>
>
{};
template
<
typename MultiPoint,
typename MultiPolygon,
typename PointOut,
overlay_type OverlayType
>
struct pointlike_areal_point
<
MultiPoint, MultiPolygon, PointOut, OverlayType, multi_point_tag, multi_polygon_tag
> : detail::overlay::multipoint_multipolygon_point
<
MultiPoint, MultiPolygon, PointOut, OverlayType,
detail::not_<detail::disjoint::reverse_covered_by>
>
{};
}} // namespace detail_dispatch::overlay
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_AREAL_HPP

View File

@@ -2,7 +2,7 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Copyright (c) 2015-2020, 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
@@ -17,13 +17,9 @@
#include <iterator>
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
@@ -37,6 +33,17 @@
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
// TEMP
#include <boost/geometry/strategies/envelope/cartesian.hpp>
#include <boost/geometry/strategies/envelope/geographic.hpp>
#include <boost/geometry/strategies/envelope/spherical.hpp>
namespace boost { namespace geometry
{
@@ -47,36 +54,28 @@ namespace detail { namespace overlay
{
// action struct for pointlike-linear difference/intersection
// it works the same as its pointlike-pointlike counterpart, hence the
// derivation
template <typename PointOut, overlay_type OverlayType>
struct action_selector_pl_l
: action_selector_pl_pl<PointOut, OverlayType>
{};
// difference/intersection of point-linear
template
<
typename Point,
typename Linear,
typename Geometry,
typename PointOut,
overlay_type OverlayType,
typename Policy
>
struct point_linear_point
struct point_single_point
{
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Point const& point,
Linear const& linear,
Geometry const& geometry,
RobustPolicy const&,
OutputIterator oit,
Strategy const& strategy)
{
action_selector_pl_l
action_selector_pl
<
PointOut, OverlayType
>::apply(point, Policy::apply(point, linear, strategy), oit);
>::apply(point, Policy::apply(point, geometry, strategy), oit);
return oit;
}
};
@@ -85,29 +84,26 @@ struct point_linear_point
template
<
typename MultiPoint,
typename Segment,
typename Geometry,
typename PointOut,
overlay_type OverlayType,
typename Policy
>
struct multipoint_segment_point
struct multipoint_single_point
{
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(MultiPoint const& multipoint,
Segment const& segment,
Geometry const& geometry,
RobustPolicy const&,
OutputIterator oit,
Strategy const& strategy)
{
for (typename boost::range_iterator<MultiPoint const>::type
it = boost::begin(multipoint);
it != boost::end(multipoint);
++it)
for (auto it = boost::begin(multipoint); it != boost::end(multipoint); ++it)
{
action_selector_pl_l
action_selector_pl
<
PointOut, OverlayType
>::apply(*it, Policy::apply(*it, segment, strategy), oit);
>::apply(*it, Policy::apply(*it, geometry, strategy), oit);
}
return oit;
@@ -128,19 +124,26 @@ class multipoint_linear_point
{
private:
// structs for partition -- start
template <typename Strategy>
struct expand_box_point
{
expand_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
static inline void apply(Box& total, Point const& point)
inline void apply(Box& total, Point const& point) const
{
geometry::expand(total, point);
geometry::expand(total, point, m_strategy);
}
Strategy const& m_strategy;
};
template <typename EnvelopeStrategy>
template <typename Strategy>
struct expand_box_segment
{
explicit expand_box_segment(EnvelopeStrategy const& strategy)
explicit expand_box_segment(Strategy const& strategy)
: m_strategy(strategy)
{}
@@ -148,25 +151,33 @@ private:
inline void apply(Box& total, Segment const& segment) const
{
geometry::expand(total,
geometry::return_envelope<Box>(segment, m_strategy));
geometry::return_envelope<Box>(segment, m_strategy),
m_strategy);
}
EnvelopeStrategy const& m_strategy;
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_point
{
explicit overlaps_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
static inline bool apply(Box const& box, Point const& point)
inline bool apply(Box const& box, Point const& point) const
{
return ! geometry::disjoint(point, box);
return ! geometry::disjoint(point, box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename DisjointStrategy>
template <typename Strategy>
struct overlaps_box_segment
{
explicit overlaps_box_segment(DisjointStrategy const& strategy)
explicit overlaps_box_segment(Strategy const& strategy)
: m_strategy(strategy)
{}
@@ -176,7 +187,7 @@ private:
return ! geometry::disjoint(segment, box, m_strategy);
}
DisjointStrategy const& m_strategy;
Strategy const& m_strategy;
};
template <typename OutputIterator, typename Strategy>
@@ -191,7 +202,7 @@ private:
template <typename Item1, typename Item2>
inline bool apply(Item1 const& item1, Item2 const& item2)
{
action_selector_pl_l
action_selector_pl
<
PointOut, overlay_intersection
>::apply(item1, Policy::apply(item1, item2, m_strategy), m_oit);
@@ -211,7 +222,7 @@ private:
typedef geometry::segment_iterator<Linear const> const_iterator;
typedef const_iterator iterator;
segment_range(Linear const& linear)
explicit segment_range(Linear const& linear)
: m_linear(linear)
{}
@@ -237,9 +248,6 @@ private:
{
item_visitor_type<OutputIterator, Strategy> item_visitor(oit, 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.
@@ -252,10 +260,10 @@ private:
typename boost::range_value<MultiPoint>::type
>
>::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()));
expand_box_point<Strategy>(strategy),
overlaps_box_point<Strategy>(strategy),
expand_box_segment<Strategy>(strategy),
overlaps_box_segment<Strategy>(strategy));
return oit;
}
@@ -321,7 +329,7 @@ template
struct pointlike_linear_point
<
Point, Linear, PointOut, OverlayType, point_tag, linear_tag
> : detail::overlay::point_linear_point
> : detail::overlay::point_single_point
<
Point, Linear, PointOut, OverlayType,
detail::not_<detail::disjoint::reverse_covered_by>
@@ -339,7 +347,7 @@ template
struct pointlike_linear_point
<
Point, Segment, PointOut, OverlayType, point_tag, segment_tag
> : detail::overlay::point_linear_point
> : detail::overlay::point_single_point
<
Point, Segment, PointOut, OverlayType,
detail::not_<detail::disjoint::reverse_covered_by>
@@ -375,7 +383,7 @@ template
struct pointlike_linear_point
<
MultiPoint, Segment, PointOut, OverlayType, multi_point_tag, segment_tag
> : detail::overlay::multipoint_segment_point
> : detail::overlay::multipoint_single_point
<
MultiPoint, Segment, PointOut, OverlayType,
detail::not_<detail::disjoint::reverse_covered_by>

View File

@@ -1,7 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2023, Oracle and/or its affiliates.
// 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
@@ -15,12 +18,10 @@
#include <algorithm>
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
@@ -28,8 +29,15 @@
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/util/condition.hpp>
namespace boost { namespace geometry
{
@@ -72,9 +80,7 @@ struct copy_points<PointOut, MultiPointIn, multi_point_tag>
static inline void apply(MultiPointIn const& multi_point_in,
OutputIterator& oit)
{
for (typename boost::range_iterator<MultiPointIn const>::type
it = boost::begin(multi_point_in);
it != boost::end(multi_point_in); ++it)
for (auto it = boost::begin(multi_point_in); it != boost::end(multi_point_in); ++it)
{
PointOut point_out;
geometry::convert(*it, point_out);
@@ -87,11 +93,11 @@ struct copy_points<PointOut, MultiPointIn, multi_point_tag>
// action struct for difference/intersection
template <typename PointOut, overlay_type OverlayType>
struct action_selector_pl_pl
struct action_selector_pl
{};
template <typename PointOut>
struct action_selector_pl_pl<PointOut, overlay_intersection>
struct action_selector_pl<PointOut, overlay_intersection>
{
template
<
@@ -112,7 +118,7 @@ struct action_selector_pl_pl<PointOut, overlay_intersection>
template <typename PointOut>
struct action_selector_pl_pl<PointOut, overlay_difference>
struct action_selector_pl<PointOut, overlay_difference>
{
template
<
@@ -150,7 +156,7 @@ struct point_point_point
OutputIterator oit,
Strategy const& strategy)
{
action_selector_pl_pl
action_selector_pl
<
PointOut, OverlayType
>::apply(point1,
@@ -186,11 +192,9 @@ struct multipoint_point_point
{
BOOST_GEOMETRY_ASSERT( OverlayType == overlay_difference );
for (typename boost::range_iterator<MultiPoint const>::type
it = boost::begin(multipoint);
it != boost::end(multipoint); ++it)
for (auto it = boost::begin(multipoint); it != boost::end(multipoint); ++it)
{
action_selector_pl_pl
action_selector_pl
<
PointOut, OverlayType
>::apply(*it,
@@ -220,11 +224,9 @@ struct point_multipoint_point
OutputIterator oit,
Strategy const& strategy)
{
typedef action_selector_pl_pl<PointOut, OverlayType> action;
typedef action_selector_pl<PointOut, OverlayType> action;
for (typename boost::range_iterator<MultiPoint const>::type
it = boost::begin(multipoint);
it != boost::end(multipoint); ++it)
for (auto it = boost::begin(multipoint); it != boost::end(multipoint); ++it)
{
if ( detail::equals::equals_point_point(*it, point, strategy) )
{
@@ -257,8 +259,10 @@ struct multipoint_multipoint_point
OutputIterator oit,
Strategy const& strategy)
{
if ( OverlayType != overlay_difference
&& boost::size(multipoint1) > boost::size(multipoint2) )
typedef geometry::less<void, -1, Strategy> less_type;
if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_difference)
&& boost::size(multipoint1) > boost::size(multipoint2))
{
return multipoint_multipoint_point
<
@@ -271,17 +275,15 @@ struct multipoint_multipoint_point
std::vector<point2_type> points2(boost::begin(multipoint2),
boost::end(multipoint2));
geometry::less<> const less = geometry::less<>();
less_type const less = less_type();
std::sort(points2.begin(), points2.end(), less);
for (typename boost::range_iterator<MultiPoint1 const>::type
it1 = boost::begin(multipoint1);
it1 != boost::end(multipoint1); ++it1)
for (auto it1 = boost::begin(multipoint1); it1 != boost::end(multipoint1); ++it1)
{
bool found = std::binary_search(points2.begin(), points2.end(),
*it1, less);
action_selector_pl_pl
action_selector_pl
<
PointOut, OverlayType
>::apply(*it1, found, oit);

View File

@@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2017 Oracle and/or its affiliates.
// Copyright (c) 2017-2022 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,
@@ -12,13 +12,11 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.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
{
@@ -100,9 +98,9 @@ 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&)
Strategy const& strategy)
{
return geometry::covered_by(point, box) ? 1 : -1;
return geometry::covered_by(point, box, strategy) ? 1 : -1;
}
};
@@ -128,15 +126,9 @@ static inline int range_in_geometry(Geometry1 const& geometry1,
++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);
result = point_in_geometry_helper<Geometry2>::apply(*it, geometry2, strategy);
if (result != 0)
{
return result;
@@ -155,15 +147,14 @@ inline int range_in_geometry(Point1 const& first_point1,
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>());
int result = point_in_geometry_helper<Geometry2>::apply(first_point1, geometry2, strategy);
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;
}

View File

@@ -2,8 +2,8 @@
// 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.
// This file was modified by Oracle on 2017-2022.
// Modifications copyright (c) 2017-2022 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,
@@ -15,8 +15,8 @@
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/within/implementation.hpp>
namespace boost { namespace geometry
@@ -56,8 +56,8 @@ struct ring_properties
, parent_area(-1)
{}
template <typename RingOrBox, typename AreaStrategy>
inline ring_properties(RingOrBox const& ring_or_box, AreaStrategy const& strategy)
template <typename RingOrBox, typename Strategy>
inline ring_properties(RingOrBox const& ring_or_box, Strategy const& strategy)
: reversed(false)
, discarded(false)
, parent_area(-1)

View File

@@ -0,0 +1,59 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2019-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_OVERLAY_SEGMENT_AS_SUBRANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP
#include <cstddef>
#include <map>
#include <boost/geometry/core/access.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Segment>
struct segment_as_subrange
{
segment_as_subrange(Segment const& s)
: m_segment(s)
{
geometry::set<0>(m_p1, geometry::get<0, 0>(m_segment));
geometry::set<1>(m_p1, geometry::get<0, 1>(m_segment));
geometry::set<0>(m_p2, geometry::get<1, 0>(m_segment));
geometry::set<1>(m_p2, geometry::get<1, 1>(m_segment));
}
typedef typename geometry::point_type<Segment>::type point_type;
point_type const& at(std::size_t index) const
{
return index == 0 ? m_p1 : m_p2;
}
static inline bool is_last_segment()
{
return true;
}
point_type m_p1, m_p2;
Segment const& m_segment;
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP

View File

@@ -20,17 +20,18 @@
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
namespace boost { namespace geometry
{
// Internal struct to uniquely identify a segment
// on a linestring,ring
// or polygon (needs ring_index)
// or multi-geometry (needs multi_index)
// It is always used for clockwise indication (even if the original is anticlockwise)
struct segment_identifier
{
inline segment_identifier()
@@ -95,7 +96,18 @@ struct segment_identifier
signed_size_type piece_index;
};
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
// Create a ring identifier from a segment identifier
inline ring_identifier ring_id_by_seg_id(segment_identifier const& seg_id)
{
return ring_identifier(seg_id.source_index, seg_id.multi_index, seg_id.ring_index);
}
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry

View File

@@ -3,8 +3,8 @@
// 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.
// This file was modified by Oracle on 2017-2022.
// Modifications copyright (c) 2017-2022 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,
@@ -17,16 +17,17 @@
#include <map>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/geometry/core/tags.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/covered_by/implementation.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>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
namespace boost { namespace geometry
@@ -60,18 +61,18 @@ namespace dispatch
template <typename Box>
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
template <typename Geometry, typename RingPropertyMap, typename Strategy>
static inline void apply(Box const& box, Geometry const& ,
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy const& strategy)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
template <typename RingPropertyMap, typename AreaStrategy>
template <typename RingPropertyMap, typename Strategy>
static inline void apply(Box const& box,
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy const& strategy)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
@@ -80,10 +81,10 @@ namespace dispatch
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
template <typename Geometry, typename RingPropertyMap, typename Strategy>
static inline void apply(Ring const& ring, Geometry const& ,
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy const& strategy)
{
if (boost::size(ring) > 0)
{
@@ -91,10 +92,10 @@ namespace dispatch
}
}
template <typename RingPropertyMap, typename AreaStrategy>
template <typename RingPropertyMap, typename Strategy>
static inline void apply(Ring const& ring,
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy const& strategy)
{
if (boost::size(ring) > 0)
{
@@ -107,40 +108,36 @@ namespace dispatch
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
template <typename Geometry, typename RingPropertyMap, typename Strategy>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy 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, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
auto const& rings = interior_rings(polygon);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, ring_properties, strategy);
}
}
template <typename RingPropertyMap, typename AreaStrategy>
template <typename RingPropertyMap, typename Strategy>
static inline void apply(Polygon const& polygon,
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy 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, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
auto const& rings = interior_rings(polygon);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, ring_properties, strategy);
@@ -151,20 +148,15 @@ namespace dispatch
template <typename Multi>
struct select_rings<multi_polygon_tag, Multi>
{
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
template <typename Geometry, typename RingPropertyMap, typename Strategy>
static inline void apply(Multi const& multi, Geometry const& geometry,
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
Strategy const& strategy)
{
typedef typename boost::range_iterator
<
Multi const
>::type iterator_type;
typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon;
id.multi_index = 0;
for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
id.ring_index = -1;
per_polygon::apply(*it, geometry, id, ring_properties, strategy);
@@ -252,15 +244,13 @@ inline void update_ring_selection(Geometry1 const& geometry1,
{
selected_ring_properties.clear();
for (typename RingPropertyMap::const_iterator it = boost::begin(all_ring_properties);
it != boost::end(all_ring_properties);
++it)
for (auto const& pair : all_ring_properties)
{
ring_identifier const& id = it->first;
ring_identifier const& id = pair.first;
ring_turn_info info;
typename TurnInfoMap::const_iterator tcit = turn_info_map.find(id);
auto tcit = turn_info_map.find(id);
if (tcit != turn_info_map.end())
{
info = tcit->second; // Copy by value
@@ -279,12 +269,12 @@ inline void update_ring_selection(Geometry1 const& geometry1,
{
// within
case 0 :
info.within_other = range_in_geometry(it->second.point,
info.within_other = range_in_geometry(pair.second.point,
geometry1, geometry2,
strategy) > 0;
break;
case 1 :
info.within_other = range_in_geometry(it->second.point,
info.within_other = range_in_geometry(pair.second.point,
geometry2, geometry1,
strategy) > 0;
break;
@@ -292,7 +282,7 @@ inline void update_ring_selection(Geometry1 const& geometry1,
if (decide<OverlayType>::include(id, info))
{
typename RingPropertyMap::mapped_type properties = it->second; // Copy by value
auto properties = pair.second; // Copy by value
properties.reversed = decide<OverlayType>::reversed(id, info);
selected_ring_properties[id] = properties;
}
@@ -319,16 +309,14 @@ inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
{
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,
strategy.template get_area_strategy<point1_type>());
strategy);
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
ring_identifier(1, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point2_type>());
strategy);
update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
all_ring_properties, selected_ring_properties,
@@ -349,12 +337,11 @@ inline void select_rings(Geometry const& geometry,
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,
strategy.template get_area_strategy<point_type>());
strategy);
update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
all_ring_properties, selected_ring_properties,

View File

@@ -3,9 +3,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2021.
// Modifications copyright (c) 2017-2021 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,
@@ -18,15 +17,6 @@
#include <cstddef>
#include <boost/mpl/vector_c.hpp>
#include <boost/range.hpp>
#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>
@@ -34,7 +24,16 @@
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#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/box.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/relate/services.hpp>
#include <boost/geometry/util/condition.hpp>
@@ -66,14 +65,14 @@ template
typename Geometry,
typename Turns,
typename TurnPolicy,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy,
typename InterruptPolicy
>
struct self_section_visitor
{
Geometry const& m_geometry;
IntersectionStrategy const& m_intersection_strategy;
Strategy const& m_strategy;
RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
@@ -81,14 +80,14 @@ struct self_section_visitor
bool m_skip_adjacent;
inline self_section_visitor(Geometry const& g,
IntersectionStrategy const& is,
Strategy const& s,
RobustPolicy const& rp,
Turns& turns,
InterruptPolicy& ip,
int source_index,
bool skip_adjacent)
: m_geometry(g)
, m_intersection_strategy(is)
, m_strategy(s)
, m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
@@ -101,7 +100,7 @@ struct self_section_visitor
{
if (! detail::disjoint::disjoint_box_box(sec1.bounding_box,
sec2.bounding_box,
m_intersection_strategy.get_disjoint_box_box_strategy())
m_strategy)
&& ! sec1.duplicate
&& ! sec2.duplicate)
{
@@ -115,7 +114,7 @@ struct self_section_visitor
>::apply(m_source_index, m_geometry, sec1,
m_source_index, m_geometry, sec2,
false, m_skip_adjacent,
m_intersection_strategy,
m_strategy,
m_rescale_policy,
m_turns, m_interrupt_policy);
}
@@ -130,10 +129,10 @@ struct self_section_visitor
template <bool Reverse, typename TurnPolicy>
struct get_turns
{
template <typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
template <typename Geometry, typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Geometry const& geometry,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
@@ -152,35 +151,26 @@ struct get_turns
// all potential spikes correctly
typedef geometry::sections<box_type, 2> sections_type;
typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
typedef std::integer_sequence<std::size_t, 0, 1> dimensions;
sections_type sec;
geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec,
intersection_strategy.get_envelope_strategy(),
intersection_strategy.get_expand_strategy());
geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy,
sec, strategy);
self_section_visitor
<
Reverse, Geometry,
Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy
> visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent);
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;
Turns, TurnPolicy, Strategy, RobustPolicy, InterruptPolicy
> visitor(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
// false if interrupted
geometry::partition
<
box_type
>::apply(sec, visitor,
get_section_box_type(),
overlaps_section_box_type());
detail::section::get_section_box<Strategy>(strategy),
detail::section::overlaps_section_box<Strategy>(strategy));
return ! interrupt_policy.has_intersections;
}
@@ -283,24 +273,103 @@ struct self_get_turn_points
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template
<
bool Reverse,
typename AssignPolicy,
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct self_get_turn_points
{
template
<
typename Geometry,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
static inline void apply(Geometry const& geometry,
Strategies const& strategies,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int source_index,
bool skip_adjacent)
{
using turn_policy = detail::overlay::get_turn_info<AssignPolicy>;
dispatch::self_get_turn_points
<
Reverse,
typename tag<Geometry>::type,
Geometry,
turn_policy
>::apply(geometry, strategies, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}
};
template <bool Reverse, typename AssignPolicy, typename Strategy>
struct self_get_turn_points<Reverse, AssignPolicy, Strategy, false>
{
template
<
typename Geometry,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
static inline void apply(Geometry const& geometry,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int source_index,
bool skip_adjacent)
{
using strategies::relate::services::strategy_converter;
self_get_turn_points
<
Reverse,
AssignPolicy,
decltype(strategy_converter<Strategy>::get(strategy))
>::apply(geometry,
strategy_converter<Strategy>::get(strategy),
robust_policy,
turns,
interrupt_policy,
source_index,
skip_adjacent);
}
};
} // namespace resolve_strategy
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace self_get_turn_points
{
// Version where Reverse can be specified manually. TODO:
// 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 Strategy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
IntersectionStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
@@ -309,14 +378,9 @@ inline void self_turns(Geometry const& geometry,
{
concepts::check<Geometry const>();
typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
dispatch::self_get_turn_points
resolve_strategy::self_get_turn_points
<
Reverse,
typename tag<Geometry>::type,
Geometry,
turn_policy
Reverse, AssignPolicy, Strategy
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}
@@ -343,13 +407,13 @@ template
<
typename AssignPolicy,
typename Geometry,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
IntersectionStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
@@ -363,12 +427,11 @@ inline void self_turns(Geometry const& geometry,
geometry::point_order<Geometry>::value
>::value;
detail::self_get_turn_points::self_turns
resolve_strategy::self_get_turn_points
<
reverse,
AssignPolicy
>(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
reverse, AssignPolicy, Strategy
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}

View File

@@ -3,9 +3,10 @@
// Copyright (c) 2015 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-2023.
// Modifications copyright (c) 2017-2023 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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,
@@ -17,14 +18,20 @@
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/approximately_equals.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/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
@@ -51,9 +58,8 @@ struct ranked_point
, operation(operation_none)
{}
template <typename Op>
ranked_point(const Point& p, signed_size_type ti, int oi,
direction_type d, Op op)
ranked_point(Point const& p, signed_size_type ti, int oi,
direction_type d, operation_type op, segment_identifier const& si)
: point(p)
, rank(0)
, zone(-1)
@@ -62,10 +68,12 @@ struct ranked_point
, direction(d)
, count_left(0)
, count_right(0)
, operation(op.operation)
, seg_id(op.seg_id)
, operation(op)
, seg_id(si)
{}
using point_type = Point;
Point point;
rank_type rank;
signed_size_type zone; // index of closed zone, in uu turn there would be 2 zones
@@ -121,31 +129,33 @@ struct less_false
}
};
template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare>
template <typename PointOrigin, typename PointTurn, typename SideStrategy, typename LessOnSame, typename Compare>
struct less_by_side
{
less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy)
: m_p1(p1)
, m_p2(p2)
less_by_side(const PointOrigin& p1, const PointTurn& p2, SideStrategy const& strategy)
: m_origin(p1)
, m_turn_point(p2)
, m_strategy(strategy)
{}
template <typename T>
inline bool operator()(const T& first, const T& second) const
{
typedef typename SideStrategy::cs_tag cs_tag;
LessOnSame on_same;
Compare compare;
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);
int const side_first = m_strategy.apply(m_origin, m_turn_point, first.point);
int const side_second = m_strategy.apply(m_origin, m_turn_point, second.point);
if (side_first == 0 && side_second == 0)
{
// Both collinear. They might point into different directions: <------*------>
// If so, order the one going backwards as the very first.
int const first_code = direction_code(m_p1, m_p2, first.point);
int const second_code = direction_code(m_p1, m_p2, second.point);
int const first_code = direction_code<cs_tag>(m_origin, m_turn_point, first.point);
int const second_code = direction_code<cs_tag>(m_origin, m_turn_point, second.point);
// Order by code, backwards first, then forward.
return first_code != second_code
@@ -154,14 +164,14 @@ struct less_by_side
;
}
else if (side_first == 0
&& direction_code(m_p1, m_p2, first.point) == -1)
&& direction_code<cs_tag>(m_origin, m_turn_point, first.point) == -1)
{
// First collinear and going backwards.
// Order as the very first, so return always true
return true;
}
else if (side_second == 0
&& direction_code(m_p1, m_p2, second.point) == -1)
&& direction_code<cs_tag>(m_origin, m_turn_point, second.point) == -1)
{
// Second is collinear and going backwards
// Order as very last, so return always false
@@ -177,14 +187,21 @@ 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 = m_strategy.apply(m_p2, first.point, second.point);
int const side_second_wrt_first = m_strategy.apply(m_turn_point, first.point, second.point);
if (side_second_wrt_first == 0)
{
return on_same(first, second);
}
int const side_first_wrt_second = -side_second_wrt_first;
int const side_first_wrt_second = m_strategy.apply(m_turn_point, second.point, first.point);
if (side_second_wrt_first != -side_first_wrt_second)
{
// (FP) accuracy error in side calculation, the sides are not opposite.
// In that case they can be handled as collinear.
// If not, then the sort-order might not be stable.
return on_same(first, second);
}
// Both are on same side, and not collinear
// Union: return true if second is right w.r.t. first, so -1,
@@ -194,7 +211,8 @@ struct less_by_side
}
private :
Point m_p1, m_p2;
PointOrigin const& m_origin;
PointTurn const& m_turn_point;
SideStrategy const& m_strategy;
};
@@ -242,37 +260,104 @@ public :
, m_strategy(strategy)
{}
template <typename Operation>
void add_segment_from(signed_size_type turn_index, int op_index,
Point const& point_from,
Operation const& op,
bool is_origin)
{
m_ranked_points.push_back(rp(point_from, turn_index, op_index,
dir_from, op.operation, op.seg_id));
if (is_origin)
{
m_origin = point_from;
m_origin_count++;
}
}
template <typename Operation>
void add_segment_to(signed_size_type turn_index, int op_index,
Point const& point_to,
Operation const& op)
{
m_ranked_points.push_back(rp(point_to, turn_index, op_index,
dir_to, op.operation, op.seg_id));
}
template <typename Operation>
void add_segment(signed_size_type turn_index, int op_index,
Point const& point_from, Point const& point_to,
Operation const& op, bool is_origin)
{
add_segment_from(turn_index, op_index, point_from, op, is_origin);
add_segment_to(turn_index, op_index, point_to, op);
}
template <typename Operation, typename Geometry1, typename Geometry2>
Point add(Operation const& op, signed_size_type turn_index, int op_index,
static Point walk_over_ring(Operation const& op, int offset,
Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
Point point;
geometry::copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, op.seg_id, offset, point);
return point;
}
template <typename Turn, typename Operation, typename Geometry1, typename Geometry2>
Point add(Turn const& turn, Operation const& op, signed_size_type turn_index, int op_index,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
bool is_origin)
{
Point point1, point2, point3;
Point point_from, point2, point3;
geometry::copy_segment_points<Reverse1, Reverse2>(geometry1, geometry2,
op.seg_id, point1, point2, point3);
Point const& point_to = op.fraction.is_one() ? point3 : point2;
op.seg_id, point_from, point2, point3);
Point point_to = op.fraction.is_one() ? point3 : point2;
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)
// If the point is in the neighbourhood (the limit is arbitrary),
// then take a point (or more) further back.
// The limit of offset avoids theoretical infinite loops.
// In practice it currently walks max 1 point back in all cases.
// Use the coordinate type, but if it is too small (e.g. std::int16), use a double
using ct_type = typename geometry::select_most_precise
<
typename geometry::coordinate_type<Point>::type,
double
>::type;
ct_type const tolerance = 1000000000;
int offset = 0;
while (approximately_equals(point_from, turn.point, tolerance)
&& offset > -10)
{
m_origin = point1;
m_origin_count++;
point_from = walk_over_ring(op, --offset, geometry1, geometry2);
}
return point1;
// Similarly for the point_to, walk forward
offset = 0;
while (approximately_equals(point_to, turn.point, tolerance)
&& offset < 10)
{
point_to = walk_over_ring(op, ++offset, geometry1, geometry2);
}
add_segment(turn_index, op_index, point_from, point_to, op, is_origin);
return point_from;
}
template <typename Operation, typename Geometry1, typename Geometry2>
void add(Operation const& op, signed_size_type turn_index, int op_index,
template <typename Turn, typename Operation, typename Geometry1, typename Geometry2>
void add(Turn const& turn,
Operation const& op, signed_size_type turn_index, int op_index,
segment_identifier const& departure_seg_id,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
bool check_origin)
bool is_departure)
{
Point const point1 = add(op, turn_index, op_index, geometry1, geometry2, false);
Point potential_origin = add(turn, op, turn_index, op_index, geometry1, geometry2, false);
if (check_origin)
if (is_departure)
{
bool const is_origin
= op.seg_id.source_index == departure_seg_id.source_index
@@ -281,40 +366,23 @@ public :
if (is_origin)
{
signed_size_type const segment_distance = calculate_segment_distance(op, departure_seg_id, geometry1, geometry2);
if (m_origin_count == 0 ||
segment_distance < m_origin_segment_distance)
signed_size_type const sd
= departure_seg_id.source_index == 0
? segment_distance(geometry1, departure_seg_id, op.seg_id)
: segment_distance(geometry2, departure_seg_id, op.seg_id);
if (m_origin_count == 0 || sd < m_origin_segment_distance)
{
m_origin = point1;
m_origin_segment_distance = segment_distance;
m_origin = potential_origin;
m_origin_segment_distance = sd;
}
m_origin_count++;
}
}
}
template <typename Operation, typename Geometry1, typename Geometry2>
static signed_size_type 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);
signed_size_type 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)
template <typename PointTurn>
void apply(PointTurn const& turn_point)
{
// We need three compare functors:
// 1) to order clockwise (union) or counter clockwise (intersection)
@@ -323,8 +391,8 @@ public :
// to give colinear points
// Sort by side and assign rank
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);
less_by_side<Point, PointTurn, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy);
less_by_side<Point, PointTurn, 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);
@@ -342,9 +410,11 @@ public :
}
}
template <signed_size_type segment_identifier::*Member, typename Map>
void find_open_generic(Map& handled, bool check)
void find_open_by_piece_index()
{
// For buffers, use piece index
std::set<signed_size_type> handled;
for (std::size_t i = 0; i < m_ranked_points.size(); i++)
{
const rp& ranked = m_ranked_points[i];
@@ -353,39 +423,47 @@ public :
continue;
}
signed_size_type const& index = ranked.seg_id.*Member;
if (check && (index < 0 || index > 1))
signed_size_type const& index = ranked.seg_id.piece_index;
if (handled.count(index) > 0)
{
// Should not occur
continue;
}
if (! handled[index])
find_polygons_for_source<&segment_identifier::piece_index>(index, i);
handled.insert(index);
}
}
void find_open_by_source_index()
{
// Check for source index 0 and 1
bool handled[2] = {false, false};
for (std::size_t i = 0; i < m_ranked_points.size(); i++)
{
const rp& ranked = m_ranked_points[i];
if (ranked.direction != dir_from)
{
find_polygons_for_source<Member>(index, i);
handled[index] = true;
continue;
}
signed_size_type const& index = ranked.seg_id.source_index;
if (index < 0 || index > 1 || handled[index])
{
continue;
}
find_polygons_for_source<&segment_identifier::source_index>(index, i);
handled[index] = true;
}
}
void find_open()
{
if (OverlayType == overlay_buffer)
if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer))
{
// For buffers, use piece index
std::map<signed_size_type, bool> handled;
find_open_generic
<
&segment_identifier::piece_index
>(handled, false);
find_open_by_piece_index();
}
else
{
// For other operations, by source (there should only source 0,1)
bool handled[2] = {false, false};
find_open_generic
<
&segment_identifier::source_index
>(handled, true);
find_open_by_source_index();
}
}
@@ -400,7 +478,7 @@ public :
// Move iterator after rank==0
bool has_first = false;
typename container_type::iterator it = m_ranked_points.begin() + 1;
auto it = m_ranked_points.begin() + 1;
for (; it != m_ranked_points.end() && it->rank == 0; ++it)
{
has_first = true;
@@ -411,8 +489,7 @@ public :
// Reverse first part (having rank == 0), if any,
// but skip the very first row
std::reverse(m_ranked_points.begin() + 1, it);
for (typename container_type::iterator fit = m_ranked_points.begin();
fit != it; ++fit)
for (auto fit = m_ranked_points.begin(); fit != it; ++fit)
{
BOOST_ASSERT(fit->rank == 0);
}
@@ -639,6 +716,23 @@ public :
};
//! Metafunction to define side_order (clockwise, ccw) by operation_type
template <operation_type OpType>
struct side_compare {};
template <>
struct side_compare<operation_union>
{
typedef std::greater<int> type;
};
template <>
struct side_compare<operation_intersection>
{
typedef std::less<int> type;
};
}}} // namespace detail::overlay::sort_by_side
#endif //DOXYGEN_NO_DETAIL

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -17,9 +17,12 @@
#include <cstddef>
#include <set>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_exits.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/turn_info.hpp>
@@ -72,24 +75,6 @@ inline void debug_traverse(Turn const& , Operation, const char*, bool = true)
}
#endif
//! Metafunction to define side_order (clockwise, ccw) by operation_type
template <operation_type OpType>
struct side_compare {};
template <>
struct side_compare<operation_union>
{
typedef std::greater<int> type;
};
template <>
struct side_compare<operation_intersection>
{
typedef std::less<int> type;
};
template
<
bool Reverse1,
@@ -106,25 +91,10 @@ template
struct traversal
{
private :
struct linked_turn_op_info
{
explicit linked_turn_op_info(signed_size_type ti = -1, int oi = -1,
signed_size_type nti = -1)
: turn_index(ti)
, op_index(oi)
, next_turn_index(nti)
, rank_index(-1)
{}
signed_size_type turn_index;
int op_index;
signed_size_type next_turn_index;
signed_size_type rank_index;
};
static const operation_type target_operation = operation_from_overlay<OverlayType>::value;
typedef typename side_compare<target_operation>::type side_compare_type;
typedef typename sort_by_side::side_compare<target_operation>::type side_compare_type;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
@@ -153,12 +123,8 @@ public :
template <typename TurnInfoMap>
inline void finalize_visit_info(TurnInfoMap& turn_info_map)
{
for (typename boost::range_iterator<Turns>::type
it = boost::begin(m_turns);
it != boost::end(m_turns);
++it)
for (auto& turn : m_turns)
{
turn_type& turn = *it;
for (int i = 0; i < 2; i++)
{
turn_operation_type& op = turn.operations[i];
@@ -166,12 +132,7 @@ public :
|| op.visited.started()
|| op.visited.finished() )
{
ring_identifier const ring_id
(
op.seg_id.source_index,
op.seg_id.multi_index,
op.seg_id.ring_index
);
ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id);
turn_info_map[ring_id].has_traversed_turn = true;
if (op.operation == operation_continue)
@@ -180,11 +141,7 @@ public :
// as traversed too
turn_operation_type& other_op = turn.operations[1 - i];
ring_identifier const other_ring_id
(
other_op.seg_id.source_index,
other_op.seg_id.multi_index,
other_op.seg_id.ring_index
);
= ring_id_by_seg_id(other_op.seg_id);
turn_info_map[other_ring_id].has_traversed_turn = true;
}
}
@@ -197,23 +154,18 @@ public :
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);
auto 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)
for (auto turn_index : cinfo.turn_indices)
{
signed_size_type const turn_index = *it;
turn_type& turn = m_turns[turn_index];
for (int i = 0; i < 2; i++)
for (auto& op : turn.operations)
{
turn_operation_type& op = turn.operations[i];
if (op.visited.none()
&& op.enriched.rank == rank)
if (op.visited.none() && op.enriched.rank == rank)
{
op.visited.set_visited();
}
@@ -282,7 +234,7 @@ public :
{
// For uu/ii, only switch sources if indicated
if (OverlayType == overlay_buffer)
if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer))
{
// Buffer does not use source_index (always 0).
return select_source_generic<&segment_identifier::multi_index>(
@@ -391,7 +343,8 @@ public :
return true;
}
if (OverlayType == overlay_buffer && possible[0] && possible[1])
if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer)
&& possible[0] && possible[1])
{
// Buffers sometimes have multiple overlapping pieces, where remaining
// distance could lead to the wrong choice. Take the matching operation.
@@ -565,7 +518,7 @@ public :
result = select_cc_operation(turn, start_turn_index,
selected_op_index);
}
else if (OverlayType == overlay_dissolve)
else if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_dissolve))
{
result = select_preferred_operation(turn, turn_index,
start_turn_index, selected_op_index);
@@ -607,28 +560,24 @@ public :
return true;
}
template <typename RankedPoint>
inline turn_operation_type const& operation_from_rank(RankedPoint const& rp) const
{
return m_turns[rp.turn_index].operations[rp.operation_index];
}
inline int select_turn_in_cluster_union(sort_by_side::rank_type selected_rank,
inline int priority_of_turn_in_cluster_union(sort_by_side::rank_type selected_rank,
typename sbs_type::rp const& ranked_point,
std::set<signed_size_type> const& cluster_indices,
signed_size_type start_turn_index, int start_op_index) const
{
// Returns 0 if it not OK
// Returns 1 if it OK
// Returns 2 if it OK and start turn matches
// Returns 3 if it OK and start turn and start op both match
// Returns 0: not OK
// Returns 1: OK but next turn is in same cluster
// Returns 2: OK
// Returns 3: OK and start turn matches
// Returns 4: OK and start turn and start op both match
if (ranked_point.rank != selected_rank
|| ranked_point.direction != sort_by_side::dir_to)
{
return 0;
}
turn_operation_type const& op = operation_from_rank(ranked_point);
auto const& turn = m_turns[ranked_point.turn_index];
auto const& op = turn.operations[ranked_point.operation_index];
// Check finalized: TODO: this should be finetuned, it is not necessary
if (op.visited.finalized())
@@ -636,7 +585,7 @@ public :
return 0;
}
if (OverlayType != overlay_dissolve
if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_dissolve)
&& (op.enriched.count_left != 0 || op.enriched.count_right == 0))
{
// Check counts: in some cases interior rings might be generated with
@@ -644,38 +593,51 @@ public :
return 0;
}
return ranked_point.turn_index == start_turn_index
&& ranked_point.operation_index == start_op_index ? 3
: ranked_point.turn_index == start_turn_index ? 2
: 1
bool const to_start = ranked_point.turn_index == start_turn_index;
bool const to_start_index = ranked_point.operation_index == start_op_index;
bool const next_in_same_cluster
= cluster_indices.count(op.enriched.get_next_turn_index()) > 0;
return to_start && to_start_index ? 4
: to_start ? 3
: next_in_same_cluster ? 1
: 2
;
}
inline sort_by_side::rank_type select_rank(sbs_type const& sbs,
bool skip_isolated) const
template <typename RankedPoint>
inline turn_operation_type const& operation_from_rank(RankedPoint const& rp) const
{
return m_turns[rp.turn_index].operations[rp.operation_index];
}
inline sort_by_side::rank_type select_rank(sbs_type const& sbs) const
{
static bool const is_intersection
= target_operation == operation_intersection;
// Take the first outgoing rank corresponding to incoming region,
// or take another region if it is not isolated
turn_operation_type const& incoming_op
= operation_from_rank(sbs.m_ranked_points.front());
auto const& in_op = operation_from_rank(sbs.m_ranked_points.front());
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
typename sbs_type::rp const& rp = sbs.m_ranked_points[i];
auto const& rp = sbs.m_ranked_points[i];
if (rp.rank == 0 || rp.direction == sort_by_side::dir_from)
{
continue;
}
turn_operation_type const& op = operation_from_rank(rp);
auto const& out_op = operation_from_rank(rp);
if (op.operation != target_operation
&& op.operation != operation_continue)
if (out_op.operation != target_operation
&& out_op.operation != operation_continue)
{
continue;
}
if (op.enriched.region_id == incoming_op.enriched.region_id
|| (skip_isolated && ! op.enriched.isolated))
if (in_op.enriched.region_id == out_op.enriched.region_id
|| (is_intersection && ! out_op.enriched.isolated))
{
// Region corresponds to incoming region, or (for intersection)
// there is a non-isolated other region which should be taken
@@ -686,250 +648,102 @@ public :
}
inline bool select_from_cluster_union(signed_size_type& turn_index,
std::set<signed_size_type> const& cluster_indices,
int& op_index, sbs_type const& sbs,
signed_size_type start_turn_index, int start_op_index) const
{
sort_by_side::rank_type const selected_rank = select_rank(sbs, false);
sort_by_side::rank_type const selected_rank = select_rank(sbs);
int best_code = 0;
bool result = false;
int current_priority = 0;
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 (ranked_point.rank > selected_rank)
{
// Sorted on rank, so it makes no sense to continue
break;
}
int const code
= select_turn_in_cluster_union(selected_rank, ranked_point,
start_turn_index, start_op_index);
int const priority = priority_of_turn_in_cluster_union(selected_rank,
ranked_point, cluster_indices, start_turn_index, start_op_index);
if (code > best_code)
if (priority > current_priority)
{
// It is 1 or higher and matching better than previous
best_code = code;
current_priority = priority;
turn_index = ranked_point.turn_index;
op_index = ranked_point.operation_index;
result = true;
}
}
return result;
return current_priority > 0;
}
inline bool analyze_cluster_intersection(signed_size_type& turn_index,
int& op_index, sbs_type const& sbs) const
{
sort_by_side::rank_type const selected_rank = select_rank(sbs, true);
// Select the rank based on regions and isolation
sort_by_side::rank_type const selected_rank = select_rank(sbs);
if (selected_rank > 0)
{
typename turn_operation_type::comparable_distance_type
min_remaining_distance = 0;
std::size_t selected_index = sbs.m_ranked_points.size();
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
if (ranked_point.rank == selected_rank)
{
turn_operation_type const& op = operation_from_rank(ranked_point);
if (op.visited.finalized())
{
// This direction is already traveled before, the same
// cannot be traveled again
continue;
}
// Take turn with the smallest remaining distance
if (selected_index == sbs.m_ranked_points.size()
|| op.remaining_distance < min_remaining_distance)
{
selected_index = i;
min_remaining_distance = op.remaining_distance;
}
}
}
if (selected_index < sbs.m_ranked_points.size())
{
typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[selected_index];
turn_index = ranked_point.turn_index;
op_index = ranked_point.operation_index;
return true;
}
}
return false;
}
inline signed_size_type get_rank(sbs_type const& sbs,
linked_turn_op_info const& info) const
{
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
typename sbs_type::rp const& rp = sbs.m_ranked_points[i];
if (rp.turn_index == info.turn_index
&& rp.operation_index == info.op_index
&& rp.direction == sort_by_side::dir_to)
{
return rp.rank;
}
}
return -1;
}
// Function checks simple cases, such as a cluster with two turns,
// arriving at the first turn, first turn points to second turn,
// second turn points further.
inline bool select_turn_from_cluster_linked(signed_size_type& turn_index,
int& op_index,
std::set<signed_size_type> const& ids,
segment_identifier const& previous_seg_id) const
{
typedef typename std::set<signed_size_type>::const_iterator sit_type;
std::vector<linked_turn_op_info> possibilities;
std::vector<linked_turn_op_info> blocked;
for (sit_type it = ids.begin(); it != ids.end(); ++it)
{
signed_size_type cluster_turn_index = *it;
turn_type const& cluster_turn = m_turns[cluster_turn_index];
if (cluster_turn.discarded)
{
continue;
}
if (is_self_turn<OverlayType>(cluster_turn)
|| cluster_turn.both(target_operation))
{
// Not (yet) supported, can be cluster of u/u turns
return false;
}
for (int i = 0; i < 2; i++)
{
turn_operation_type const& op = cluster_turn.operations[i];
turn_operation_type const& other_op = cluster_turn.operations[1 - i];
signed_size_type const ni = op.enriched.get_next_turn_index();
if (op.operation == target_operation
|| op.operation == operation_continue)
{
if (ni == cluster_turn_index)
{
// Not (yet) supported, traveling to itself, can be
// hole
return false;
}
possibilities.push_back(
linked_turn_op_info(cluster_turn_index, i, ni));
}
else if (op.operation == operation_blocked
&& ! (ni == other_op.enriched.get_next_turn_index())
&& ids.count(ni) == 0)
{
// Points to turn, not part of this cluster,
// and that way is blocked. But if the other operation
// points at the same turn, it is still fine.
blocked.push_back(
linked_turn_op_info(cluster_turn_index, i, ni));
}
}
}
typedef typename std::vector<linked_turn_op_info>::const_iterator const_it_type;
if (! blocked.empty())
{
sbs_type sbs(m_strategy);
if (! fill_sbs(sbs, turn_index, ids, previous_seg_id))
{
return false;
}
for (typename std::vector<linked_turn_op_info>::iterator it = possibilities.begin();
it != possibilities.end(); ++it)
{
linked_turn_op_info& info = *it;
info.rank_index = get_rank(sbs, info);
}
for (typename std::vector<linked_turn_op_info>::iterator it = blocked.begin();
it != blocked.end(); ++it)
{
linked_turn_op_info& info = *it;
info.rank_index = get_rank(sbs, info);
}
for (const_it_type it = possibilities.begin();
it != possibilities.end(); ++it)
{
linked_turn_op_info const& lti = *it;
for (const_it_type bit = blocked.begin();
bit != blocked.end(); ++bit)
{
linked_turn_op_info const& blti = *bit;
if (blti.next_turn_index == lti.next_turn_index
&& blti.rank_index == lti.rank_index)
{
return false;
}
}
}
}
// Traversal can either enter the cluster in the first turn,
// or it can start halfway.
// If there is one (and only one) possibility pointing outside
// the cluster, take that one.
linked_turn_op_info target;
for (const_it_type it = possibilities.begin();
it != possibilities.end(); ++it)
{
linked_turn_op_info const& lti = *it;
if (ids.count(lti.next_turn_index) == 0)
{
if (target.turn_index >= 0
&& target.next_turn_index != lti.next_turn_index)
{
// Points to different target
return false;
}
if (OverlayType == overlay_buffer && target.turn_index > 0)
{
// Target already assigned, so there are more targets
// or more ways to the same target
return false;
}
target = lti;
}
}
if (target.turn_index < 0)
if (selected_rank <= 0)
{
return false;
}
turn_index = target.turn_index;
op_index = target.op_index;
// From these ranks, select the index: the first, or the one with
// the smallest remaining distance
typename turn_operation_type::comparable_distance_type
min_remaining_distance = 0;
std::size_t selected_index = sbs.m_ranked_points.size();
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
auto const& ranked_point = sbs.m_ranked_points[i];
if (ranked_point.rank > selected_rank)
{
break;
}
else if (ranked_point.rank == selected_rank)
{
auto const& op = operation_from_rank(ranked_point);
if (op.visited.finalized())
{
// This direction is already traveled,
// it cannot be traveled again
continue;
}
if (selected_index == sbs.m_ranked_points.size()
|| op.remaining_distance < min_remaining_distance)
{
// It was unassigned or it is better
selected_index = i;
min_remaining_distance = op.remaining_distance;
}
}
}
if (selected_index == sbs.m_ranked_points.size())
{
// Should not happen, there must be points with the selected rank
return false;
}
auto const& ranked_point = sbs.m_ranked_points[selected_index];
turn_index = ranked_point.turn_index;
op_index = ranked_point.operation_index;
return true;
}
inline bool fill_sbs(sbs_type& sbs,
signed_size_type turn_index,
std::set<signed_size_type> const& ids,
std::set<signed_size_type> const& cluster_indices,
segment_identifier const& previous_seg_id) const
{
for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
for (auto cluster_turn_index : cluster_indices)
{
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
@@ -938,10 +752,11 @@ public :
for (int i = 0; i < 2; i++)
{
sbs.add(cluster_turn.operations[i],
sbs.add(cluster_turn,
cluster_turn.operations[i],
cluster_turn_index, i, previous_seg_id,
m_geometry1, m_geometry2,
departure_turn);
cluster_turn_index == turn_index);
}
}
@@ -965,30 +780,37 @@ public :
turn_type const& turn = m_turns[turn_index];
BOOST_ASSERT(turn.is_clustered());
typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id);
auto mit = m_clusters.find(turn.cluster_id);
BOOST_ASSERT(mit != m_clusters.end());
cluster_info const& cinfo = mit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
if (select_turn_from_cluster_linked(turn_index, op_index, ids, previous_seg_id))
{
return true;
}
sbs_type sbs(m_strategy);
if (! fill_sbs(sbs, turn_index, ids, previous_seg_id))
if (! fill_sbs(sbs, turn_index, cinfo.turn_indices, previous_seg_id))
{
return false;
}
cluster_exits<OverlayType, Turns, sbs_type> exits(m_turns, cinfo.turn_indices, sbs);
if (exits.apply(turn_index, op_index))
{
return true;
}
bool result = false;
if (is_union)
{
result = select_from_cluster_union(turn_index, op_index, sbs,
start_turn_index, start_op_index);
result = select_from_cluster_union(turn_index, cinfo.turn_indices,
op_index, sbs,
start_turn_index, start_op_index);
if (! result)
{
// There no way out found, try second pass in collected cluster exits
result = exits.apply(turn_index, op_index, false);
}
}
else
{
@@ -997,6 +819,7 @@ public :
return result;
}
// Analyzes a non-clustered "ii" intersection, as if it is clustered.
inline bool analyze_ii_intersection(signed_size_type& turn_index, int& op_index,
turn_type const& current_turn,
segment_identifier const& previous_seg_id)
@@ -1006,7 +829,8 @@ public :
// Add this turn to the sort-by-side sorter
for (int i = 0; i < 2; i++)
{
sbs.add(current_turn.operations[i],
sbs.add(current_turn,
current_turn.operations[i],
turn_index, i, previous_seg_id,
m_geometry1, m_geometry2,
true);
@@ -1029,7 +853,8 @@ public :
turn_operation_type const& start_op,
int start_op_index) const
{
if (OverlayType != overlay_buffer && OverlayType != overlay_dissolve)
if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_buffer
&& OverlayType != overlay_dissolve))
{
return;
}
@@ -1128,17 +953,19 @@ public :
int previous_op_index,
signed_size_type previous_turn_index,
segment_identifier const& previous_seg_id,
bool is_start)
bool is_start, bool has_points)
{
turn_type const& current_turn = m_turns[turn_index];
bool const back_at_start_cluster
= has_points
&& current_turn.is_clustered()
&& m_turns[start_turn_index].cluster_id == current_turn.cluster_id;
if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection))
{
bool const back_at_start_cluster
= current_turn.is_clustered()
&& m_turns[start_turn_index].cluster_id == current_turn.cluster_id;
// Intersection or difference
if (turn_index == start_turn_index || back_at_start_cluster)
if (has_points && (turn_index == start_turn_index || back_at_start_cluster))
{
// Intersection can always be finished if returning
turn_index = start_turn_index;
@@ -1147,13 +974,26 @@ public :
}
if (! current_turn.is_clustered()
&& current_turn.both(operation_intersection))
{
if (analyze_ii_intersection(turn_index, op_index,
&& current_turn.both(operation_intersection)
&& analyze_ii_intersection(turn_index, op_index,
current_turn, previous_seg_id))
{
return true;
}
{
return true;
}
}
else if (turn_index == start_turn_index || back_at_start_cluster)
{
// Union or buffer: cannot return immediately to starting turn, because it then
// might miss a formed multi polygon with a touching point.
auto const& current_op = current_turn.operations[op_index];
signed_size_type const next_turn_index = current_op.enriched.get_next_turn_index();
bool const to_other_turn = next_turn_index >= 0 && m_turns[next_turn_index].cluster_id != current_turn.cluster_id;
if (! to_other_turn)
{
// Return to starting point
turn_index = start_turn_index;
op_index = start_op_index;
return true;
}
}

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020, 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,
@@ -15,7 +15,7 @@
#include <cstddef>
#include <boost/range.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
@@ -44,7 +44,7 @@ template
typename Turns,
typename TurnInfoMap,
typename Clusters,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy,
typename Visitor,
typename Backtrack
@@ -55,7 +55,8 @@ struct traversal_ring_creator
<
Reverse1, Reverse2, OverlayType,
Geometry1, Geometry2, Turns, Clusters,
RobustPolicy, typename IntersectionStrategy::side_strategy_type,
RobustPolicy,
decltype(std::declval<Strategy>().side()),
Visitor
> traversal_type;
@@ -68,17 +69,16 @@ struct traversal_ring_creator
inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2,
Turns& turns, TurnInfoMap& turn_info_map,
Clusters const& clusters,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy, Visitor& visitor)
: m_trav(geometry1, geometry2, turns, clusters,
robust_policy, intersection_strategy.get_side_strategy(),
visitor)
robust_policy, strategy.side(), visitor)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
, m_turn_info_map(turn_info_map)
, m_clusters(clusters)
, m_intersection_strategy(intersection_strategy)
, m_strategy(strategy)
, m_robust_policy(robust_policy)
, m_visitor(visitor)
{
@@ -113,15 +113,13 @@ 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);
m_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);
m_strategy, m_robust_policy, current_ring);
}
}
@@ -142,7 +140,7 @@ struct traversal_ring_creator
if (! m_trav.select_turn(start_turn_index, start_op_index,
turn_index, op_index,
previous_op_index, previous_turn_index, previous_seg_id,
is_start))
is_start, current_ring.size() > 1))
{
return is_start
? traverse_error_no_next_ip_at_start
@@ -164,8 +162,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_collinear(current_ring, current_turn.point,
m_intersection_strategy.get_side_strategy(),
m_robust_policy);
m_strategy, m_robust_policy);
// Register the visit
m_trav.set_visited(current_turn, op);
@@ -182,8 +179,7 @@ struct traversal_ring_creator
turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
detail::overlay::append_no_collinear(ring, start_turn.point,
m_intersection_strategy.get_side_strategy(),
m_robust_policy);
m_strategy, m_robust_policy);
signed_size_type current_turn_index = start_turn_index;
int current_op_index = start_op_index;
@@ -286,9 +282,7 @@ struct traversal_ring_creator
if (geometry::num_points(ring) >= min_num_points)
{
clean_closing_dups_and_spikes(ring,
m_intersection_strategy.get_side_strategy(),
m_robust_policy);
clean_closing_dups_and_spikes(ring, m_strategy, m_robust_policy);
rings.push_back(ring);
m_trav.finalize_visit_info(m_turn_info_map);
@@ -297,14 +291,13 @@ struct traversal_ring_creator
}
else
{
Backtrack::apply(
finalized_ring_size,
rings, ring, m_turns, start_turn,
m_turns[turn_index].operations[op_index],
traverse_error,
m_geometry1, m_geometry2,
m_intersection_strategy, m_robust_policy,
state, m_visitor);
Backtrack::apply(finalized_ring_size,
rings, ring, m_turns, start_turn,
m_turns[turn_index].operations[op_index],
traverse_error,
m_geometry1, m_geometry2,
m_strategy, m_robust_policy,
state, m_visitor);
}
}
@@ -413,7 +406,7 @@ private:
Turns& m_turns;
TurnInfoMap& m_turn_info_map; // contains turn-info information per ring
Clusters const& m_clusters;
IntersectionStrategy const& m_intersection_strategy;
Strategy const& m_strategy;
RobustPolicy const& m_robust_policy;
Visitor& m_visitor;
};

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2015-2016 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2018-2020.
// Modifications copyright (c) 2018-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -14,10 +14,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP
#include <cstddef>
#include <map>
#include <boost/range.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
@@ -25,9 +22,11 @@
#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>
#include <boost/geometry/util/condition.hpp>
#include <cstddef>
#include <map>
namespace boost { namespace geometry
{
@@ -35,12 +34,42 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
// Generic function (is this used somewhere else too?)
inline ring_identifier ring_id_by_seg_id(segment_identifier const& seg_id)
{
return ring_identifier(seg_id.source_index, seg_id.multi_index, seg_id.ring_index);
}
// The switch detector, the first phase in traversal, inspects UU and II turns.
// Suppose you have these two polygons in a union. There is one UU turn.
// +-------+
// | |
// | A |
// | |
// +-------U---------+ U = UU turn
// | |
// | B |
// | |
// +---------+
// It first assigns region ids, A gets id 1 and B gets id 2.
// Because of that, it should NOT switch sources in traversal at U.
// So coming from upper left, it follows A, and also at U it keeps following A.
// The result is two rings. (See for example testcase "case_31" or others.)
//
// But suppose you have two larger input polygons, partially overlapping:
// +-----------------+
// | |
// | A +-----T---C I = interior in output
// | | I | O | O = overlap A & B (included in output)
// +-------U-----T---C U = UU turn
// | | T = normal turn (u/i)
// | B | C = collinear turn (c/c)
// | |
// +---------+
// Rings A and B will be connected (by inspecting turn information)
// and there will be one region 1.
// Because of that, it will switch sources in traversal at U.
// So coming from lower right, it follows B but at U it will switch to A.
// Also for the generated interior ring, coming from the top via A it will at U
// switch to B and go to the right, generating I. (See for example "case_91")
// Switching using region_id is only relevant for UU or II turns.
// In all T turns it will follow "u" for union or "i" for intersection,
// and in C turns it will follow either direction (they are the same).
// There is also "isolated", making it more complex, and documented below.
template
<
bool Reverse1,
@@ -57,72 +86,54 @@ struct traversal_switch_detector
{
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;
enum isolation_type
{
isolation_unknown = -1,
isolation_no = 0,
isolation_yes = 1,
isolation_multiple = 2
};
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
typedef std::set<signed_size_type> set_type;
using turn_type = typename boost::range_value<Turns>::type;
using set_type= std::set<signed_size_type>;
// 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;
signed_size_type region_id = -1;
set_type turn_indices;
merged_ring_properties()
: region_id(-1)
{}
};
struct connection_properties
{
std::size_t count;
// Contains turn-index OR, if clustered, minus-cluster_id
std::size_t count = 0;
// Set with turn-index OR (if clustered) the negative cluster_id
set_type unique_turn_ids;
connection_properties()
: count(0)
{}
};
typedef std::map<signed_size_type, connection_properties> connection_map;
// Maps region_id -> properties
using connection_map = std::map<signed_size_type, connection_properties>;
// 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;
signed_size_type region_id = -1;
isolation_type isolated = isolation_no;
set_type unique_turn_ids;
// 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;
// Maps ring -> properties
using merge_map = std::map<ring_identifier, merged_ring_properties>;
typedef set_type::const_iterator set_iterator;
// Maps region_id -> properties
using region_connection_map = std::map<signed_size_type, region_properties>;
inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2,
Turns& turns, Clusters& clusters,
inline traversal_switch_detector(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Turns& turns, Clusters const& clusters,
RobustPolicy const& robust_policy, Visitor& visitor)
: m_geometry1(geometry1)
, m_geometry2(geometry2)
@@ -146,7 +157,7 @@ struct traversal_switch_detector
if (region.connected_region_counts.size() == 1)
{
connection_properties const& cprop = region.connected_region_counts.begin()->second;
auto const& cprop = region.connected_region_counts.begin()->second;
return cprop.count <= 1;
}
return region.connected_region_counts.empty();
@@ -169,7 +180,7 @@ struct traversal_switch_detector
if (region.connected_region_counts.size() == 1)
{
connection_properties const& cprop = region.connected_region_counts.begin()->second;
auto const& cprop = region.connected_region_counts.begin()->second;
return cprop.count > 1;
}
return false;
@@ -188,16 +199,15 @@ struct traversal_switch_detector
bool first = true;
signed_size_type first_turn_id = 0;
for (typename connection_map::const_iterator it = region.connected_region_counts.begin();
it != region.connected_region_counts.end(); ++it)
for (auto const& key_val : region.connected_region_counts)
{
connection_properties const& cprop = it->second;
auto const& cprop = key_val.second;
if (cprop.count != 1)
{
return false;
}
signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin();
auto const unique_turn_id = *cprop.unique_turn_ids.begin();
if (first)
{
first_turn_id = unique_turn_id;
@@ -239,10 +249,9 @@ struct traversal_switch_detector
// First step: compare turns of regions with turns of connected region
set_type turn_ids = region.unique_turn_ids;
for (set_iterator sit = connected_region.unique_turn_ids.begin();
sit != connected_region.unique_turn_ids.end(); ++sit)
for (auto turn_id : connected_region.unique_turn_ids)
{
turn_ids.erase(*sit);
turn_ids.erase(turn_id);
}
// There should be one connection (turn or cluster) left
@@ -251,10 +260,8 @@ struct traversal_switch_detector
return false;
}
for (set_iterator sit = connected_region.unique_turn_ids.begin();
sit != connected_region.unique_turn_ids.end(); ++sit)
for (auto id_or_index : connected_region.unique_turn_ids)
{
signed_size_type const id_or_index = *sit;
if (id_or_index >= 0)
{
if (! ii_turn_connects_two_regions(region, connected_region, id_or_index))
@@ -265,14 +272,13 @@ struct traversal_switch_detector
else
{
signed_size_type const cluster_id = -id_or_index;
typename Clusters::const_iterator it = m_clusters.find(cluster_id);
auto it = m_clusters.find(cluster_id);
if (it != m_clusters.end())
{
cluster_info const& cinfo = it->second;
for (set_iterator cit = cinfo.turn_indices.begin();
cit != cinfo.turn_indices.end(); ++cit)
for (auto turn_index : cinfo.turn_indices)
{
if (! ii_turn_connects_two_regions(region, connected_region, *cit))
if (! ii_turn_connects_two_regions(region, connected_region, turn_index))
{
return false;
}
@@ -289,13 +295,12 @@ struct traversal_switch_detector
bool first_with_turn = true;
signed_size_type first_turn_id = 0;
for (typename connection_map::const_iterator it = region.connected_region_counts.begin();
it != region.connected_region_counts.end(); ++it)
for (auto const& key_val : region.connected_region_counts)
{
signed_size_type const region_id = it->first;
connection_properties const& cprop = it->second;
signed_size_type const region_id = key_val.first;
connection_properties const& cprop = key_val.second;
typename region_connection_map::const_iterator mit = m_connected_regions.find(region_id);
auto mit = m_connected_regions.find(region_id);
if (mit == m_connected_regions.end())
{
// Should not occur
@@ -336,16 +341,13 @@ struct traversal_switch_detector
void get_isolated_regions()
{
typedef typename region_connection_map::iterator it_type;
// First time: check regions isolated (one connection only),
// semi-isolated (multiple connections between same region),
// and complex isolated (connection with multiple rings but all
// at same point)
for (it_type it = m_connected_regions.begin();
it != m_connected_regions.end(); ++it)
for (auto& key_val : m_connected_regions)
{
region_properties& properties = it->second;
region_properties& properties = key_val.second;
if (one_connection_to_another_region(properties))
{
properties.isolated = isolation_yes;
@@ -367,12 +369,11 @@ struct traversal_switch_detector
while (changed && defensive_check++ < m_connected_regions.size())
{
changed = false;
for (it_type it = m_connected_regions.begin();
it != m_connected_regions.end(); ++it)
for (auto& key_val : m_connected_regions)
{
region_properties& properties = it->second;
region_properties& properties = key_val.second;
if (properties.isolated == isolation_unknown
if (properties.isolated == isolation_no
&& has_only_isolated_children(properties))
{
properties.isolated = isolation_yes;
@@ -382,37 +383,55 @@ struct traversal_switch_detector
}
}
void assign_isolation()
void assign_isolation_to_enriched()
{
for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
for (turn_type& turn : m_turns)
{
turn_type& turn = m_turns[turn_index];
// For difference, for the input walked through in reverse,
// the meaning is reversed: what is isolated is actually not,
// and vice versa.
bool const reverseMeaningInTurn
= (Reverse1 || Reverse2)
&& ! turn.is_self()
&& ! turn.is_clustered()
&& uu_or_ii(turn)
&& turn.operations[0].enriched.region_id
!= turn.operations[1].enriched.region_id;
for (int op_index = 0; op_index < 2; op_index++)
for (auto& op : turn.operations)
{
turn_operation_type& op = turn.operations[op_index];
typename region_connection_map::const_iterator mit = m_connected_regions.find(op.enriched.region_id);
auto mit = m_connected_regions.find(op.enriched.region_id);
if (mit != m_connected_regions.end())
{
bool const reverseMeaningInOp
= reverseMeaningInTurn
&& ((op.seg_id.source_index == 0 && Reverse1)
|| (op.seg_id.source_index == 1 && Reverse2));
// It is assigned to isolated if it's property is "Yes",
// (one connected interior, or chained).
// "Multiple" doesn't count for isolation,
// neither for intersection, neither for difference.
region_properties const& prop = mit->second;
op.enriched.isolated = prop.isolated == isolation_yes;
op.enriched.isolated
= reverseMeaningInOp
? false
: prop.isolated == isolation_yes;
}
}
}
}
void assign_region_ids()
void assign_region_ids_to_enriched()
{
for (typename merge_map::const_iterator it
= m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
for (auto const& key_val : m_turns_per_ring)
{
ring_identifier const& ring_id = it->first;
merged_ring_properties const& properties = it->second;
ring_identifier const& ring_id = key_val.first;
merged_ring_properties const& properties = key_val.second;
for (set_iterator sit = properties.turn_indices.begin();
sit != properties.turn_indices.end(); ++sit)
for (auto turn_index : properties.turn_indices)
{
turn_type& turn = m_turns[*sit];
turn_type& turn = m_turns[turn_index];
if (! acceptable(turn))
{
@@ -420,9 +439,8 @@ struct traversal_switch_detector
continue;
}
for (int i = 0; i < 2; i++)
for (auto& op : turn.operations)
{
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;
@@ -441,11 +459,8 @@ struct traversal_switch_detector
signed_size_type const unique_turn_id
= turn.is_clustered() ? -turn.cluster_id : turn_index;
turn_operation_type op0 = turn.operations[0];
turn_operation_type op1 = turn.operations[1];
signed_size_type const& id0 = op0.enriched.region_id;
signed_size_type const& id1 = op1.enriched.region_id;
signed_size_type const& id0 = turn.operations[0].enriched.region_id;
signed_size_type const& id1 = turn.operations[1].enriched.region_id;
// Add region (by assigning) and add involved turns
if (id0 != -1)
@@ -485,8 +500,12 @@ struct traversal_switch_detector
// Discarded turns don't connect rings to the same region
// Also xx are not relevant
// (otherwise discarded colocated uu turn could make a connection)
return ! turn.discarded
&& ! turn.both(operation_blocked);
return ! turn.discarded && ! turn.both(operation_blocked);
}
inline bool uu_or_ii(turn_type const& turn) const
{
return turn.both(operation_union) || turn.both(operation_intersection);
}
inline bool connects_same_region(turn_type const& turn) const
@@ -499,7 +518,7 @@ struct traversal_switch_detector
if (! turn.is_clustered())
{
// If it is a uu/ii-turn (non clustered), it is never same region
return ! (turn.both(operation_union) || turn.both(operation_intersection));
return ! uu_or_ii(turn);
}
if (BOOST_GEOMETRY_CONDITION(target_operation == operation_union))
@@ -517,13 +536,6 @@ struct traversal_switch_detector
|| turn.combination(operation_intersection, operation_union));
}
inline signed_size_type get_region_id(turn_operation_type const& op) const
{
return op.enriched.region_id;
}
void create_region(signed_size_type& new_region_id, ring_identifier const& ring_id,
merged_ring_properties& properties, signed_size_type region_id = -1)
{
@@ -543,14 +555,12 @@ struct traversal_switch_detector
properties.region_id = region_id;
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl;
std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl;
#endif
// Find connecting rings, recursively
for (set_iterator sit = properties.turn_indices.begin();
sit != properties.turn_indices.end(); ++sit)
for (auto turn_index : properties.turn_indices)
{
signed_size_type const turn_index = *sit;
turn_type const& turn = m_turns[turn_index];
if (! connects_same_region(turn))
{
@@ -560,9 +570,8 @@ struct traversal_switch_detector
// 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++)
for (auto const& op : turn.operations)
{
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)
{
@@ -575,18 +584,90 @@ struct traversal_switch_detector
void propagate_region(signed_size_type& new_region_id,
ring_identifier const& ring_id, signed_size_type region_id)
{
typename merge_map::iterator it = m_turns_per_ring.find(ring_id);
auto it = m_turns_per_ring.find(ring_id);
if (it != m_turns_per_ring.end())
{
create_region(new_region_id, ring_id, it->second, region_id);
}
}
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
void debug_show_results()
{
auto isolation_to_string = [](isolation_type const& iso) -> std::string
{
switch(iso)
{
case isolation_no : return "no";
case isolation_yes : return "yes";
case isolation_multiple : return "multiple";
}
return "error";
};
auto set_to_string = [](auto const& s) -> std::string
{
std::ostringstream result;
for (auto item : s) { result << " " << item; }
return result.str();
};
for (auto const& kv : m_connected_regions)
{
auto const& prop = kv.second;
std::ostringstream sub;
sub << "[turns" << set_to_string(prop.unique_turn_ids)
<< "] regions";
for (auto const& kvs : prop.connected_region_counts)
{
sub << " { " << kvs.first
<< " : via [" << set_to_string(kvs.second.unique_turn_ids)
<< " ] }";
}
std::cout << "REGION " << prop.region_id
<< " " << isolation_to_string(prop.isolated)
<< " " << sub.str()
<< std::endl;
}
for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
{
turn_type const& turn = m_turns[turn_index];
if (uu_or_ii(turn) && ! turn.is_clustered())
{
std::cout << (turn.both(operation_union) ? "UU" : "II")
<< " " << turn_index
<< " (" << geometry::get<0>(turn.point)
<< ", " << geometry::get<1>(turn.point) << ")"
<< " -> " << std::boolalpha
<< " [" << turn.operations[0].seg_id.source_index
<< "/" << turn.operations[1].seg_id.source_index << "] "
<< "(" << turn.operations[0].enriched.region_id
<< " " << turn.operations[0].enriched.isolated
<< ") / (" << turn.operations[1].enriched.region_id
<< " " << turn.operations[1].enriched.isolated << ")"
<< std::endl;
}
}
for (auto const& key_val : m_clusters)
{
cluster_info const& cinfo = key_val.second;
std::cout << "CL RESULT " << key_val.first
<< " -> " << cinfo.open_count << std::endl;
}
}
#endif
void iterate()
{
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
std::cout << "BEGIN ITERATION GETTING REGION_IDS" << std::endl;
std::cout << "BEGIN SWITCH DETECTOR (region_ids and isolation)"
<< (Reverse1 ? " REVERSE_1" : "")
<< (Reverse2 ? " REVERSE_2" : "")
<< std::endl;
#endif
// Collect turns per ring
@@ -604,9 +685,8 @@ struct traversal_switch_detector
continue;
}
for (int op_index = 0; op_index < 2; op_index++)
for (auto const& op : turn.operations)
{
turn_operation_type const& op = turn.operations[op_index];
m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].turn_indices.insert(turn_index);
}
}
@@ -614,42 +694,20 @@ struct traversal_switch_detector
// All rings having turns are in turns/ring map. Process them.
{
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)
for (auto& key_val : m_turns_per_ring)
{
create_region(new_region_id, it->first, it->second);
create_region(new_region_id, key_val.first, key_val.second);
}
assign_region_ids();
assign_region_ids_to_enriched();
assign_connected_regions();
get_isolated_regions();
assign_isolation();
assign_isolation_to_enriched();
}
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
std::cout << "END ITERATION GETTIN REGION_IDS" << std::endl;
for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
{
turn_type const& turn = m_turns[turn_index];
if ((turn.both(operation_union) || turn.both(operation_intersection))
&& ! turn.is_clustered())
{
std::cout << "UU/II RESULT "
<< turn_index << " -> "
<< turn.operations[0].enriched.region_id
<< " " << turn.operations[1].enriched.region_id
<< std::endl;
}
}
for (typename Clusters::const_iterator it = m_clusters.begin(); it != m_clusters.end(); ++it)
{
cluster_info const& cinfo = it->second;
std::cout << "CL RESULT " << it->first
<< " -> " << cinfo.open_count << std::endl;
}
std::cout << "END SWITCH DETECTOR" << std::endl;
debug_show_results();
#endif
}
@@ -659,7 +717,7 @@ private:
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
Turns& m_turns;
Clusters& m_clusters;
Clusters const& m_clusters;
merge_map m_turns_per_ring;
region_connection_map m_connected_regions;
RobustPolicy const& m_robust_policy;

View File

@@ -42,14 +42,11 @@ class traverse
template <typename Turns>
static void reset_visits(Turns& turns)
{
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
for (auto& turn : turns)
{
for (int i = 0; i < 2; i++)
for (auto& op : turn.operations)
{
it->operations[i].visited.reset();
op.visited.reset();
}
}
}

View File

@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -10,12 +11,13 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP
#include <boost/array.hpp>
#include <array>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
namespace boost { namespace geometry
{
@@ -33,6 +35,7 @@ enum method_type
method_touch_interior,
method_collinear,
method_equal,
method_start,
method_error
};
@@ -76,9 +79,9 @@ struct turn_operation
template
<
typename Point,
typename SegmentRatio,
typename SegmentRatio = geometry::segment_ratio<typename coordinate_type<Point>::type>,
typename Operation = turn_operation<Point, SegmentRatio>,
typename Container = boost::array<Operation, 2>
typename Container = std::array<Operation, 2>
>
struct turn_info
{
@@ -92,7 +95,6 @@ struct turn_info
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. 0 is unused.
bool discarded;
bool has_colocated_both; // Colocated with a uu turn (for union) or ii (other)
Container operations;
@@ -137,6 +139,11 @@ struct turn_info
{
return cluster_id > 0;
}
inline bool is_self() const
{
return operations[0].seg_id.source_index
== operations[1].seg_id.source_index;
}
private :
inline bool has12(operation_type type1, operation_type type2) const