Initial commit

This commit is contained in:
Bassem Girgis
2018-12-20 17:34:07 -06:00
parent 7a2d899662
commit 81b4b9e273
34743 changed files with 5940233 additions and 0 deletions

View File

@@ -0,0 +1,878 @@
// 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_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());
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());
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>
void apply(Result & result, TurnIt it)
{
//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) )
{
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) )
{
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>
static inline void analyse_each_turn(Result & res,
Analyser & analyser,
TurnIt first, TurnIt last)
{
if ( first == last )
return;
for ( TurnIt it = first ; it != last ; ++it )
{
analyser.apply(res, it);
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

View File

@@ -0,0 +1,160 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014 Oracle and/or its affiliates.
// 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)
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/util/has_nan_coordinate.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 Tag = typename geometry::tag<Geometry>::type>
class boundary_checker {};
template <typename Geometry>
class boundary_checker<Geometry, linestring_tag>
{
typedef typename point_type<Geometry>::type point_type;
public:
boundary_checker(Geometry const& g)
: has_boundary( boost::size(g) >= 2
&& !detail::equals::equals_point_point(range::front(g), range::back(g)) )
, geometry(g)
{}
template <boundary_query BoundaryQuery>
bool is_endpoint_boundary(point_type const& pt) const
{
boost::ignore_unused_variable_warning(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))
|| (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
&& detail::equals::equals_point_point(pt, range::back(geometry)) );
#endif
return has_boundary;
}
private:
bool has_boundary;
Geometry const& geometry;
};
template <typename Geometry>
class boundary_checker<Geometry, multi_linestring_tag>
{
typedef typename point_type<Geometry>::type point_type;
public:
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))
{
// 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

View 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

View File

@@ -0,0 +1,404 @@
// 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.
// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
// 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)
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_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>
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_variable_warning(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>
inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn)
{
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);
}
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_variable_warning(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

View File

@@ -0,0 +1,113 @@
// 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/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 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

View File

@@ -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

View File

@@ -0,0 +1,83 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// 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)
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace detail_dispatch { namespace relate {
// TODO: Integrate it with geometry::less?
template <typename Point1,
typename Point2,
std::size_t I = 0,
std::size_t D = geometry::dimension<Point1>::value>
struct less
{
static inline bool apply(Point1 const& left, Point2 const& right)
{
typename geometry::coordinate_type<Point1>::type
cleft = geometry::get<I>(left);
typename geometry::coordinate_type<Point2>::type
cright = geometry::get<I>(right);
if ( geometry::math::equals(cleft, cright) )
{
return less<Point1, Point2, I + 1, D>::apply(left, right);
}
else
{
return cleft < cright;
}
}
};
template <typename Point1, typename Point2, std::size_t D>
struct less<Point1, Point2, D, D>
{
static inline bool apply(Point1 const&, Point2 const&)
{
return false;
}
};
}} // namespace detail_dispatch::relate
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace relate {
struct less
{
template <typename Point1, typename Point2>
inline bool operator()(Point1 const& point1, Point2 const& point2) const
{
return detail_dispatch::relate::less<Point1, Point2>::apply(point1, point2);
}
};
}} // namespace detail::relate
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,793 @@
// 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_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
{
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)) )
{
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;
boundary_checker<Geometry1> boundary_checker1(geometry1);
disjoint_linestring_pred<Result, boundary_checker<Geometry1>, 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;
boundary_checker<Geometry2> boundary_checker2(geometry2);
disjoint_linestring_pred<Result, boundary_checker<Geometry2>, 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)
{
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) )
{
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) )
{
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)
{
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));
bool const is_point2 = boost::size(ls2_ref) == 2
&& equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref));
// 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

View File

