mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-02 21:02:13 +00:00
[relate] helpers like segment_watcher, exit_watcher, etc. moved to a separate file, implemented preliminary version of L/A (commented out for now), found bug in L/L, added failing tests
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
// 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
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// TODO:
|
||||
// For 1-point linestrings or with all equal points turns won't be generated!
|
||||
// Check for those degenerated cases may be connected with this one!
|
||||
|
||||
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)
|
||||
{
|
||||
BOOST_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 )
|
||||
{
|
||||
int multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_ASSERT(multi_index >= 0);
|
||||
std::size_t index = static_cast<std::size_t>(multi_index);
|
||||
BOOST_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;
|
||||
bool cont = pred(
|
||||
*(boost::begin(geometry)
|
||||
+ std::distance(detected_intersections.begin(), it)));
|
||||
if ( !cont )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: rename to point_id_ref?
|
||||
template <typename Point>
|
||||
class point_identifier
|
||||
{
|
||||
public:
|
||||
point_identifier() : sid_ptr(0), pt_ptr(0) {}
|
||||
point_identifier(segment_identifier const& sid, Point const& pt)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
, pt_ptr(boost::addressof(pt))
|
||||
{}
|
||||
segment_identifier const& seg_id() const
|
||||
{
|
||||
BOOST_ASSERT(sid_ptr);
|
||||
return *sid_ptr;
|
||||
}
|
||||
Point const& point() const
|
||||
{
|
||||
BOOST_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;
|
||||
};
|
||||
|
||||
class same_ranges
|
||||
{
|
||||
public:
|
||||
same_ranges(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;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
bool operator()(point_identifier<Point> const& pid) const
|
||||
{
|
||||
return operator()(pid.seg_id());
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
};
|
||||
|
||||
class segment_watcher
|
||||
{
|
||||
public:
|
||||
segment_watcher()
|
||||
: m_seg_id_ptr(0)
|
||||
{}
|
||||
|
||||
bool update(segment_identifier const& seg_id)
|
||||
{
|
||||
bool result = m_seg_id_ptr == 0 || !same_ranges(*m_seg_id_ptr)(seg_id);
|
||||
m_seg_id_ptr = boost::addressof(seg_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * m_seg_id_ptr;
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
class exit_watcher
|
||||
{
|
||||
typedef point_identifier<Point> point_info;
|
||||
|
||||
public:
|
||||
exit_watcher()
|
||||
: exit_operation(overlay::operation_none)
|
||||
{}
|
||||
|
||||
// returns true if before the call we were outside
|
||||
bool enter(Point const& point, segment_identifier const& other_id)
|
||||
{
|
||||
bool result = other_entry_points.empty();
|
||||
other_entry_points.push_back(point_info(other_id, point));
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns true if before the call we were outside
|
||||
bool exit(Point const& point,
|
||||
segment_identifier const& other_id,
|
||||
overlay::operation_type exit_op)
|
||||
{
|
||||
// if we didn't entered anything in the past, we're outside
|
||||
if ( other_entry_points.empty() )
|
||||
return true;
|
||||
|
||||
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(other_entry_points.begin(),
|
||||
other_entry_points.end(),
|
||||
same_ranges(other_id));
|
||||
|
||||
// this end point has corresponding entry point
|
||||
if ( entry_it != other_entry_points.end() )
|
||||
{
|
||||
// here we know that we possibly left LS
|
||||
// we must still check if we didn't get back on the same point
|
||||
exit_operation = exit_op;
|
||||
exit_id = point_info(other_id, point);
|
||||
|
||||
// erase the corresponding entry point
|
||||
other_entry_points.erase(entry_it);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay::operation_type get_exit_operation() const
|
||||
{
|
||||
return exit_operation;
|
||||
}
|
||||
|
||||
Point const& get_exit_point() const
|
||||
{
|
||||
BOOST_ASSERT(exit_operation != overlay::operation_none);
|
||||
return exit_id.point();
|
||||
}
|
||||
|
||||
void reset_detected_exit()
|
||||
{
|
||||
exit_operation = overlay::operation_none;
|
||||
}
|
||||
|
||||
private:
|
||||
overlay::operation_type exit_operation;
|
||||
point_info exit_id;
|
||||
std::vector<point_info> other_entry_points; // TODO: use map here or sorted vector?
|
||||
};
|
||||
|
||||
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 ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& operation_info.operation == overlay::operation_blocked )
|
||||
{
|
||||
BOOST_ASSERT(operation_info.position == overlay::position_back);
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_back>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP on the last point of the linestring
|
||||
else if ( (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);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_front>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP somewhere in the interior
|
||||
else
|
||||
{
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_any>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
|
||||
@@ -20,6 +20,7 @@
|
||||
#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
|
||||
{
|
||||
@@ -54,15 +55,9 @@ private:
|
||||
template <typename Geometry1, typename Geometry2, bool TransposeResult = false>
|
||||
struct linear_areal
|
||||
{
|
||||
static const bool is_linear1 = boost::is_base_of<
|
||||
linear_tag,
|
||||
typename geometry::tag<Geometry1>::type
|
||||
>::value;
|
||||
static const bool is_areal2 = boost::is_base_of<
|
||||
areal_tag,
|
||||
typename geometry::tag<Geometry2>::type
|
||||
>::value;
|
||||
BOOST_STATIC_ASSERT(is_linear1 && is_areal2);
|
||||
// check Linear / Areal
|
||||
BOOST_STATIC_ASSERT(detail::group_dim<Geometry1>::value == 1
|
||||
&& detail::group_dim<Geometry2>::value == 2);
|
||||
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
@@ -71,13 +66,13 @@ struct linear_areal
|
||||
|
||||
// if the result should be transposed, because the order of geometries was reversed
|
||||
// then not transposed result becomes the transposed one, and the opposite
|
||||
static const bool transpose = !TransposeResult;
|
||||
static const bool transpose_result = !TransposeResult;
|
||||
|
||||
template <typename Result>
|
||||
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
|
||||
{
|
||||
// The result should be FFFFFFFFF
|
||||
set<exterior, exterior, result_dimension<Geometry1>::value, !transpose>(result);// FFFFFFFFd, d in [1,9] or T
|
||||
set<exterior, exterior, result_dimension<Geometry1>::value, !transpose_result>(result);// FFFFFFFFd, d in [1,9] or T
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
@@ -91,12 +86,12 @@ struct linear_areal
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2);
|
||||
|
||||
boundary_checker<Geometry1> boundary_checker1(geometry1);
|
||||
disjoint_linestring_pred<Result, boundary_checker<Geometry1>, !transpose> pred1(result, boundary_checker1);
|
||||
disjoint_linestring_pred<Result, boundary_checker<Geometry1>, !transpose_result> pred1(result, boundary_checker1);
|
||||
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
|
||||
disjoint_areal_pred<Result, transpose> pred2(result);
|
||||
disjoint_areal_pred<Result, transpose_result> pred2(result);
|
||||
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
if ( result.interrupt )
|
||||
return;
|
||||
@@ -113,367 +108,252 @@ struct linear_areal
|
||||
// geometry1, geometry2,
|
||||
// boundary_checker1);
|
||||
}
|
||||
//
|
||||
// // This analyser should be used like Input or SinglePass Iterator
|
||||
// template <typename TurnInfo>
|
||||
// class turns_analyser
|
||||
// {
|
||||
// typedef typename TurnInfo::point_type turn_point_type;
|
||||
//
|
||||
// static const std::size_t op_id = 0;
|
||||
// static const std::size_t other_op_id = 1;
|
||||
// // if the result should be transposed, because the order of geometries was reversed
|
||||
// // then not transposed result becomes the transposed one, and the opposite
|
||||
// static const bool transpose_result = !TransposeResult;
|
||||
//
|
||||
// public:
|
||||
// turns_analyser()
|
||||
// : m_previous_turn_ptr(0)
|
||||
// , m_previous_operation(overlay::operation_none)
|
||||
// {}
|
||||
//
|
||||
// template <typename Result,
|
||||
// typename TurnIt,
|
||||
// typename Geometry,
|
||||
// typename OtherGeometry,
|
||||
// typename BoundaryChecker,
|
||||
// typename OtherBoundaryChecker>
|
||||
// void apply(Result & res,
|
||||
// TurnIt first, TurnIt it, TurnIt last,
|
||||
// Geometry const& geometry,
|
||||
// OtherGeometry const& other_geometry,
|
||||
// BoundaryChecker & boundary_checker)
|
||||
// {
|
||||
// if ( it != last )
|
||||
// {
|
||||
// overlay::operation_type op = it->operations[op_id].operation;
|
||||
//
|
||||
// if ( op != overlay::operation_union
|
||||
// && op != overlay::operation_intersection
|
||||
// && op != overlay::operation_blocked )
|
||||
// {
|
||||
// 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);
|
||||
//
|
||||
// // 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 ( !detail::equals::equals_point_point(it->point, m_exit_watcher.get_exit_point()) )
|
||||
// {
|
||||
// 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;
|
||||
//
|
||||
// m_exit_watcher.reset_detected_exit();
|
||||
// }
|
||||
//
|
||||
// // if the new linestring started just now,
|
||||
// // but the previous one went out on the previous point,
|
||||
// // we must check if the boundary of the previous segment is outside
|
||||
// // NOTE: couldn't it be integrated with the handling of the union above?
|
||||
// if ( first_in_range
|
||||
// && ! fake_enter_detected
|
||||
// && m_previous_operation == overlay::operation_union )
|
||||
// {
|
||||
// BOOST_ASSERT(it != first);
|
||||
// BOOST_ASSERT(m_previous_turn_ptr);
|
||||
//
|
||||
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
//
|
||||
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
// range::back(sub_geometry::get(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);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // i/i, i/x, i/u
|
||||
// if ( op == overlay::operation_intersection )
|
||||
// {
|
||||
// bool was_outside = m_exit_watcher.enter(it->point, other_id);
|
||||
//
|
||||
// // interiors overlaps
|
||||
// update<interior, interior, '1', transpose_result>(res);
|
||||
//
|
||||
// bool this_b = 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 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 )
|
||||
// {
|
||||
// update<interior, exterior, '1', transpose_result>(res);
|
||||
//
|
||||
// // if it's the first IP then the first point is outside
|
||||
// if ( first_in_range )
|
||||
// {
|
||||
// bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
// range::front(sub_geometry::get(geometry, seg_id)),
|
||||
// boundary_checker);
|
||||
//
|
||||
// // if there is a boundary on the first point
|
||||
// if ( front_b )
|
||||
// {
|
||||
// update<boundary, exterior, '0', transpose_result>(res);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // u/i, u/u, u/x, x/i, x/u, x/x
|
||||
// else if ( op == overlay::operation_union || op == overlay::operation_blocked )
|
||||
// {
|
||||
// bool op_blocked = op == overlay::operation_blocked;
|
||||
// bool was_outside = m_exit_watcher.exit(it->point, other_id, op);
|
||||
//
|
||||
// // we're inside, possibly going out right now
|
||||
// if ( ! was_outside )
|
||||
// {
|
||||
// if ( op_blocked )
|
||||
// {
|
||||
// // 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 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
|
||||
// else
|
||||
// {
|
||||
// update<interior, exterior, '1', transpose_result>(res);
|
||||
//
|
||||
// // boundaries don't overlap - just an optimization
|
||||
// if ( it->method == overlay::method_crosses )
|
||||
// {
|
||||
// update<interior, interior, '0', transpose_result>(res);
|
||||
//
|
||||
// // it's the first point in range
|
||||
// if ( first_in_range )
|
||||
// {
|
||||
// bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
// range::front(sub_geometry::get(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 this_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
// it->operations[op_id],
|
||||
// boundary_checker,
|
||||
// seg_id);
|
||||
//
|
||||
// bool 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 ) )
|
||||
// {
|
||||
// bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
// range::front(sub_geometry::get(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;
|
||||
// }
|
||||
// // it == last
|
||||
// else
|
||||
// {
|
||||
// // 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 )
|
||||
// {
|
||||
// // for sure
|
||||
// update<interior, exterior, '1', transpose_result>(res);
|
||||
//
|
||||
// BOOST_ASSERT(first != last);
|
||||
// BOOST_ASSERT(m_previous_turn_ptr);
|
||||
//
|
||||
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[OpId].seg_id;
|
||||
//
|
||||
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
// range::back(sub_geometry::get(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);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// 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 ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
// && operation_info.operation == overlay::operation_blocked )
|
||||
// {
|
||||
// BOOST_ASSERT(operation_info.position == overlay::position_back);
|
||||
// // check if this point is a boundary
|
||||
// res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
|
||||
//
|
||||
//#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
// BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_back>(ip, seg_id));
|
||||
//#endif
|
||||
// }
|
||||
// // IP on the last point of the linestring
|
||||
// else if ( (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);
|
||||
//
|
||||
//#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
// BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_front>(ip, seg_id));
|
||||
//#endif
|
||||
// }
|
||||
// // IP somewhere in the interior
|
||||
// else
|
||||
// {
|
||||
//#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
// BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_any>(ip, seg_id));
|
||||
//#endif
|
||||
// }
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// exit_watcher<turn_point_type> m_exit_watcher;
|
||||
// segment_watcher m_seg_watcher;
|
||||
// TurnInfo * m_previous_turn_ptr;
|
||||
// overlay::operation_type m_previous_operation;
|
||||
// };
|
||||
|
||||
//// This analyser should be used like Input or SinglePass Iterator
|
||||
//template <typename TurnInfo>
|
||||
//class turns_analyser
|
||||
//{
|
||||
// typedef typename TurnInfo::point_type turn_point_type;
|
||||
|
||||
// static const std::size_t op_id = 0;
|
||||
// static const std::size_t other_op_id = 1;
|
||||
// // if the result should be transposed, because the order of geometries was reversed
|
||||
// // then not transposed result becomes the transposed one, and the opposite
|
||||
// static const bool transpose_result = !TransposeResult;
|
||||
|
||||
//public:
|
||||
// turns_analyser()
|
||||
// : m_previous_turn_ptr(0)
|
||||
// , m_previous_operation(overlay::operation_none)
|
||||
// {}
|
||||
|
||||
// template <typename Result,
|
||||
// typename TurnIt,
|
||||
// typename Geometry,
|
||||
// typename OtherGeometry,
|
||||
// typename BoundaryChecker>
|
||||
// void apply(Result & res,
|
||||
// TurnIt first, TurnIt it, TurnIt last,
|
||||
// Geometry const& geometry,
|
||||
// OtherGeometry const& other_geometry,
|
||||
// BoundaryChecker & boundary_checker)
|
||||
// {
|
||||
// if ( it != last )
|
||||
// {
|
||||
// overlay::operation_type op = it->operations[op_id].operation;
|
||||
|
||||
// if ( op != overlay::operation_union
|
||||
// && op != overlay::operation_intersection
|
||||
// && op != overlay::operation_blocked
|
||||
// && op != overlay::operation_continue ) // operation_boundary / operation_boundary_intersection
|
||||
// {
|
||||
// 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);
|
||||
|
||||
// // 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 ( !detail::equals::equals_point_point(it->point, m_exit_watcher.get_exit_point()) )
|
||||
// {
|
||||
// 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
|
||||
// || op == overlay::operation_continue ) // operation_boundary
|
||||
// {
|
||||
// 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;
|
||||
|
||||
// m_exit_watcher.reset_detected_exit();
|
||||
// }
|
||||
|
||||
// // if the new linestring started just now,
|
||||
// // but the previous one went out on the previous point,
|
||||
// // we must check if the boundary of the previous segment is outside
|
||||
// // NOTE: couldn't it be integrated with the handling of the union above?
|
||||
// if ( first_in_range
|
||||
// && ! fake_enter_detected
|
||||
// && m_previous_operation == overlay::operation_union )
|
||||
// {
|
||||
// BOOST_ASSERT(it != first);
|
||||
// BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
// range::back(sub_geometry::get(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);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // i/u, c/u
|
||||
// if ( op == overlay::operation_intersection
|
||||
// || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection
|
||||
// {
|
||||
// bool was_outside = m_exit_watcher.enter(it->point, other_id);
|
||||
|
||||
// if ( op == overlay::operation_intersection )
|
||||
// {
|
||||
// // interiors overlaps
|
||||
// update<interior, interior, '1', transpose_result>(res);
|
||||
// update<interior, boundary, '0', transpose_result>(res);
|
||||
// }
|
||||
// else // operation_boundary
|
||||
// {
|
||||
// update<interior, boundary, '1', transpose_result>(res);
|
||||
// }
|
||||
|
||||
// bool this_b = is_ip_on_boundary<boundary_front>(it->point,
|
||||
// it->operations[op_id],
|
||||
// boundary_checker,
|
||||
// seg_id);
|
||||
// // going inside on boundary point
|
||||
// if ( this_b )
|
||||
// {
|
||||
// update<boundary, boundary, '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 )
|
||||
// {
|
||||
// update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
// // if it's the first IP then the first point is outside
|
||||
// if ( first_in_range )
|
||||
// {
|
||||
// bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
// range::front(sub_geometry::get(geometry, seg_id)),
|
||||
// boundary_checker);
|
||||
|
||||
// // if there is a boundary on the first point
|
||||
// if ( front_b )
|
||||
// {
|
||||
// update<boundary, exterior, '0', transpose_result>(res);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // u/u, x/u
|
||||
// else if ( op == overlay::operation_union || op == overlay::operation_blocked )
|
||||
// {
|
||||
// bool op_blocked = op == overlay::operation_blocked;
|
||||
// bool was_outside = m_exit_watcher.exit(it->point, other_id, op);
|
||||
|
||||
// // we're inside, possibly going out right now
|
||||
// if ( ! was_outside )
|
||||
// {
|
||||
// if ( op_blocked )
|
||||
// {
|
||||
// // 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) )
|
||||
// {
|
||||
// update<boundary, boundary, '0', transpose_result>(res);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // we're outside
|
||||
// else
|
||||
// {
|
||||
// update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
// bool this_b = is_ip_on_boundary<boundary_any>(it->point,
|
||||
// it->operations[op_id],
|
||||
// boundary_checker,
|
||||
// seg_id);
|
||||
// // if current IP is on boundary of the geometry
|
||||
// if ( this_b )
|
||||
// {
|
||||
// update<boundary, boundary, '0', transpose_result>(res);
|
||||
// }
|
||||
// // if current IP is not on boundary of the geometry
|
||||
// else
|
||||
// {
|
||||
// update<interior, boundary, '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 ) )
|
||||
// {
|
||||
// bool front_b = is_endpoint_on_boundary<boundary_front>(
|
||||
// range::front(sub_geometry::get(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;
|
||||
// }
|
||||
// // it == last
|
||||
// else
|
||||
// {
|
||||
// // 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 )
|
||||
// {
|
||||
// // for sure
|
||||
// update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
// BOOST_ASSERT(first != last);
|
||||
// BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
// range::back(sub_geometry::get(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);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
//private:
|
||||
// exit_watcher<turn_point_type> m_exit_watcher;
|
||||
// segment_watcher m_seg_watcher;
|
||||
// TurnInfo * m_previous_turn_ptr;
|
||||
// overlay::operation_type m_previous_operation;
|
||||
//};
|
||||
|
||||
template <typename Result,
|
||||
typename TurnIt,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#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
|
||||
{
|
||||
@@ -27,85 +28,6 @@ namespace boost { namespace geometry
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// TODO:
|
||||
// For 1-point linestrings or with all equal points turns won't be generated!
|
||||
// Check for those degenerated cases may be connected with this one!
|
||||
|
||||
// TODO:
|
||||
// Move this to separate file, maybe name it differently e.g. for_each_turnless_geometry_if
|
||||
|
||||
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)
|
||||
{
|
||||
BOOST_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 )
|
||||
{
|
||||
int multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_ASSERT(multi_index >= 0);
|
||||
std::size_t index = static_cast<std::size_t>(multi_index);
|
||||
BOOST_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;
|
||||
bool cont = pred(
|
||||
*(boost::begin(geometry)
|
||||
+ std::distance(detected_intersections.begin(), it)));
|
||||
if ( !cont )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Result, typename BoundaryChecker, bool TransposeResult>
|
||||
class disjoint_linestring_pred
|
||||
{
|
||||
@@ -341,149 +263,6 @@ struct linear_linear
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rename to point_id_ref?
|
||||
template <typename Point>
|
||||
class point_identifier
|
||||
{
|
||||
public:
|
||||
point_identifier() : sid_ptr(0), pt_ptr(0) {}
|
||||
point_identifier(segment_identifier const& sid, Point const& pt)
|
||||
: sid_ptr(boost::addressof(sid))
|
||||
, pt_ptr(boost::addressof(pt))
|
||||
{}
|
||||
segment_identifier const& seg_id() const
|
||||
{
|
||||
BOOST_ASSERT(sid_ptr);
|
||||
return *sid_ptr;
|
||||
}
|
||||
Point const& point() const
|
||||
{
|
||||
BOOST_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;
|
||||
};
|
||||
|
||||
class same_ranges
|
||||
{
|
||||
public:
|
||||
same_ranges(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;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
bool operator()(point_identifier<Point> const& pid) const
|
||||
{
|
||||
return operator()(pid.seg_id());
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * sid_ptr;
|
||||
};
|
||||
|
||||
class segment_watcher
|
||||
{
|
||||
public:
|
||||
segment_watcher()
|
||||
: m_seg_id_ptr(0)
|
||||
{}
|
||||
|
||||
bool update(segment_identifier const& seg_id)
|
||||
{
|
||||
bool result = m_seg_id_ptr == 0 || !same_ranges(*m_seg_id_ptr)(seg_id);
|
||||
m_seg_id_ptr = boost::addressof(seg_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const segment_identifier * m_seg_id_ptr;
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
class exit_watcher
|
||||
{
|
||||
typedef point_identifier<Point> point_info;
|
||||
|
||||
public:
|
||||
exit_watcher()
|
||||
: exit_operation(overlay::operation_none)
|
||||
{}
|
||||
|
||||
// returns true if before the call we were outside
|
||||
bool enter(Point const& point, segment_identifier const& other_id)
|
||||
{
|
||||
bool result = other_entry_points.empty();
|
||||
other_entry_points.push_back(point_info(other_id, point));
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns true if before the call we were outside
|
||||
bool exit(Point const& point,
|
||||
segment_identifier const& other_id,
|
||||
overlay::operation_type exit_op)
|
||||
{
|
||||
// if we didn't entered anything in the past, we're outside
|
||||
if ( other_entry_points.empty() )
|
||||
return true;
|
||||
|
||||
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(other_entry_points.begin(),
|
||||
other_entry_points.end(),
|
||||
same_ranges(other_id));
|
||||
|
||||
// this end point has corresponding entry point
|
||||
if ( entry_it != other_entry_points.end() )
|
||||
{
|
||||
// here we know that we possibly left LS
|
||||
// we must still check if we didn't get back on the same point
|
||||
exit_operation = exit_op;
|
||||
exit_id = point_info(other_id, point);
|
||||
|
||||
// erase the corresponding entry point
|
||||
other_entry_points.erase(entry_it);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay::operation_type get_exit_operation() const
|
||||
{
|
||||
return exit_operation;
|
||||
}
|
||||
|
||||
Point const& get_exit_point() const
|
||||
{
|
||||
BOOST_ASSERT(exit_operation != overlay::operation_none);
|
||||
return exit_id.point();
|
||||
}
|
||||
|
||||
void reset_detected_exit()
|
||||
{
|
||||
exit_operation = overlay::operation_none;
|
||||
}
|
||||
|
||||
private:
|
||||
overlay::operation_type exit_operation;
|
||||
point_info exit_id;
|
||||
std::vector<point_info> other_entry_points; // TODO: use map here or sorted vector?
|
||||
};
|
||||
|
||||
// This analyser should be used like Input or SinglePass Iterator
|
||||
template <std::size_t OpId, typename TurnInfo>
|
||||
class turns_analyser
|
||||
@@ -679,6 +458,7 @@ struct linear_linear
|
||||
// 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
|
||||
@@ -764,7 +544,7 @@ struct linear_linear
|
||||
BOOST_ASSERT(first != last);
|
||||
BOOST_ASSERT(m_previous_turn_ptr);
|
||||
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[OpId].seg_id;
|
||||
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
|
||||
|
||||
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
|
||||
range::back(sub_geometry::get(geometry, prev_seg_id)),
|
||||
@@ -779,64 +559,6 @@ struct linear_linear
|
||||
}
|
||||
}
|
||||
|
||||
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 ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
|
||||
&& operation_info.operation == overlay::operation_blocked )
|
||||
{
|
||||
BOOST_ASSERT(operation_info.position == overlay::position_back);
|
||||
// check if this point is a boundary
|
||||
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_back>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP on the last point of the linestring
|
||||
else if ( (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);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_front>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
// IP somewhere in the interior
|
||||
else
|
||||
{
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_LINEAR_LINEAR
|
||||
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_any>(ip, seg_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
exit_watcher<turn_point_type> m_exit_watcher;
|
||||
segment_watcher m_seg_watcher;
|
||||
|
||||
@@ -290,6 +290,20 @@ void test_linestring_linestring()
|
||||
"LINESTRING(30 0,4 0,3 1,2 0,1 0,0 0,-1 -1)",
|
||||
"101FF0102");
|
||||
|
||||
// self-IP
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,10 10,5 0,0 10)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,5 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,10 10,5 0,0 10)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,10 10,5 10,5 -1)",
|
||||
"1FF0FF102");
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,9 0)",
|
||||
"LINESTRING(0 0,10 0,5 0,5 5)",
|
||||
"1FF0FF102");
|
||||
|
||||
// linear ring
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,5 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2");
|
||||
|
||||
Reference in New Issue
Block a user