123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
- // Copyright (c) 2014-2020, Oracle and/or its affiliates.
- // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // Licensed under the Boost Software License version 1.0.
- // http://www.boost.org/users/license.html
- #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
- #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
- #include <cstddef>
- #include <algorithm>
- #include <iterator>
- #include <boost/range/begin.hpp>
- #include <boost/range/end.hpp>
- #include <boost/range/size.hpp>
- #include <boost/range/value_type.hpp>
- #include <boost/throw_exception.hpp>
- #include <boost/geometry/core/assert.hpp>
- #include <boost/geometry/core/tag.hpp>
- #include <boost/geometry/core/tags.hpp>
- #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
- #include <boost/geometry/algorithms/detail/overlay/follow.hpp>
- #include <boost/geometry/algorithms/detail/overlay/inconsistent_turns_exception.hpp>
- #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
- #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
- #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
- #include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
- #include <boost/geometry/algorithms/detail/tupled_output.hpp>
- #include <boost/geometry/algorithms/convert.hpp>
- #include <boost/geometry/algorithms/not_implemented.hpp>
- #include <boost/geometry/util/condition.hpp>
- namespace boost { namespace geometry
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail { namespace overlay
- {
- namespace following { namespace linear
- {
- // follower for linear/linear geometries set operations
- template <typename Turn, typename Operation>
- static inline bool is_entering(Turn const& turn,
- Operation const& operation)
- {
- if ( turn.method != method_touch && turn.method != method_touch_interior )
- {
- return false;
- }
- return operation.operation == operation_intersection;
- }
- template <typename Turn, typename Operation>
- static inline bool is_staying_inside(Turn const& turn,
- Operation const& operation,
- bool entered)
- {
- if ( !entered )
- {
- return false;
- }
- if ( turn.method != method_equal && turn.method != method_collinear )
- {
- return false;
- }
- return operation.operation == operation_continue;
- }
- template <typename Turn, typename Operation>
- static inline bool is_leaving(Turn const& turn,
- Operation const& operation,
- bool entered)
- {
- if ( !entered )
- {
- return false;
- }
- if ( turn.method != method_touch
- && turn.method != method_touch_interior
- && turn.method != method_equal
- && turn.method != method_collinear )
- {
- return false;
- }
- if ( operation.operation == operation_blocked )
- {
- return true;
- }
- if ( operation.operation != operation_union )
- {
- return false;
- }
- return operation.is_collinear;
- }
- template <typename Turn, typename Operation>
- static inline bool is_isolated_point(Turn const& turn,
- Operation const& operation,
- bool entered)
- {
- if ( entered )
- {
- return false;
- }
- if ( turn.method == method_none )
- {
- BOOST_GEOMETRY_ASSERT( operation.operation == operation_continue );
- return true;
- }
- if ( turn.method == method_crosses )
- {
- return true;
- }
- if ( turn.method != method_touch && turn.method != method_touch_interior )
- {
- return false;
- }
- if ( operation.operation == operation_blocked )
- {
- return true;
- }
- if ( operation.operation != operation_union )
- {
- return false;
- }
- return !operation.is_collinear;
- }
- // GeometryOut - linestring or tuple of at least point and linestring
- template
- <
- typename GeometryOut,
- typename Linestring,
- typename Linear,
- overlay_type OverlayType,
- bool FollowIsolatedPoints,
- bool FollowContinueTurns
- >
- class follow_linestring_linear
- {
- protected:
- // allow spikes (false indicates: do not remove spikes)
- typedef following::action_selector<OverlayType, false> action;
- typedef geometry::detail::output_geometry_access
- <
- GeometryOut, linestring_tag, linestring_tag
- > linear;
- typedef geometry::detail::output_geometry_access
- <
- GeometryOut, point_tag, linestring_tag
- > pointlike;
- template
- <
- typename TurnIterator,
- typename TurnOperationIterator,
- typename LinestringOut,
- typename SegmentIdentifier,
- typename OutputIterator,
- typename SideStrategy
- >
- static inline OutputIterator
- process_turn(TurnIterator it,
- TurnOperationIterator op_it,
- bool& entered,
- std::size_t& enter_count,
- Linestring const& linestring,
- LinestringOut& current_piece,
- SegmentIdentifier& current_segment_id,
- OutputIterator oit,
- SideStrategy const& strategy)
- {
- // We don't rescale linear/linear
- detail::no_rescale_policy robust_policy;
- if ( is_entering(*it, *op_it) )
- {
- detail::turns::debug_turn(*it, *op_it, "-> Entering");
- entered = true;
- if ( enter_count == 0 )
- {
- action::enter(current_piece,
- linestring,
- current_segment_id,
- op_it->seg_id.segment_index,
- it->point, *op_it, strategy, robust_policy,
- linear::get(oit));
- }
- ++enter_count;
- }
- else if ( is_leaving(*it, *op_it, entered) )
- {
- detail::turns::debug_turn(*it, *op_it, "-> Leaving");
- --enter_count;
- if ( enter_count == 0 )
- {
- entered = false;
- action::leave(current_piece,
- linestring,
- current_segment_id,
- op_it->seg_id.segment_index,
- it->point, *op_it, strategy, robust_policy,
- linear::get(oit));
- }
- }
- else if ( BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints)
- && is_isolated_point(*it, *op_it, entered) )
- {
- detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
- action::template isolated_point
- <
- typename pointlike::type
- >(it->point, pointlike::get(oit));
- }
- else if ( BOOST_GEOMETRY_CONDITION(FollowContinueTurns)
- && is_staying_inside(*it, *op_it, entered) )
- {
- detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
- entered = true;
- }
- return oit;
- }
- template
- <
- typename SegmentIdentifier,
- typename LinestringOut,
- typename OutputIterator,
- typename SideStrategy
- >
- static inline OutputIterator
- process_end(bool entered,
- Linestring const& linestring,
- SegmentIdentifier const& current_segment_id,
- LinestringOut& current_piece,
- OutputIterator oit,
- SideStrategy const& strategy)
- {
- if ( action::is_entered(entered) )
- {
- // We don't rescale linear/linear
- detail::no_rescale_policy robust_policy;
- detail::copy_segments::copy_segments_linestring
- <
- false, false // do not reverse; do not remove spikes
- >::apply(linestring,
- current_segment_id,
- static_cast<signed_size_type>(boost::size(linestring) - 1),
- strategy,
- robust_policy,
- current_piece);
- }
- // Output the last one, if applicable
- if (::boost::size(current_piece) > 1)
- {
- *linear::get(oit)++ = current_piece;
- }
- return oit;
- }
- public:
- template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
- static inline OutputIterator
- apply(Linestring const& linestring, Linear const&,
- TurnIterator first, TurnIterator beyond,
- OutputIterator oit,
- SideStrategy const& strategy)
- {
- // Iterate through all intersection points (they are
- // ordered along the each line)
- typename linear::type current_piece;
- geometry::segment_identifier current_segment_id(0, -1, -1, -1);
- bool entered = false;
- std::size_t enter_count = 0;
- for (TurnIterator it = first; it != beyond; ++it)
- {
- oit = process_turn(it, boost::begin(it->operations),
- entered, enter_count,
- linestring,
- current_piece, current_segment_id,
- oit,
- strategy);
- }
- if (enter_count != 0)
- {
- return oit;
- }
- return process_end(entered, linestring,
- current_segment_id, current_piece,
- oit,
- strategy);
- }
- };
- template
- <
- typename LinestringOut,
- typename MultiLinestring,
- typename Linear,
- overlay_type OverlayType,
- bool FollowIsolatedPoints,
- bool FollowContinueTurns
- >
- class follow_multilinestring_linear
- : follow_linestring_linear
- <
- LinestringOut,
- typename boost::range_value<MultiLinestring>::type,
- Linear,
- OverlayType,
- FollowIsolatedPoints,
- FollowContinueTurns
- >
- {
- protected:
- typedef typename boost::range_value<MultiLinestring>::type Linestring;
- typedef follow_linestring_linear
- <
- LinestringOut, Linestring, Linear,
- OverlayType, FollowIsolatedPoints, FollowContinueTurns
- > Base;
- typedef following::action_selector<OverlayType> action;
- typedef typename boost::range_iterator
- <
- MultiLinestring const
- >::type linestring_iterator;
- template <typename OutputIt, overlay_type OT>
- struct copy_linestrings_in_range
- {
- static inline OutputIt
- apply(linestring_iterator, linestring_iterator, OutputIt oit)
- {
- return oit;
- }
- };
- template <typename OutputIt>
- struct copy_linestrings_in_range<OutputIt, overlay_difference>
- {
- static inline OutputIt
- apply(linestring_iterator first, linestring_iterator beyond,
- OutputIt oit)
- {
- for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
- {
- LinestringOut line_out;
- geometry::convert(*ls_it, line_out);
- *oit++ = line_out;
- }
- return oit;
- }
- };
- template <typename TurnIterator>
- static inline signed_size_type get_multi_index(TurnIterator it)
- {
- return boost::begin(it->operations)->seg_id.multi_index;
- }
- class has_other_multi_id
- {
- private:
- signed_size_type m_multi_id;
- public:
- has_other_multi_id(signed_size_type multi_id)
- : m_multi_id(multi_id) {}
- template <typename Turn>
- bool operator()(Turn const& turn) const
- {
- return boost::begin(turn.operations)->seg_id.multi_index
- != m_multi_id;
- }
- };
- public:
- template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
- static inline OutputIterator
- apply(MultiLinestring const& multilinestring, Linear const& linear,
- TurnIterator first, TurnIterator beyond,
- OutputIterator oit,
- SideStrategy const& strategy)
- {
- BOOST_GEOMETRY_ASSERT( first != beyond );
- typedef copy_linestrings_in_range
- <
- OutputIterator, OverlayType
- > copy_linestrings;
- linestring_iterator ls_first = boost::begin(multilinestring);
- linestring_iterator ls_beyond = boost::end(multilinestring);
- // Iterate through all intersection points (they are
- // ordered along the each linestring)
- signed_size_type current_multi_id = get_multi_index(first);
- oit = copy_linestrings::apply(ls_first,
- ls_first + current_multi_id,
- oit);
- TurnIterator per_ls_next = first;
- do {
- TurnIterator per_ls_current = per_ls_next;
- // find turn with different multi-index
- per_ls_next = std::find_if(per_ls_current, beyond,
- has_other_multi_id(current_multi_id));
- oit = Base::apply(*(ls_first + current_multi_id),
- linear, per_ls_current, per_ls_next, oit, strategy);
- signed_size_type next_multi_id = -1;
- linestring_iterator ls_next = ls_beyond;
- if ( per_ls_next != beyond )
- {
- next_multi_id = get_multi_index(per_ls_next);
- ls_next = ls_first + next_multi_id;
- }
- oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
- ls_next,
- oit);
- current_multi_id = next_multi_id;
- }
- while ( per_ls_next != beyond );
- return oit;
- }
- };
- template
- <
- typename LinestringOut,
- typename Geometry1,
- typename Geometry2,
- overlay_type OverlayType,
- bool FollowIsolatedPoints,
- bool FollowContinueTurns,
- typename TagIn1 = typename tag<Geometry1>::type
- >
- struct follow
- : not_implemented<Geometry1>
- {};
- template
- <
- typename LinestringOut,
- typename Linestring,
- typename Linear,
- overlay_type OverlayType,
- bool FollowIsolatedPoints,
- bool FollowContinueTurns
- >
- struct follow
- <
- LinestringOut, Linestring, Linear,
- OverlayType, FollowIsolatedPoints, FollowContinueTurns,
- linestring_tag
- > : follow_linestring_linear
- <
- LinestringOut, Linestring, Linear,
- OverlayType, FollowIsolatedPoints, FollowContinueTurns
- >
- {};
- template
- <
- typename LinestringOut,
- typename MultiLinestring,
- typename Linear,
- overlay_type OverlayType,
- bool FollowIsolatedPoints,
- bool FollowContinueTurns
- >
- struct follow
- <
- LinestringOut, MultiLinestring, Linear,
- OverlayType, FollowIsolatedPoints, FollowContinueTurns,
- multi_linestring_tag
- > : follow_multilinestring_linear
- <
- LinestringOut, MultiLinestring, Linear,
- OverlayType, FollowIsolatedPoints, FollowContinueTurns
- >
- {};
- }} // namespace following::linear
- }} // namespace detail::overlay
- #endif // DOXYGEN_NO_DETAIL
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
|