@@ -0,0 +1,208 @@
// 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_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;
// 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
// check if there are other boundaries outside
typedef detail::relate::topology_check<Geometry> tc_t;
//tc_t tc(geometry, point);
//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);
}
else
{
// check if there is a boundary in Geometry
typedef detail::relate::topology_check<Geometry> tc_t;
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

View File

@@ -0,0 +1,253 @@
// 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.
// 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_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/less.hpp>
#include <boost/geometry/algorithms/detail/relate/result.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);
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>
std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point)
{
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);
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);
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;
}
}
// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
// 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
// TODO: Also, the geometry with the smaller number of points may be analysed first
//if ( boost::size(multi_point1) < boost::size(multi_point2) )
// NlogN + MlogN
bool all_handled = search<false>(multi_point1, multi_point2, result);
if ( BOOST_GEOMETRY_CONDITION(all_handled || result.interrupt) )
return;
// MlogM + NlogM
search<true>(multi_point2, multi_point1, 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));
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;
}
// an optimization
bool all_handled = false;
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
all_handled = true;
}
relate::set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result);
return all_handled;
}
};
}} // namespace detail::relate
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,265 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// 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)
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/util/has_nan_coordinate.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 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>
struct topology_check<Linestring, linestring_tag>
{
static const char interior = '1';
static const char boundary = '0';
bool has_interior;
bool has_boundary;
topology_check(Linestring const& ls)
{
init(ls, 0); /*dummy param*/
}
template <typename IgnoreBoundaryPoint>
topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp)
{
init(ls, ibp); /*dummy param, won't be used*/
}
// Even if some point is on the boundary, if the Linestring has the boundary,
// there will be second boundary point different than IgnoreBoundaryPoint
template <typename IgnoreBoundaryPoint>
void init(Linestring const& ls, IgnoreBoundaryPoint const&)
{
std::size_t count = boost::size(ls);
has_interior = count > 0;
// NOTE: Linestring with all points equal is treated as 1d linear ring
has_boundary = count > 1
&& ! detail::equals::equals_point_point(range::front(ls), range::back(ls));
}
};
template <typename MultiLinestring>
struct topology_check<MultiLinestring, multi_linestring_tag>
{
static const char interior = '1';
static const char boundary = '0';
bool has_interior;
bool has_boundary;
topology_check(MultiLinestring const& mls)
{
init(mls, not_ignoring_counter());
}
template <typename IgnoreBoundaryPoint>
topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp)
{
init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp));
}
template <typename OddCounter>
void init(MultiLinestring const& mls, OddCounter const& odd_counter)
{
typedef typename geometry::point_type<MultiLinestring>::type point_type;
std::vector<point_type> endpoints;
endpoints.reserve(boost::size(mls) * 2);
typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it )
{
typename boost::range_reference<MultiLinestring const>::type
ls = *it;
std::size_t count = boost::size(ls);
if (count > 0)
{
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))
{
// 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))
{
endpoints.push_back(front_pt);
}
if (! geometry::has_nan_coordinate(back_pt))
{
endpoints.push_back(back_pt);
}
}
}
}
has_boundary = false;
if ( !endpoints.empty() )
{
std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>());
has_boundary = odd_counter(endpoints.begin(), endpoints.end());
}
}
struct not_ignoring_counter
{
template <typename It>
bool operator()(It first, It last) const
{
return find_odd_count(first, last);
}
};
template <typename Point>
struct ignoring_counter
{
ignoring_counter(Point const& pt) : m_pt(pt) {}
template <typename It>
bool operator()(It first, It last) const
{
typedef typename std::iterator_traits<It>::value_type point_type;
std::pair<It, It> ignore_range
= std::equal_range(first, last, m_pt,
geometry::less<point_type>());
if ( find_odd_count(first, ignore_range.first) )
return true;
return find_odd_count(ignore_range.second, last);
}
Point const& m_pt;
};
template <typename It>
static inline bool find_odd_count(It first, It last)
{
if ( first == last )
return false;
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) )
{
if ( count % 2 != 0 )
return true;
count = 1;
}
else
{
++count;
}
}
return count % 2 != 0;
}
};
template <typename Ring>
struct topology_check<Ring, ring_tag>
{
static const char interior = '2';
static const char boundary = '1';
static const bool has_interior = true;
static const bool has_boundary = true;
topology_check(Ring const&) {}
template <typename P>
topology_check(Ring const&, P const&) {}
};
template <typename Polygon>
struct topology_check<Polygon, polygon_tag>
{
static const char interior = '2';
static const char boundary = '1';
static const bool has_interior = true;
static const bool has_boundary = true;
topology_check(Polygon const&) {}
template <typename P>
topology_check(Polygon const&, P const&) {}
};
template <typename MultiPolygon>
struct topology_check<MultiPolygon, multi_polygon_tag>
{
static const char interior = '2';
static const char boundary = '1';
static const bool has_interior = true;
static const bool has_boundary = true;
topology_check(MultiPolygon const&) {}
template <typename P>
topology_check(MultiPolygon const&, P const&) {}
};
}} // namespace detail::relate
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP

View File

@@ -0,0 +1,307 @@
// 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 = detail::no_rescale_policy
>
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