mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-11 13:34:10 +00:00
[relate] Refactor relate utilities and implementation.
Implement boundary_checker and follow helpers for geometry collection. They are commented-out for now because they are not used anywhere. The code is there in case they were needed in the future.
This commit is contained in:
parent
e2496e2fed
commit
f80cacc4cb
@ -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-2020.
|
||||
// Modifications copyright (c) 2014-2020 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
|
||||
|
||||
@ -438,8 +438,7 @@ public :
|
||||
// for different ring id: c, i, u, x
|
||||
typedef relate::turns::less
|
||||
<
|
||||
0, relate::turns::less_op_linear_areal_single<0>,
|
||||
typename Strategy::cs_tag
|
||||
0, relate::turns::less_op_linear_areal_single<0>, Strategy
|
||||
> turn_less;
|
||||
std::sort(boost::begin(turns), boost::end(turns), turn_less());
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014-2020, Oracle and/or its affiliates.
|
||||
// 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
|
||||
|
||||
@ -160,14 +160,10 @@ protected:
|
||||
|
||||
detail::get_turns::no_interrupt_policy interrupt_policy;
|
||||
|
||||
using point_type = typename geometry::point_type<LinearGeometry1>::type;
|
||||
using mutable_point_type = typename helper_geometry<point_type>::type;
|
||||
|
||||
geometry::detail::relate::turns::get_turns
|
||||
<
|
||||
LinearGeometry1,
|
||||
LinearGeometry2,
|
||||
mutable_point_type,
|
||||
detail::get_turns::get_turn_info_type
|
||||
<
|
||||
LinearGeometry1,
|
||||
@ -235,13 +231,10 @@ public:
|
||||
OutputIterator oit,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
using point_type = typename geometry::point_type<Linear1>::type;
|
||||
using mutable_point_type = typename helper_geometry<point_type>::type;
|
||||
typedef typename detail::relate::turns::get_turns
|
||||
<
|
||||
Linear1,
|
||||
Linear2,
|
||||
mutable_point_type,
|
||||
detail::get_turns::get_turn_info_type
|
||||
<
|
||||
Linear1,
|
||||
|
@ -208,9 +208,6 @@ struct areal_areal
|
||||
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
typedef typename geometry::point_type<Geometry1>::type point1_type;
|
||||
typedef typename geometry::point_type<Geometry2>::type point2_type;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
Result & result,
|
||||
@ -225,23 +222,18 @@ struct areal_areal
|
||||
return;
|
||||
|
||||
// get and analyse turns
|
||||
using point_type = typename geometry::point_type<Geometry1>::type;
|
||||
using mutable_point_type = typename helper_geometry<point_type>::type;
|
||||
|
||||
typedef typename turns::get_turns
|
||||
using turn_type = typename turns::get_turns
|
||||
<
|
||||
Geometry1, Geometry2, mutable_point_type
|
||||
>::template turn_info_type<Strategy>::type turn_type;
|
||||
Geometry1, Geometry2
|
||||
>::template turn_info_type<Strategy>::type;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
|
||||
|
||||
turns::get_turns<Geometry1, Geometry2, mutable_point_type>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
|
||||
typedef typename Strategy::cs_tag cs_tag;
|
||||
|
||||
no_turns_aa_pred<Geometry2, Result, Strategy, false>
|
||||
pred1(geometry2, result, strategy);
|
||||
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
@ -264,8 +256,8 @@ struct areal_areal
|
||||
|| may_update<exterior, interior, '2'>(result) )
|
||||
{
|
||||
// sort turns
|
||||
typedef turns::less<0, turns::less_op_areal_areal<0>, cs_tag> less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
using less_t = turns::less<0, turns::less_op_areal_areal<0>, Strategy>;
|
||||
std::sort(turns.begin(), turns.end(), less_t());
|
||||
|
||||
/*if ( may_update<interior, exterior, '2'>(result)
|
||||
|| may_update<boundary, exterior, '1'>(result)
|
||||
@ -304,8 +296,8 @@ struct areal_areal
|
||||
|| may_update<exterior, interior, '2', true>(result) )
|
||||
{
|
||||
// sort turns
|
||||
typedef turns::less<1, turns::less_op_areal_areal<1>, cs_tag> less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
using less_t = turns::less<1, turns::less_op_areal_areal<1>, Strategy>;
|
||||
std::sort(turns.begin(), turns.end(), less_t());
|
||||
|
||||
/*if ( may_update<interior, exterior, '2', true>(result)
|
||||
|| may_update<boundary, exterior, '1', true>(result)
|
||||
@ -357,9 +349,7 @@ struct areal_areal
|
||||
template <typename Range>
|
||||
inline bool apply(Range const& turns)
|
||||
{
|
||||
typedef typename boost::range_iterator<Range const>::type iterator;
|
||||
|
||||
for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
{
|
||||
per_turn<0>(*it);
|
||||
per_turn<1>(*it);
|
||||
@ -657,10 +647,9 @@ struct areal_areal
|
||||
return;
|
||||
}
|
||||
|
||||
typename detail::sub_range_return_type<Geometry const>::type
|
||||
range_ref = detail::sub_range(geometry, seg_id);
|
||||
auto const& sub_range = detail::sub_range(geometry, seg_id);
|
||||
|
||||
if ( boost::empty(range_ref) )
|
||||
if ( boost::empty(sub_range) )
|
||||
{
|
||||
// TODO: throw an exception?
|
||||
return; // ignore
|
||||
@ -673,7 +662,7 @@ struct areal_areal
|
||||
// TODO: optimize! e.g. use spatial index
|
||||
// O(N) - running it in a loop gives O(NM)
|
||||
using detail::within::point_in_geometry;
|
||||
int const pig = point_in_geometry(range::front(range_ref),
|
||||
int const pig = point_in_geometry(range::front(sub_range),
|
||||
other_geometry,
|
||||
m_point_in_areal_strategy);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014-2020 Oracle and/or its affiliates.
|
||||
// Copyright (c) 2014-2022 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/sub_range.hpp>
|
||||
//#include <boost/geometry/algorithms/detail/visit.hpp>
|
||||
#include <boost/geometry/algorithms/num_points.hpp>
|
||||
|
||||
#include <boost/geometry/geometries/helper_geometry.hpp>
|
||||
@ -28,9 +29,9 @@ namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
namespace detail { namespace relate
|
||||
{
|
||||
|
||||
enum boundary_query { boundary_front, boundary_back, boundary_any };
|
||||
|
||||
template
|
||||
<
|
||||
@ -43,31 +44,26 @@ class boundary_checker {};
|
||||
template <typename Geometry, typename Strategy>
|
||||
class boundary_checker<Geometry, Strategy, linestring_tag>
|
||||
{
|
||||
using mutable_point_type
|
||||
= typename helper_geometry<typename point_type<Geometry>::type>::type;
|
||||
|
||||
public:
|
||||
boundary_checker(Geometry const& g, Strategy const& s)
|
||||
: m_has_boundary( boost::size(g) >= 2
|
||||
&& ! detail::equals::equals_point_point(range::front(g),
|
||||
range::back(g),
|
||||
s) )
|
||||
: m_has_boundary(
|
||||
boost::size(g) >= 2
|
||||
&& ! detail::equals::equals_point_point(range::front(g), range::back(g), s))
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
|
||||
, m_geometry(g)
|
||||
#endif
|
||||
, m_strategy(s)
|
||||
{}
|
||||
|
||||
template <boundary_query BoundaryQuery, typename Point>
|
||||
template <typename Point>
|
||||
bool is_endpoint_boundary(Point const& pt) const
|
||||
{
|
||||
boost::ignore_unused(pt);
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
|
||||
// may give false positives for INT
|
||||
BOOST_GEOMETRY_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
|
||||
&& detail::equals::equals_point_point(pt, range::front(m_geometry), m_strategy)
|
||||
|| (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& detail::equals::equals_point_point(pt, range::back(m_geometry), m_strategy) );
|
||||
BOOST_GEOMETRY_ASSERT(
|
||||
detail::equals::equals_point_point(pt, range::front(m_geometry), m_strategy)
|
||||
|| detail::equals::equals_point_point(pt, range::back(m_geometry), m_strategy));
|
||||
#endif
|
||||
return m_has_boundary;
|
||||
}
|
||||
@ -85,6 +81,67 @@ private:
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
|
||||
template <typename Point, typename Strategy, typename Out>
|
||||
inline void copy_pts_boundary_points(Point const& front_pt, Point const& back_pt,
|
||||
Strategy const& strategy, Out & boundary_points)
|
||||
{
|
||||
using mutable_point_type = typename Out::value_type;
|
||||
// linear ring or point - no boundary
|
||||
if (! equals::equals_point_point(front_pt, back_pt, strategy))
|
||||
{
|
||||
// do not add points containing NaN coordinates
|
||||
// because they cannot be reasonably compared, e.g. with MSVC
|
||||
// an assertion failure is reported in std::equal_range()
|
||||
if (! geometry::has_nan_coordinate(front_pt))
|
||||
{
|
||||
mutable_point_type pt;
|
||||
geometry::convert(front_pt, pt);
|
||||
boundary_points.push_back(front_pt);
|
||||
}
|
||||
if (! geometry::has_nan_coordinate(back_pt))
|
||||
{
|
||||
mutable_point_type pt;
|
||||
geometry::convert(back_pt, pt);
|
||||
boundary_points.push_back(back_pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Segment, typename Strategy, typename Out>
|
||||
inline void copy_seg_boundary_points(Segment const& seg, Strategy const& strategy,
|
||||
Out & boundary_points)
|
||||
{
|
||||
typename Out::value_type front_pt, back_pt;
|
||||
assign_point_from_index<0>(seg, front_pt);
|
||||
assign_point_from_index<1>(seg, back_pt);
|
||||
copy_pts_boundary_points(front_pt, back_pt, strategy, boundary_points);
|
||||
}
|
||||
|
||||
template <typename Linestring, typename Strategy, typename Out>
|
||||
inline void copy_ls_boundary_points(Linestring const& ls, Strategy const& strategy,
|
||||
Out & boundary_points)
|
||||
{
|
||||
// empty or point - no boundary
|
||||
if (boost::size(ls) >= 2)
|
||||
{
|
||||
auto const& front_pt = range::front(ls);
|
||||
auto const& back_pt = range::back(ls);
|
||||
copy_pts_boundary_points(front_pt, back_pt, strategy, boundary_points);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MultiLinestring, typename Strategy, typename Out>
|
||||
inline void copy_mls_boundary_points(MultiLinestring const& mls, Strategy const& strategy,
|
||||
Out & boundary_points)
|
||||
{
|
||||
for (auto it = boost::begin(mls); it != boost::end(mls); ++it)
|
||||
{
|
||||
copy_ls_boundary_points(*it, strategy, boundary_points);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Geometry, typename Strategy>
|
||||
class boundary_checker<Geometry, Strategy, multi_linestring_tag>
|
||||
{
|
||||
@ -98,72 +155,36 @@ public:
|
||||
|
||||
// First call O(NlogN)
|
||||
// Each next call O(logN)
|
||||
template <boundary_query BoundaryQuery, typename Point>
|
||||
template <typename Point>
|
||||
bool is_endpoint_boundary(Point const& pt) const
|
||||
{
|
||||
using less_type = geometry::less<mutable_point_type, -1, typename Strategy::cs_tag>;
|
||||
|
||||
auto const multi_count = boost::size(m_geometry);
|
||||
|
||||
if ( multi_count < 1 )
|
||||
if (multi_count < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! m_is_filled )
|
||||
if (! m_is_filled)
|
||||
{
|
||||
//boundary_points.clear();
|
||||
m_boundary_points.reserve(multi_count * 2);
|
||||
|
||||
for (auto it = boost::begin(m_geometry); it != boost::end(m_geometry); ++it)
|
||||
{
|
||||
auto const& ls = *it;
|
||||
copy_mls_boundary_points(m_geometry, m_strategy, m_boundary_points);
|
||||
|
||||
// empty or only one point - no boundary
|
||||
if (boost::size(ls) < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const& front_pt = range::front(ls);
|
||||
auto const& back_pt = range::back(ls);
|
||||
|
||||
// linear ring or point - no boundary
|
||||
if (! equals::equals_point_point(front_pt, back_pt, m_strategy))
|
||||
{
|
||||
// do not add points containing NaN coordinates
|
||||
// because they cannot be reasonably compared, e.g. with MSVC
|
||||
// an assertion failure is reported in std::equal_range()
|
||||
if (! geometry::has_nan_coordinate(front_pt))
|
||||
{
|
||||
mutable_point_type pt;
|
||||
geometry::convert(front_pt, pt);
|
||||
m_boundary_points.push_back(pt);
|
||||
}
|
||||
if (! geometry::has_nan_coordinate(back_pt))
|
||||
{
|
||||
mutable_point_type pt;
|
||||
geometry::convert(back_pt, pt);
|
||||
m_boundary_points.push_back(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(m_boundary_points.begin(),
|
||||
m_boundary_points.end(),
|
||||
less_type());
|
||||
std::sort(m_boundary_points.begin(), m_boundary_points.end(), less_type());
|
||||
|
||||
m_is_filled = true;
|
||||
}
|
||||
|
||||
auto const equal_points_count
|
||||
= boost::size(
|
||||
std::equal_range(m_boundary_points.begin(),
|
||||
m_boundary_points.end(),
|
||||
pt,
|
||||
less_type())
|
||||
);
|
||||
auto const equal_range = std::equal_range(m_boundary_points.begin(),
|
||||
m_boundary_points.end(),
|
||||
pt,
|
||||
less_type());
|
||||
|
||||
std::size_t const equal_points_count = boost::size(equal_range);
|
||||
return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
|
||||
}
|
||||
|
||||
@ -181,6 +202,98 @@ private:
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
// NOTE: In case it was needed in the future. Commented-out for now.
|
||||
/*
|
||||
template <typename Geometry, typename Strategy>
|
||||
class boundary_checker<Geometry, Strategy, geometry_collection_tag>
|
||||
{
|
||||
using point_type = typename point_type<Geometry>::type;
|
||||
using mutable_point_type = typename helper_geometry<point_type>::type;
|
||||
|
||||
public:
|
||||
boundary_checker(Geometry const& g, Strategy const& s)
|
||||
: m_is_filled(false), m_geometry(g), m_strategy(s)
|
||||
{}
|
||||
|
||||
// First call O(NlogN)
|
||||
// Each next call O(logN)
|
||||
template <typename Point>
|
||||
bool is_endpoint_boundary(Point const& pt) const
|
||||
{
|
||||
using less_t = geometry::less<mutable_point_type, -1, typename Strategy::cs_tag>;
|
||||
|
||||
auto multi_count = boost::size(m_geometry);
|
||||
|
||||
if (multi_count < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! m_is_filled)
|
||||
{
|
||||
//boundary_points.clear();
|
||||
m_boundary_points.reserve(multi_count * 2);
|
||||
|
||||
detail::visit_breadth_first([&](auto const& g)
|
||||
{
|
||||
add_boundary_points(g);
|
||||
return true;
|
||||
}, m_geometry);
|
||||
|
||||
std::sort(m_boundary_points.begin(),
|
||||
m_boundary_points.end(),
|
||||
less_t());
|
||||
|
||||
m_is_filled = true;
|
||||
}
|
||||
|
||||
auto const equal_range = std::equal_range(m_boundary_points.begin(),
|
||||
m_boundary_points.end(),
|
||||
pt,
|
||||
less_t());
|
||||
|
||||
std::size_t const equal_points_count = boost::size(equal_range);
|
||||
return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
|
||||
}
|
||||
|
||||
Strategy const& strategy() const
|
||||
{
|
||||
return m_strategy;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Geom, std::enable_if_t<util::is_multi_linestring<Geom>::value, int> = 0>
|
||||
void add_boundary_points(Geom const& geom) const
|
||||
{
|
||||
copy_mls_boundary_points(geom, m_strategy, m_boundary_points);
|
||||
}
|
||||
|
||||
template <typename Geom, std::enable_if_t<util::is_linestring<Geom>::value, int> = 0>
|
||||
void add_boundary_points(Geom const& geom) const
|
||||
{
|
||||
copy_ls_boundary_points(geom, m_strategy, m_boundary_points);
|
||||
}
|
||||
|
||||
template <typename Geom, std::enable_if_t<util::is_segment<Geom>::value, int> = 0>
|
||||
void add_boundary_points(Geom const& geom) const
|
||||
{
|
||||
copy_seg_boundary_points(geom, m_strategy, m_boundary_points);
|
||||
}
|
||||
|
||||
template <typename Geom, std::enable_if_t<! util::is_linear<Geom>::value, int> = 0>
|
||||
void add_boundary_points(Geom const& ) const
|
||||
{}
|
||||
|
||||
mutable bool m_is_filled;
|
||||
// TODO: store references/pointers instead of converted points?
|
||||
mutable std::vector<mutable_point_type> m_boundary_points;
|
||||
|
||||
Geometry const& m_geometry;
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014, 2018.
|
||||
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013-2022.
|
||||
// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
@ -52,14 +52,12 @@ template <std::size_t OpId, typename Geometry, typename Tag>
|
||||
struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
static void apply(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred)
|
||||
{
|
||||
if ( first != last )
|
||||
return false;
|
||||
pred(geometry);
|
||||
return true;
|
||||
if (first == last)
|
||||
{
|
||||
pred(geometry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -67,49 +65,43 @@ template <std::size_t OpId, typename Geometry, typename Tag>
|
||||
struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
static void apply(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred)
|
||||
{
|
||||
if ( first != last )
|
||||
return for_turns(first, last, geometry, pred);
|
||||
if (first == last)
|
||||
{
|
||||
for_empty(geometry, pred);
|
||||
}
|
||||
else
|
||||
return for_empty(geometry, pred);
|
||||
{
|
||||
for_turns(first, last, geometry, pred);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pred>
|
||||
static inline bool for_empty(Geometry const& geometry,
|
||||
Pred & pred)
|
||||
static void for_empty(Geometry const& geometry, Pred & pred)
|
||||
{
|
||||
typedef typename boost::range_iterator<Geometry const>::type iterator;
|
||||
|
||||
// O(N)
|
||||
// check predicate for each contained geometry without generated turn
|
||||
for ( iterator it = boost::begin(geometry) ;
|
||||
it != boost::end(geometry) ; ++it )
|
||||
for (auto it = boost::begin(geometry); it != boost::end(geometry) ; ++it)
|
||||
{
|
||||
bool cont = pred(*it);
|
||||
if ( !cont )
|
||||
if (! pred(*it))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !boost::empty(geometry);
|
||||
}
|
||||
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool for_turns(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
static void for_turns(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(first != last);
|
||||
|
||||
const std::size_t count = boost::size(geometry);
|
||||
boost::ignore_unused(count);
|
||||
|
||||
// O(I)
|
||||
// gather info about turns generated for contained geometries
|
||||
std::vector<bool> detected_intersections(count, false);
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
for (TurnIt it = first; it != last; ++it)
|
||||
{
|
||||
signed_size_type multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_GEOMETRY_ASSERT(multi_index >= 0);
|
||||
@ -118,28 +110,167 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
|
||||
detected_intersections[index] = true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
// O(N)
|
||||
// check predicate for each contained geometry without generated turn
|
||||
for ( std::vector<bool>::iterator it = detected_intersections.begin() ;
|
||||
it != detected_intersections.end() ; ++it )
|
||||
for (std::size_t index = 0; index < detected_intersections.size(); ++index)
|
||||
{
|
||||
// if there were no intersections for this multi_index
|
||||
if ( *it == false )
|
||||
if (detected_intersections[index] == false)
|
||||
{
|
||||
found = true;
|
||||
std::size_t const index = std::size_t(std::distance(detected_intersections.begin(), it));
|
||||
bool cont = pred(range::at(geometry, index));
|
||||
if ( !cont )
|
||||
if (! pred(range::at(geometry, index)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// In case it was needed in the future. Commented-out for now.
|
||||
/*
|
||||
// GC is expected to support random access, i.e. random_access_view has to be passed.
|
||||
// Predicate is called for each segmental single geometry.
|
||||
// Point-like geometries and boxes are ignored.
|
||||
template <std::size_t OpId, typename RandomGC>
|
||||
struct for_each_disjoint_geometry_if<OpId, RandomGC, geometry_collection_tag, true>
|
||||
{
|
||||
struct detected_data
|
||||
{
|
||||
void set_multi_index(std::size_t multi_index)
|
||||
{
|
||||
if (multi_index >= multi.size())
|
||||
{
|
||||
multi.resize(multi_index + 1, false);
|
||||
}
|
||||
multi[multi_index] = true;
|
||||
}
|
||||
|
||||
std::vector<bool> multi;
|
||||
bool is_detected = false;
|
||||
};
|
||||
|
||||
template <typename TurnIt, typename Pred>
|
||||
static void apply(TurnIt first, TurnIt last, RandomGC const& random_gc, Pred & pred)
|
||||
{
|
||||
return first != last
|
||||
? for_turns(first, last, random_gc, pred)
|
||||
: for_empty(random_gc, pred);
|
||||
}
|
||||
|
||||
template <typename Pred>
|
||||
static void for_empty(RandomGC const& random_gc, Pred & pred)
|
||||
{
|
||||
auto const end = boost::end(random_gc);
|
||||
for (auto it = boost::begin(random_gc); it != end; ++it)
|
||||
{
|
||||
bool ok = true;
|
||||
traits::iter_visit<RandomGC>::apply([&](auto const& g)
|
||||
{
|
||||
ok = call_pred(pred, g);
|
||||
}, it);
|
||||
if (! ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TurnIt, typename Pred>
|
||||
static void for_turns(TurnIt first, TurnIt last, RandomGC const& random_gc, Pred & pred)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(first != last);
|
||||
|
||||
const std::size_t count = boost::size(random_gc);
|
||||
|
||||
std::vector<detected_data> detected_intersections(count);
|
||||
for (TurnIt it = first; it != last; ++it)
|
||||
{
|
||||
auto const& op = it->operations[OpId];
|
||||
auto const& seg_id = op.seg_id;
|
||||
BOOST_GEOMETRY_ASSERT(op.gc_index >= 0);
|
||||
detected_intersections[op.gc_index].is_detected = true;
|
||||
if (seg_id.multi_index >= 0)
|
||||
{
|
||||
detected_intersections[op.gc_index].set_multi_index(std::size_t(seg_id.multi_index));
|
||||
}
|
||||
}
|
||||
|
||||
auto const begin = boost::begin(random_gc);
|
||||
auto const end = boost::end(random_gc);
|
||||
for (auto it = begin; it != end; ++it)
|
||||
{
|
||||
bool ok = true;
|
||||
traits::iter_visit<RandomGC>::apply([&](auto const& g)
|
||||
{
|
||||
std::size_t gc_index = it - begin;
|
||||
// either single or the whole multi was not detected
|
||||
if (detected_intersections[gc_index].is_detected == false)
|
||||
{
|
||||
ok = call_pred(pred, g);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = check_multi_elements(pred, g, detected_intersections[gc_index].multi);
|
||||
}
|
||||
}, it);
|
||||
if (! ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pred, typename Geometry, std::enable_if_t<util::is_segmental<Geometry>::value && util::is_multi<Geometry>::value, int> = 0>
|
||||
static bool call_pred(Pred & pred, Geometry const& geometry)
|
||||
{
|
||||
for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it)
|
||||
{
|
||||
if (! pred(*it))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Pred, typename Geometry, std::enable_if_t<util::is_segmental<Geometry>::value && util::is_single<Geometry>::value, int> = 0>
|
||||
static bool call_pred(Pred & pred, Geometry const& geometry)
|
||||
{
|
||||
return pred(geometry);
|
||||
}
|
||||
|
||||
template <typename Pred, typename Geometry, std::enable_if_t<! util::is_segmental<Geometry>::value, int> = 0>
|
||||
static bool call_pred(Pred & , Geometry const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Pred, typename Geometry, std::enable_if_t<util::is_segmental<Geometry>::value && util::is_multi<Geometry>::value, int> = 0>
|
||||
static bool check_multi_elements(Pred & pred, Geometry const& geometry, std::vector<bool> const& detected_multi)
|
||||
{
|
||||
std::size_t size = boost::size(geometry);
|
||||
for (std::size_t multi_index = 0; multi_index < size; ++multi_index)
|
||||
{
|
||||
if (multi_index >= detected_multi.size() || detected_multi[multi_index] == false)
|
||||
{
|
||||
if (! pred(range::at(geometry, multi_index)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Pred, typename Geometry, std::enable_if_t<! util::is_segmental<Geometry>::value || ! util::is_multi<Geometry>::value, int> = 0>
|
||||
static bool check_multi_elements(Pred & , Geometry const& , std::vector<bool> const& )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// WARNING! This class stores pointers!
|
||||
// Passing a reference to local variable will result in undefined behavior!
|
||||
template <typename Point>
|
||||
@ -365,44 +496,17 @@ inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn,
|
||||
return detail::equals::equals_point_point(prev_turn.point, curr_turn.point, strategy);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename Point,
|
||||
typename BoundaryChecker>
|
||||
inline bool is_endpoint_on_boundary(Point const& pt,
|
||||
BoundaryChecker & boundary_checker)
|
||||
template <typename IntersectionPoint, typename OperationInfo, typename BoundaryChecker>
|
||||
static inline bool is_ip_on_boundary(IntersectionPoint const& ip,
|
||||
OperationInfo const& operation_info,
|
||||
BoundaryChecker const& boundary_checker)
|
||||
{
|
||||
return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename IntersectionPoint,
|
||||
typename OperationInfo,
|
||||
typename BoundaryChecker>
|
||||
inline bool is_ip_on_boundary(IntersectionPoint const& ip,
|
||||
OperationInfo const& operation_info,
|
||||
BoundaryChecker & boundary_checker,
|
||||
segment_identifier const& seg_id)
|
||||
{
|
||||
boost::ignore_unused(seg_id);
|
||||
|
||||
bool res = false;
|
||||
|
||||
// IP on the last point of the linestring
|
||||
if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& operation_info.position == overlay::position_back )
|
||||
{
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
|
||||
}
|
||||
// IP on the last point of the linestring
|
||||
else if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
|
||||
&& operation_info.position == overlay::position_front )
|
||||
{
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip);
|
||||
}
|
||||
|
||||
return res;
|
||||
// IP on the first or the last point of the linestring
|
||||
return (operation_info.position == overlay::position_back
|
||||
|| operation_info.position == overlay::position_front)
|
||||
// check if this point is a boundary
|
||||
? boundary_checker.is_endpoint_boundary(ip)
|
||||
: false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,9 +2,8 @@
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013-2021.
|
||||
// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates.
|
||||
|
||||
// This file was modified by Oracle on 2013-2022.
|
||||
// Modifications copyright (c) 2013-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,16 +14,15 @@
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP
|
||||
|
||||
|
||||
#include <boost/geometry/core/tags.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/interface.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/interface.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/point_point.hpp>
|
||||
|
||||
#include <boost/geometry/core/tags.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/relate/cartesian.hpp>
|
||||
#include <boost/geometry/strategies/relate/geographic.hpp>
|
||||
@ -116,6 +114,7 @@ struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true>
|
||||
: detail::relate::areal_areal<Areal1, Areal2>
|
||||
{};
|
||||
|
||||
|
||||
} // namespace dispatch
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013-2021.
|
||||
// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013-2022.
|
||||
// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
@ -53,7 +53,7 @@ template
|
||||
<
|
||||
typename Geometry2,
|
||||
typename Result,
|
||||
typename PointInArealStrategy,
|
||||
typename Strategy,
|
||||
typename BoundaryChecker,
|
||||
bool TransposeResult
|
||||
>
|
||||
@ -62,11 +62,11 @@ class no_turns_la_linestring_pred
|
||||
public:
|
||||
no_turns_la_linestring_pred(Geometry2 const& geometry2,
|
||||
Result & res,
|
||||
PointInArealStrategy const& point_in_areal_strategy,
|
||||
Strategy const& strategy,
|
||||
BoundaryChecker const& boundary_checker)
|
||||
: m_geometry2(geometry2)
|
||||
, m_result(res)
|
||||
, m_point_in_areal_strategy(point_in_areal_strategy)
|
||||
, m_strategy(strategy)
|
||||
, m_boundary_checker(boundary_checker)
|
||||
, m_interrupt_flags(0)
|
||||
{
|
||||
@ -112,7 +112,7 @@ public:
|
||||
|
||||
int const pig = detail::within::point_in_geometry(range::front(linestring),
|
||||
m_geometry2,
|
||||
m_point_in_areal_strategy);
|
||||
m_strategy);
|
||||
//BOOST_GEOMETRY_ASSERT_MSG(pig != 0, "There should be no IPs");
|
||||
|
||||
if ( pig > 0 )
|
||||
@ -127,11 +127,9 @@ public:
|
||||
}
|
||||
|
||||
// check if there is a boundary
|
||||
if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set
|
||||
&& ( m_boundary_checker.template
|
||||
is_endpoint_boundary<boundary_front>(range::front(linestring))
|
||||
|| m_boundary_checker.template
|
||||
is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
|
||||
if ((m_interrupt_flags & 0xC) != 0xC // if wasn't already set
|
||||
&& (m_boundary_checker.is_endpoint_boundary(range::front(linestring))
|
||||
|| m_boundary_checker.is_endpoint_boundary(range::back(linestring))))
|
||||
{
|
||||
if ( pig > 0 )
|
||||
{
|
||||
@ -152,7 +150,7 @@ public:
|
||||
private:
|
||||
Geometry2 const& m_geometry2;
|
||||
Result & m_result;
|
||||
PointInArealStrategy const& m_point_in_areal_strategy;
|
||||
Strategy const& m_strategy;
|
||||
BoundaryChecker const& m_boundary_checker;
|
||||
unsigned m_interrupt_flags;
|
||||
};
|
||||
@ -200,13 +198,134 @@ private:
|
||||
bool const interrupt;
|
||||
};
|
||||
|
||||
|
||||
template <typename It, typename Strategy>
|
||||
inline It find_next_non_duplicated(It first, It current, It last, Strategy const& strategy)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(current != last);
|
||||
|
||||
It it = current;
|
||||
for (++it ; it != last ; ++it)
|
||||
{
|
||||
if (! equals::equals_point_point(*current, *it, strategy))
|
||||
{
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
// if not found start from the beginning
|
||||
for (it = first ; it != current ; ++it)
|
||||
{
|
||||
if (! equals::equals_point_point(*current, *it, strategy))
|
||||
{
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
// calculate inside or outside based on side_calc
|
||||
// this is simplified version of a check from equal<>
|
||||
template
|
||||
<
|
||||
typename Pi, typename Pj, typename Pk,
|
||||
typename Qi, typename Qj, typename Qk,
|
||||
typename Strategy
|
||||
>
|
||||
inline bool calculate_from_inside_sides(Pi const& pi, Pj const& pj, Pk const& pk,
|
||||
Qi const& qi, Qj const& qj, Qk const& qk,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
auto const side_strategy = strategy.side();
|
||||
|
||||
int const side_pk_p = side_strategy.apply(pi, pj, pk);
|
||||
int const side_qk_p = side_strategy.apply(pi, pj, qk);
|
||||
// If they turn to same side (not opposite sides)
|
||||
if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
|
||||
{
|
||||
int const side_pk_q2 = side_strategy.apply(qj, qk, pk);
|
||||
return side_pk_q2 == -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return side_pk_p == -1;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the passed turn's segment of Linear geometry arrived
|
||||
// from the inside or the outside of the Areal geometry
|
||||
template
|
||||
<
|
||||
std::size_t OpId,
|
||||
typename Geometry1, typename Geometry2,
|
||||
typename Turn, typename Strategy
|
||||
>
|
||||
inline bool calculate_from_inside(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Turn const& turn,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
static const std::size_t op_id = OpId;
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
|
||||
if (turn.operations[op_id].position == overlay::position_front)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const& range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
|
||||
|
||||
using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>;
|
||||
using range2_iterator = typename boost::range_iterator<range2_view const>::type;
|
||||
range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(boost::size(range1));
|
||||
std::size_t const s2 = boost::size(range2);
|
||||
BOOST_GEOMETRY_ASSERT(s2 > 2);
|
||||
std::size_t const seg_count2 = s2 - 1;
|
||||
|
||||
std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index);
|
||||
std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index);
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1));
|
||||
BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2);
|
||||
|
||||
auto const& pi = range::at(range1, p_seg_ij);
|
||||
auto const& qi = range::at(range2, q_seg_ij);
|
||||
auto const& qj = range::at(range2, q_seg_ij + 1);
|
||||
|
||||
bool const is_ip_qj = equals::equals_point_point(turn.point, qj, strategy);
|
||||
// TODO: test this!
|
||||
// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi));
|
||||
// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi));
|
||||
|
||||
if (is_ip_qj)
|
||||
{
|
||||
std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
|
||||
// TODO: the following function should return immediately, however the worst case complexity is O(N)
|
||||
// It would be good to replace it with some O(1) mechanism
|
||||
range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
|
||||
range::pos(range2, q_seg_jk),
|
||||
boost::end(range2),
|
||||
strategy);
|
||||
|
||||
// Calculate sides in a different point order for P and Q
|
||||
// Will this sequence of points be always correct?
|
||||
return calculate_from_inside_sides(qi, turn.point, pi, qi, qj, *qk_it, strategy);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate sides with different points for P and Q
|
||||
return calculate_from_inside_sides(qi, turn.point, pi, qi, turn.point, qj, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The implementation of an algorithm calculating relate() for L/A
|
||||
template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
|
||||
struct linear_areal
|
||||
{
|
||||
using point_type = typename geometry::point_type<Geometry1>::type;
|
||||
using mutable_point_type = typename helper_geometry<point_type>::type;
|
||||
|
||||
// check Linear / Areal
|
||||
BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 1
|
||||
&& topological_dimension<Geometry2>::value == 2);
|
||||
@ -215,7 +334,7 @@ struct linear_areal
|
||||
|
||||
template <typename Geom1, typename Geom2, typename Strategy>
|
||||
struct multi_turn_info
|
||||
: turns::get_turns<Geom1, Geom2, mutable_point_type>::template turn_info_type<Strategy>::type
|
||||
: turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type
|
||||
{
|
||||
multi_turn_info() : priority(0) {}
|
||||
int priority; // single-geometry sorting priority
|
||||
@ -227,7 +346,7 @@ struct linear_areal
|
||||
<
|
||||
util::is_multi<Geometry2>::value,
|
||||
multi_turn_info<Geom1, Geom2, Strategy>,
|
||||
typename turns::get_turns<Geom1, Geom2, mutable_point_type>::template turn_info_type<Strategy>::type
|
||||
typename turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type
|
||||
>
|
||||
{};
|
||||
|
||||
@ -236,7 +355,7 @@ struct linear_areal
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
// TODO: If Areal geometry may have infinite size, change the following line:
|
||||
// TODO: If Areal geometry may have infinite size, change the following line:
|
||||
|
||||
// The result should be FFFFFFFFF
|
||||
relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
|
||||
@ -245,12 +364,12 @@ struct linear_areal
|
||||
return;
|
||||
|
||||
// get and analyse turns
|
||||
typedef typename turn_info_type<Geometry1, Geometry2, Strategy>::type turn_type;
|
||||
using turn_type = typename turn_info_type<Geometry1, Geometry2, Strategy>::type;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
|
||||
|
||||
turns::get_turns<Geometry1, Geometry2, mutable_point_type>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
|
||||
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
|
||||
return;
|
||||
|
||||
@ -293,7 +412,7 @@ struct linear_areal
|
||||
return;
|
||||
|
||||
{
|
||||
sort_dispatch<cs_tag>(turns.begin(), turns.end(), util::is_multi<Geometry2>());
|
||||
sort_dispatch(turns.begin(), turns.end(), strategy, util::is_multi<Geometry2>());
|
||||
|
||||
turns_analyser<turn_type> analyser;
|
||||
analyse_each_turn(result, analyser,
|
||||
@ -325,12 +444,9 @@ struct linear_areal
|
||||
// sort by multi_index and rind_index
|
||||
std::sort(turns.begin(), turns.end(), less_ring());
|
||||
|
||||
typedef typename std::vector<turn_type>::iterator turn_iterator;
|
||||
|
||||
turn_iterator it = turns.begin();
|
||||
segment_identifier * prev_seg_id_ptr = NULL;
|
||||
// for each ring
|
||||
for ( ; it != turns.end() ; )
|
||||
for (auto it = turns.begin() ; it != turns.end() ; )
|
||||
{
|
||||
// it's the next single geometry
|
||||
if ( prev_seg_id_ptr == NULL
|
||||
@ -377,7 +493,7 @@ struct linear_areal
|
||||
|
||||
// find the next ring first iterator and check if the analysis should be performed
|
||||
has_boundary_intersection has_boundary_inters;
|
||||
turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters);
|
||||
auto next = find_next_ring(it, turns.end(), has_boundary_inters);
|
||||
|
||||
// if there is no 1d overlap with the boundary
|
||||
if ( !has_boundary_inters.result )
|
||||
@ -390,12 +506,12 @@ struct linear_areal
|
||||
else
|
||||
{
|
||||
// u, c
|
||||
typedef turns::less<1, turns::less_op_areal_linear<1>, cs_tag> less;
|
||||
std::sort(it, next, less());
|
||||
using less_t = turns::less<1, turns::less_op_areal_linear<1>, Strategy>;
|
||||
std::sort(it, next, less_t());
|
||||
|
||||
// analyse
|
||||
areal_boundary_analyser<turn_type> analyser;
|
||||
for ( turn_iterator rit = it ; rit != next ; ++rit )
|
||||
for (auto rit = it ; rit != next ; ++rit)
|
||||
{
|
||||
// if the analyser requests, break the search
|
||||
if ( !analyser.apply(it, rit, next, strategy) )
|
||||
@ -518,12 +634,13 @@ struct linear_areal
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CSTag, typename TurnIt>
|
||||
static void sort_dispatch(TurnIt first, TurnIt last, std::true_type const& /*is_multi*/)
|
||||
template <typename TurnIt, typename Strategy>
|
||||
static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& ,
|
||||
std::true_type const& /*is_multi*/)
|
||||
{
|
||||
// sort turns by Linear seg_id, then by fraction, then by other multi_index
|
||||
typedef turns::less<0, turns::less_other_multi_index<0>, CSTag> less;
|
||||
std::sort(first, last, less());
|
||||
using less_t = turns::less<0, turns::less_other_multi_index<0>, Strategy>;
|
||||
std::sort(first, last, less_t());
|
||||
|
||||
// For the same IP and multi_index - the same other's single geometry
|
||||
// set priorities as the least operation found for the whole single geometry
|
||||
@ -536,20 +653,21 @@ struct linear_areal
|
||||
// When priorities for single geometries are set now sort turns for the same IP
|
||||
// if multi_index is the same sort them according to the single-less
|
||||
// else use priority of the whole single-geometry set earlier
|
||||
typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> single_less;
|
||||
using single_less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>;
|
||||
for_each_equal_range(first, last,
|
||||
sort_turns_group<single_less>(),
|
||||
sort_turns_group<single_less_t>(),
|
||||
same_ip());
|
||||
}
|
||||
|
||||
template <typename CSTag, typename TurnIt>
|
||||
static void sort_dispatch(TurnIt first, TurnIt last, std::false_type const& /*is_multi*/)
|
||||
template <typename TurnIt, typename Strategy>
|
||||
static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& ,
|
||||
std::false_type const& /*is_multi*/)
|
||||
{
|
||||
// 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
|
||||
typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> less;
|
||||
std::sort(first, last, less());
|
||||
using less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>;
|
||||
std::sort(first, last, less_t());
|
||||
}
|
||||
|
||||
|
||||
@ -571,9 +689,7 @@ struct linear_areal
|
||||
template <typename Range>
|
||||
inline bool apply(Range const& turns)
|
||||
{
|
||||
typedef typename boost::range_iterator<Range const>::type iterator;
|
||||
|
||||
for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
{
|
||||
if ( it->operations[0].operation == overlay::operation_intersection )
|
||||
{
|
||||
@ -621,37 +737,6 @@ struct linear_areal
|
||||
static const std::size_t op_id = 0;
|
||||
static const std::size_t other_op_id = 1;
|
||||
|
||||
template <typename Strategy,
|
||||
typename Pi, typename Pj, typename Pk,
|
||||
typename Qi, typename Qj, typename Qk>
|
||||
struct la_side_calculator
|
||||
{
|
||||
typedef decltype(std::declval<Strategy>().side()) side_strategy_type;
|
||||
|
||||
inline la_side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
|
||||
Qi const& qi, Qj const& qj, Qk const& qk,
|
||||
Strategy const& strategy)
|
||||
: m_pi(pi), m_pj(pj), m_pk(pk)
|
||||
, m_qi(qi), m_qj(qj), m_qk(qk)
|
||||
, m_side_strategy(strategy.side())
|
||||
{}
|
||||
|
||||
inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); }
|
||||
inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); }
|
||||
inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); }
|
||||
|
||||
private :
|
||||
Pi const& m_pi;
|
||||
Pj const& m_pj;
|
||||
Pk const& m_pk;
|
||||
Qi const& m_qi;
|
||||
Qj const& m_qj;
|
||||
Qk const& m_qk;
|
||||
|
||||
side_strategy_type m_side_strategy;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
turns_analyser()
|
||||
: m_previous_turn_ptr(NULL)
|
||||
@ -714,9 +799,8 @@ struct linear_areal
|
||||
// NOTE: similar code is in the post-last-ip-apply()
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_range(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
bool const prev_back_b = boundary_checker.is_endpoint_boundary(
|
||||
range::back(sub_range(geometry, prev_seg_id)));
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
@ -809,9 +893,8 @@ struct linear_areal
|
||||
{
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_range(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
bool const prev_back_b = boundary_checker.is_endpoint_boundary(
|
||||
range::back(sub_range(geometry, prev_seg_id)));
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
@ -890,11 +973,8 @@ struct linear_areal
|
||||
update<interior, boundary, '1', TransposeResult>(res);
|
||||
}
|
||||
|
||||
bool const this_b
|
||||
= is_ip_on_boundary<boundary_front>(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker,
|
||||
seg_id);
|
||||
bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id],
|
||||
boundary_checker);
|
||||
// going inside on boundary point
|
||||
if ( this_b )
|
||||
{
|
||||
@ -911,11 +991,11 @@ struct linear_areal
|
||||
&& it->operations[op_id].position != overlay::position_front )
|
||||
{
|
||||
// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
|
||||
bool const from_inside = first_point
|
||||
&& calculate_from_inside(geometry,
|
||||
other_geometry,
|
||||
*it,
|
||||
strategy);
|
||||
bool const from_inside =
|
||||
first_point && calculate_from_inside<op_id>(geometry,
|
||||
other_geometry,
|
||||
*it,
|
||||
strategy);
|
||||
|
||||
if ( from_inside )
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
@ -925,9 +1005,8 @@ struct linear_areal
|
||||
// if it's the first IP then the first point is outside
|
||||
if ( first_point )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_range(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(sub_range(geometry, seg_id)));
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
@ -974,7 +1053,7 @@ struct linear_areal
|
||||
{
|
||||
// check if this is indeed the boundary point
|
||||
// NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
|
||||
if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
|
||||
if (boundary_checker.is_endpoint_boundary(it->point))
|
||||
{
|
||||
update<boundary, boundary, '0', TransposeResult>(res);
|
||||
}
|
||||
@ -989,10 +1068,8 @@ struct linear_areal
|
||||
// we're outside or inside and this is the first turn
|
||||
else
|
||||
{
|
||||
bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker,
|
||||
seg_id);
|
||||
bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id],
|
||||
boundary_checker);
|
||||
// if current IP is on boundary of the geometry
|
||||
if ( this_b )
|
||||
{
|
||||
@ -1012,11 +1089,11 @@ struct linear_areal
|
||||
// For LS/MultiPolygon multiple x/u turns may be generated
|
||||
// the first checked Polygon may be the one which LS is outside for.
|
||||
bool const first_point = first_in_range || m_first_from_unknown;
|
||||
bool const first_from_inside = first_point
|
||||
&& calculate_from_inside(geometry,
|
||||
other_geometry,
|
||||
*it,
|
||||
strategy);
|
||||
bool const first_from_inside =
|
||||
first_point && calculate_from_inside<op_id>(geometry,
|
||||
other_geometry,
|
||||
*it,
|
||||
strategy);
|
||||
if ( first_from_inside )
|
||||
{
|
||||
update<interior, interior, '1', TransposeResult>(res);
|
||||
@ -1044,9 +1121,8 @@ struct linear_areal
|
||||
// first IP on the last segment point - this means that the first point is outside or inside
|
||||
if ( first_point && ( !this_b || op_blocked ) )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_range(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(sub_range(geometry, seg_id)));
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
@ -1135,9 +1211,8 @@ struct linear_areal
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_range(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
bool const prev_back_b = boundary_checker.is_endpoint_boundary(
|
||||
range::back(sub_range(geometry, prev_seg_id)));
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
@ -1158,9 +1233,8 @@ struct linear_areal
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_range(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
bool const prev_back_b = boundary_checker.is_endpoint_boundary(
|
||||
range::back(sub_range(geometry, prev_seg_id)));
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
@ -1184,9 +1258,8 @@ struct linear_areal
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_range(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
bool const prev_back_b = boundary_checker.is_endpoint_boundary(
|
||||
range::back(sub_range(geometry, prev_seg_id)));
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
@ -1202,122 +1275,6 @@ struct linear_areal
|
||||
m_first_from_unknown_boundary_detected = false;
|
||||
}
|
||||
|
||||
// check if the passed turn's segment of Linear geometry arrived
|
||||
// from the inside or the outside of the Areal geometry
|
||||
template <typename Turn, typename Strategy>
|
||||
static inline bool calculate_from_inside(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Turn const& turn,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
if ( turn.operations[op_id].position == overlay::position_front )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
typename sub_range_return_type<Geometry1 const>::type
|
||||
range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
|
||||
|
||||
using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>;
|
||||
using range2_iterator = typename boost::range_iterator<range2_view const>::type;
|
||||
range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(boost::size(range1));
|
||||
std::size_t const s2 = boost::size(range2);
|
||||
BOOST_GEOMETRY_ASSERT(s2 > 2);
|
||||
std::size_t const seg_count2 = s2 - 1;
|
||||
|
||||
std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index);
|
||||
std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index);
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1));
|
||||
BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2);
|
||||
|
||||
auto const& pi = range::at(range1, p_seg_ij);
|
||||
auto const& qi = range::at(range2, q_seg_ij);
|
||||
auto const& qj = range::at(range2, q_seg_ij + 1);
|
||||
|
||||
bool const is_ip_qj = equals::equals_point_point(turn.point, qj, strategy);
|
||||
// TODO: test this!
|
||||
// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi));
|
||||
// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi));
|
||||
|
||||
if (is_ip_qj)
|
||||
{
|
||||
std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
|
||||
// TODO: the following function should return immediately, however the worst case complexity is O(N)
|
||||
// It would be good to replace it with some O(1) mechanism
|
||||
range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
|
||||
range::pos(range2, q_seg_jk),
|
||||
boost::end(range2),
|
||||
strategy);
|
||||
|
||||
// Calculate sides in a different point order for P and Q
|
||||
// Will this sequence of points be always correct?
|
||||
return calculate_from_inside_sides(qi, turn.point, pi, qi, qj, *qk_it, strategy);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate sides with different points for P and Q
|
||||
return calculate_from_inside_sides(qi, turn.point, pi, qi, turn.point, qj, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename It, typename Strategy>
|
||||
static inline It find_next_non_duplicated(It first, It current, It last,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT( current != last );
|
||||
|
||||
It it = current;
|
||||
|
||||
for ( ++it ; it != last ; ++it )
|
||||
{
|
||||
if ( !equals::equals_point_point(*current, *it, strategy) )
|
||||
return it;
|
||||
}
|
||||
|
||||
// if not found start from the beginning
|
||||
for ( it = first ; it != current ; ++it )
|
||||
{
|
||||
if ( !equals::equals_point_point(*current, *it, strategy) )
|
||||
return it;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
// calculate inside or outside based on side_calc
|
||||
// this is simplified version of a check from equal<>
|
||||
template <typename Strategy,
|
||||
typename Pi, typename Pj, typename Pk,
|
||||
typename Qi, typename Qj, typename Qk>
|
||||
static inline
|
||||
bool calculate_from_inside_sides(Pi const& pi, Pj const& pj, Pk const& pk,
|
||||
Qi const& qi, Qj const& qj, Qk const& qk,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
la_side_calculator
|
||||
<
|
||||
Strategy,
|
||||
Pi, Pj, Pk,
|
||||
Qi, Qj, Qk
|
||||
> side_calc(pi, pj, pk, qi, qj, qk, strategy);
|
||||
|
||||
int const side_pk_p = side_calc.pk_wrt_p1();
|
||||
int const side_qk_p = side_calc.qk_wrt_p1();
|
||||
// If they turn to same side (not opposite sides)
|
||||
if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
|
||||
{
|
||||
int const side_pk_q2 = side_calc.pk_wrt_q2();
|
||||
return side_pk_q2 == -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return side_pk_p == -1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
exit_watcher<TurnInfo, op_id> m_exit_watcher;
|
||||
segment_watcher<same_single> m_seg_watcher;
|
||||
|
@ -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, 2019.
|
||||
// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013-2022.
|
||||
// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
@ -93,11 +93,9 @@ public:
|
||||
m_flags |= 1;
|
||||
|
||||
// check if there is a boundary
|
||||
if ( m_flags < 2
|
||||
&& ( m_boundary_checker.template
|
||||
is_endpoint_boundary<boundary_front>(range::front(linestring))
|
||||
|| m_boundary_checker.template
|
||||
is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
|
||||
if (m_flags < 2
|
||||
&& (m_boundary_checker.is_endpoint_boundary(range::front(linestring))
|
||||
|| m_boundary_checker.is_endpoint_boundary(range::back(linestring))))
|
||||
{
|
||||
update<boundary, exterior, '0', TransposeResult>(m_result);
|
||||
m_flags |= 2;
|
||||
@ -124,20 +122,16 @@ struct linear_linear
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
typedef typename Strategy::cs_tag cs_tag;
|
||||
|
||||
// The result should be FFFFFFFFF
|
||||
relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
|
||||
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
|
||||
return;
|
||||
|
||||
// get and analyse turns
|
||||
using point_type = typename geometry::point_type<Geometry1>::type;
|
||||
using mutable_point_type = typename helper_geometry<point_type>::type;
|
||||
typedef typename turns::get_turns
|
||||
using turn_type = typename turns::get_turns
|
||||
<
|
||||
Geometry1, Geometry2, mutable_point_type
|
||||
>::template turn_info_type<Strategy>::type turn_type;
|
||||
Geometry1, Geometry2
|
||||
>::template turn_info_type<Strategy>::type;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
interrupt_policy_linear_linear<Result> interrupt_policy(result);
|
||||
@ -146,7 +140,6 @@ struct linear_linear
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
mutable_point_type,
|
||||
detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
|
||||
>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
|
||||
|
||||
@ -180,8 +173,8 @@ struct linear_linear
|
||||
|| may_update<boundary, boundary, '0'>(result)
|
||||
|| may_update<boundary, exterior, '0'>(result) )
|
||||
{
|
||||
typedef turns::less<0, turns::less_op_linear_linear<0>, cs_tag> less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
using less_t = turns::less<0, turns::less_op_linear_linear<0>, Strategy>;
|
||||
std::sort(turns.begin(), turns.end(), less_t());
|
||||
|
||||
turns_analyser<turn_type, 0> analyser;
|
||||
analyse_each_turn(result, analyser,
|
||||
@ -200,8 +193,8 @@ struct linear_linear
|
||||
|| may_update<boundary, boundary, '0', true>(result)
|
||||
|| may_update<boundary, exterior, '0', true>(result) )
|
||||
{
|
||||
typedef turns::less<1, turns::less_op_linear_linear<1>, cs_tag> less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
using less_t = turns::less<1, turns::less_op_linear_linear<1>, Strategy>;
|
||||
std::sort(turns.begin(), turns.end(), less_t());
|
||||
|
||||
turns_analyser<turn_type, 1> analyser;
|
||||
analyse_each_turn(result, analyser,
|
||||
@ -226,9 +219,7 @@ struct linear_linear
|
||||
template <typename Range>
|
||||
inline bool apply(Range const& turns)
|
||||
{
|
||||
typedef typename boost::range_iterator<Range const>::type iterator;
|
||||
|
||||
for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
|
||||
{
|
||||
if ( it->operations[0].operation == overlay::operation_intersection
|
||||
|| it->operations[1].operation == overlay::operation_intersection )
|
||||
@ -376,20 +367,16 @@ struct linear_linear
|
||||
update<interior, interior, '1', transpose_result>(res);
|
||||
|
||||
bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes!
|
||||
&& is_ip_on_boundary<boundary_front>(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker,
|
||||
seg_id);
|
||||
&& is_ip_on_boundary(it->point, it->operations[op_id],
|
||||
boundary_checker);
|
||||
|
||||
// going inside on boundary point
|
||||
// may be front only
|
||||
if ( this_b )
|
||||
{
|
||||
// may be front and back
|
||||
bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
it->operations[other_op_id],
|
||||
other_boundary_checker,
|
||||
other_id);
|
||||
bool const other_b = is_ip_on_boundary(it->point, it->operations[other_op_id],
|
||||
other_boundary_checker);
|
||||
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
@ -415,9 +402,8 @@ struct linear_linear
|
||||
// if it's the first IP then the first point is outside
|
||||
if ( first_in_range )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_range(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(sub_range(geometry, seg_id)));
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
@ -463,13 +449,12 @@ struct linear_linear
|
||||
{
|
||||
// check if this is indeed the boundary point
|
||||
// NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
|
||||
if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
|
||||
if (boundary_checker.is_endpoint_boundary(it->point))
|
||||
{
|
||||
// may be front and back
|
||||
bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
it->operations[other_op_id],
|
||||
other_boundary_checker,
|
||||
other_id);
|
||||
bool const other_b = is_ip_on_boundary(it->point,
|
||||
it->operations[other_op_id],
|
||||
other_boundary_checker);
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
@ -503,9 +488,8 @@ struct linear_linear
|
||||
// it's the first point in range
|
||||
if ( first_in_range )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_range(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(sub_range(geometry, seg_id)));
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
@ -517,16 +501,14 @@ struct linear_linear
|
||||
// method other than crosses, check more conditions
|
||||
else
|
||||
{
|
||||
bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker,
|
||||
seg_id);
|
||||
|
||||
bool const other_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
it->operations[other_op_id],
|
||||
other_boundary_checker,
|
||||
other_id);
|
||||
bool const this_b = is_ip_on_boundary(it->point,
|
||||
it->operations[op_id],
|
||||
boundary_checker);
|
||||
|
||||
bool const other_b = is_ip_on_boundary(it->point,
|
||||
it->operations[other_op_id],
|
||||
other_boundary_checker);
|
||||
|
||||
// if current IP is on boundary of the geometry
|
||||
if ( this_b )
|
||||
{
|
||||
@ -562,9 +544,8 @@ struct linear_linear
|
||||
&& ! m_collinear_spike_exit
|
||||
/*&& !is_collinear*/ )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(sub_range(geometry, seg_id)),
|
||||
boundary_checker);
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(sub_range(geometry, seg_id)));
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
@ -621,9 +602,8 @@ struct linear_linear
|
||||
segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
//BOOST_GEOMETRY_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id)));
|
||||
bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_range(geometry, prev_seg_id)),
|
||||
boundary_checker);
|
||||
bool const prev_back_b = boundary_checker.is_endpoint_boundary(
|
||||
range::back(sub_range(geometry, prev_seg_id)));
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
@ -661,19 +641,17 @@ struct linear_linear
|
||||
OtherBoundaryChecker const& other_boundary_checker,
|
||||
bool first_in_range)
|
||||
{
|
||||
typename detail::single_geometry_return_type<Geometry const>::type
|
||||
ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id);
|
||||
typename detail::single_geometry_return_type<OtherGeometry const>::type
|
||||
ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id);
|
||||
auto const& ls1 = detail::single_geometry(geometry, turn.operations[op_id].seg_id);
|
||||
auto const& ls2 = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id);
|
||||
|
||||
// only one of those should be true:
|
||||
|
||||
if ( turn.operations[op_id].position == overlay::position_front )
|
||||
{
|
||||
// valid, point-sized
|
||||
if ( boost::size(ls2_ref) == 2 )
|
||||
if ( boost::size(ls2) == 2 )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker);
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(turn.point);
|
||||
|
||||
if ( front_b )
|
||||
{
|
||||
@ -693,11 +671,11 @@ struct linear_linear
|
||||
else if ( turn.operations[op_id].position == overlay::position_back )
|
||||
{
|
||||
// valid, point-sized
|
||||
if ( boost::size(ls2_ref) == 2 )
|
||||
if ( boost::size(ls2) == 2 )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker);
|
||||
bool const back_b = boundary_checker.is_endpoint_boundary(turn.point);
|
||||
|
||||
if ( back_b )
|
||||
{
|
||||
@ -710,9 +688,9 @@ struct linear_linear
|
||||
|
||||
if ( first_in_range )
|
||||
{
|
||||
//BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref));
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(ls1_ref), boundary_checker);
|
||||
//BOOST_GEOMETRY_ASSERT(!boost::empty(ls1));
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(ls1));
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
@ -727,13 +705,13 @@ struct linear_linear
|
||||
|
||||
// here we don't know which one is degenerated
|
||||
|
||||
bool const is_point1 = boost::size(ls1_ref) == 2
|
||||
&& equals::equals_point_point(range::front(ls1_ref),
|
||||
range::back(ls1_ref),
|
||||
bool const is_point1 = boost::size(ls1) == 2
|
||||
&& equals::equals_point_point(range::front(ls1),
|
||||
range::back(ls1),
|
||||
boundary_checker.strategy());
|
||||
bool const is_point2 = boost::size(ls2_ref) == 2
|
||||
&& equals::equals_point_point(range::front(ls2_ref),
|
||||
range::back(ls2_ref),
|
||||
bool const is_point2 = boost::size(ls2) == 2
|
||||
&& equals::equals_point_point(range::front(ls2),
|
||||
range::back(ls2),
|
||||
other_boundary_checker.strategy());
|
||||
|
||||
// if the second one is degenerated
|
||||
@ -743,9 +721,9 @@ struct linear_linear
|
||||
|
||||
if ( first_in_range )
|
||||
{
|
||||
//BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref));
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
range::front(ls1_ref), boundary_checker);
|
||||
//BOOST_GEOMETRY_ASSERT(!boost::empty(ls1));
|
||||
bool const front_b = boundary_checker.is_endpoint_boundary(
|
||||
range::front(ls1));
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013-2020.
|
||||
// Modifications copyright (c) 2013-2020 Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013-2022.
|
||||
// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
|
||||
@ -20,6 +20,8 @@
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
|
||||
|
||||
#include <boost/geometry/geometries/helper_geometry.hpp>
|
||||
|
||||
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
|
||||
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
|
||||
|
||||
@ -46,7 +48,6 @@ template
|
||||
<
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename Point,
|
||||
typename GetTurnPolicy = detail::get_turns::get_turn_info_type
|
||||
<
|
||||
Geometry1, Geometry2, assign_policy<>
|
||||
@ -54,6 +55,11 @@ template
|
||||
>
|
||||
struct get_turns
|
||||
{
|
||||
using turn_point_type = typename helper_geometry
|
||||
<
|
||||
typename geometry::point_type<Geometry1>::type
|
||||
>::type;
|
||||
|
||||
template <typename Strategy>
|
||||
struct robust_policy_type
|
||||
: geometry::rescale_overlay_policy_type
|
||||
@ -71,14 +77,14 @@ struct get_turns
|
||||
>
|
||||
struct turn_info_type
|
||||
{
|
||||
using ratio_type = typename segment_ratio_type<Point, RobustPolicy>::type;
|
||||
using ratio_type = typename segment_ratio_type<turn_point_type, RobustPolicy>::type;
|
||||
using type = overlay::turn_info
|
||||
<
|
||||
Point,
|
||||
turn_point_type,
|
||||
ratio_type,
|
||||
typename detail::get_turns::turn_operation_type
|
||||
<
|
||||
Geometry1, Geometry2, Point, ratio_type
|
||||
Geometry1, Geometry2, turn_point_type, ratio_type
|
||||
>::type
|
||||
>;
|
||||
};
|
||||
@ -166,7 +172,7 @@ struct less_op_xxx_linear
|
||||
|
||||
template <std::size_t OpId>
|
||||
struct less_op_linear_linear
|
||||
: less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> >
|
||||
: less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> > // xuic
|
||||
{};
|
||||
|
||||
template <std::size_t OpId>
|
||||
@ -269,7 +275,7 @@ struct less_other_multi_index
|
||||
|
||||
// sort turns by G1 - source_index == 0 by:
|
||||
// seg_id -> distance and coordinates -> operation
|
||||
template <std::size_t OpId, typename LessOp, typename CSTag>
|
||||
template <std::size_t OpId, typename LessOp, typename Strategy>
|
||||
struct less
|
||||
{
|
||||
BOOST_STATIC_ASSERT(OpId < 2);
|
||||
@ -277,14 +283,8 @@ struct less
|
||||
template <typename Turn>
|
||||
static inline bool use_fraction(Turn const& left, Turn const& right)
|
||||
{
|
||||
typedef typename geometry::strategy::within::services::default_strategy
|
||||
<
|
||||
typename Turn::point_type, typename Turn::point_type,
|
||||
point_tag, point_tag,
|
||||
pointlike_tag, pointlike_tag,
|
||||
typename tag_cast<CSTag, spherical_tag>::type,
|
||||
typename tag_cast<CSTag, spherical_tag>::type
|
||||
>::type eq_pp_strategy_type;
|
||||
using eq_pp_strategy_type = decltype(std::declval<Strategy>().relate(
|
||||
detail::dummy_point(), detail::dummy_point()));
|
||||
|
||||
static LessOp less_op;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2015-2020, Oracle and/or its affiliates.
|
||||
// Copyright (c) 2015-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
|
||||
@ -87,7 +87,6 @@ struct check_turn_less
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
typename bg::point_type<Geometry1>::type,
|
||||
bg::detail::get_turns::get_turn_info_type
|
||||
<
|
||||
Geometry1, Geometry2, assign_policy<>
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014-2021, Oracle and/or its affiliates.
|
||||
// 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
|
||||
@ -84,7 +84,6 @@ private:
|
||||
<
|
||||
LinearGeometry1,
|
||||
LinearGeometry2,
|
||||
typename bg::point_type<LinearGeometry1>::type,
|
||||
bg_detail::get_turns::get_turn_info_type
|
||||
<
|
||||
LinearGeometry1,
|
||||
@ -110,7 +109,7 @@ public:
|
||||
|
||||
typedef typename bg_detail::relate::turns::get_turns
|
||||
<
|
||||
Linear1, Linear2, typename bg::point_type<Linear1>::type
|
||||
Linear1, Linear2
|
||||
>::template turn_info_type<strategy_type>::type turn_info;
|
||||
|
||||
typedef std::vector<turn_info> turns_container;
|
||||
|
Loading…
x
Reference in New Issue
Block a user