update boost
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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 '?';
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user