add boost on mac
This commit is contained in:
@@ -0,0 +1,884 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// 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.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
|
||||
|
||||
#include <boost/geometry/core/topological_dimension.hpp>
|
||||
|
||||
#include <boost/geometry/util/condition.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/num_interior_rings.hpp>
|
||||
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
|
||||
#include <boost/geometry/algorithms/detail/sub_range.hpp>
|
||||
#include <boost/geometry/algorithms/detail/single_geometry.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// WARNING!
|
||||
// TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM)
|
||||
// Use the rtree in this case!
|
||||
|
||||
// may be used to set EI and EB for an Areal geometry for which no turns were generated
|
||||
template
|
||||
<
|
||||
typename OtherAreal,
|
||||
typename Result,
|
||||
typename PointInArealStrategy,
|
||||
bool TransposeResult
|
||||
>
|
||||
class no_turns_aa_pred
|
||||
{
|
||||
public:
|
||||
no_turns_aa_pred(OtherAreal const& other_areal,
|
||||
Result & res,
|
||||
PointInArealStrategy const& point_in_areal_strategy)
|
||||
: m_result(res)
|
||||
, m_point_in_areal_strategy(point_in_areal_strategy)
|
||||
, m_other_areal(other_areal)
|
||||
, m_flags(0)
|
||||
{
|
||||
// check which relations must be analysed
|
||||
|
||||
if ( ! may_update<interior, interior, '2', TransposeResult>(m_result)
|
||||
&& ! may_update<boundary, interior, '1', TransposeResult>(m_result)
|
||||
&& ! may_update<exterior, interior, '2', TransposeResult>(m_result) )
|
||||
{
|
||||
m_flags |= 1;
|
||||
}
|
||||
|
||||
if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result)
|
||||
&& ! may_update<boundary, exterior, '1', TransposeResult>(m_result) )
|
||||
{
|
||||
m_flags |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Areal>
|
||||
bool operator()(Areal const& areal)
|
||||
{
|
||||
using detail::within::point_in_geometry;
|
||||
|
||||
// if those flags are set nothing will change
|
||||
if ( m_flags == 3 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef typename geometry::point_type<Areal>::type point_type;
|
||||
point_type pt;
|
||||
bool const ok = boost::geometry::point_on_border(pt, areal);
|
||||
|
||||
// TODO: for now ignore, later throw an exception?
|
||||
if ( !ok )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if the areal is inside the other_areal
|
||||
// TODO: This is O(N)
|
||||
// Run in a loop O(NM) - optimize!
|
||||
int const pig = point_in_geometry(pt,
|
||||
m_other_areal,
|
||||
m_point_in_areal_strategy);
|
||||
//BOOST_GEOMETRY_ASSERT( pig != 0 );
|
||||
|
||||
// inside
|
||||
if ( pig > 0 )
|
||||
{
|
||||
update<interior, interior, '2', TransposeResult>(m_result);
|
||||
update<boundary, interior, '1', TransposeResult>(m_result);
|
||||
update<exterior, interior, '2', TransposeResult>(m_result);
|
||||
m_flags |= 1;
|
||||
|
||||
// TODO: OPTIMIZE!
|
||||
// Only the interior rings of other ONE single geometry must be checked
|
||||
// NOT all geometries
|
||||
|
||||
// Check if any interior ring is outside
|
||||
ring_identifier ring_id(0, -1, 0);
|
||||
std::size_t const irings_count = geometry::num_interior_rings(areal);
|
||||
for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
|
||||
++ring_id.ring_index )
|
||||
{
|
||||
typename detail::sub_range_return_type<Areal const>::type
|
||||
range_ref = detail::sub_range(areal, ring_id);
|
||||
|
||||
if ( boost::empty(range_ref) )
|
||||
{
|
||||
// TODO: throw exception?
|
||||
continue; // ignore
|
||||
}
|
||||
|
||||
// TODO: O(N)
|
||||
// Optimize!
|
||||
int const hpig = point_in_geometry(range::front(range_ref),
|
||||
m_other_areal,
|
||||
m_point_in_areal_strategy);
|
||||
|
||||
// hole outside
|
||||
if ( hpig < 0 )
|
||||
{
|
||||
update<interior, exterior, '2', TransposeResult>(m_result);
|
||||
update<boundary, exterior, '1', TransposeResult>(m_result);
|
||||
m_flags |= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// outside
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '2', TransposeResult>(m_result);
|
||||
update<boundary, exterior, '1', TransposeResult>(m_result);
|
||||
m_flags |= 2;
|
||||
|
||||
// Check if any interior ring is inside
|
||||
ring_identifier ring_id(0, -1, 0);
|
||||
std::size_t const irings_count = geometry::num_interior_rings(areal);
|
||||
for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ;
|
||||
++ring_id.ring_index )
|
||||
{
|
||||
typename detail::sub_range_return_type<Areal const>::type
|
||||
range_ref = detail::sub_range(areal, ring_id);
|
||||
|
||||
if ( boost::empty(range_ref) )
|
||||
{
|
||||
// TODO: throw exception?
|
||||
continue; // ignore
|
||||
}
|
||||
|
||||
// TODO: O(N)
|
||||
// Optimize!
|
||||
int const hpig = point_in_geometry(range::front(range_ref),
|
||||
m_other_areal,
|
||||
m_point_in_areal_strategy);
|
||||
|
||||
// hole inside
|
||||
if ( hpig > 0 )
|
||||
{
|
||||
update<interior, interior, '2', TransposeResult>(m_result);
|
||||
update<boundary, interior, '1', TransposeResult>(m_result);
|
||||
update<exterior, interior, '2', TransposeResult>(m_result);
|
||||
m_flags |= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_flags != 3 && !m_result.interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
Result & m_result;
|
||||
PointInArealStrategy const& m_point_in_areal_strategy;
|
||||
OtherAreal const& m_other_areal;
|
||||
int m_flags;
|
||||
};
|
||||
|
||||
// The implementation of an algorithm calculating relate() for A/A
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct areal_areal
|
||||
{
|
||||
// check Linear / Areal
|
||||
BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2
|
||||
&& topological_dimension<Geometry2>::value == 2);
|
||||
|
||||
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 IntersectionStrategy>
|
||||
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
Result & result,
|
||||
IntersectionStrategy const& intersection_strategy)
|
||||
{
|
||||
// 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>(result);// FFFFFFFFd, d in [1,9] or T
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
|
||||
// get and analyse turns
|
||||
typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
|
||||
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy);
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
|
||||
typedef typename IntersectionStrategy::template point_in_geometry_strategy
|
||||
<
|
||||
Geometry1, Geometry2
|
||||
>::type point_in_areal_strategy12_type;
|
||||
point_in_areal_strategy12_type point_in_areal_strategy12
|
||||
= intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>();
|
||||
typedef typename IntersectionStrategy::template point_in_geometry_strategy
|
||||
<
|
||||
Geometry2, Geometry1
|
||||
>::type point_in_areal_strategy21_type;
|
||||
point_in_areal_strategy21_type point_in_areal_strategy21
|
||||
= intersection_strategy.template get_point_in_geometry_strategy<Geometry2, Geometry1>();
|
||||
|
||||
no_turns_aa_pred<Geometry2, Result, point_in_areal_strategy12_type, false>
|
||||
pred1(geometry2, result, point_in_areal_strategy12);
|
||||
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
|
||||
no_turns_aa_pred<Geometry1, Result, point_in_areal_strategy21_type, true>
|
||||
pred2(geometry1, result, point_in_areal_strategy21);
|
||||
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
|
||||
if ( turns.empty() )
|
||||
return;
|
||||
|
||||
if ( may_update<interior, interior, '2'>(result)
|
||||
|| may_update<interior, exterior, '2'>(result)
|
||||
|| may_update<boundary, interior, '1'>(result)
|
||||
|| may_update<boundary, exterior, '1'>(result)
|
||||
|| may_update<exterior, interior, '2'>(result) )
|
||||
{
|
||||
// sort turns
|
||||
typedef turns::less<0, turns::less_op_areal_areal<0> > less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
|
||||
/*if ( may_update<interior, exterior, '2'>(result)
|
||||
|| may_update<boundary, exterior, '1'>(result)
|
||||
|| may_update<boundary, interior, '1'>(result)
|
||||
|| may_update<exterior, interior, '2'>(result) )*/
|
||||
{
|
||||
// analyse sorted turns
|
||||
turns_analyser<turn_type, 0> analyser;
|
||||
analyse_each_turn(result, analyser, turns.begin(), turns.end(),
|
||||
point_in_areal_strategy12.get_equals_point_point_strategy());
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( may_update<interior, interior, '2'>(result)
|
||||
|| may_update<interior, exterior, '2'>(result)
|
||||
|| may_update<boundary, interior, '1'>(result)
|
||||
|| may_update<boundary, exterior, '1'>(result)
|
||||
|| may_update<exterior, interior, '2'>(result) )
|
||||
{
|
||||
// analyse rings for which turns were not generated
|
||||
// or only i/i or u/u was generated
|
||||
uncertain_rings_analyser<0, Result, Geometry1, Geometry2, point_in_areal_strategy12_type>
|
||||
rings_analyser(result, geometry1, geometry2, point_in_areal_strategy12);
|
||||
analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( may_update<interior, interior, '2', true>(result)
|
||||
|| may_update<interior, exterior, '2', true>(result)
|
||||
|| may_update<boundary, interior, '1', true>(result)
|
||||
|| may_update<boundary, exterior, '1', true>(result)
|
||||
|| may_update<exterior, interior, '2', true>(result) )
|
||||
{
|
||||
// sort turns
|
||||
typedef turns::less<1, turns::less_op_areal_areal<1> > less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
|
||||
/*if ( may_update<interior, exterior, '2', true>(result)
|
||||
|| may_update<boundary, exterior, '1', true>(result)
|
||||
|| may_update<boundary, interior, '1', true>(result)
|
||||
|| may_update<exterior, interior, '2', true>(result) )*/
|
||||
{
|
||||
// analyse sorted turns
|
||||
turns_analyser<turn_type, 1> analyser;
|
||||
analyse_each_turn(result, analyser, turns.begin(), turns.end(),
|
||||
point_in_areal_strategy21.get_equals_point_point_strategy());
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( may_update<interior, interior, '2', true>(result)
|
||||
|| may_update<interior, exterior, '2', true>(result)
|
||||
|| may_update<boundary, interior, '1', true>(result)
|
||||
|| may_update<boundary, exterior, '1', true>(result)
|
||||
|| may_update<exterior, interior, '2', true>(result) )
|
||||
{
|
||||
// analyse rings for which turns were not generated
|
||||
// or only i/i or u/u was generated
|
||||
uncertain_rings_analyser<1, Result, Geometry2, Geometry1, point_in_areal_strategy21_type>
|
||||
rings_analyser(result, geometry2, geometry1, point_in_areal_strategy21);
|
||||
analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end());
|
||||
|
||||
//if ( result.interrupt )
|
||||
// return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// interrupt policy which may be passed to get_turns to interrupt the analysis
|
||||
// based on the info in the passed result/mask
|
||||
template <typename Result>
|
||||
class interrupt_policy_areal_areal
|
||||
{
|
||||
public:
|
||||
static bool const enabled = true;
|
||||
|
||||
interrupt_policy_areal_areal(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Result & result)
|
||||
: m_result(result)
|
||||
, m_geometry1(geometry1)
|
||||
, m_geometry2(geometry2)
|
||||
{}
|
||||
|
||||
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)
|
||||
{
|
||||
per_turn<0>(*it);
|
||||
per_turn<1>(*it);
|
||||
}
|
||||
|
||||
return m_result.interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
template <std::size_t OpId, typename Turn>
|
||||
inline void per_turn(Turn const& turn)
|
||||
{
|
||||
//static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
overlay::operation_type const op = turn.operations[OpId].operation;
|
||||
|
||||
if ( op == overlay::operation_union )
|
||||
{
|
||||
// ignore u/u
|
||||
/*if ( turn.operations[other_op_id].operation != overlay::operation_union )
|
||||
{
|
||||
update<interior, exterior, '2', transpose_result>(m_result);
|
||||
update<boundary, exterior, '1', transpose_result>(m_result);
|
||||
}*/
|
||||
|
||||
update<boundary, boundary, '0', transpose_result>(m_result);
|
||||
}
|
||||
else if ( op == overlay::operation_intersection )
|
||||
{
|
||||
// ignore i/i
|
||||
/*if ( turn.operations[other_op_id].operation != overlay::operation_intersection )
|
||||
{
|
||||
// not correct e.g. for G1 touching G2 in a point where a hole is touching the exterior ring
|
||||
// in this case 2 turns i/... and u/u will be generated for this IP
|
||||
//update<interior, interior, '2', transpose_result>(m_result);
|
||||
|
||||
//update<boundary, interior, '1', transpose_result>(m_result);
|
||||
}*/
|
||||
|
||||
update<boundary, boundary, '0', transpose_result>(m_result);
|
||||
}
|
||||
else if ( op == overlay::operation_continue )
|
||||
{
|
||||
update<boundary, boundary, '1', transpose_result>(m_result);
|
||||
update<interior, interior, '2', transpose_result>(m_result);
|
||||
}
|
||||
else if ( op == overlay::operation_blocked )
|
||||
{
|
||||
update<boundary, boundary, '1', transpose_result>(m_result);
|
||||
update<interior, exterior, '2', transpose_result>(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
Result & m_result;
|
||||
Geometry1 const& m_geometry1;
|
||||
Geometry2 const& m_geometry2;
|
||||
};
|
||||
|
||||
// This analyser should be used like Input or SinglePass Iterator
|
||||
// IMPORTANT! It should be called also for the end iterator - last
|
||||
template <typename TurnInfo, std::size_t OpId>
|
||||
class turns_analyser
|
||||
{
|
||||
typedef typename TurnInfo::point_type turn_point_type;
|
||||
|
||||
static const std::size_t op_id = OpId;
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
public:
|
||||
turns_analyser()
|
||||
: m_previous_turn_ptr(0)
|
||||
, m_previous_operation(overlay::operation_none)
|
||||
, m_enter_detected(false)
|
||||
, m_exit_detected(false)
|
||||
{}
|
||||
|
||||
template <typename Result, typename TurnIt, typename EqPPStrategy>
|
||||
void apply(Result & result, TurnIt it, EqPPStrategy const& strategy)
|
||||
{
|
||||
//BOOST_GEOMETRY_ASSERT( it != last );
|
||||
|
||||
overlay::operation_type const op = it->operations[op_id].operation;
|
||||
|
||||
if ( op != overlay::operation_union
|
||||
&& op != overlay::operation_intersection
|
||||
&& op != overlay::operation_blocked
|
||||
&& op != overlay::operation_continue )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
segment_identifier const& seg_id = it->operations[op_id].seg_id;
|
||||
//segment_identifier const& other_id = it->operations[other_op_id].seg_id;
|
||||
|
||||
const bool first_in_range = m_seg_watcher.update(seg_id);
|
||||
|
||||
if ( m_previous_turn_ptr )
|
||||
{
|
||||
if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
|
||||
{
|
||||
// real exit point - may be multiple
|
||||
if ( first_in_range
|
||||
|| ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
|
||||
{
|
||||
update_exit(result);
|
||||
m_exit_detected = false;
|
||||
}
|
||||
// fake exit point, reset state
|
||||
else if ( op != overlay::operation_union )
|
||||
{
|
||||
m_exit_detected = false;
|
||||
}
|
||||
}
|
||||
/*else*/
|
||||
if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
|
||||
{
|
||||
// real entry point
|
||||
if ( first_in_range
|
||||
|| ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) )
|
||||
{
|
||||
update_enter(result);
|
||||
m_enter_detected = false;
|
||||
}
|
||||
// fake entry point, reset state
|
||||
else if ( op != overlay::operation_intersection )
|
||||
{
|
||||
m_enter_detected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( op == overlay::operation_union )
|
||||
{
|
||||
// already set in interrupt policy
|
||||
//update<boundary, boundary, '0', transpose_result>(m_result);
|
||||
|
||||
// ignore u/u
|
||||
//if ( it->operations[other_op_id].operation != overlay::operation_union )
|
||||
{
|
||||
m_exit_detected = true;
|
||||
}
|
||||
}
|
||||
else if ( op == overlay::operation_intersection )
|
||||
{
|
||||
// ignore i/i
|
||||
if ( it->operations[other_op_id].operation != overlay::operation_intersection )
|
||||
{
|
||||
// this was set in the interrupt policy but it was wrong
|
||||
// also here it's wrong since it may be a fake entry point
|
||||
//update<interior, interior, '2', transpose_result>(result);
|
||||
|
||||
// already set in interrupt policy
|
||||
//update<boundary, boundary, '0', transpose_result>(result);
|
||||
m_enter_detected = true;
|
||||
}
|
||||
}
|
||||
else if ( op == overlay::operation_blocked )
|
||||
{
|
||||
// already set in interrupt policy
|
||||
}
|
||||
else // if ( op == overlay::operation_continue )
|
||||
{
|
||||
// already set in interrupt policy
|
||||
}
|
||||
|
||||
// store ref to previously analysed (valid) turn
|
||||
m_previous_turn_ptr = boost::addressof(*it);
|
||||
// and previously analysed (valid) operation
|
||||
m_previous_operation = op;
|
||||
}
|
||||
|
||||
// it == last
|
||||
template <typename Result>
|
||||
void apply(Result & result)
|
||||
{
|
||||
//BOOST_GEOMETRY_ASSERT( first != last );
|
||||
|
||||
if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ )
|
||||
{
|
||||
update_exit(result);
|
||||
m_exit_detected = false;
|
||||
}
|
||||
|
||||
if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ )
|
||||
{
|
||||
update_enter(result);
|
||||
m_enter_detected = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
static inline void update_exit(Result & result)
|
||||
{
|
||||
update<interior, exterior, '2', transpose_result>(result);
|
||||
update<boundary, exterior, '1', transpose_result>(result);
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
static inline void update_enter(Result & result)
|
||||
{
|
||||
update<interior, interior, '2', transpose_result>(result);
|
||||
update<boundary, interior, '1', transpose_result>(result);
|
||||
update<exterior, interior, '2', transpose_result>(result);
|
||||
}
|
||||
|
||||
private:
|
||||
segment_watcher<same_ring> m_seg_watcher;
|
||||
TurnInfo * m_previous_turn_ptr;
|
||||
overlay::operation_type m_previous_operation;
|
||||
bool m_enter_detected;
|
||||
bool m_exit_detected;
|
||||
};
|
||||
|
||||
// call analyser.apply() for each turn in range
|
||||
// IMPORTANT! The analyser is also called for the end iterator - last
|
||||
template
|
||||
<
|
||||
typename Result,
|
||||
typename Analyser,
|
||||
typename TurnIt,
|
||||
typename EqPPStrategy
|
||||
>
|
||||
static inline void analyse_each_turn(Result & res,
|
||||
Analyser & analyser,
|
||||
TurnIt first, TurnIt last,
|
||||
EqPPStrategy const& strategy)
|
||||
{
|
||||
if ( first == last )
|
||||
return;
|
||||
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
analyser.apply(res, it, strategy);
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(res.interrupt) )
|
||||
return;
|
||||
}
|
||||
|
||||
analyser.apply(res);
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
std::size_t OpId,
|
||||
typename Result,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename PointInArealStrategy
|
||||
>
|
||||
class uncertain_rings_analyser
|
||||
{
|
||||
static const bool transpose_result = OpId != 0;
|
||||
static const int other_id = (OpId + 1) % 2;
|
||||
|
||||
public:
|
||||
inline uncertain_rings_analyser(Result & result,
|
||||
Geometry const& geom,
|
||||
OtherGeometry const& other_geom,
|
||||
PointInArealStrategy const& point_in_areal_strategy)
|
||||
: geometry(geom)
|
||||
, other_geometry(other_geom)
|
||||
, interrupt(result.interrupt) // just in case, could be false as well
|
||||
, m_result(result)
|
||||
, m_point_in_areal_strategy(point_in_areal_strategy)
|
||||
, m_flags(0)
|
||||
{
|
||||
// check which relations must be analysed
|
||||
// NOTE: 1 and 4 could probably be connected
|
||||
|
||||
if ( ! may_update<interior, interior, '2', transpose_result>(m_result) )
|
||||
{
|
||||
m_flags |= 1;
|
||||
}
|
||||
|
||||
if ( ! may_update<interior, exterior, '2', transpose_result>(m_result)
|
||||
&& ! may_update<boundary, exterior, '1', transpose_result>(m_result) )
|
||||
{
|
||||
m_flags |= 2;
|
||||
}
|
||||
|
||||
if ( ! may_update<boundary, interior, '1', transpose_result>(m_result)
|
||||
&& ! may_update<exterior, interior, '2', transpose_result>(m_result) )
|
||||
{
|
||||
m_flags |= 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline void no_turns(segment_identifier const& seg_id)
|
||||
{
|
||||
// if those flags are set nothing will change
|
||||
if ( m_flags == 7 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
typename detail::sub_range_return_type<Geometry const>::type
|
||||
range_ref = detail::sub_range(geometry, seg_id);
|
||||
|
||||
if ( boost::empty(range_ref) )
|
||||
{
|
||||
// TODO: throw an exception?
|
||||
return; // ignore
|
||||
}
|
||||
|
||||
// TODO: possible optimization
|
||||
// if the range is an interior ring we may use other IPs generated for this single geometry
|
||||
// to know which other single geometries should be checked
|
||||
|
||||
// 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),
|
||||
other_geometry,
|
||||
m_point_in_areal_strategy);
|
||||
|
||||
//BOOST_GEOMETRY_ASSERT(pig != 0);
|
||||
if ( pig > 0 )
|
||||
{
|
||||
update<interior, interior, '2', transpose_result>(m_result);
|
||||
m_flags |= 1;
|
||||
|
||||
update<boundary, interior, '1', transpose_result>(m_result);
|
||||
update<exterior, interior, '2', transpose_result>(m_result);
|
||||
m_flags |= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
update<boundary, exterior, '1', transpose_result>(m_result);
|
||||
update<interior, exterior, '2', transpose_result>(m_result);
|
||||
m_flags |= 2;
|
||||
}
|
||||
|
||||
// TODO: break if all things are set
|
||||
// also some of them could be checked outside, before the analysis
|
||||
// In this case we shouldn't relay just on dummy flags
|
||||
// Flags should be initialized with proper values
|
||||
// or the result should be checked directly
|
||||
// THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A
|
||||
|
||||
interrupt = m_flags == 7 || m_result.interrupt;
|
||||
}
|
||||
|
||||
template <typename TurnIt>
|
||||
inline void turns(TurnIt first, TurnIt last)
|
||||
{
|
||||
// if those flags are set nothing will change
|
||||
if ( (m_flags & 6) == 6 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool found_ii = false;
|
||||
bool found_uu = false;
|
||||
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
if ( it->operations[0].operation == overlay::operation_intersection
|
||||
&& it->operations[1].operation == overlay::operation_intersection )
|
||||
{
|
||||
found_ii = true;
|
||||
}
|
||||
else if ( it->operations[0].operation == overlay::operation_union
|
||||
&& it->operations[1].operation == overlay::operation_union )
|
||||
{
|
||||
found_uu = true;
|
||||
}
|
||||
else // ignore
|
||||
{
|
||||
return; // don't interrupt
|
||||
}
|
||||
}
|
||||
|
||||
// only i/i was generated for this ring
|
||||
if ( found_ii )
|
||||
{
|
||||
update<interior, interior, '2', transpose_result>(m_result);
|
||||
m_flags |= 1;
|
||||
|
||||
//update<boundary, boundary, '0', transpose_result>(m_result);
|
||||
|
||||
update<boundary, interior, '1', transpose_result>(m_result);
|
||||
update<exterior, interior, '2', transpose_result>(m_result);
|
||||
m_flags |= 4;
|
||||
}
|
||||
|
||||
// only u/u was generated for this ring
|
||||
if ( found_uu )
|
||||
{
|
||||
update<boundary, exterior, '1', transpose_result>(m_result);
|
||||
update<interior, exterior, '2', transpose_result>(m_result);
|
||||
m_flags |= 2;
|
||||
}
|
||||
|
||||
interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future
|
||||
}
|
||||
|
||||
Geometry const& geometry;
|
||||
OtherGeometry const& other_geometry;
|
||||
bool interrupt;
|
||||
|
||||
private:
|
||||
Result & m_result;
|
||||
PointInArealStrategy const& m_point_in_areal_strategy;
|
||||
int m_flags;
|
||||
};
|
||||
|
||||
template <std::size_t OpId>
|
||||
class analyse_uncertain_rings
|
||||
{
|
||||
public:
|
||||
template <typename Analyser, typename TurnIt>
|
||||
static inline void apply(Analyser & analyser, TurnIt first, TurnIt last)
|
||||
{
|
||||
if ( first == last )
|
||||
return;
|
||||
|
||||
for_preceding_rings(analyser, *first);
|
||||
//analyser.per_turn(*first);
|
||||
|
||||
TurnIt prev = first;
|
||||
for ( ++first ; first != last ; ++first, ++prev )
|
||||
{
|
||||
// same multi
|
||||
if ( prev->operations[OpId].seg_id.multi_index
|
||||
== first->operations[OpId].seg_id.multi_index )
|
||||
{
|
||||
// same ring
|
||||
if ( prev->operations[OpId].seg_id.ring_index
|
||||
== first->operations[OpId].seg_id.ring_index )
|
||||
{
|
||||
//analyser.per_turn(*first);
|
||||
}
|
||||
// same multi, next ring
|
||||
else
|
||||
{
|
||||
//analyser.end_ring(*prev);
|
||||
analyser.turns(prev, first);
|
||||
|
||||
//if ( prev->operations[OpId].seg_id.ring_index + 1
|
||||
// < first->operations[OpId].seg_id.ring_index)
|
||||
{
|
||||
for_no_turns_rings(analyser,
|
||||
*first,
|
||||
prev->operations[OpId].seg_id.ring_index + 1,
|
||||
first->operations[OpId].seg_id.ring_index);
|
||||
}
|
||||
|
||||
//analyser.per_turn(*first);
|
||||
}
|
||||
}
|
||||
// next multi
|
||||
else
|
||||
{
|
||||
//analyser.end_ring(*prev);
|
||||
analyser.turns(prev, first);
|
||||
for_following_rings(analyser, *prev);
|
||||
for_preceding_rings(analyser, *first);
|
||||
//analyser.per_turn(*first);
|
||||
}
|
||||
|
||||
if ( analyser.interrupt )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//analyser.end_ring(*prev);
|
||||
analyser.turns(prev, first); // first == last
|
||||
for_following_rings(analyser, *prev);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Analyser, typename Turn>
|
||||
static inline void for_preceding_rings(Analyser & analyser, Turn const& turn)
|
||||
{
|
||||
segment_identifier const& seg_id = turn.operations[OpId].seg_id;
|
||||
|
||||
for_no_turns_rings(analyser, turn, -1, seg_id.ring_index);
|
||||
}
|
||||
|
||||
template <typename Analyser, typename Turn>
|
||||
static inline void for_following_rings(Analyser & analyser, Turn const& turn)
|
||||
{
|
||||
segment_identifier const& seg_id = turn.operations[OpId].seg_id;
|
||||
|
||||
signed_size_type
|
||||
count = boost::numeric_cast<signed_size_type>(
|
||||
geometry::num_interior_rings(
|
||||
detail::single_geometry(analyser.geometry, seg_id)));
|
||||
|
||||
for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count);
|
||||
}
|
||||
|
||||
template <typename Analyser, typename Turn>
|
||||
static inline void for_no_turns_rings(Analyser & analyser,
|
||||
Turn const& turn,
|
||||
signed_size_type first,
|
||||
signed_size_type last)
|
||||
{
|
||||
segment_identifier seg_id = turn.operations[OpId].seg_id;
|
||||
|
||||
for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index )
|
||||
{
|
||||
analyser.no_turns(seg_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
|
||||
@@ -0,0 +1,174 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014-2018 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/sub_range.hpp>
|
||||
#include <boost/geometry/algorithms/num_points.hpp>
|
||||
|
||||
#include <boost/geometry/policies/compare.hpp>
|
||||
|
||||
#include <boost/geometry/util/has_nan_coordinate.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
enum boundary_query { boundary_front, boundary_back, boundary_any };
|
||||
|
||||
template <typename Geometry,
|
||||
typename WithinStrategy, // Point/Point equals (within) strategy
|
||||
typename Tag = typename geometry::tag<Geometry>::type>
|
||||
class boundary_checker {};
|
||||
|
||||
template <typename Geometry, typename WithinStrategy>
|
||||
class boundary_checker<Geometry, WithinStrategy, linestring_tag>
|
||||
{
|
||||
typedef typename point_type<Geometry>::type point_type;
|
||||
|
||||
public:
|
||||
typedef WithinStrategy equals_strategy_type;
|
||||
|
||||
boundary_checker(Geometry const& g)
|
||||
: has_boundary( boost::size(g) >= 2
|
||||
&& !detail::equals::equals_point_point(range::front(g),
|
||||
range::back(g),
|
||||
equals_strategy_type()) )
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
|
||||
, geometry(g)
|
||||
#endif
|
||||
{}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_endpoint_boundary(point_type 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(geometry), WithinStrategy())
|
||||
|| (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& detail::equals::equals_point_point(pt, range::back(geometry), WithinStrategy()) );
|
||||
#endif
|
||||
return has_boundary;
|
||||
}
|
||||
|
||||
private:
|
||||
bool has_boundary;
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
|
||||
Geometry const& geometry;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename Geometry, typename WithinStrategy>
|
||||
class boundary_checker<Geometry, WithinStrategy, multi_linestring_tag>
|
||||
{
|
||||
typedef typename point_type<Geometry>::type point_type;
|
||||
|
||||
public:
|
||||
typedef WithinStrategy equals_strategy_type;
|
||||
|
||||
boundary_checker(Geometry const& g)
|
||||
: is_filled(false), geometry(g)
|
||||
{}
|
||||
|
||||
// First call O(NlogN)
|
||||
// Each next call O(logN)
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_endpoint_boundary(point_type const& pt) const
|
||||
{
|
||||
typedef typename boost::range_size<Geometry>::type size_type;
|
||||
size_type multi_count = boost::size(geometry);
|
||||
|
||||
if ( multi_count < 1 )
|
||||
return false;
|
||||
|
||||
if ( ! is_filled )
|
||||
{
|
||||
//boundary_points.clear();
|
||||
boundary_points.reserve(multi_count * 2);
|
||||
|
||||
typedef typename boost::range_iterator<Geometry const>::type multi_iterator;
|
||||
for ( multi_iterator it = boost::begin(geometry) ;
|
||||
it != boost::end(geometry) ; ++ it )
|
||||
{
|
||||
typename boost::range_reference<Geometry const>::type
|
||||
ls = *it;
|
||||
|
||||
// empty or point - no boundary
|
||||
if (boost::size(ls) < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
typedef typename boost::range_reference
|
||||
<
|
||||
typename boost::range_value<Geometry const>::type const
|
||||
>::type point_reference;
|
||||
|
||||
point_reference front_pt = range::front(ls);
|
||||
point_reference back_pt = range::back(ls);
|
||||
|
||||
// linear ring or point - no boundary
|
||||
if (! equals::equals_point_point(front_pt, back_pt, equals_strategy_type()))
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
boundary_points.push_back(front_pt);
|
||||
}
|
||||
if (! geometry::has_nan_coordinate(back_pt))
|
||||
{
|
||||
boundary_points.push_back(back_pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(boundary_points.begin(),
|
||||
boundary_points.end(),
|
||||
geometry::less<point_type>());
|
||||
|
||||
is_filled = true;
|
||||
}
|
||||
|
||||
std::size_t equal_points_count
|
||||
= boost::size(
|
||||
std::equal_range(boundary_points.begin(),
|
||||
boundary_points.end(),
|
||||
pt,
|
||||
geometry::less<point_type>())
|
||||
);
|
||||
|
||||
return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
|
||||
}
|
||||
|
||||
private:
|
||||
mutable bool is_filled;
|
||||
// TODO: store references/pointers instead of points?
|
||||
mutable std::vector<point_type> boundary_points;
|
||||
|
||||
Geometry const& geometry;
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
|
||||
439
macx64/include/boost/geometry/algorithms/detail/relate/de9im.hpp
Normal file
439
macx64/include/boost/geometry/algorithms/detail/relate/de9im.hpp
Normal file
@@ -0,0 +1,439 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014, 2015.
|
||||
// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_DE9IM_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_DE9IM_HPP
|
||||
|
||||
#include <boost/mpl/is_sequence.hpp>
|
||||
#include <boost/mpl/push_back.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/vector_c.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
#include <boost/geometry/algorithms/not_implemented.hpp>
|
||||
#include <boost/geometry/core/topological_dimension.hpp>
|
||||
#include <boost/geometry/core/tag.hpp>
|
||||
|
||||
// TEMP - move this header to geometry/detail
|
||||
#include <boost/geometry/index/detail/tuples.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace de9im
|
||||
{
|
||||
|
||||
/*!
|
||||
\brief DE-9IM model intersection matrix.
|
||||
\ingroup de9im
|
||||
\details This matrix can be used to express spatial relations as defined in
|
||||
Dimensionally Extended 9-Intersection Model.
|
||||
|
||||
\qbk{[heading See also]}
|
||||
\qbk{* [link geometry.reference.algorithms.relation relation]}
|
||||
*/
|
||||
class matrix
|
||||
: public detail::relate::matrix<3, 3>
|
||||
{
|
||||
#ifdef DOXYGEN_INVOKED
|
||||
public:
|
||||
/*!
|
||||
\brief Initializes all of the matrix elements to F
|
||||
*/
|
||||
matrix();
|
||||
/*!
|
||||
\brief Subscript operator
|
||||
\param index The index of the element
|
||||
\return The element
|
||||
*/
|
||||
char operator[](std::size_t index) const;
|
||||
/*!
|
||||
\brief Returns the iterator to the first element
|
||||
\return const RandomAccessIterator
|
||||
*/
|
||||
const_iterator begin() const;
|
||||
/*!
|
||||
\brief Returns the iterator past the last element
|
||||
\return const RandomAccessIterator
|
||||
*/
|
||||
const_iterator end() const;
|
||||
/*!
|
||||
\brief Returns the number of elements
|
||||
\return 9
|
||||
*/
|
||||
static std::size_t size();
|
||||
/*!
|
||||
\brief Returns raw pointer to elements
|
||||
\return const pointer to array of elements
|
||||
*/
|
||||
inline const char * data() const;
|
||||
/*!
|
||||
\brief Returns std::string containing elements
|
||||
\return string containing elements
|
||||
*/
|
||||
inline std::string str() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief DE-9IM model intersection mask.
|
||||
\ingroup de9im
|
||||
\details This mask can be used to check spatial relations as defined in
|
||||
Dimensionally Extended 9-Intersection Model.
|
||||
|
||||
\qbk{[heading See also]}
|
||||
\qbk{* [link geometry.reference.algorithms.relate relate]}
|
||||
*/
|
||||
class mask
|
||||
: public detail::relate::mask<3, 3>
|
||||
{
|
||||
typedef detail::relate::mask<3, 3> base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief The constructor.
|
||||
\param code The mask pattern.
|
||||
*/
|
||||
inline explicit mask(const char* code)
|
||||
: base_type(code)
|
||||
{}
|
||||
|
||||
/*!
|
||||
\brief The constructor.
|
||||
\param code The mask pattern.
|
||||
*/
|
||||
inline explicit mask(std::string const& code)
|
||||
: base_type(code.c_str(), code.size())
|
||||
{}
|
||||
};
|
||||
|
||||
// static_mask
|
||||
|
||||
/*!
|
||||
\brief DE-9IM model intersection mask (static version).
|
||||
\ingroup de9im
|
||||
\details This mask can be used to check spatial relations as defined in
|
||||
Dimensionally Extended 9-Intersection Model.
|
||||
\tparam II Interior/Interior intersection mask element
|
||||
\tparam IB Interior/Boundary intersection mask element
|
||||
\tparam IE Interior/Exterior intersection mask element
|
||||
\tparam BI Boundary/Interior intersection mask element
|
||||
\tparam BB Boundary/Boundary intersection mask element
|
||||
\tparam BE Boundary/Exterior intersection mask element
|
||||
\tparam EI Exterior/Interior intersection mask element
|
||||
\tparam EB Exterior/Boundary intersection mask element
|
||||
\tparam EE Exterior/Exterior intersection mask element
|
||||
|
||||
\qbk{[heading See also]}
|
||||
\qbk{* [link geometry.reference.algorithms.relate relate]}
|
||||
*/
|
||||
template
|
||||
<
|
||||
char II = '*', char IB = '*', char IE = '*',
|
||||
char BI = '*', char BB = '*', char BE = '*',
|
||||
char EI = '*', char EB = '*', char EE = '*'
|
||||
>
|
||||
class static_mask
|
||||
: public detail::relate::static_mask
|
||||
<
|
||||
boost::mpl::vector_c
|
||||
<
|
||||
char, II, IB, IE, BI, BB, BE, EI, EB, EE
|
||||
>,
|
||||
3, 3
|
||||
>
|
||||
{};
|
||||
|
||||
} // namespace de9im
|
||||
|
||||
namespace detail { namespace de9im
|
||||
{
|
||||
|
||||
// a small helper util for ORing static masks
|
||||
|
||||
template
|
||||
<
|
||||
typename Seq,
|
||||
typename T,
|
||||
bool IsSeq = boost::mpl::is_sequence<Seq>::value
|
||||
>
|
||||
struct push_back
|
||||
{
|
||||
typedef typename boost::mpl::push_back
|
||||
<
|
||||
Seq,
|
||||
T
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <typename Seq, typename T>
|
||||
struct push_back<Seq, T, false>
|
||||
{};
|
||||
|
||||
}} // namespace detail::de9im
|
||||
|
||||
namespace de9im
|
||||
{
|
||||
|
||||
inline
|
||||
boost::tuples::cons
|
||||
<
|
||||
mask,
|
||||
boost::tuples::cons<mask, boost::tuples::null_type>
|
||||
>
|
||||
operator||(mask const& m1, mask const& m2)
|
||||
{
|
||||
namespace bt = boost::tuples;
|
||||
|
||||
return bt::cons<mask, bt::cons<mask, bt::null_type> >
|
||||
( m1, bt::cons<mask, bt::null_type>(m2, bt::null_type()) );
|
||||
}
|
||||
|
||||
template <typename Tail>
|
||||
inline
|
||||
typename index::detail::tuples::push_back
|
||||
<
|
||||
boost::tuples::cons<mask, Tail>,
|
||||
mask
|
||||
>::type
|
||||
operator||(boost::tuples::cons<mask, Tail> const& t, mask const& m)
|
||||
{
|
||||
namespace bt = boost::tuples;
|
||||
|
||||
return index::detail::tuples::push_back
|
||||
<
|
||||
bt::cons<mask, Tail>,
|
||||
mask
|
||||
>::apply(t, m);
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
char II1, char IB1, char IE1,
|
||||
char BI1, char BB1, char BE1,
|
||||
char EI1, char EB1, char EE1,
|
||||
char II2, char IB2, char IE2,
|
||||
char BI2, char BB2, char BE2,
|
||||
char EI2, char EB2, char EE2
|
||||
>
|
||||
inline
|
||||
boost::mpl::vector<
|
||||
static_mask<II1, IB1, IE1, BI1, BB1, BE1, EI1, EB1, EE1>,
|
||||
static_mask<II2, IB2, IE2, BI2, BB2, BE2, EI2, EB2, EE2>
|
||||
>
|
||||
operator||(static_mask<II1, IB1, IE1, BI1, BB1, BE1, EI1, EB1, EE1> const& ,
|
||||
static_mask<II2, IB2, IE2, BI2, BB2, BE2, EI2, EB2, EE2> const& )
|
||||
{
|
||||
return boost::mpl::vector
|
||||
<
|
||||
static_mask<II1, IB1, IE1, BI1, BB1, BE1, EI1, EB1, EE1>,
|
||||
static_mask<II2, IB2, IE2, BI2, BB2, BE2, EI2, EB2, EE2>
|
||||
>();
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Seq,
|
||||
char II, char IB, char IE,
|
||||
char BI, char BB, char BE,
|
||||
char EI, char EB, char EE
|
||||
>
|
||||
inline
|
||||
typename detail::de9im::push_back
|
||||
<
|
||||
Seq,
|
||||
static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>
|
||||
>::type
|
||||
operator||(Seq const& ,
|
||||
static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> const& )
|
||||
{
|
||||
return typename detail::de9im::push_back
|
||||
<
|
||||
Seq,
|
||||
static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>
|
||||
>::type();
|
||||
}
|
||||
|
||||
} // namespace de9im
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace de9im
|
||||
{
|
||||
|
||||
// PREDEFINED MASKS
|
||||
|
||||
// TODO:
|
||||
// 1. specialize for simplified masks if available
|
||||
// e.g. for TOUCHES use 1 mask for A/A
|
||||
// 2. Think about dimensions > 2 e.g. should TOUCHES be true
|
||||
// if the interior of the Areal overlaps the boundary of the Volumetric
|
||||
// like it's true for Linear/Areal
|
||||
|
||||
// EQUALS
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_equals_type
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> type; // wikipedia
|
||||
//typedef geometry::de9im::static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> type; // OGC
|
||||
};
|
||||
|
||||
// DISJOINT
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_disjoint_type
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> type;
|
||||
};
|
||||
|
||||
// TOUCHES - NOT P/P
|
||||
template
|
||||
<
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
std::size_t Dim1 = geometry::topological_dimension<Geometry1>::value,
|
||||
std::size_t Dim2 = geometry::topological_dimension<Geometry2>::value
|
||||
>
|
||||
struct static_mask_touches_impl
|
||||
{
|
||||
typedef boost::mpl::vector
|
||||
<
|
||||
geometry::de9im::static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>,
|
||||
geometry::de9im::static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>,
|
||||
geometry::de9im::static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'>
|
||||
> type;
|
||||
};
|
||||
// According to OGC, doesn't apply to P/P
|
||||
// Using the above mask the result would be always false
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0>
|
||||
: not_implemented<typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type>
|
||||
{};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_touches_type
|
||||
: static_mask_touches_impl<Geometry1, Geometry2>
|
||||
{};
|
||||
|
||||
// WITHIN
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_within_type
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> type;
|
||||
};
|
||||
|
||||
// COVERED_BY (non OGC)
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_covered_by_type
|
||||
{
|
||||
typedef boost::mpl::vector
|
||||
<
|
||||
geometry::de9im::static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>,
|
||||
geometry::de9im::static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>,
|
||||
geometry::de9im::static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>,
|
||||
geometry::de9im::static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'>
|
||||
> type;
|
||||
};
|
||||
|
||||
// CROSSES
|
||||
// dim(G1) < dim(G2) - P/L P/A L/A
|
||||
template
|
||||
<
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
std::size_t Dim1 = geometry::topological_dimension<Geometry1>::value,
|
||||
std::size_t Dim2 = geometry::topological_dimension<Geometry2>::value,
|
||||
bool D1LessD2 = (Dim1 < Dim2)
|
||||
>
|
||||
struct static_mask_crosses_impl
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type;
|
||||
};
|
||||
// TODO: I'm not sure if this one below should be available!
|
||||
// dim(G1) > dim(G2) - L/P A/P A/L
|
||||
template
|
||||
<
|
||||
typename Geometry1, typename Geometry2, std::size_t Dim1, std::size_t Dim2
|
||||
>
|
||||
struct static_mask_crosses_impl<Geometry1, Geometry2, Dim1, Dim2, false>
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type;
|
||||
};
|
||||
// dim(G1) == dim(G2) - P/P A/A
|
||||
template
|
||||
<
|
||||
typename Geometry1, typename Geometry2, std::size_t Dim
|
||||
>
|
||||
struct static_mask_crosses_impl<Geometry1, Geometry2, Dim, Dim, false>
|
||||
: not_implemented
|
||||
<
|
||||
typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type
|
||||
>
|
||||
{};
|
||||
// dim(G1) == 1 && dim(G2) == 1 - L/L
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_crosses_impl<Geometry1, Geometry2, 1, 1, false>
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_crosses_type
|
||||
: static_mask_crosses_impl<Geometry1, Geometry2>
|
||||
{};
|
||||
|
||||
// OVERLAPS
|
||||
|
||||
// dim(G1) != dim(G2) - NOT P/P, L/L, A/A
|
||||
template
|
||||
<
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
std::size_t Dim1 = geometry::topological_dimension<Geometry1>::value,
|
||||
std::size_t Dim2 = geometry::topological_dimension<Geometry2>::value
|
||||
>
|
||||
struct static_mask_overlaps_impl
|
||||
: not_implemented
|
||||
<
|
||||
typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type
|
||||
>
|
||||
{};
|
||||
// dim(G1) == D && dim(G2) == D - P/P A/A
|
||||
template <typename Geometry1, typename Geometry2, std::size_t Dim>
|
||||
struct static_mask_overlaps_impl<Geometry1, Geometry2, Dim, Dim>
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
|
||||
};
|
||||
// dim(G1) == 1 && dim(G2) == 1 - L/L
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_overlaps_impl<Geometry1, Geometry2, 1, 1>
|
||||
{
|
||||
typedef geometry::de9im::static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct static_mask_overlaps_type
|
||||
: static_mask_overlaps_impl<Geometry1, Geometry2>
|
||||
{};
|
||||
|
||||
}} // namespace detail::de9im
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_DE9IM_HPP
|
||||
@@ -0,0 +1,415 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// 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.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
|
||||
#include <boost/geometry/algorithms/not_implemented.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
|
||||
#include <boost/geometry/util/condition.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// NOTE: This iterates through single geometries for which turns were not generated.
|
||||
// It doesn't mean that the geometry is disjoint, only that no turns were detected.
|
||||
|
||||
template <std::size_t OpId,
|
||||
typename Geometry,
|
||||
typename Tag = typename geometry::tag<Geometry>::type,
|
||||
bool IsMulti = boost::is_base_of<multi_tag, Tag>::value
|
||||
>
|
||||
struct for_each_disjoint_geometry_if
|
||||
: public not_implemented<Tag>
|
||||
{};
|
||||
|
||||
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)
|
||||
{
|
||||
if ( first != last )
|
||||
return false;
|
||||
pred(geometry);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
if ( first != last )
|
||||
return for_turns(first, last, geometry, pred);
|
||||
else
|
||||
return for_empty(geometry, pred);
|
||||
}
|
||||
|
||||
template <typename Pred>
|
||||
static inline bool 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 )
|
||||
{
|
||||
bool cont = pred(*it);
|
||||
if ( !cont )
|
||||
break;
|
||||
}
|
||||
|
||||
return !boost::empty(geometry);
|
||||
}
|
||||
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool 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 )
|
||||
{
|
||||
signed_size_type multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_GEOMETRY_ASSERT(multi_index >= 0);
|
||||
std::size_t const index = static_cast<std::size_t>(multi_index);
|
||||
BOOST_GEOMETRY_ASSERT(index < count);
|
||||
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 )
|
||||
{
|
||||
// if there were no intersections for this multi_index
|
||||
if ( *it == 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 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
// WARNING! This class stores pointers!
|
||||
// Passing a reference to local variable will result in undefined behavior!
|
||||
template <typename Point>
|
||||
class point_info
|
||||
{
|
||||
public:
|
||||
point_info() : sid_ptr(NULL), pt_ptr(NULL) {}
|
||||
point_info(Point const& pt, segment_identifier const& sid)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
, pt_ptr(boost::addressof(pt))
|
||||
{}
|
||||
segment_identifier const& seg_id() const
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(sid_ptr);
|
||||
return *sid_ptr;
|
||||
}
|
||||
Point const& point() const
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(pt_ptr);
|
||||
return *pt_ptr;
|
||||
}
|
||||
|
||||
//friend bool operator==(point_identifier const& l, point_identifier const& r)
|
||||
//{
|
||||
// return l.seg_id() == r.seg_id()
|
||||
// && detail::equals::equals_point_point(l.point(), r.point());
|
||||
//}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
const Point * pt_ptr;
|
||||
};
|
||||
|
||||
// WARNING! This class stores pointers!
|
||||
// Passing a reference to local variable will result in undefined behavior!
|
||||
class same_single
|
||||
{
|
||||
public:
|
||||
same_single(segment_identifier const& sid)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
{}
|
||||
|
||||
bool operator()(segment_identifier const& sid) const
|
||||
{
|
||||
return sid.multi_index == sid_ptr->multi_index;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
bool operator()(point_info<Point> const& pid) const
|
||||
{
|
||||
return operator()(pid.seg_id());
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
};
|
||||
|
||||
class same_ring
|
||||
{
|
||||
public:
|
||||
same_ring(segment_identifier const& sid)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
{}
|
||||
|
||||
bool operator()(segment_identifier const& sid) const
|
||||
{
|
||||
return sid.multi_index == sid_ptr->multi_index
|
||||
&& sid.ring_index == sid_ptr->ring_index;
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
};
|
||||
|
||||
// WARNING! This class stores pointers!
|
||||
// Passing a reference to local variable will result in undefined behavior!
|
||||
template <typename SameRange = same_single>
|
||||
class segment_watcher
|
||||
{
|
||||
public:
|
||||
segment_watcher()
|
||||
: m_seg_id_ptr(NULL)
|
||||
{}
|
||||
|
||||
bool update(segment_identifier const& seg_id)
|
||||
{
|
||||
bool result = m_seg_id_ptr == 0 || !SameRange(*m_seg_id_ptr)(seg_id);
|
||||
m_seg_id_ptr = boost::addressof(seg_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * m_seg_id_ptr;
|
||||
};
|
||||
|
||||
// WARNING! This class stores pointers!
|
||||
// Passing a reference to local variable will result in undefined behavior!
|
||||
template <typename TurnInfo, std::size_t OpId>
|
||||
class exit_watcher
|
||||
{
|
||||
static const std::size_t op_id = OpId;
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
|
||||
typedef typename TurnInfo::point_type point_type;
|
||||
typedef detail::relate::point_info<point_type> point_info;
|
||||
|
||||
public:
|
||||
exit_watcher()
|
||||
: m_exit_operation(overlay::operation_none)
|
||||
, m_exit_turn_ptr(NULL)
|
||||
{}
|
||||
|
||||
void enter(TurnInfo const& turn)
|
||||
{
|
||||
m_other_entry_points.push_back(
|
||||
point_info(turn.point, turn.operations[other_op_id].seg_id) );
|
||||
}
|
||||
|
||||
// TODO: exit_per_geometry parameter looks not very safe
|
||||
// wrong value may be easily passed
|
||||
|
||||
void exit(TurnInfo const& turn, bool exit_per_geometry = true)
|
||||
{
|
||||
//segment_identifier const& seg_id = turn.operations[op_id].seg_id;
|
||||
segment_identifier const& other_id = turn.operations[other_op_id].seg_id;
|
||||
overlay::operation_type exit_op = turn.operations[op_id].operation;
|
||||
|
||||
typedef typename std::vector<point_info>::iterator point_iterator;
|
||||
// search for the entry point in the same range of other geometry
|
||||
point_iterator entry_it = std::find_if(m_other_entry_points.begin(),
|
||||
m_other_entry_points.end(),
|
||||
same_single(other_id));
|
||||
|
||||
// this end point has corresponding entry point
|
||||
if ( entry_it != m_other_entry_points.end() )
|
||||
{
|
||||
// erase the corresponding entry point
|
||||
m_other_entry_points.erase(entry_it);
|
||||
|
||||
if ( exit_per_geometry || m_other_entry_points.empty() )
|
||||
{
|
||||
// here we know that we possibly left LS
|
||||
// we must still check if we didn't get back on the same point
|
||||
m_exit_operation = exit_op;
|
||||
m_exit_turn_ptr = boost::addressof(turn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_outside() const
|
||||
{
|
||||
// if we didn't entered anything in the past, we're outside
|
||||
return m_other_entry_points.empty();
|
||||
}
|
||||
|
||||
bool is_outside(TurnInfo const& turn) const
|
||||
{
|
||||
return m_other_entry_points.empty()
|
||||
|| std::find_if(m_other_entry_points.begin(),
|
||||
m_other_entry_points.end(),
|
||||
same_single(
|
||||
turn.operations[other_op_id].seg_id))
|
||||
== m_other_entry_points.end();
|
||||
}
|
||||
|
||||
overlay::operation_type get_exit_operation() const
|
||||
{
|
||||
return m_exit_operation;
|
||||
}
|
||||
|
||||
point_type const& get_exit_point() const
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(m_exit_operation != overlay::operation_none);
|
||||
BOOST_GEOMETRY_ASSERT(m_exit_turn_ptr);
|
||||
return m_exit_turn_ptr->point;
|
||||
}
|
||||
|
||||
TurnInfo const& get_exit_turn() const
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(m_exit_operation != overlay::operation_none);
|
||||
BOOST_GEOMETRY_ASSERT(m_exit_turn_ptr);
|
||||
return *m_exit_turn_ptr;
|
||||
}
|
||||
|
||||
void reset_detected_exit()
|
||||
{
|
||||
m_exit_operation = overlay::operation_none;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_exit_operation = overlay::operation_none;
|
||||
m_other_entry_points.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
overlay::operation_type m_exit_operation;
|
||||
const TurnInfo * m_exit_turn_ptr;
|
||||
std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector?
|
||||
};
|
||||
|
||||
template <std::size_t OpId, typename Turn, typename EqPPStrategy>
|
||||
inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn,
|
||||
EqPPStrategy const& strategy)
|
||||
{
|
||||
segment_identifier const& prev_seg_id = prev_turn.operations[OpId].seg_id;
|
||||
segment_identifier const& curr_seg_id = curr_turn.operations[OpId].seg_id;
|
||||
|
||||
if ( prev_seg_id.multi_index != curr_seg_id.multi_index
|
||||
|| prev_seg_id.ring_index != curr_seg_id.ring_index )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: will this work if between segments there will be some number of degenerated ones?
|
||||
|
||||
if ( prev_seg_id.segment_index != curr_seg_id.segment_index
|
||||
&& ( ! curr_turn.operations[OpId].fraction.is_zero()
|
||||
|| prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return detail::equals::equals_point_point(prev_turn.point, curr_turn.point, strategy);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename Point,
|
||||
typename BoundaryChecker>
|
||||
static inline bool is_endpoint_on_boundary(Point const& pt,
|
||||
BoundaryChecker & boundary_checker)
|
||||
{
|
||||
return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery,
|
||||
typename IntersectionPoint,
|
||||
typename OperationInfo,
|
||||
typename BoundaryChecker>
|
||||
static 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;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
@@ -0,0 +1,124 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014, 2015, 2017.
|
||||
// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP
|
||||
#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/strategies/intersection.hpp>
|
||||
#include <boost/geometry/strategies/within.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DISPATCH
|
||||
namespace dispatch {
|
||||
|
||||
template <typename Point1, typename Point2>
|
||||
struct relate<Point1, Point2, point_tag, point_tag, 0, 0, false>
|
||||
: detail::relate::point_point<Point1, Point2>
|
||||
{};
|
||||
|
||||
template <typename Point, typename MultiPoint>
|
||||
struct relate<Point, MultiPoint, point_tag, multi_point_tag, 0, 0, false>
|
||||
: detail::relate::point_multipoint<Point, MultiPoint>
|
||||
{};
|
||||
|
||||
template <typename MultiPoint, typename Point>
|
||||
struct relate<MultiPoint, Point, multi_point_tag, point_tag, 0, 0, false>
|
||||
: detail::relate::multipoint_point<MultiPoint, Point>
|
||||
{};
|
||||
|
||||
template <typename MultiPoint1, typename MultiPoint2>
|
||||
struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, 0, 0, false>
|
||||
: detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2>
|
||||
{};
|
||||
|
||||
// TODO - for now commented out because before implementing it we must consider:
|
||||
// 1. how the Box degenerated to a Point should be treated
|
||||
// 2. what should be the definition of a Box degenerated to a Point
|
||||
// 3. what fields should the matrix/mask contain for dimension > 2 and dimension > 9
|
||||
//
|
||||
//template <typename Point, typename Box, int TopDim2>
|
||||
//struct relate<Point, Box, point_tag, box_tag, 0, TopDim2, false>
|
||||
// : detail::relate::point_box<Point, Box>
|
||||
//{};
|
||||
//
|
||||
//template <typename Box, typename Point, int TopDim1>
|
||||
//struct relate<Box, Point, box_tag, point_tag, TopDim1, 0, false>
|
||||
// : detail::relate::box_point<Box, Point>
|
||||
//{};
|
||||
|
||||
|
||||
template <typename Point, typename Geometry, typename Tag2, int TopDim2>
|
||||
struct relate<Point, Geometry, point_tag, Tag2, 0, TopDim2, true>
|
||||
: detail::relate::point_geometry<Point, Geometry>
|
||||
{};
|
||||
|
||||
template <typename Geometry, typename Point, typename Tag1, int TopDim1>
|
||||
struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true>
|
||||
: detail::relate::geometry_point<Geometry, Point>
|
||||
{};
|
||||
|
||||
template <typename MultiPoint, typename Geometry, typename Tag2, int TopDim2>
|
||||
struct relate<MultiPoint, Geometry, multi_point_tag, Tag2, 0, TopDim2, false>
|
||||
: detail::relate::multi_point_geometry<MultiPoint, Geometry>
|
||||
{};
|
||||
|
||||
template <typename Geometry, typename MultiPoint, typename Tag1, int TopDim1>
|
||||
struct relate<Geometry, MultiPoint, Tag1, multi_point_tag, TopDim1, 0, false>
|
||||
: detail::relate::geometry_multi_point<Geometry, MultiPoint>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
|
||||
struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true>
|
||||
: detail::relate::linear_linear<Linear1, Linear2>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Linear, typename Areal, typename Tag1, typename Tag2>
|
||||
struct relate<Linear, Areal, Tag1, Tag2, 1, 2, true>
|
||||
: detail::relate::linear_areal<Linear, Areal>
|
||||
{};
|
||||
|
||||
template <typename Areal, typename Linear, typename Tag1, typename Tag2>
|
||||
struct relate<Areal, Linear, Tag1, Tag2, 2, 1, true>
|
||||
: detail::relate::areal_linear<Areal, Linear>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
|
||||
struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true>
|
||||
: detail::relate::areal_areal<Areal1, Areal2>
|
||||
{};
|
||||
|
||||
} // namespace dispatch
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP
|
||||
@@ -0,0 +1,421 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014, 2015, 2017.
|
||||
// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP
|
||||
|
||||
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/variant/apply_visitor.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
#include <boost/variant/variant_fwd.hpp>
|
||||
|
||||
#include <boost/geometry/core/coordinate_dimension.hpp>
|
||||
#include <boost/geometry/core/tag.hpp>
|
||||
#include <boost/geometry/core/tags.hpp>
|
||||
#include <boost/geometry/core/topological_dimension.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/de9im.hpp>
|
||||
#include <boost/geometry/algorithms/not_implemented.hpp>
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
#include <boost/geometry/strategies/default_strategy.hpp>
|
||||
#include <boost/geometry/strategies/relate.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// Those are used only to allow dispatch::relate to produce compile-time error
|
||||
|
||||
template <typename Geometry,
|
||||
typename Tag = typename geometry::tag<Geometry>::type>
|
||||
struct is_supported_by_generic
|
||||
{
|
||||
static const bool value
|
||||
= boost::is_same<Tag, linestring_tag>::value
|
||||
|| boost::is_same<Tag, multi_linestring_tag>::value
|
||||
|| boost::is_same<Tag, ring_tag>::value
|
||||
|| boost::is_same<Tag, polygon_tag>::value
|
||||
|| boost::is_same<Tag, multi_polygon_tag>::value;
|
||||
};
|
||||
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename Tag1 = typename geometry::tag<Geometry1>::type,
|
||||
typename Tag2 = typename geometry::tag<Geometry2>::type>
|
||||
struct is_generic
|
||||
{
|
||||
static const bool value = is_supported_by_generic<Geometry1>::value
|
||||
&& is_supported_by_generic<Geometry2>::value;
|
||||
};
|
||||
|
||||
|
||||
template <typename Point, typename Geometry, typename Tag>
|
||||
struct is_generic<Point, Geometry, point_tag, Tag>
|
||||
{
|
||||
static const bool value = is_supported_by_generic<Geometry>::value;
|
||||
};
|
||||
|
||||
template <typename Geometry, typename Point, typename Tag>
|
||||
struct is_generic<Geometry, Point, Tag, point_tag>
|
||||
{
|
||||
static const bool value = is_supported_by_generic<Geometry>::value;
|
||||
};
|
||||
|
||||
template <typename Point1, typename Point2>
|
||||
struct is_generic<Point1, Point2, point_tag, point_tag>
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DISPATCH
|
||||
namespace dispatch {
|
||||
|
||||
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename Tag1 = typename geometry::tag<Geometry1>::type,
|
||||
typename Tag2 = typename geometry::tag<Geometry2>::type,
|
||||
int TopDim1 = geometry::topological_dimension<Geometry1>::value,
|
||||
int TopDim2 = geometry::topological_dimension<Geometry2>::value,
|
||||
bool IsGeneric = detail::relate::is_generic<Geometry1, Geometry2>::value
|
||||
>
|
||||
struct relate : not_implemented<Tag1, Tag2>
|
||||
{};
|
||||
|
||||
} // namespace dispatch
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct interruption_enabled
|
||||
{
|
||||
static const bool value =
|
||||
dispatch::relate<Geometry1, Geometry2>::interruption_enabled;
|
||||
};
|
||||
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename Result,
|
||||
bool IsSequence = boost::mpl::is_sequence<Result>::value>
|
||||
struct result_handler_type
|
||||
: not_implemented<Result>
|
||||
{};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct result_handler_type<Geometry1, Geometry2, geometry::de9im::mask, false>
|
||||
{
|
||||
typedef mask_handler
|
||||
<
|
||||
geometry::de9im::mask,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename Head, typename Tail>
|
||||
struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail>, false>
|
||||
{
|
||||
typedef mask_handler
|
||||
<
|
||||
boost::tuples::cons<Head, Tail>,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2,
|
||||
char II, char IB, char IE,
|
||||
char BI, char BB, char BE,
|
||||
char EI, char EB, char EE>
|
||||
struct result_handler_type
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
geometry::de9im::static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
|
||||
false
|
||||
>
|
||||
{
|
||||
typedef static_mask_handler
|
||||
<
|
||||
geometry::de9im::static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename StaticSequence>
|
||||
struct result_handler_type<Geometry1, Geometry2, StaticSequence, true>
|
||||
{
|
||||
typedef static_mask_handler
|
||||
<
|
||||
StaticSequence,
|
||||
interruption_enabled
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::value
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
namespace resolve_strategy {
|
||||
|
||||
struct relate
|
||||
{
|
||||
template <typename Geometry1, typename Geometry2, typename ResultHandler, typename Strategy>
|
||||
static inline void apply(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
ResultHandler & handler,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
dispatch::relate
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::apply(geometry1, geometry2, handler, strategy);
|
||||
}
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename ResultHandler>
|
||||
static inline void apply(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
ResultHandler & handler,
|
||||
default_strategy)
|
||||
{
|
||||
typedef typename strategy::relate::services::default_strategy
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::type strategy_type;
|
||||
|
||||
dispatch::relate
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::apply(geometry1, geometry2, handler, strategy_type());
|
||||
}
|
||||
};
|
||||
|
||||
} // resolve_strategy
|
||||
|
||||
namespace resolve_variant {
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct relate
|
||||
{
|
||||
template <typename Mask, typename Strategy>
|
||||
static inline bool apply(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Mask const& mask,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
concepts::check<Geometry1 const>();
|
||||
concepts::check<Geometry2 const>();
|
||||
assert_dimension_equal<Geometry1, Geometry2>();
|
||||
|
||||
typename detail::relate::result_handler_type
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
Mask
|
||||
>::type handler(mask);
|
||||
|
||||
resolve_strategy::relate::apply(geometry1, geometry2, handler, strategy);
|
||||
|
||||
return handler.result();
|
||||
}
|
||||
};
|
||||
|
||||
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
|
||||
struct relate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
|
||||
{
|
||||
template <typename Mask, typename Strategy>
|
||||
struct visitor : boost::static_visitor<bool>
|
||||
{
|
||||
Geometry2 const& m_geometry2;
|
||||
Mask const& m_mask;
|
||||
Strategy const& m_strategy;
|
||||
|
||||
visitor(Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy)
|
||||
: m_geometry2(geometry2), m_mask(mask), m_strategy(strategy) {}
|
||||
|
||||
template <typename Geometry1>
|
||||
bool operator()(Geometry1 const& geometry1) const
|
||||
{
|
||||
return relate<Geometry1, Geometry2>
|
||||
::apply(geometry1, m_geometry2, m_mask, m_strategy);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mask, typename Strategy>
|
||||
static inline bool
|
||||
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Mask const& mask,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return boost::apply_visitor(visitor<Mask, Strategy>(geometry2, mask, strategy), geometry1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
struct relate<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
|
||||
{
|
||||
template <typename Mask, typename Strategy>
|
||||
struct visitor : boost::static_visitor<bool>
|
||||
{
|
||||
Geometry1 const& m_geometry1;
|
||||
Mask const& m_mask;
|
||||
Strategy const& m_strategy;
|
||||
|
||||
visitor(Geometry1 const& geometry1, Mask const& mask, Strategy const& strategy)
|
||||
: m_geometry1(geometry1), m_mask(mask), m_strategy(strategy) {}
|
||||
|
||||
template <typename Geometry2>
|
||||
bool operator()(Geometry2 const& geometry2) const
|
||||
{
|
||||
return relate<Geometry1, Geometry2>
|
||||
::apply(m_geometry1, geometry2, m_mask, m_strategy);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mask, typename Strategy>
|
||||
static inline bool
|
||||
apply(Geometry1 const& geometry1,
|
||||
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
|
||||
Mask const& mask,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return boost::apply_visitor(visitor<Mask, Strategy>(geometry1, mask, strategy), geometry2);
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
BOOST_VARIANT_ENUM_PARAMS(typename T1),
|
||||
BOOST_VARIANT_ENUM_PARAMS(typename T2)
|
||||
>
|
||||
struct relate<
|
||||
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
|
||||
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
|
||||
>
|
||||
{
|
||||
template <typename Mask, typename Strategy>
|
||||
struct visitor : boost::static_visitor<bool>
|
||||
{
|
||||
Mask const& m_mask;
|
||||
Strategy const& m_strategy;
|
||||
|
||||
visitor(Mask const& mask, Strategy const& strategy)
|
||||
: m_mask(mask), m_strategy(strategy) {}
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
bool operator()(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2) const
|
||||
{
|
||||
return relate<Geometry1, Geometry2>
|
||||
::apply(geometry1, geometry2, m_mask, m_strategy);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mask, typename Strategy>
|
||||
static inline bool
|
||||
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
|
||||
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
|
||||
Mask const& mask,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return boost::apply_visitor(visitor<Mask, Strategy>(mask, strategy), geometry1, geometry2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace resolve_variant
|
||||
|
||||
/*!
|
||||
\brief Checks relation between a pair of geometries defined by a mask.
|
||||
\ingroup relate
|
||||
\tparam Geometry1 \tparam_geometry
|
||||
\tparam Geometry2 \tparam_geometry
|
||||
\tparam Mask An intersection model Mask type.
|
||||
\tparam Strategy \tparam_strategy{Relate}
|
||||
\param geometry1 \param_geometry
|
||||
\param geometry2 \param_geometry
|
||||
\param mask An intersection model mask object.
|
||||
\param strategy \param_strategy{relate}
|
||||
\return true if the relation is compatible with the mask, false otherwise.
|
||||
|
||||
\qbk{distinguish,with strategy}
|
||||
\qbk{[include reference/algorithms/relate.qbk]}
|
||||
*/
|
||||
template <typename Geometry1, typename Geometry2, typename Mask, typename Strategy>
|
||||
inline bool relate(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Mask const& mask,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return resolve_variant::relate
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::apply(geometry1, geometry2, mask, strategy);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Checks relation between a pair of geometries defined by a mask.
|
||||
\ingroup relate
|
||||
\tparam Geometry1 \tparam_geometry
|
||||
\tparam Geometry2 \tparam_geometry
|
||||
\tparam Mask An intersection model Mask type.
|
||||
\param geometry1 \param_geometry
|
||||
\param geometry2 \param_geometry
|
||||
\param mask An intersection model mask object.
|
||||
\return true if the relation is compatible with the mask, false otherwise.
|
||||
|
||||
\qbk{[include reference/algorithms/relate.qbk]}
|
||||
*/
|
||||
template <typename Geometry1, typename Geometry2, typename Mask>
|
||||
inline bool relate(Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
Mask const& mask)
|
||||
{
|
||||
return resolve_variant::relate
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::apply(geometry1, geometry2, mask, default_strategy());
|
||||
}
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,821 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// 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.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/range/size.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
|
||||
#include <boost/geometry/util/condition.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/sub_range.hpp>
|
||||
#include <boost/geometry/algorithms/detail/single_geometry.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
template <typename Result, typename BoundaryChecker, bool TransposeResult>
|
||||
class disjoint_linestring_pred
|
||||
{
|
||||
typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type;
|
||||
|
||||
public:
|
||||
disjoint_linestring_pred(Result & res,
|
||||
BoundaryChecker const& boundary_checker)
|
||||
: m_result(res)
|
||||
, m_boundary_checker(boundary_checker)
|
||||
, m_flags(0)
|
||||
{
|
||||
if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) )
|
||||
{
|
||||
m_flags |= 1;
|
||||
}
|
||||
if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) )
|
||||
{
|
||||
m_flags |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Linestring>
|
||||
bool operator()(Linestring const& linestring)
|
||||
{
|
||||
if ( m_flags == 3 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t const count = boost::size(linestring);
|
||||
|
||||
// invalid input
|
||||
if ( count < 2 )
|
||||
{
|
||||
// ignore
|
||||
// TODO: throw an exception?
|
||||
return true;
|
||||
}
|
||||
|
||||
// point-like linestring
|
||||
if ( count == 2
|
||||
&& equals::equals_point_point(range::front(linestring),
|
||||
range::back(linestring),
|
||||
equals_strategy_type()) )
|
||||
{
|
||||
update<interior, exterior, '0', TransposeResult>(m_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '1', TransposeResult>(m_result);
|
||||
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)) ) )
|
||||
{
|
||||
update<boundary, exterior, '0', TransposeResult>(m_result);
|
||||
m_flags |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return m_flags != 3
|
||||
&& ! m_result.interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
Result & m_result;
|
||||
BoundaryChecker const& m_boundary_checker;
|
||||
unsigned m_flags;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
struct linear_linear
|
||||
{
|
||||
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 IntersectionStrategy>
|
||||
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
Result & result,
|
||||
IntersectionStrategy const& intersection_strategy)
|
||||
{
|
||||
// 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
|
||||
typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
|
||||
std::vector<turn_type> turns;
|
||||
|
||||
interrupt_policy_linear_linear<Result> interrupt_policy(result);
|
||||
|
||||
turns::get_turns
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
|
||||
>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy);
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
|
||||
return;
|
||||
|
||||
typedef boundary_checker
|
||||
<
|
||||
Geometry1,
|
||||
typename IntersectionStrategy::point_in_point_strategy_type
|
||||
> boundary_checker1_type;
|
||||
boundary_checker1_type boundary_checker1(geometry1);
|
||||
disjoint_linestring_pred<Result, boundary_checker1_type, false> pred1(result, boundary_checker1);
|
||||
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
|
||||
return;
|
||||
|
||||
typedef boundary_checker
|
||||
<
|
||||
Geometry2,
|
||||
typename IntersectionStrategy::point_in_point_strategy_type
|
||||
> boundary_checker2_type;
|
||||
boundary_checker2_type boundary_checker2(geometry2);
|
||||
disjoint_linestring_pred<Result, boundary_checker2_type, true> pred2(result, boundary_checker2);
|
||||
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
|
||||
return;
|
||||
|
||||
if ( turns.empty() )
|
||||
return;
|
||||
|
||||
// TODO: turns must be sorted and followed only if it's possible to go out and in on the same point
|
||||
// for linear geometries union operation must be detected which I guess would be quite often
|
||||
|
||||
if ( may_update<interior, interior, '1'>(result)
|
||||
|| may_update<interior, boundary, '0'>(result)
|
||||
|| may_update<interior, exterior, '1'>(result)
|
||||
|| may_update<boundary, interior, '0'>(result)
|
||||
|| may_update<boundary, boundary, '0'>(result)
|
||||
|| may_update<boundary, exterior, '0'>(result) )
|
||||
{
|
||||
typedef turns::less<0, turns::less_op_linear_linear<0> > less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
|
||||
turns_analyser<turn_type, 0> analyser;
|
||||
analyse_each_turn(result, analyser,
|
||||
turns.begin(), turns.end(),
|
||||
geometry1, geometry2,
|
||||
boundary_checker1, boundary_checker2);
|
||||
}
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
|
||||
return;
|
||||
|
||||
if ( may_update<interior, interior, '1', true>(result)
|
||||
|| may_update<interior, boundary, '0', true>(result)
|
||||
|| may_update<interior, exterior, '1', true>(result)
|
||||
|| may_update<boundary, interior, '0', true>(result)
|
||||
|| may_update<boundary, boundary, '0', true>(result)
|
||||
|| may_update<boundary, exterior, '0', true>(result) )
|
||||
{
|
||||
typedef turns::less<1, turns::less_op_linear_linear<1> > less;
|
||||
std::sort(turns.begin(), turns.end(), less());
|
||||
|
||||
turns_analyser<turn_type, 1> analyser;
|
||||
analyse_each_turn(result, analyser,
|
||||
turns.begin(), turns.end(),
|
||||
geometry2, geometry1,
|
||||
boundary_checker2, boundary_checker1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
class interrupt_policy_linear_linear
|
||||
{
|
||||
public:
|
||||
static bool const enabled = true;
|
||||
|
||||
explicit interrupt_policy_linear_linear(Result & result)
|
||||
: m_result(result)
|
||||
{}
|
||||
|
||||
// TODO: since we update result for some operations here, we may not do it in the analyser!
|
||||
|
||||
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)
|
||||
{
|
||||
if ( it->operations[0].operation == overlay::operation_intersection
|
||||
|| it->operations[1].operation == overlay::operation_intersection )
|
||||
{
|
||||
update<interior, interior, '1'>(m_result);
|
||||
}
|
||||
else if ( ( it->operations[0].operation == overlay::operation_union
|
||||
|| it->operations[0].operation == overlay::operation_blocked
|
||||
|| it->operations[1].operation == overlay::operation_union
|
||||
|| it->operations[1].operation == overlay::operation_blocked )
|
||||
&& it->operations[0].position == overlay::position_middle
|
||||
&& it->operations[1].position == overlay::position_middle )
|
||||
{
|
||||
// TODO: here we could also check the boundaries and set IB,BI,BB at this point
|
||||
update<interior, interior, '0'>(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
return m_result.interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
Result & m_result;
|
||||
};
|
||||
|
||||
// This analyser should be used like Input or SinglePass Iterator
|
||||
template <typename TurnInfo, std::size_t OpId>
|
||||
class turns_analyser
|
||||
{
|
||||
typedef typename TurnInfo::point_type turn_point_type;
|
||||
|
||||
static const std::size_t op_id = OpId;
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
public:
|
||||
turns_analyser()
|
||||
: m_previous_turn_ptr(NULL)
|
||||
, m_previous_operation(overlay::operation_none)
|
||||
, m_degenerated_turn_ptr(NULL)
|
||||
, m_collinear_spike_exit(false)
|
||||
{}
|
||||
|
||||
template <typename Result,
|
||||
typename TurnIt,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename BoundaryChecker,
|
||||
typename OtherBoundaryChecker>
|
||||
void apply(Result & res, TurnIt it,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker const& boundary_checker,
|
||||
OtherBoundaryChecker const& other_boundary_checker)
|
||||
{
|
||||
typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type;
|
||||
|
||||
overlay::operation_type const op = it->operations[op_id].operation;
|
||||
|
||||
segment_identifier const& seg_id = it->operations[op_id].seg_id;
|
||||
segment_identifier const& other_id = it->operations[other_op_id].seg_id;
|
||||
|
||||
bool const first_in_range = m_seg_watcher.update(seg_id);
|
||||
|
||||
if ( op != overlay::operation_union
|
||||
&& op != overlay::operation_intersection
|
||||
&& op != overlay::operation_blocked )
|
||||
{
|
||||
// degenerated turn
|
||||
if ( op == overlay::operation_continue
|
||||
&& it->method == overlay::method_none
|
||||
&& m_exit_watcher.is_outside(*it)
|
||||
/*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none
|
||||
|| ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ )
|
||||
{
|
||||
// TODO: rewrite the above condition
|
||||
|
||||
// WARNING! For spikes the above condition may be TRUE
|
||||
// When degenerated turns are be marked in a different way than c,c/c
|
||||
// different condition will be checked
|
||||
|
||||
handle_degenerated(res, *it,
|
||||
geometry, other_geometry,
|
||||
boundary_checker, other_boundary_checker,
|
||||
first_in_range);
|
||||
|
||||
// TODO: not elegant solution! should be rewritten.
|
||||
if ( it->operations[op_id].position == overlay::position_back )
|
||||
{
|
||||
m_previous_operation = overlay::operation_blocked;
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// reset
|
||||
m_degenerated_turn_ptr = NULL;
|
||||
|
||||
// handle possible exit
|
||||
bool fake_enter_detected = false;
|
||||
if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
|
||||
{
|
||||
// real exit point - may be multiple
|
||||
// we know that we entered and now we exit
|
||||
if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(),
|
||||
*it,
|
||||
equals_strategy_type()) )
|
||||
{
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
|
||||
// not the last IP
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
}
|
||||
// fake exit point, reset state
|
||||
else if ( op == overlay::operation_intersection )
|
||||
{
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
fake_enter_detected = true;
|
||||
}
|
||||
}
|
||||
else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
|
||||
{
|
||||
// ignore multiple BLOCKs
|
||||
if ( op == overlay::operation_blocked )
|
||||
return;
|
||||
|
||||
if ( op == overlay::operation_intersection
|
||||
&& turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(),
|
||||
*it,
|
||||
equals_strategy_type()) )
|
||||
{
|
||||
fake_enter_detected = true;
|
||||
}
|
||||
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
}
|
||||
|
||||
// i/i, i/x, i/u
|
||||
if ( op == overlay::operation_intersection )
|
||||
{
|
||||
bool const was_outside = m_exit_watcher.is_outside();
|
||||
m_exit_watcher.enter(*it);
|
||||
|
||||
// interiors overlaps
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update<boundary, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
// going inside on non-boundary point
|
||||
else
|
||||
{
|
||||
// if we didn't enter in the past, we were outside
|
||||
if ( was_outside
|
||||
&& ! fake_enter_detected
|
||||
&& it->operations[op_id].position != overlay::position_front
|
||||
&& ! m_collinear_spike_exit )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
// 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);
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_collinear_spike_exit = false;
|
||||
}
|
||||
// u/i, u/u, u/x, x/i, x/u, x/x
|
||||
else if ( op == overlay::operation_union || op == overlay::operation_blocked )
|
||||
{
|
||||
// TODO: is exit watcher still needed?
|
||||
// couldn't is_collinear and some going inside counter be used instead?
|
||||
|
||||
bool const is_collinear = it->operations[op_id].is_collinear;
|
||||
bool const was_outside = m_exit_watcher.is_outside()
|
||||
&& m_exit_watcher.get_exit_operation() == overlay::operation_none;
|
||||
// TODO: move the above condition into the exit_watcher?
|
||||
|
||||
// to exit we must be currently inside and the current segment must be collinear
|
||||
if ( !was_outside && is_collinear )
|
||||
{
|
||||
m_exit_watcher.exit(*it, false);
|
||||
// if the position is not set to back it must be a spike
|
||||
if ( it->operations[op_id].position != overlay::position_back )
|
||||
{
|
||||
m_collinear_spike_exit = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool const op_blocked = op == overlay::operation_blocked;
|
||||
|
||||
// we're inside and going out from inside
|
||||
// possibly going out right now
|
||||
if ( ! was_outside && is_collinear )
|
||||
{
|
||||
if ( op_blocked
|
||||
&& it->operations[op_id].position == overlay::position_back ) // ignore spikes!
|
||||
{
|
||||
// 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) )
|
||||
{
|
||||
// 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);
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update<boundary, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// we're outside or intersects some segment from the outside
|
||||
else
|
||||
{
|
||||
// if we are truly outside
|
||||
if ( was_outside
|
||||
&& it->operations[op_id].position != overlay::position_front
|
||||
&& ! m_collinear_spike_exit
|
||||
/*&& !is_collinear*/ )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
}
|
||||
|
||||
// boundaries don't overlap - just an optimization
|
||||
if ( it->method == overlay::method_crosses )
|
||||
{
|
||||
// the L1 is going from one side of the L2 to the other through the point
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
|
||||
// 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);
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
|
||||
// if current IP is on boundary of the geometry
|
||||
if ( this_b )
|
||||
{
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update<boundary, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
// if current IP is not on boundary of the geometry
|
||||
else
|
||||
{
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update<interior, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
|
||||
// first IP on the last segment point - this means that the first point is outside
|
||||
if ( first_in_range
|
||||
&& ( !this_b || op_blocked )
|
||||
&& was_outside
|
||||
&& it->operations[op_id].position != overlay::position_front
|
||||
&& ! 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);
|
||||
|
||||
// if there is a boundary on the first point
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store ref to previously analysed (valid) turn
|
||||
m_previous_turn_ptr = boost::addressof(*it);
|
||||
// and previously analysed (valid) operation
|
||||
m_previous_operation = op;
|
||||
}
|
||||
|
||||
// Called for last
|
||||
template <typename Result,
|
||||
typename TurnIt,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename BoundaryChecker,
|
||||
typename OtherBoundaryChecker>
|
||||
void apply(Result & res,
|
||||
TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& /*other_geometry*/,
|
||||
BoundaryChecker const& boundary_checker,
|
||||
OtherBoundaryChecker const& /*other_boundary_checker*/)
|
||||
{
|
||||
boost::ignore_unused(first, last);
|
||||
//BOOST_GEOMETRY_ASSERT( first != last );
|
||||
|
||||
// here, the possible exit is the real one
|
||||
// we know that we entered and now we exit
|
||||
if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
|
||||
||*/ m_previous_operation == overlay::operation_union
|
||||
|| m_degenerated_turn_ptr )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(first != last);
|
||||
|
||||
const TurnInfo * turn_ptr = NULL;
|
||||
if ( m_degenerated_turn_ptr )
|
||||
turn_ptr = m_degenerated_turn_ptr;
|
||||
else if ( m_previous_turn_ptr )
|
||||
turn_ptr = m_previous_turn_ptr;
|
||||
|
||||
if ( turn_ptr )
|
||||
{
|
||||
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);
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( prev_back_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just in case,
|
||||
// reset exit watcher before the analysis of the next Linestring
|
||||
// note that if there are some enters stored there may be some error above
|
||||
m_exit_watcher.reset();
|
||||
|
||||
m_previous_turn_ptr = NULL;
|
||||
m_previous_operation = overlay::operation_none;
|
||||
m_degenerated_turn_ptr = NULL;
|
||||
|
||||
// actually if this is set to true here there is some error
|
||||
// in get_turns_ll or relate_ll, an assert could be checked here
|
||||
m_collinear_spike_exit = false;
|
||||
}
|
||||
|
||||
template <typename Result,
|
||||
typename Turn,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename BoundaryChecker,
|
||||
typename OtherBoundaryChecker>
|
||||
void handle_degenerated(Result & res,
|
||||
Turn const& turn,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker const& boundary_checker,
|
||||
OtherBoundaryChecker const& /*other_boundary_checker*/,
|
||||
bool first_in_range)
|
||||
{
|
||||
typedef typename BoundaryChecker::equals_strategy_type
|
||||
equals_strategy1_type;
|
||||
typedef typename OtherBoundaryChecker::equals_strategy_type
|
||||
equals_strategy2_type;
|
||||
|
||||
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);
|
||||
|
||||
// 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 )
|
||||
{
|
||||
bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker);
|
||||
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
}
|
||||
|
||||
// operation 'c' should be last for the same IP so we know that the next point won't be the same
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
m_degenerated_turn_ptr = boost::addressof(turn);
|
||||
}
|
||||
}
|
||||
else if ( turn.operations[op_id].position == overlay::position_back )
|
||||
{
|
||||
// valid, point-sized
|
||||
if ( boost::size(ls2_ref) == 2 )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker);
|
||||
|
||||
if ( back_b )
|
||||
{
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
}
|
||||
|
||||
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);
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( turn.operations[op_id].position == overlay::position_middle
|
||||
&& turn.operations[other_op_id].position == overlay::position_middle )
|
||||
{
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
|
||||
// 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),
|
||||
equals_strategy1_type());
|
||||
bool const is_point2 = boost::size(ls2_ref) == 2
|
||||
&& equals::equals_point_point(range::front(ls2_ref),
|
||||
range::back(ls2_ref),
|
||||
equals_strategy2_type());
|
||||
|
||||
// if the second one is degenerated
|
||||
if ( !is_point1 && is_point2 )
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
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);
|
||||
if ( front_b )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
|
||||
m_degenerated_turn_ptr = boost::addressof(turn);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: other.position == front and other.position == back
|
||||
// will be handled later, for the other geometry
|
||||
}
|
||||
|
||||
private:
|
||||
exit_watcher<TurnInfo, OpId> m_exit_watcher;
|
||||
segment_watcher<same_single> m_seg_watcher;
|
||||
const TurnInfo * m_previous_turn_ptr;
|
||||
overlay::operation_type m_previous_operation;
|
||||
const TurnInfo * m_degenerated_turn_ptr;
|
||||
bool m_collinear_spike_exit;
|
||||
};
|
||||
|
||||
template <typename Result,
|
||||
typename TurnIt,
|
||||
typename Analyser,
|
||||
typename Geometry,
|
||||
typename OtherGeometry,
|
||||
typename BoundaryChecker,
|
||||
typename OtherBoundaryChecker>
|
||||
static inline void analyse_each_turn(Result & res,
|
||||
Analyser & analyser,
|
||||
TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
OtherGeometry const& other_geometry,
|
||||
BoundaryChecker const& boundary_checker,
|
||||
OtherBoundaryChecker const& other_boundary_checker)
|
||||
{
|
||||
if ( first == last )
|
||||
return;
|
||||
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
analyser.apply(res, it,
|
||||
geometry, other_geometry,
|
||||
boundary_checker, other_boundary_checker);
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) )
|
||||
return;
|
||||
}
|
||||
|
||||
analyser.apply(res, first, last,
|
||||
geometry, other_geometry,
|
||||
boundary_checker, other_boundary_checker);
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
|
||||
@@ -0,0 +1,615 @@
|
||||
// Boost.Geometry
|
||||
|
||||
// Copyright (c) 2017-2018 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
|
||||
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
|
||||
#include <boost/geometry/algorithms/detail/partition.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
|
||||
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/envelope.hpp>
|
||||
|
||||
#include <boost/geometry/core/is_areal.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
#include <boost/geometry/geometries/box.hpp>
|
||||
|
||||
#include <boost/geometry/index/rtree.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename Geometry,
|
||||
typename EqPPStrategy,
|
||||
typename Tag = typename tag<Geometry>::type
|
||||
>
|
||||
struct multi_point_geometry_eb
|
||||
{
|
||||
template <typename MultiPoint>
|
||||
static inline bool apply(MultiPoint const& ,
|
||||
detail::relate::topology_check<Geometry, EqPPStrategy> const& )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Geometry, typename EqPPStrategy>
|
||||
struct multi_point_geometry_eb<Geometry, EqPPStrategy, linestring_tag>
|
||||
{
|
||||
template <typename Points>
|
||||
struct boundary_visitor
|
||||
{
|
||||
boundary_visitor(Points const& points)
|
||||
: m_points(points)
|
||||
, m_boundary_found(false)
|
||||
{}
|
||||
|
||||
template <typename Point>
|
||||
struct find_pred
|
||||
{
|
||||
find_pred(Point const& point)
|
||||
: m_point(point)
|
||||
{}
|
||||
|
||||
template <typename Pt>
|
||||
bool operator()(Pt const& pt) const
|
||||
{
|
||||
return detail::equals::equals_point_point(pt, m_point, EqPPStrategy());
|
||||
}
|
||||
|
||||
Point const& m_point;
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
bool apply(Point const& boundary_point)
|
||||
{
|
||||
if (std::find_if(m_points.begin(), m_points.end(), find_pred<Point>(boundary_point)) == m_points.end())
|
||||
{
|
||||
m_boundary_found = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result() const { return m_boundary_found; }
|
||||
|
||||
private:
|
||||
Points const& m_points;
|
||||
bool m_boundary_found;
|
||||
};
|
||||
|
||||
template <typename MultiPoint>
|
||||
static inline bool apply(MultiPoint const& multi_point,
|
||||
detail::relate::topology_check<Geometry, EqPPStrategy> const& tc)
|
||||
{
|
||||
boundary_visitor<MultiPoint> visitor(multi_point);
|
||||
tc.for_each_boundary_point(visitor);
|
||||
return visitor.result();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Geometry, typename EqPPStrategy>
|
||||
struct multi_point_geometry_eb<Geometry, EqPPStrategy, multi_linestring_tag>
|
||||
{
|
||||
// TODO: CS-specific less compare strategy derived from EqPPStrategy
|
||||
typedef geometry::less<> less_type;
|
||||
|
||||
template <typename Points>
|
||||
struct boundary_visitor
|
||||
{
|
||||
boundary_visitor(Points const& points)
|
||||
: m_points(points)
|
||||
, m_boundary_found(false)
|
||||
{}
|
||||
|
||||
template <typename Point>
|
||||
bool apply(Point const& boundary_point)
|
||||
{
|
||||
if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, less_type()))
|
||||
{
|
||||
m_boundary_found = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result() const { return m_boundary_found; }
|
||||
|
||||
private:
|
||||
Points const& m_points;
|
||||
bool m_boundary_found;
|
||||
};
|
||||
|
||||
template <typename MultiPoint>
|
||||
static inline bool apply(MultiPoint const& multi_point,
|
||||
detail::relate::topology_check<Geometry, EqPPStrategy> const& tc)
|
||||
{
|
||||
typedef typename boost::range_value<MultiPoint>::type point_type;
|
||||
typedef std::vector<point_type> points_type;
|
||||
points_type points(boost::begin(multi_point), boost::end(multi_point));
|
||||
std::sort(points.begin(), points.end(), less_type());
|
||||
|
||||
boundary_visitor<points_type> visitor(points);
|
||||
tc.for_each_boundary_point(visitor);
|
||||
return visitor.result();
|
||||
}
|
||||
};
|
||||
|
||||
// SingleGeometry - Linear or Areal
|
||||
template <typename MultiPoint, typename SingleGeometry, bool Transpose = false>
|
||||
struct multi_point_single_geometry
|
||||
{
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint const& multi_point,
|
||||
SingleGeometry const& single_geometry,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
typedef typename point_type<SingleGeometry>::type point2_type;
|
||||
typedef model::box<point2_type> box2_type;
|
||||
typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type;
|
||||
typedef typename Strategy::disjoint_point_box_strategy_type d_pb_strategy_type;
|
||||
|
||||
box2_type box2;
|
||||
geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
|
||||
geometry::detail::expand_by_epsilon(box2);
|
||||
|
||||
typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
|
||||
for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
|
||||
{
|
||||
if (! (relate::may_update<interior, interior, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, boundary, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, exterior, '0', Transpose>(result) ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// The default strategy is enough for Point/Box
|
||||
if (detail::disjoint::disjoint_point_box(*it, box2, d_pb_strategy_type()))
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy);
|
||||
|
||||
if (in_val > 0) // within
|
||||
{
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
}
|
||||
else if (in_val == 0)
|
||||
{
|
||||
relate::set<interior, boundary, '0', Transpose>(result);
|
||||
}
|
||||
else // in_val < 0 - not within
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
}
|
||||
}
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
typedef detail::relate::topology_check
|
||||
<
|
||||
SingleGeometry, eq_pp_strategy_type
|
||||
> tc_t;
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
|| relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
|
||||
{
|
||||
tc_t tc(single_geometry);
|
||||
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
&& tc.has_interior() )
|
||||
{
|
||||
// TODO: this is not true if a linestring is degenerated to a point
|
||||
// then the interior has topological dimension = 0, not 1
|
||||
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
}
|
||||
|
||||
if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
|
||||
&& tc.has_boundary() )
|
||||
{
|
||||
if (multi_point_geometry_eb
|
||||
<
|
||||
SingleGeometry, eq_pp_strategy_type
|
||||
>::apply(multi_point, tc))
|
||||
{
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// MultiGeometry - Linear or Areal
|
||||
// part of the algorithm calculating II and IB when no IE has to be calculated
|
||||
// using partition()
|
||||
template <typename MultiPoint, typename MultiGeometry, bool Transpose>
|
||||
class multi_point_multi_geometry_ii_ib
|
||||
{
|
||||
struct expand_box_point
|
||||
{
|
||||
template <typename Box, typename Point>
|
||||
static inline void apply(Box& total, Point const& point)
|
||||
{
|
||||
geometry::expand(total, point);
|
||||
}
|
||||
};
|
||||
|
||||
struct expand_box_box_pair
|
||||
{
|
||||
template <typename Box, typename BoxPair>
|
||||
static inline void apply(Box& total, BoxPair const& box_pair)
|
||||
{
|
||||
geometry::expand(total, box_pair.first);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DisjointPointBoxStrategy>
|
||||
struct overlaps_box_point
|
||||
{
|
||||
template <typename Box, typename Point>
|
||||
static inline bool apply(Box const& box, Point const& point)
|
||||
{
|
||||
// The default strategy is enough for Point/Box
|
||||
return ! detail::disjoint::disjoint_point_box(point, box,
|
||||
DisjointPointBoxStrategy());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DisjointBoxBoxStrategy>
|
||||
struct overlaps_box_box_pair
|
||||
{
|
||||
template <typename Box, typename BoxPair>
|
||||
static inline bool apply(Box const& box, BoxPair const& box_pair)
|
||||
{
|
||||
// The default strategy is enough for Box/Box
|
||||
return ! detail::disjoint::disjoint_box_box(box_pair.first, box,
|
||||
DisjointBoxBoxStrategy());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Result, typename PtSegStrategy>
|
||||
class item_visitor_type
|
||||
{
|
||||
typedef typename PtSegStrategy::equals_point_point_strategy_type pp_strategy_type;
|
||||
typedef typename PtSegStrategy::disjoint_point_box_strategy_type d_pp_strategy_type;
|
||||
typedef detail::relate::topology_check<MultiGeometry, pp_strategy_type> topology_check_type;
|
||||
|
||||
public:
|
||||
item_visitor_type(MultiGeometry const& multi_geometry,
|
||||
topology_check_type const& tc,
|
||||
Result & result,
|
||||
PtSegStrategy const& strategy)
|
||||
: m_multi_geometry(multi_geometry)
|
||||
, m_tc(tc)
|
||||
, m_result(result)
|
||||
, m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Point, typename BoxPair>
|
||||
inline bool apply(Point const& point, BoxPair const& box_pair)
|
||||
{
|
||||
// The default strategy is enough for Point/Box
|
||||
if (! detail::disjoint::disjoint_point_box(point, box_pair.first, d_pp_strategy_type()))
|
||||
{
|
||||
typename boost::range_value<MultiGeometry>::type const&
|
||||
single = range::at(m_multi_geometry, box_pair.second);
|
||||
|
||||
int in_val = detail::within::point_in_geometry(point, single, m_strategy);
|
||||
|
||||
if (in_val > 0) // within
|
||||
{
|
||||
relate::set<interior, interior, '0', Transpose>(m_result);
|
||||
}
|
||||
else if (in_val == 0)
|
||||
{
|
||||
if (m_tc.check_boundary_point(point))
|
||||
relate::set<interior, boundary, '0', Transpose>(m_result);
|
||||
else
|
||||
relate::set<interior, interior, '0', Transpose>(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! (relate::may_update<interior, interior, '0', Transpose>(m_result)
|
||||
|| relate::may_update<interior, boundary, '0', Transpose>(m_result) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
MultiGeometry const& m_multi_geometry;
|
||||
topology_check_type const& m_tc;
|
||||
Result & m_result;
|
||||
PtSegStrategy const& m_strategy;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename point_type<MultiPoint>::type point1_type;
|
||||
typedef typename point_type<MultiGeometry>::type point2_type;
|
||||
typedef model::box<point1_type> box1_type;
|
||||
typedef model::box<point2_type> box2_type;
|
||||
typedef std::pair<box2_type, std::size_t> box_pair_type;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint const& multi_point,
|
||||
MultiGeometry const& multi_geometry,
|
||||
std::vector<box_pair_type> const& boxes,
|
||||
detail::relate::topology_check
|
||||
<
|
||||
MultiGeometry,
|
||||
typename Strategy::equals_point_point_strategy_type
|
||||
> const& tc,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy);
|
||||
|
||||
typedef overlaps_box_point
|
||||
<
|
||||
typename Strategy::disjoint_point_box_strategy_type
|
||||
> overlaps_box_point_type;
|
||||
typedef overlaps_box_box_pair
|
||||
<
|
||||
typename Strategy::disjoint_box_box_strategy_type
|
||||
> overlaps_box_box_pair_type;
|
||||
|
||||
geometry::partition
|
||||
<
|
||||
box1_type
|
||||
>::apply(multi_point, boxes, visitor,
|
||||
expand_box_point(),
|
||||
overlaps_box_point_type(),
|
||||
expand_box_box_pair(),
|
||||
overlaps_box_box_pair_type());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// MultiGeometry - Linear or Areal
|
||||
// part of the algorithm calculating II, IB and IE
|
||||
// using rtree
|
||||
template <typename MultiPoint, typename MultiGeometry, bool Transpose>
|
||||
struct multi_point_multi_geometry_ii_ib_ie
|
||||
{
|
||||
typedef typename point_type<MultiPoint>::type point1_type;
|
||||
typedef typename point_type<MultiGeometry>::type point2_type;
|
||||
typedef model::box<point1_type> box1_type;
|
||||
typedef model::box<point2_type> box2_type;
|
||||
typedef std::pair<box2_type, std::size_t> box_pair_type;
|
||||
typedef std::vector<box_pair_type> boxes_type;
|
||||
typedef typename boxes_type::const_iterator boxes_iterator;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint const& multi_point,
|
||||
MultiGeometry const& multi_geometry,
|
||||
std::vector<box_pair_type> const& boxes,
|
||||
detail::relate::topology_check
|
||||
<
|
||||
MultiGeometry,
|
||||
typename Strategy::equals_point_point_strategy_type
|
||||
> const& tc,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
index::rtree<box_pair_type, index::rstar<4> > rt(boxes.begin(), boxes.end());
|
||||
|
||||
typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
|
||||
for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
|
||||
{
|
||||
if (! (relate::may_update<interior, interior, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, boundary, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, exterior, '0', Transpose>(result) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
typename boost::range_value<MultiPoint>::type const& point = *it;
|
||||
|
||||
boxes_type boxes_found;
|
||||
rt.query(index::intersects(point), std::back_inserter(boxes_found));
|
||||
|
||||
bool found_ii_or_ib = false;
|
||||
for (boxes_iterator bi = boxes_found.begin() ; bi != boxes_found.end() ; ++bi)
|
||||
{
|
||||
typename boost::range_value<MultiGeometry>::type const&
|
||||
single = range::at(multi_geometry, bi->second);
|
||||
|
||||
int in_val = detail::within::point_in_geometry(point, single, strategy);
|
||||
|
||||
if (in_val > 0) // within
|
||||
{
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
found_ii_or_ib = true;
|
||||
}
|
||||
else if (in_val == 0) // on boundary of single
|
||||
{
|
||||
if (tc.check_boundary_point(point))
|
||||
relate::set<interior, boundary, '0', Transpose>(result);
|
||||
else
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
found_ii_or_ib = true;
|
||||
}
|
||||
}
|
||||
|
||||
// neither interior nor boundary found -> exterior
|
||||
if (found_ii_or_ib == false)
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
}
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// MultiGeometry - Linear or Areal
|
||||
template <typename MultiPoint, typename MultiGeometry, bool Transpose = false>
|
||||
struct multi_point_multi_geometry
|
||||
{
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint const& multi_point,
|
||||
MultiGeometry const& multi_geometry,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
typedef typename point_type<MultiGeometry>::type point2_type;
|
||||
typedef model::box<point2_type> box2_type;
|
||||
typedef std::pair<box2_type, std::size_t> box_pair_type;
|
||||
|
||||
typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type;
|
||||
|
||||
typename Strategy::envelope_strategy_type const
|
||||
envelope_strategy = strategy.get_envelope_strategy();
|
||||
|
||||
std::size_t count2 = boost::size(multi_geometry);
|
||||
std::vector<box_pair_type> boxes(count2);
|
||||
for (std::size_t i = 0 ; i < count2 ; ++i)
|
||||
{
|
||||
geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
|
||||
geometry::detail::expand_by_epsilon(boxes[i].first);
|
||||
boxes[i].second = i;
|
||||
}
|
||||
|
||||
typedef detail::relate::topology_check<MultiGeometry, eq_pp_strategy_type> tc_t;
|
||||
tc_t tc(multi_geometry);
|
||||
|
||||
if ( relate::may_update<interior, interior, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, boundary, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, exterior, '0', Transpose>(result) )
|
||||
{
|
||||
// If there is no need to calculate IE, use partition
|
||||
if (! relate::may_update<interior, exterior, '0', Transpose>(result) )
|
||||
{
|
||||
multi_point_multi_geometry_ii_ib<MultiPoint, MultiGeometry, Transpose>
|
||||
::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
|
||||
}
|
||||
else // otherwise use rtree
|
||||
{
|
||||
multi_point_multi_geometry_ii_ib_ie<MultiPoint, MultiGeometry, Transpose>
|
||||
::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
|| relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
|
||||
{
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
&& tc.has_interior() )
|
||||
{
|
||||
// TODO: this is not true if a linestring is degenerated to a point
|
||||
// then the interior has topological dimension = 0, not 1
|
||||
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
}
|
||||
|
||||
if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
|
||||
&& tc.has_boundary() )
|
||||
{
|
||||
if (multi_point_geometry_eb
|
||||
<
|
||||
MultiGeometry, eq_pp_strategy_type
|
||||
>::apply(multi_point, tc))
|
||||
{
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename MultiPoint, typename Geometry,
|
||||
bool Transpose = false,
|
||||
bool isMulti = boost::is_same
|
||||
<
|
||||
typename tag_cast
|
||||
<
|
||||
typename tag<Geometry>::type, multi_tag
|
||||
>::type,
|
||||
multi_tag
|
||||
>::value
|
||||
>
|
||||
struct multi_point_geometry
|
||||
: multi_point_single_geometry<MultiPoint, Geometry, Transpose>
|
||||
{};
|
||||
|
||||
template <typename MultiPoint, typename Geometry, bool Transpose>
|
||||
struct multi_point_geometry<MultiPoint, Geometry, Transpose, true>
|
||||
: multi_point_multi_geometry<MultiPoint, Geometry, Transpose>
|
||||
{};
|
||||
|
||||
|
||||
// transposed result of multi_point_geometry
|
||||
template <typename Geometry, typename MultiPoint>
|
||||
struct geometry_multi_point
|
||||
{
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Geometry const& geometry, MultiPoint const& multi_point,
|
||||
Result & result, Strategy const& strategy)
|
||||
{
|
||||
multi_point_geometry<MultiPoint, Geometry, true>::apply(multi_point, geometry, result, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
|
||||
@@ -0,0 +1,210 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// 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.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
|
||||
//#include <boost/geometry/algorithms/within.hpp>
|
||||
//#include <boost/geometry/algorithms/covered_by.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
|
||||
|
||||
#include <boost/geometry/util/condition.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// non-point geometry
|
||||
template <typename Point, typename Geometry, bool Transpose = false>
|
||||
struct point_geometry
|
||||
{
|
||||
// TODO: interrupt only if the topology check is complex
|
||||
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Point const& point, Geometry const& geometry, Result & result, Strategy const& strategy)
|
||||
{
|
||||
int pig = detail::within::point_in_geometry(point, geometry, strategy);
|
||||
|
||||
if ( pig > 0 ) // within
|
||||
{
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
}
|
||||
else if ( pig == 0 )
|
||||
{
|
||||
relate::set<interior, boundary, '0', Transpose>(result);
|
||||
}
|
||||
else // pig < 0 - not within
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
}
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
return;
|
||||
|
||||
typedef detail::relate::topology_check
|
||||
<
|
||||
Geometry,
|
||||
typename Strategy::equals_point_point_strategy_type
|
||||
> tc_t;
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
|| relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
|
||||
{
|
||||
// the point is on the boundary
|
||||
if ( pig == 0 )
|
||||
{
|
||||
// NOTE: even for MLs, if there is at least one boundary point,
|
||||
// somewhere there must be another one
|
||||
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if there is a boundary in Geometry
|
||||
tc_t tc(geometry);
|
||||
if ( tc.has_interior() )
|
||||
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
if ( tc.has_boundary() )
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// transposed result of point_geometry
|
||||
template <typename Geometry, typename Point>
|
||||
struct geometry_point
|
||||
{
|
||||
// TODO: interrupt only if the topology check is complex
|
||||
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Geometry const& geometry, Point const& point, Result & result, Strategy const& strategy)
|
||||
{
|
||||
point_geometry<Point, Geometry, true>::apply(point, geometry, result, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: rewrite the folowing:
|
||||
|
||||
//// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box)
|
||||
//// There is no EPS used in those functions, values are compared using < or <=
|
||||
//// so comparing MIN and MAX in the same way should be fine
|
||||
//
|
||||
//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
|
||||
//struct box_has_interior
|
||||
//{
|
||||
// static inline bool apply(Box const& box)
|
||||
// {
|
||||
// return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box)
|
||||
// && box_has_interior<Box, I + 1, D>::apply(box);
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//template <typename Box, std::size_t D>
|
||||
//struct box_has_interior<Box, D, D>
|
||||
//{
|
||||
// static inline bool apply(Box const&) { return true; }
|
||||
//};
|
||||
//
|
||||
//// NOTE: especially important here (see the NOTE above).
|
||||
//
|
||||
//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
|
||||
//struct box_has_equal_min_max
|
||||
//{
|
||||
// static inline bool apply(Box const& box)
|
||||
// {
|
||||
// return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box)
|
||||
// && box_has_equal_min_max<Box, I + 1, D>::apply(box);
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//template <typename Box, std::size_t D>
|
||||
//struct box_has_equal_min_max<Box, D, D>
|
||||
//{
|
||||
// static inline bool apply(Box const&) { return true; }
|
||||
//};
|
||||
//
|
||||
//template <typename Point, typename Box>
|
||||
//struct point_box
|
||||
//{
|
||||
// static inline result apply(Point const& point, Box const& box)
|
||||
// {
|
||||
// result res;
|
||||
//
|
||||
// if ( geometry::within(point, box) ) // this also means that the box has interior
|
||||
// {
|
||||
// return result("0FFFFFTTT");
|
||||
// }
|
||||
// else if ( geometry::covered_by(point, box) ) // point is on the boundary
|
||||
// {
|
||||
// //if ( box_has_interior<Box>::apply(box) )
|
||||
// //{
|
||||
// // return result("F0FFFFTTT");
|
||||
// //}
|
||||
// //else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point
|
||||
// //{
|
||||
// // return result("F0FFFFFFT");
|
||||
// //}
|
||||
// //else // no interior outside point
|
||||
// //{
|
||||
// // return result("F0FFFFFTT");
|
||||
// //}
|
||||
// return result("F0FFFF**T");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /*if ( box_has_interior<Box>::apply(box) )
|
||||
// {
|
||||
// return result("FF0FFFTTT");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return result("FF0FFFFTT");
|
||||
// }*/
|
||||
// return result("FF0FFF*TT");
|
||||
// }
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//template <typename Box, typename Point>
|
||||
//struct box_point
|
||||
//{
|
||||
// static inline result apply(Box const& box, Point const& point)
|
||||
// {
|
||||
// if ( geometry::within(point, box) )
|
||||
// return result("0FTFFTFFT");
|
||||
// else if ( geometry::covered_by(point, box) )
|
||||
// return result("FF*0F*FFT");
|
||||
// else
|
||||
// return result("FF*FFT0FT");
|
||||
// }
|
||||
//};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
|
||||
@@ -0,0 +1,270 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// 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.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/range/empty.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
|
||||
#include <boost/geometry/policies/compare.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
template <typename Point1, typename Point2>
|
||||
struct point_point
|
||||
{
|
||||
static const bool interruption_enabled = false;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Point1 const& point1, Point2 const& point2,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
bool equal = detail::equals::equals_point_point(point1, point2, strategy);
|
||||
if ( equal )
|
||||
{
|
||||
relate::set<interior, interior, '0'>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
relate::set<interior, exterior, '0'>(result);
|
||||
relate::set<exterior, interior, '0'>(result);
|
||||
}
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<Point1>::value>(result);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Point, typename MultiPoint, typename EqPPStrategy>
|
||||
std::pair<bool, bool> point_multipoint_check(Point const& point,
|
||||
MultiPoint const& multi_point,
|
||||
EqPPStrategy const& strategy)
|
||||
{
|
||||
bool found_inside = false;
|
||||
bool found_outside = false;
|
||||
|
||||
// point_in_geometry could be used here but why iterate over MultiPoint twice?
|
||||
// we must search for a point in the exterior because all points in MultiPoint can be equal
|
||||
|
||||
typedef typename boost::range_iterator<MultiPoint const>::type iterator;
|
||||
iterator it = boost::begin(multi_point);
|
||||
iterator last = boost::end(multi_point);
|
||||
for ( ; it != last ; ++it )
|
||||
{
|
||||
bool ii = detail::equals::equals_point_point(point, *it, strategy);
|
||||
|
||||
if ( ii )
|
||||
found_inside = true;
|
||||
else
|
||||
found_outside = true;
|
||||
|
||||
if ( found_inside && found_outside )
|
||||
break;
|
||||
}
|
||||
|
||||
return std::make_pair(found_inside, found_outside);
|
||||
}
|
||||
|
||||
template <typename Point, typename MultiPoint, bool Transpose = false>
|
||||
struct point_multipoint
|
||||
{
|
||||
static const bool interruption_enabled = false;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Point const& point, MultiPoint const& multi_point,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
if ( boost::empty(multi_point) )
|
||||
{
|
||||
// TODO: throw on empty input?
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
return;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> rel = point_multipoint_check(point, multi_point, strategy);
|
||||
|
||||
if ( rel.first ) // some point of MP is equal to P
|
||||
{
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
|
||||
if ( rel.second ) // a point of MP was found outside P
|
||||
{
|
||||
relate::set<exterior, interior, '0', Transpose>(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
relate::set<exterior, interior, '0', Transpose>(result);
|
||||
}
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MultiPoint, typename Point>
|
||||
struct multipoint_point
|
||||
{
|
||||
static const bool interruption_enabled = false;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint const& multi_point, Point const& point,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MultiPoint1, typename MultiPoint2>
|
||||
struct multipoint_multipoint
|
||||
{
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2,
|
||||
Result & result,
|
||||
Strategy const& /*strategy*/)
|
||||
{
|
||||
{
|
||||
// TODO: throw on empty input?
|
||||
bool empty1 = boost::empty(multi_point1);
|
||||
bool empty2 = boost::empty(multi_point2);
|
||||
if ( empty1 && empty2 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ( empty1 )
|
||||
{
|
||||
relate::set<exterior, interior, '0'>(result);
|
||||
return;
|
||||
}
|
||||
else if ( empty2 )
|
||||
{
|
||||
relate::set<interior, exterior, '0'>(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The geometry containing smaller number of points will be analysed first
|
||||
if ( boost::size(multi_point1) < boost::size(multi_point2) )
|
||||
{
|
||||
search_both<false>(multi_point1, multi_point2, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_both<true>(multi_point2, multi_point1, result);
|
||||
}
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<MultiPoint1>::value>(result);
|
||||
}
|
||||
|
||||
template <bool Transpose, typename MPt1, typename MPt2, typename Result>
|
||||
static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt,
|
||||
Result & result)
|
||||
{
|
||||
if ( relate::may_update<interior, interior, '0'>(result)
|
||||
|| relate::may_update<interior, exterior, '0'>(result)
|
||||
|| relate::may_update<exterior, interior, '0'>(result) )
|
||||
{
|
||||
// NlogN + MlogN
|
||||
bool is_disjoint = search<Transpose>(first_sorted_mpt, first_iterated_mpt, result);
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( relate::may_update<interior, interior, '0'>(result)
|
||||
|| relate::may_update<interior, exterior, '0'>(result)
|
||||
|| relate::may_update<exterior, interior, '0'>(result) )
|
||||
{
|
||||
// MlogM + NlogM
|
||||
search<! Transpose>(first_iterated_mpt, first_sorted_mpt, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool Transpose,
|
||||
typename SortedMultiPoint,
|
||||
typename IteratedMultiPoint,
|
||||
typename Result>
|
||||
static inline bool search(SortedMultiPoint const& sorted_mpt,
|
||||
IteratedMultiPoint const& iterated_mpt,
|
||||
Result & result)
|
||||
{
|
||||
// sort points from the 1 MPt
|
||||
typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
|
||||
std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
|
||||
|
||||
geometry::less<> const less = geometry::less<>();
|
||||
std::sort(points.begin(), points.end(), less);
|
||||
|
||||
bool found_inside = false;
|
||||
bool found_outside = false;
|
||||
|
||||
// for each point in the second MPt
|
||||
typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator;
|
||||
for ( iterator it = boost::begin(iterated_mpt) ;
|
||||
it != boost::end(iterated_mpt) ; ++it )
|
||||
{
|
||||
bool ii =
|
||||
std::binary_search(points.begin(), points.end(), *it, less);
|
||||
if ( ii )
|
||||
found_inside = true;
|
||||
else
|
||||
found_outside = true;
|
||||
|
||||
if ( found_inside && found_outside )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( found_inside ) // some point of MP2 is equal to some of MP1
|
||||
{
|
||||
// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
|
||||
// so if e.g. only I/I must be analysed we musn't check the other MPt
|
||||
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
|
||||
if ( found_outside ) // some point of MP2 was found outside of MP1
|
||||
{
|
||||
relate::set<exterior, interior, '0', Transpose>(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
relate::set<exterior, interior, '0', Transpose>(result);
|
||||
}
|
||||
|
||||
// if no point is intersecting the other MPt then we musn't analyse the reversed case
|
||||
return ! found_inside;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP
|
||||
@@ -0,0 +1,81 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014, 2015.
|
||||
// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_IMPL_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_IMPL_HPP
|
||||
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/or.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/interface.hpp>
|
||||
#include <boost/geometry/algorithms/not_implemented.hpp>
|
||||
#include <boost/geometry/core/tag.hpp>
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
struct implemented_tag {};
|
||||
|
||||
template <template <typename, typename> class StaticMaskTrait,
|
||||
typename Geometry1,
|
||||
typename Geometry2>
|
||||
struct relate_impl
|
||||
: boost::mpl::if_
|
||||
<
|
||||
boost::mpl::or_
|
||||
<
|
||||
boost::is_base_of
|
||||
<
|
||||
nyi::not_implemented_tag,
|
||||
StaticMaskTrait<Geometry1, Geometry2>
|
||||
>,
|
||||
boost::is_base_of
|
||||
<
|
||||
nyi::not_implemented_tag,
|
||||
dispatch::relate<Geometry1, Geometry2>
|
||||
>
|
||||
>,
|
||||
not_implemented
|
||||
<
|
||||
typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type
|
||||
>,
|
||||
implemented_tag
|
||||
>::type
|
||||
{
|
||||
template <typename Strategy>
|
||||
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
|
||||
{
|
||||
typename detail::relate::result_handler_type
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
typename StaticMaskTrait<Geometry1, Geometry2>::type
|
||||
>::type handler;
|
||||
|
||||
dispatch::relate<Geometry1, Geometry2>::apply(g1, g2, handler, strategy);
|
||||
|
||||
return handler.result();
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_IMPL_HPP
|
||||
1298
macx64/include/boost/geometry/algorithms/detail/relate/result.hpp
Normal file
1298
macx64/include/boost/geometry/algorithms/detail/relate/result.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,346 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
|
||||
|
||||
|
||||
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/not_implemented.hpp>
|
||||
|
||||
#include <boost/geometry/policies/compare.hpp>
|
||||
|
||||
#include <boost/geometry/util/has_nan_coordinate.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// TODO: change the name for e.g. something with the word "exterior"
|
||||
|
||||
template <typename Geometry,
|
||||
typename EqPPStrategy,
|
||||
typename Tag = typename geometry::tag<Geometry>::type>
|
||||
struct topology_check
|
||||
: not_implemented<Tag>
|
||||
{};
|
||||
|
||||
//template <typename Point>
|
||||
//struct topology_check<Point, point_tag>
|
||||
//{
|
||||
// static const char interior = '0';
|
||||
// static const char boundary = 'F';
|
||||
//
|
||||
// static const bool has_interior = true;
|
||||
// static const bool has_boundary = false;
|
||||
//
|
||||
// topology_check(Point const&) {}
|
||||
// template <typename IgnoreBoundaryPoint>
|
||||
// topology_check(Point const&, IgnoreBoundaryPoint const&) {}
|
||||
//};
|
||||
|
||||
template <typename Linestring, typename EqPPStrategy>
|
||||
struct topology_check<Linestring, EqPPStrategy, linestring_tag>
|
||||
{
|
||||
static const char interior = '1';
|
||||
static const char boundary = '0';
|
||||
|
||||
topology_check(Linestring const& ls)
|
||||
: m_ls(ls)
|
||||
, m_is_initialized(false)
|
||||
{}
|
||||
|
||||
bool has_interior() const
|
||||
{
|
||||
init();
|
||||
return m_has_interior;
|
||||
}
|
||||
|
||||
bool has_boundary() const
|
||||
{
|
||||
init();
|
||||
return m_has_boundary;
|
||||
}
|
||||
|
||||
/*template <typename Point>
|
||||
bool check_boundary_point(Point const& point) const
|
||||
{
|
||||
init();
|
||||
return m_has_boundary
|
||||
&& ( equals::equals_point_point(point, range::front(m_ls))
|
||||
|| equals::equals_point_point(point, range::back(m_ls)) );
|
||||
}*/
|
||||
|
||||
template <typename Visitor>
|
||||
void for_each_boundary_point(Visitor & visitor) const
|
||||
{
|
||||
init();
|
||||
if (m_has_boundary)
|
||||
{
|
||||
if (visitor.apply(range::front(m_ls)))
|
||||
visitor.apply(range::back(m_ls));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void init() const
|
||||
{
|
||||
if (m_is_initialized)
|
||||
return;
|
||||
|
||||
std::size_t count = boost::size(m_ls);
|
||||
m_has_interior = count > 0;
|
||||
// NOTE: Linestring with all points equal is treated as 1d linear ring
|
||||
m_has_boundary = count > 1
|
||||
&& ! detail::equals::equals_point_point(range::front(m_ls),
|
||||
range::back(m_ls),
|
||||
EqPPStrategy());
|
||||
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
Linestring const& m_ls;
|
||||
mutable bool m_is_initialized;
|
||||
|
||||
mutable bool m_has_interior;
|
||||
mutable bool m_has_boundary;
|
||||
};
|
||||
|
||||
template <typename MultiLinestring, typename EqPPStrategy>
|
||||
struct topology_check<MultiLinestring, EqPPStrategy, multi_linestring_tag>
|
||||
{
|
||||
static const char interior = '1';
|
||||
static const char boundary = '0';
|
||||
|
||||
topology_check(MultiLinestring const& mls)
|
||||
: m_mls(mls)
|
||||
, m_is_initialized(false)
|
||||
{}
|
||||
|
||||
bool has_interior() const
|
||||
{
|
||||
init();
|
||||
return m_has_interior;
|
||||
}
|
||||
|
||||
bool has_boundary() const
|
||||
{
|
||||
init();
|
||||
return m_has_boundary;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
bool check_boundary_point(Point const& point) const
|
||||
{
|
||||
init();
|
||||
|
||||
if (! m_has_boundary)
|
||||
return false;
|
||||
|
||||
std::size_t count = count_equal(m_endpoints.begin(), m_endpoints.end(), point);
|
||||
|
||||
return count % 2 != 0; // odd count -> boundary
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void for_each_boundary_point(Visitor & visitor) const
|
||||
{
|
||||
init();
|
||||
if (m_has_boundary)
|
||||
{
|
||||
for_each_boundary_point(m_endpoints.begin(), m_endpoints.end(), visitor);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO: CS-specific less derived from EqPPStrategy
|
||||
typedef geometry::less<> less_type;
|
||||
|
||||
void init() const
|
||||
{
|
||||
if (m_is_initialized)
|
||||
return;
|
||||
|
||||
m_endpoints.reserve(boost::size(m_mls) * 2);
|
||||
|
||||
m_has_interior = false;
|
||||
|
||||
typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
|
||||
for ( ls_iterator it = boost::begin(m_mls) ; it != boost::end(m_mls) ; ++it )
|
||||
{
|
||||
typename boost::range_reference<MultiLinestring const>::type
|
||||
ls = *it;
|
||||
|
||||
std::size_t count = boost::size(ls);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
m_has_interior = true;
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
typedef typename boost::range_reference
|
||||
<
|
||||
typename boost::range_value<MultiLinestring const>::type const
|
||||
>::type point_reference;
|
||||
|
||||
point_reference front_pt = range::front(ls);
|
||||
point_reference back_pt = range::back(ls);
|
||||
|
||||
// don't store boundaries of linear rings, this doesn't change anything
|
||||
if (! equals::equals_point_point(front_pt, back_pt, EqPPStrategy()))
|
||||
{
|
||||
// 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()
|
||||
// NOTE: currently ignoring_counter calling std::equal_range()
|
||||
// is not used anywhere in the code, still it's safer this way
|
||||
if (! geometry::has_nan_coordinate(front_pt))
|
||||
{
|
||||
m_endpoints.push_back(front_pt);
|
||||
}
|
||||
if (! geometry::has_nan_coordinate(back_pt))
|
||||
{
|
||||
m_endpoints.push_back(back_pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_has_boundary = false;
|
||||
|
||||
if (! m_endpoints.empty() )
|
||||
{
|
||||
std::sort(m_endpoints.begin(), m_endpoints.end(), less_type());
|
||||
m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end());
|
||||
}
|
||||
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
template <typename It, typename Point>
|
||||
static inline std::size_t count_equal(It first, It last, Point const& point)
|
||||
{
|
||||
std::pair<It, It> rng = std::equal_range(first, last, point, less_type());
|
||||
return (std::size_t)std::distance(rng.first, rng.second);
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
static inline bool find_odd_count(It first, It last)
|
||||
{
|
||||
interrupting_visitor visitor;
|
||||
for_each_boundary_point(first, last, visitor);
|
||||
return visitor.found;
|
||||
}
|
||||
|
||||
struct interrupting_visitor
|
||||
{
|
||||
bool found;
|
||||
interrupting_visitor() : found(false) {}
|
||||
template <typename Point>
|
||||
bool apply(Point const&)
|
||||
{
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename It, typename Visitor>
|
||||
static void for_each_boundary_point(It first, It last, Visitor& visitor)
|
||||
{
|
||||
if ( first == last )
|
||||
return;
|
||||
|
||||
std::size_t count = 1;
|
||||
It prev = first;
|
||||
++first;
|
||||
for ( ; first != last ; ++first, ++prev )
|
||||
{
|
||||
// the end of the equal points subrange
|
||||
if ( ! equals::equals_point_point(*first, *prev, EqPPStrategy()) )
|
||||
{
|
||||
// odd count -> boundary
|
||||
if ( count % 2 != 0 )
|
||||
{
|
||||
if (! visitor.apply(*prev))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
// odd count -> boundary
|
||||
if ( count % 2 != 0 )
|
||||
{
|
||||
visitor.apply(*prev);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MultiLinestring const& m_mls;
|
||||
mutable bool m_is_initialized;
|
||||
|
||||
mutable bool m_has_interior;
|
||||
mutable bool m_has_boundary;
|
||||
|
||||
typedef typename geometry::point_type<MultiLinestring>::type point_type;
|
||||
mutable std::vector<point_type> m_endpoints;
|
||||
};
|
||||
|
||||
struct topology_check_areal
|
||||
{
|
||||
static const char interior = '2';
|
||||
static const char boundary = '1';
|
||||
|
||||
static bool has_interior() { return true; }
|
||||
static bool has_boundary() { return true; }
|
||||
};
|
||||
|
||||
template <typename Ring, typename EqPPStrategy>
|
||||
struct topology_check<Ring, EqPPStrategy, ring_tag>
|
||||
: topology_check_areal
|
||||
{
|
||||
topology_check(Ring const&) {}
|
||||
};
|
||||
|
||||
template <typename Polygon, typename EqPPStrategy>
|
||||
struct topology_check<Polygon, EqPPStrategy, polygon_tag>
|
||||
: topology_check_areal
|
||||
{
|
||||
topology_check(Polygon const&) {}
|
||||
};
|
||||
|
||||
template <typename MultiPolygon, typename EqPPStrategy>
|
||||
struct topology_check<MultiPolygon, EqPPStrategy, multi_polygon_tag>
|
||||
: topology_check_areal
|
||||
{
|
||||
topology_check(MultiPolygon const&) {}
|
||||
|
||||
template <typename Point>
|
||||
static bool check_boundary_point(Point const& ) { return true; }
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
|
||||
311
macx64/include/boost/geometry/algorithms/detail/relate/turns.hpp
Normal file
311
macx64/include/boost/geometry/algorithms/detail/relate/turns.hpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2013, 2014, 2015, 2017.
|
||||
// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
|
||||
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
|
||||
|
||||
#include <boost/geometry/strategies/distance.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
|
||||
|
||||
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
|
||||
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
|
||||
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate { namespace turns {
|
||||
|
||||
template <bool IncludeDegenerate = false>
|
||||
struct assign_policy
|
||||
: overlay::assign_null_policy
|
||||
{
|
||||
static bool const include_degenerate = IncludeDegenerate;
|
||||
};
|
||||
|
||||
// GET_TURNS
|
||||
|
||||
template
|
||||
<
|
||||
typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename GetTurnPolicy = detail::get_turns::get_turn_info_type
|
||||
<
|
||||
Geometry1, Geometry2, assign_policy<>
|
||||
>,
|
||||
typename RobustPolicy = typename geometry::rescale_overlay_policy_type
|
||||
<
|
||||
Geometry1,
|
||||
Geometry2
|
||||
>::type
|
||||
>
|
||||
struct get_turns
|
||||
{
|
||||
typedef typename geometry::point_type<Geometry1>::type point1_type;
|
||||
|
||||
typedef overlay::turn_info
|
||||
<
|
||||
point1_type,
|
||||
typename segment_ratio_type<point1_type, RobustPolicy>::type,
|
||||
typename detail::get_turns::turn_operation_type
|
||||
<
|
||||
Geometry1, Geometry2,
|
||||
typename segment_ratio_type
|
||||
<
|
||||
point1_type, RobustPolicy
|
||||
>::type
|
||||
>::type
|
||||
> turn_info;
|
||||
|
||||
template <typename Turns>
|
||||
static inline void apply(Turns & turns,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2)
|
||||
{
|
||||
detail::get_turns::no_interrupt_policy interrupt_policy;
|
||||
|
||||
typename strategy::intersection::services::default_strategy
|
||||
<
|
||||
typename cs_tag<Geometry1>::type
|
||||
>::type intersection_strategy;
|
||||
|
||||
apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy);
|
||||
}
|
||||
|
||||
template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy>
|
||||
static inline void apply(Turns & turns,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
InterruptPolicy & interrupt_policy,
|
||||
IntersectionStrategy const& intersection_strategy)
|
||||
{
|
||||
RobustPolicy robust_policy = geometry::get_rescale_policy
|
||||
<
|
||||
RobustPolicy
|
||||
>(geometry1, geometry2);
|
||||
|
||||
apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy, robust_policy);
|
||||
}
|
||||
|
||||
template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy>
|
||||
static inline void apply(Turns & turns,
|
||||
Geometry1 const& geometry1,
|
||||
Geometry2 const& geometry2,
|
||||
InterruptPolicy & interrupt_policy,
|
||||
IntersectionStrategy const& intersection_strategy,
|
||||
RobustPolicy const& robust_policy)
|
||||
{
|
||||
static const bool reverse1 = detail::overlay::do_reverse
|
||||
<
|
||||
geometry::point_order<Geometry1>::value
|
||||
>::value;
|
||||
|
||||
static const bool reverse2 = detail::overlay::do_reverse
|
||||
<
|
||||
geometry::point_order<Geometry2>::value
|
||||
>::value;
|
||||
|
||||
dispatch::get_turns
|
||||
<
|
||||
typename geometry::tag<Geometry1>::type,
|
||||
typename geometry::tag<Geometry2>::type,
|
||||
Geometry1,
|
||||
Geometry2,
|
||||
reverse1,
|
||||
reverse2,
|
||||
GetTurnPolicy
|
||||
>::apply(0, geometry1, 1, geometry2,
|
||||
intersection_strategy, robust_policy,
|
||||
turns, interrupt_policy);
|
||||
}
|
||||
};
|
||||
|
||||
// TURNS SORTING AND SEARCHING
|
||||
|
||||
template <int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0>
|
||||
struct op_to_int
|
||||
{
|
||||
template <typename Operation>
|
||||
inline int operator()(Operation const& op) const
|
||||
{
|
||||
switch(op.operation)
|
||||
{
|
||||
case detail::overlay::operation_none : return N;
|
||||
case detail::overlay::operation_union : return U;
|
||||
case detail::overlay::operation_intersection : return I;
|
||||
case detail::overlay::operation_blocked : return B;
|
||||
case detail::overlay::operation_continue : return C;
|
||||
case detail::overlay::operation_opposite : return O;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId, typename OpToInt>
|
||||
struct less_op_xxx_linear
|
||||
{
|
||||
template <typename Turn>
|
||||
inline bool operator()(Turn const& left, Turn const& right) const
|
||||
{
|
||||
static OpToInt op_to_int;
|
||||
return op_to_int(left.operations[OpId]) < op_to_int(right.operations[OpId]);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId>
|
||||
struct less_op_linear_linear
|
||||
: less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> >
|
||||
{};
|
||||
|
||||
template <std::size_t OpId>
|
||||
struct less_op_linear_areal_single
|
||||
{
|
||||
template <typename Turn>
|
||||
inline bool operator()(Turn const& left, Turn const& right) const
|
||||
{
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
|
||||
static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc;
|
||||
|
||||
segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
|
||||
segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
|
||||
|
||||
typedef typename Turn::turn_operation_type operation_type;
|
||||
operation_type const& left_operation = left.operations[OpId];
|
||||
operation_type const& right_operation = right.operations[OpId];
|
||||
|
||||
if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
|
||||
{
|
||||
return op_to_int_xuic(left_operation)
|
||||
< op_to_int_xuic(right_operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
return op_to_int_xiuc(left_operation)
|
||||
< op_to_int_xiuc(right_operation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId>
|
||||
struct less_op_areal_linear
|
||||
: less_op_xxx_linear< OpId, op_to_int<0,1,0,0,2,0> >
|
||||
{};
|
||||
|
||||
template <std::size_t OpId>
|
||||
struct less_op_areal_areal
|
||||
{
|
||||
template <typename Turn>
|
||||
inline bool operator()(Turn const& left, Turn const& right) const
|
||||
{
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
static op_to_int<0, 1, 2, 3, 4, 0> op_to_int_uixc;
|
||||
static op_to_int<0, 2, 1, 3, 4, 0> op_to_int_iuxc;
|
||||
|
||||
segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
|
||||
segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
|
||||
|
||||
typedef typename Turn::turn_operation_type operation_type;
|
||||
operation_type const& left_operation = left.operations[OpId];
|
||||
operation_type const& right_operation = right.operations[OpId];
|
||||
|
||||
if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
|
||||
{
|
||||
if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
|
||||
{
|
||||
return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( left_other_seg_id.ring_index == -1 )
|
||||
{
|
||||
if ( left_operation.operation == overlay::operation_union )
|
||||
return false;
|
||||
else if ( left_operation.operation == overlay::operation_intersection )
|
||||
return true;
|
||||
}
|
||||
else if ( right_other_seg_id.ring_index == -1 )
|
||||
{
|
||||
if ( right_operation.operation == overlay::operation_union )
|
||||
return true;
|
||||
else if ( right_operation.operation == overlay::operation_intersection )
|
||||
return false;
|
||||
}
|
||||
|
||||
return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId>
|
||||
struct less_other_multi_index
|
||||
{
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
|
||||
template <typename Turn>
|
||||
inline bool operator()(Turn const& left, Turn const& right) const
|
||||
{
|
||||
return left.operations[other_op_id].seg_id.multi_index
|
||||
< right.operations[other_op_id].seg_id.multi_index;
|
||||
}
|
||||
};
|
||||
|
||||
// sort turns by G1 - source_index == 0 by:
|
||||
// seg_id -> distance -> operation
|
||||
template <std::size_t OpId = 0,
|
||||
typename LessOp = less_op_xxx_linear< OpId, op_to_int<> > >
|
||||
struct less
|
||||
{
|
||||
BOOST_STATIC_ASSERT(OpId < 2);
|
||||
|
||||
template <typename Turn>
|
||||
static inline bool use_fraction(Turn const& left, Turn const& right)
|
||||
{
|
||||
static LessOp less_op;
|
||||
|
||||
return
|
||||
geometry::math::equals(left.operations[OpId].fraction,
|
||||
right.operations[OpId].fraction)
|
||||
?
|
||||
less_op(left, right)
|
||||
:
|
||||
(left.operations[OpId].fraction < right.operations[OpId].fraction)
|
||||
;
|
||||
}
|
||||
|
||||
template <typename Turn>
|
||||
inline bool operator()(Turn const& left, Turn const& right) const
|
||||
{
|
||||
segment_identifier const& sl = left.operations[OpId].seg_id;
|
||||
segment_identifier const& sr = right.operations[OpId].seg_id;
|
||||
|
||||
return sl < sr || ( sl == sr && use_fraction(left, right) );
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace detail::relate::turns
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
|
||||
Reference in New Issue
Block a user