summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/relate/linear_areal.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/relate/linear_areal.hpp')
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_areal.hpp513
1 files changed, 251 insertions, 262 deletions
diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
index e32c4afcba..1e35e64fc5 100644
--- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp
+++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
@@ -1,10 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013-2021.
-// Modifications copyright (c) 2013-2021 Oracle and/or its affiliates.
-
+// This file was modified by Oracle on 2013-2022.
+// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -34,6 +34,8 @@
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
+#include <boost/geometry/geometries/helper_geometry.hpp>
+
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
@@ -51,7 +53,7 @@ template
<
typename Geometry2,
typename Result,
- typename PointInArealStrategy,
+ typename Strategy,
typename BoundaryChecker,
bool TransposeResult
>
@@ -60,11 +62,11 @@ class no_turns_la_linestring_pred
public:
no_turns_la_linestring_pred(Geometry2 const& geometry2,
Result & res,
- PointInArealStrategy const& point_in_areal_strategy,
+ Strategy const& strategy,
BoundaryChecker const& boundary_checker)
: m_geometry2(geometry2)
, m_result(res)
- , m_point_in_areal_strategy(point_in_areal_strategy)
+ , m_strategy(strategy)
, m_boundary_checker(boundary_checker)
, m_interrupt_flags(0)
{
@@ -93,7 +95,7 @@ public:
bool operator()(Linestring const& linestring)
{
std::size_t const count = boost::size(linestring);
-
+
// invalid input
if ( count < 2 )
{
@@ -110,7 +112,7 @@ public:
int const pig = detail::within::point_in_geometry(range::front(linestring),
m_geometry2,
- m_point_in_areal_strategy);
+ m_strategy);
//BOOST_GEOMETRY_ASSERT_MSG(pig != 0, "There should be no IPs");
if ( pig > 0 )
@@ -125,11 +127,9 @@ public:
}
// check if there is a boundary
- if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set
- && ( m_boundary_checker.template
- is_endpoint_boundary<boundary_front>(range::front(linestring))
- || m_boundary_checker.template
- is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
+ if ((m_interrupt_flags & 0xC) != 0xC // if wasn't already set
+ && (m_boundary_checker.is_endpoint_boundary(range::front(linestring))
+ || m_boundary_checker.is_endpoint_boundary(range::back(linestring))))
{
if ( pig > 0 )
{
@@ -150,7 +150,7 @@ public:
private:
Geometry2 const& m_geometry2;
Result & m_result;
- PointInArealStrategy const& m_point_in_areal_strategy;
+ Strategy const& m_strategy;
BoundaryChecker const& m_boundary_checker;
unsigned m_interrupt_flags;
};
@@ -177,9 +177,9 @@ public:
// TODO:
// handle empty/invalid geometries in a different way than below?
- typedef typename geometry::point_type<Areal>::type point_type;
- point_type dummy;
- bool const ok = boost::geometry::point_on_border(dummy, areal);
+ using point_type = typename geometry::point_type<Areal>::type;
+ typename helper_geometry<point_type>::type pt;
+ bool const ok = geometry::point_on_border(pt, areal);
// TODO: for now ignore, later throw an exception?
if ( !ok )
@@ -189,7 +189,7 @@ public:
update<interior, exterior, '2', TransposeResult>(m_result);
update<boundary, exterior, '1', TransposeResult>(m_result);
-
+
return false;
}
@@ -198,6 +198,129 @@ private:
bool const interrupt;
};
+
+template <typename It, typename Strategy>
+inline It find_next_non_duplicated(It first, It current, It last, Strategy const& strategy)
+{
+ BOOST_GEOMETRY_ASSERT(current != last);
+
+ It it = current;
+ for (++it ; it != last ; ++it)
+ {
+ if (! equals::equals_point_point(*current, *it, strategy))
+ {
+ return it;
+ }
+ }
+
+ // if not found start from the beginning
+ for (it = first ; it != current ; ++it)
+ {
+ if (! equals::equals_point_point(*current, *it, strategy))
+ {
+ return it;
+ }
+ }
+
+ return current;
+}
+
+// calculate inside or outside based on side_calc
+// this is simplified version of a check from equal<>
+template
+<
+ typename Pi, typename Pj, typename Pk,
+ typename Qi, typename Qj, typename Qk,
+ typename Strategy
+>
+inline bool calculate_from_inside_sides(Pi const& pi, Pj const& pj, Pk const& pk,
+ Qi const& , Qj const& qj, Qk const& qk,
+ Strategy const& strategy)
+{
+ auto const side_strategy = strategy.side();
+
+ int const side_pk_p = side_strategy.apply(pi, pj, pk);
+ int const side_qk_p = side_strategy.apply(pi, pj, qk);
+ // If they turn to same side (not opposite sides)
+ if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
+ {
+ int const side_pk_q2 = side_strategy.apply(qj, qk, pk);
+ return side_pk_q2 == -1;
+ }
+ else
+ {
+ return side_pk_p == -1;
+ }
+}
+
+// check if the passed turn's segment of Linear geometry arrived
+// from the inside or the outside of the Areal geometry
+template
+<
+ std::size_t OpId,
+ typename Geometry1, typename Geometry2,
+ typename Turn, typename Strategy
+>
+inline bool calculate_from_inside(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Turn const& turn,
+ Strategy const& strategy)
+{
+ static const std::size_t op_id = OpId;
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+
+ if (turn.operations[op_id].position == overlay::position_front)
+ {
+ return false;
+ }
+
+ auto const& range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
+
+ using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>;
+ range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
+
+ BOOST_GEOMETRY_ASSERT(boost::size(range1));
+ std::size_t const s2 = boost::size(range2);
+ BOOST_GEOMETRY_ASSERT(s2 > 2);
+ std::size_t const seg_count2 = s2 - 1;
+
+ std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index);
+ std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index);
+
+ BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1));
+ BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2);
+
+ auto const& pi = range::at(range1, p_seg_ij);
+ auto const& qi = range::at(range2, q_seg_ij);
+ auto const& qj = range::at(range2, q_seg_ij + 1);
+
+ bool const is_ip_qj = equals::equals_point_point(turn.point, qj, strategy);
+ // TODO: test this!
+ // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi));
+ // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi));
+
+ if (is_ip_qj)
+ {
+ std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
+ // TODO: the following function should return immediately, however the worst case complexity is O(N)
+ // It would be good to replace it with some O(1) mechanism
+ auto qk_it = find_next_non_duplicated(boost::begin(range2),
+ range::pos(range2, q_seg_jk),
+ boost::end(range2),
+ strategy);
+
+ // Calculate sides in a different point order for P and Q
+ // Will this sequence of points be always correct?
+ return calculate_from_inside_sides(qi, turn.point, pi, qi, qj, *qk_it, strategy);
+ }
+ else
+ {
+ // Calculate sides with different points for P and Q
+ return calculate_from_inside_sides(qi, turn.point, pi, qi, turn.point, qj, strategy);
+ }
+}
+
+
// The implementation of an algorithm calculating relate() for L/A
template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
struct linear_areal
@@ -208,9 +331,6 @@ struct linear_areal
static const bool interruption_enabled = true;
- typedef typename geometry::point_type<Geometry1>::type point1_type;
- typedef typename geometry::point_type<Geometry2>::type point2_type;
-
template <typename Geom1, typename Geom2, typename Strategy>
struct multi_turn_info
: turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type
@@ -228,45 +348,49 @@ struct linear_areal
typename turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type
>
{};
-
+
template <typename Result, typename Strategy>
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Result & result,
Strategy const& strategy)
{
-// TODO: If Areal geometry may have infinite size, change the following line:
+ boundary_checker<Geometry1, Strategy> boundary_checker1(geometry1, strategy);
+ apply(geometry1, geometry2, boundary_checker1, result, strategy);
+ }
+
+ template <typename BoundaryChecker1, typename Result, typename Strategy>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ BoundaryChecker1 const& boundary_checker1,
+ Result & result,
+ Strategy const& 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, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
+ update<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
+ {
return;
+ }
// get and analyse turns
- typedef typename turn_info_type<Geometry1, Geometry2, Strategy>::type turn_type;
+ using turn_type = typename turn_info_type<Geometry1, Geometry2, Strategy>::type;
std::vector<turn_type> turns;
interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, strategy);
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
+ {
return;
-
- typedef typename Strategy::cs_tag cs_tag;
-
- typedef boundary_checker
- <
- Geometry1,
- Strategy
- > boundary_checker1_type;
- boundary_checker1_type boundary_checker1(geometry1, strategy);
+ }
no_turns_la_linestring_pred
<
Geometry2,
Result,
Strategy,
- boundary_checker1_type,
+ BoundaryChecker1,
TransposeResult
> pred1(geometry2,
result,
@@ -274,24 +398,32 @@ struct linear_areal
boundary_checker1);
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
+ {
return;
+ }
no_turns_la_areal_pred<Result, !TransposeResult> pred2(result);
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;
+ }
// This is set here because in the case if empty Areal geometry were passed
// those shouldn't be set
- relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
+ update<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
+ {
return;
+ }
{
- sort_dispatch<cs_tag>(turns.begin(), turns.end(), util::is_multi<Geometry2>());
+ sort_dispatch(turns.begin(), turns.end(), strategy, util::is_multi<Geometry2>());
turns_analyser<turn_type> analyser;
analyse_each_turn(result, analyser,
@@ -301,13 +433,15 @@ struct linear_areal
strategy);
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
+ {
return;
+ }
}
// If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings
if ( !interrupt_policy.is_boundary_found )
{
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
}
// Don't calculate it if it's required
else if ( may_update<exterior, boundary, '1', TransposeResult>(result) )
@@ -323,12 +457,9 @@ struct linear_areal
// sort by multi_index and rind_index
std::sort(turns.begin(), turns.end(), less_ring());
- typedef typename std::vector<turn_type>::iterator turn_iterator;
-
- turn_iterator it = turns.begin();
segment_identifier * prev_seg_id_ptr = NULL;
// for each ring
- for ( ; it != turns.end() ; )
+ for (auto it = turns.begin() ; it != turns.end() ; )
{
// it's the next single geometry
if ( prev_seg_id_ptr == NULL
@@ -338,7 +469,7 @@ struct linear_areal
if ( it->operations[1].seg_id.ring_index > -1 )
{
// we can be sure that the exterior overlaps the boundary
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
break;
}
// if there was some previous ring
@@ -346,14 +477,14 @@ struct linear_areal
{
signed_size_type const next_ring_index = prev_seg_id_ptr->ring_index + 1;
BOOST_GEOMETRY_ASSERT(next_ring_index >= 0);
-
+
// if one of the last rings of previous single geometry was ommited
if ( static_cast<std::size_t>(next_ring_index)
< geometry::num_interior_rings(
single_geometry(geometry2, *prev_seg_id_ptr)) )
{
// we can be sure that the exterior overlaps the boundary
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
break;
}
}
@@ -366,7 +497,7 @@ struct linear_areal
&& prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index )
{
// we can be sure that the exterior overlaps the boundary
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
break;
}
}
@@ -375,25 +506,25 @@ struct linear_areal
// find the next ring first iterator and check if the analysis should be performed
has_boundary_intersection has_boundary_inters;
- turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters);
+ auto next = find_next_ring(it, turns.end(), has_boundary_inters);
// if there is no 1d overlap with the boundary
if ( !has_boundary_inters.result )
{
// we can be sure that the exterior overlaps the boundary
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
break;
}
// else there is 1d overlap with the boundary so we must analyse the boundary
else
{
// u, c
- typedef turns::less<1, turns::less_op_areal_linear<1>, cs_tag> less;
- std::sort(it, next, less());
+ using less_t = turns::less<1, turns::less_op_areal_linear<1>, Strategy>;
+ std::sort(it, next, less_t());
// analyse
areal_boundary_analyser<turn_type> analyser;
- for ( turn_iterator rit = it ; rit != next ; ++rit )
+ for (auto rit = it ; rit != next ; ++rit)
{
// if the analyser requests, break the search
if ( !analyser.apply(it, rit, next, strategy) )
@@ -404,7 +535,7 @@ struct linear_areal
if ( analyser.is_union_detected )
{
// we can be sure that the boundary of Areal overlaps the exterior of Linear
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
break;
}
}
@@ -424,7 +555,7 @@ struct linear_areal
single_geometry(geometry2, *prev_seg_id_ptr)) )
{
// we can be sure that the exterior overlaps the boundary
- relate::set<exterior, boundary, '1', TransposeResult>(result);
+ update<exterior, boundary, '1', TransposeResult>(result);
}
}
}
@@ -434,7 +565,9 @@ struct linear_areal
static void for_each_equal_range(It first, It last, Pred pred, Comp comp)
{
if ( first == last )
+ {
return;
+ }
It first_equal = first;
It prev = first;
@@ -445,9 +578,11 @@ struct linear_areal
pred(first_equal, first);
first_equal = first;
}
-
+
if ( first == last )
+ {
break;
+ }
}
}
@@ -516,12 +651,13 @@ struct linear_areal
}
};
- template <typename CSTag, typename TurnIt>
- static void sort_dispatch(TurnIt first, TurnIt last, std::true_type const& /*is_multi*/)
+ template <typename TurnIt, typename Strategy>
+ static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& ,
+ std::true_type const& /*is_multi*/)
{
// sort turns by Linear seg_id, then by fraction, then by other multi_index
- typedef turns::less<0, turns::less_other_multi_index<0>, CSTag> less;
- std::sort(first, last, less());
+ using less_t = turns::less<0, turns::less_other_multi_index<0>, Strategy>;
+ std::sort(first, last, less_t());
// For the same IP and multi_index - the same other's single geometry
// set priorities as the least operation found for the whole single geometry
@@ -534,22 +670,23 @@ struct linear_areal
// When priorities for single geometries are set now sort turns for the same IP
// if multi_index is the same sort them according to the single-less
// else use priority of the whole single-geometry set earlier
- typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> single_less;
+ using single_less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>;
for_each_equal_range(first, last,
- sort_turns_group<single_less>(),
+ sort_turns_group<single_less_t>(),
same_ip());
}
- template <typename CSTag, typename TurnIt>
- static void sort_dispatch(TurnIt first, TurnIt last, std::false_type const& /*is_multi*/)
+ template <typename TurnIt, typename Strategy>
+ static void sort_dispatch(TurnIt first, TurnIt last, Strategy const& ,
+ std::false_type const& /*is_multi*/)
{
// sort turns by Linear seg_id, then by fraction, then
// for same ring id: x, u, i, c
// for different ring id: c, i, u, x
- typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> less;
- std::sort(first, last, less());
+ using less_t = turns::less<0, turns::less_op_linear_areal_single<0>, Strategy>;
+ std::sort(first, last, less_t());
}
-
+
// interrupt policy which may be passed to get_turns to interrupt the analysis
// based on the info in the passed result/mask
@@ -569,9 +706,7 @@ struct linear_areal
template <typename Range>
inline bool apply(Range const& turns)
{
- typedef typename boost::range_iterator<Range const>::type iterator;
-
- for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
+ for (auto it = boost::begin(turns) ; it != boost::end(turns) ; ++it)
{
if ( it->operations[0].operation == overlay::operation_intersection )
{
@@ -619,39 +754,6 @@ struct linear_areal
static const std::size_t op_id = 0;
static const std::size_t other_op_id = 1;
- template <typename TurnPointCSTag, typename PointP, typename PointQ,
- typename Strategy,
- typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
- typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
- >
- struct la_side_calculator
- {
- typedef decltype(std::declval<Strategy>().side()) side_strategy_type;
-
- inline la_side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
- Qi const& qi, Qj const& qj, Qk const& qk,
- Strategy const& strategy)
- : m_pi(pi), m_pj(pj), m_pk(pk)
- , m_qi(qi), m_qj(qj), m_qk(qk)
- , m_side_strategy(strategy.side())
- {}
-
- inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); }
- inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); }
- inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); }
-
- private :
- Pi const& m_pi;
- Pj const& m_pj;
- Pk const& m_pk;
- Qi const& m_qi;
- Qj const& m_qj;
- Qk const& m_qk;
-
- side_strategy_type m_side_strategy;
- };
-
-
public:
turns_analyser()
: m_previous_turn_ptr(NULL)
@@ -705,7 +807,7 @@ struct linear_areal
strategy) )
{
m_exit_watcher.reset_detected_exit();
-
+
update<interior, exterior, '1', TransposeResult>(res);
// next single geometry
@@ -714,9 +816,8 @@ struct linear_areal
// NOTE: similar code is in the post-last-ip-apply()
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
- bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
- range::back(sub_range(geometry, prev_seg_id)),
- boundary_checker);
+ bool const prev_back_b = boundary_checker.is_endpoint_boundary(
+ range::back(sub_range(geometry, prev_seg_id)));
// if there is a boundary on the last point
if ( prev_back_b )
@@ -790,7 +891,7 @@ struct linear_areal
// TODO: THIS IS POTENTIALLY ERROREOUS!
// THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS
// IT WOULD GIVE WRONG RESULTS E.G.
-// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u'
+// IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u'
// handle the interior overlap
if ( m_interior_detected )
@@ -809,9 +910,8 @@ struct linear_areal
{
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
- bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
- range::back(sub_range(geometry, prev_seg_id)),
- boundary_checker);
+ bool const prev_back_b = boundary_checker.is_endpoint_boundary(
+ range::back(sub_range(geometry, prev_seg_id)));
// if there is a boundary on the last point
if ( prev_back_b )
@@ -890,11 +990,8 @@ struct linear_areal
update<interior, boundary, '1', TransposeResult>(res);
}
- bool const this_b
- = is_ip_on_boundary<boundary_front>(it->point,
- it->operations[op_id],
- boundary_checker,
- seg_id);
+ bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id],
+ boundary_checker);
// going inside on boundary point
if ( this_b )
{
@@ -911,11 +1008,11 @@ struct linear_areal
&& it->operations[op_id].position != overlay::position_front )
{
// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
- bool const from_inside = first_point
- && calculate_from_inside(geometry,
- other_geometry,
- *it,
- strategy);
+ bool const from_inside =
+ first_point && calculate_from_inside<op_id>(geometry,
+ other_geometry,
+ *it,
+ strategy);
if ( from_inside )
update<interior, interior, '1', TransposeResult>(res);
@@ -925,9 +1022,8 @@ struct linear_areal
// if it's the first IP then the first point is outside
if ( first_point )
{
- bool const front_b = is_endpoint_on_boundary<boundary_front>(
- range::front(sub_range(geometry, seg_id)),
- boundary_checker);
+ bool const front_b = boundary_checker.is_endpoint_boundary(
+ range::front(sub_range(geometry, seg_id)));
// if there is a boundary on the first point
if ( front_b )
@@ -955,7 +1051,7 @@ struct linear_areal
// TODO: is this condition ok?
// TODO: move it into the exit_watcher?
&& m_exit_watcher.get_exit_operation() == overlay::operation_none;
-
+
if ( op == overlay::operation_union )
{
if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear )
@@ -974,7 +1070,7 @@ struct linear_areal
{
// check if this is indeed the boundary point
// NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
- if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) )
+ if (boundary_checker.is_endpoint_boundary(it->point))
{
update<boundary, boundary, '0', TransposeResult>(res);
}
@@ -989,10 +1085,8 @@ struct linear_areal
// we're outside or inside and this is the first turn
else
{
- bool const this_b = is_ip_on_boundary<boundary_any>(it->point,
- it->operations[op_id],
- boundary_checker,
- seg_id);
+ bool const this_b = is_ip_on_boundary(it->point, it->operations[op_id],
+ boundary_checker);
// if current IP is on boundary of the geometry
if ( this_b )
{
@@ -1012,11 +1106,11 @@ struct linear_areal
// For LS/MultiPolygon multiple x/u turns may be generated
// the first checked Polygon may be the one which LS is outside for.
bool const first_point = first_in_range || m_first_from_unknown;
- bool const first_from_inside = first_point
- && calculate_from_inside(geometry,
- other_geometry,
- *it,
- strategy);
+ bool const first_from_inside =
+ first_point && calculate_from_inside<op_id>(geometry,
+ other_geometry,
+ *it,
+ strategy);
if ( first_from_inside )
{
update<interior, interior, '1', TransposeResult>(res);
@@ -1044,9 +1138,8 @@ struct linear_areal
// first IP on the last segment point - this means that the first point is outside or inside
if ( first_point && ( !this_b || op_blocked ) )
{
- bool const front_b = is_endpoint_on_boundary<boundary_front>(
- range::front(sub_range(geometry, seg_id)),
- boundary_checker);
+ bool const front_b = boundary_checker.is_endpoint_boundary(
+ range::front(sub_range(geometry, seg_id)));
// if there is a boundary on the first point
if ( front_b )
@@ -1135,9 +1228,8 @@ struct linear_areal
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
- bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
- range::back(sub_range(geometry, prev_seg_id)),
- boundary_checker);
+ bool const prev_back_b = boundary_checker.is_endpoint_boundary(
+ range::back(sub_range(geometry, prev_seg_id)));
// if there is a boundary on the last point
if ( prev_back_b )
@@ -1158,9 +1250,8 @@ struct linear_areal
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
- bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
- range::back(sub_range(geometry, prev_seg_id)),
- boundary_checker);
+ bool const prev_back_b = boundary_checker.is_endpoint_boundary(
+ range::back(sub_range(geometry, prev_seg_id)));
// if there is a boundary on the last point
if ( prev_back_b )
@@ -1184,9 +1275,8 @@ struct linear_areal
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
- bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
- range::back(sub_range(geometry, prev_seg_id)),
- boundary_checker);
+ bool const prev_back_b = boundary_checker.is_endpoint_boundary(
+ range::back(sub_range(geometry, prev_seg_id)));
// if there is a boundary on the last point
if ( prev_back_b )
@@ -1202,120 +1292,6 @@ struct linear_areal
m_first_from_unknown_boundary_detected = false;
}
- // check if the passed turn's segment of Linear geometry arrived
- // from the inside or the outside of the Areal geometry
- template <typename Turn, typename Strategy>
- static inline bool calculate_from_inside(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Turn const& turn,
- Strategy const& strategy)
- {
- typedef typename cs_tag<typename Turn::point_type>::type cs_tag;
-
- if ( turn.operations[op_id].position == overlay::position_front )
- return false;
-
- typename sub_range_return_type<Geometry1 const>::type
- range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
-
- using range2_view = detail::closed_clockwise_view<typename ring_type<Geometry2>::type const>;
- using range2_iterator = typename boost::range_iterator<range2_view const>::type;
- range2_view const range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
-
- BOOST_GEOMETRY_ASSERT(boost::size(range1));
- std::size_t const s2 = boost::size(range2);
- BOOST_GEOMETRY_ASSERT(s2 > 2);
- std::size_t const seg_count2 = s2 - 1;
-
- std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index);
- std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index);
-
- BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1));
- BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2);
-
- point1_type const& pi = range::at(range1, p_seg_ij);
- point2_type const& qi = range::at(range2, q_seg_ij);
- point2_type const& qj = range::at(range2, q_seg_ij + 1);
- point1_type qi_conv;
- geometry::convert(qi, qi_conv);
- bool const is_ip_qj = equals::equals_point_point(turn.point, qj, strategy);
-// TODO: test this!
-// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi));
-// BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi));
- point1_type new_pj;
- geometry::convert(turn.point, new_pj);
-
- if ( is_ip_qj )
- {
- std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2;
-// TODO: the following function should return immediately, however the worst case complexity is O(N)
-// It would be good to replace it with some O(1) mechanism
- range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
- range::pos(range2, q_seg_jk),
- boost::end(range2),
- strategy);
-
- // Will this sequence of points be always correct?
- la_side_calculator<cs_tag, point1_type, point2_type, Strategy>
- side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it, strategy);
-
- return calculate_from_inside_sides(side_calc);
- }
- else
- {
- point2_type new_qj;
- geometry::convert(turn.point, new_qj);
-
- la_side_calculator<cs_tag, point1_type, point2_type, Strategy>
- side_calc(qi_conv, new_pj, pi, qi, new_qj, qj, strategy);
-
- return calculate_from_inside_sides(side_calc);
- }
- }
-
- template <typename It, typename Strategy>
- static inline It find_next_non_duplicated(It first, It current, It last,
- Strategy const& strategy)
- {
- BOOST_GEOMETRY_ASSERT( current != last );
-
- It it = current;
-
- for ( ++it ; it != last ; ++it )
- {
- if ( !equals::equals_point_point(*current, *it, strategy) )
- return it;
- }
-
- // if not found start from the beginning
- for ( it = first ; it != current ; ++it )
- {
- if ( !equals::equals_point_point(*current, *it, strategy) )
- return it;
- }
-
- return current;
- }
-
- // calculate inside or outside based on side_calc
- // this is simplified version of a check from equal<>
- template <typename SideCalc>
- static inline bool calculate_from_inside_sides(SideCalc const& side_calc)
- {
- int const side_pk_p = side_calc.pk_wrt_p1();
- int const side_qk_p = side_calc.qk_wrt_p1();
- // If they turn to same side (not opposite sides)
- if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p))
- {
- int const side_pk_q2 = side_calc.pk_wrt_q2();
- return side_pk_q2 == -1;
- }
- else
- {
- return side_pk_p == -1;
- }
- }
-
private:
exit_watcher<TurnInfo, op_id> m_exit_watcher;
segment_watcher<same_single> m_seg_watcher;
@@ -1346,7 +1322,9 @@ struct linear_areal
Strategy const& strategy)
{
if ( first == last )
+ {
return;
+ }
for ( TurnIt it = first ; it != last ; ++it )
{
@@ -1356,7 +1334,9 @@ struct linear_areal
strategy);
if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) )
+ {
return;
+ }
}
analyser.apply(res, first, last,
@@ -1472,7 +1452,7 @@ struct linear_areal
else
{
return false;
- }
+ }
}
bool is_union_detected;
@@ -1496,6 +1476,15 @@ struct areal_linear
{
linear_areal_type::apply(geometry2, geometry1, result, strategy);
}
+
+ template <typename BoundaryChecker2, typename Result, typename Strategy>
+ static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ BoundaryChecker2 const& boundary_checker2,
+ Result & result,
+ Strategy const& strategy)
+ {
+ linear_areal_type::apply(geometry2, geometry1, boundary_checker2, result, strategy);
+ }
};
}} // namespace detail::relate