Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:42:45

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2014-2024, Oracle and/or its affiliates.
0004 
0005 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0006 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0007 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0008 
0009 // Licensed under the Boost Software License version 1.0.
0010 // http://www.boost.org/users/license.html
0011 
0012 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
0013 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
0014 
0015 #include <algorithm>
0016 #include <deque>
0017 
0018 #include <boost/range/begin.hpp>
0019 #include <boost/range/empty.hpp>
0020 #include <boost/range/end.hpp>
0021 #include <boost/range/size.hpp>
0022 #include <boost/range/value_type.hpp>
0023 
0024 #include <boost/geometry/core/assert.hpp>
0025 #include <boost/geometry/core/closure.hpp>
0026 #include <boost/geometry/core/coordinate_type.hpp>
0027 #include <boost/geometry/core/point_type.hpp>
0028 #include <boost/geometry/core/tag.hpp>
0029 #include <boost/geometry/core/tags.hpp>
0030 
0031 #include <boost/geometry/util/range.hpp>
0032 
0033 #include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
0034 #include <boost/geometry/policies/robustness/segment_ratio.hpp>
0035 
0036 #include <boost/geometry/algorithms/intersects.hpp>
0037 #include <boost/geometry/algorithms/not_implemented.hpp>
0038 
0039 #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
0040 
0041 #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
0042 #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
0043 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
0044 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0045 #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
0046 #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
0047 #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
0048 
0049 #include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp>
0050 #include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp>
0051 #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
0052 
0053 #include <boost/geometry/algorithms/dispatch/is_simple.hpp>
0054 
0055 #include <boost/geometry/strategies/intersection.hpp>
0056 
0057 
0058 namespace boost { namespace geometry
0059 {
0060 
0061 
0062 #ifndef DOXYGEN_NO_DETAIL
0063 namespace detail { namespace is_simple
0064 {
0065 
0066 
0067 template <typename Turn>
0068 inline bool check_segment_indices(Turn const& turn,
0069                                   signed_size_type last_index)
0070 {
0071     return (turn.operations[0].seg_id.segment_index == 0
0072          && turn.operations[1].seg_id.segment_index == last_index)
0073         ||
0074         (turn.operations[1].seg_id.segment_index == 0
0075          && turn.operations[0].seg_id.segment_index == last_index);
0076 }
0077 
0078 
0079 template
0080 <
0081     typename Geometry,
0082     typename Strategy,
0083     typename Tag = tag_t<Geometry>
0084 >
0085 class is_acceptable_turn
0086     : not_implemented<Geometry>
0087 {};
0088 
0089 template <typename Linestring, typename Strategy>
0090 class is_acceptable_turn<Linestring, Strategy, linestring_tag>
0091 {
0092 public:
0093     is_acceptable_turn(Linestring const& linestring, Strategy const& strategy)
0094         : m_linestring(linestring)
0095         , m_is_closed(geometry::detail::equals::equals_point_point(
0096                           range::front(linestring), range::back(linestring), strategy))
0097     {}
0098 
0099     template <typename Turn>
0100     inline bool apply(Turn const& turn) const
0101     {
0102         BOOST_GEOMETRY_ASSERT(boost::size(m_linestring) > 1);
0103         return m_is_closed
0104             && turn.method == overlay::method_none
0105             && check_segment_indices(turn, boost::size(m_linestring) - 2)
0106             && turn.operations[0].fraction.is_zero();
0107     }
0108 
0109 private:
0110     Linestring const& m_linestring;
0111     bool const m_is_closed;
0112 };
0113 
0114 template <typename MultiLinestring, typename Strategy>
0115 class is_acceptable_turn<MultiLinestring, Strategy, multi_linestring_tag>
0116 {
0117 private:
0118     template <typename Point, typename Linestring>
0119     inline bool is_boundary_point_of(Point const& point, Linestring const& linestring) const
0120     {
0121         BOOST_GEOMETRY_ASSERT(boost::size(linestring) > 1);
0122         using geometry::detail::equals::equals_point_point;
0123         return ! equals_point_point(range::front(linestring), range::back(linestring), m_strategy)
0124             && (equals_point_point(point, range::front(linestring), m_strategy)
0125                 || equals_point_point(point, range::back(linestring), m_strategy));
0126     }
0127 
0128     template <typename Turn, typename Linestring>
0129     inline bool is_closing_point_of(Turn const& turn, Linestring const& linestring) const
0130     {
0131         BOOST_GEOMETRY_ASSERT(boost::size(linestring) > 1);
0132         using geometry::detail::equals::equals_point_point;
0133         return turn.method == overlay::method_none
0134             && check_segment_indices(turn, boost::size(linestring) - 2)
0135             && equals_point_point(range::front(linestring), range::back(linestring), m_strategy)
0136             && turn.operations[0].fraction.is_zero();
0137     }
0138 
0139     template <typename Linestring1, typename Linestring2>
0140     inline bool have_same_boundary_points(Linestring1 const& ls1, Linestring2 const& ls2) const
0141     {
0142         using geometry::detail::equals::equals_point_point;
0143         return equals_point_point(range::front(ls1), range::front(ls2), m_strategy)
0144              ? equals_point_point(range::back(ls1), range::back(ls2), m_strategy)
0145              : (equals_point_point(range::front(ls1), range::back(ls2), m_strategy)
0146                 && equals_point_point(range::back(ls1), range::front(ls2), m_strategy));
0147     }
0148 
0149 public:
0150     is_acceptable_turn(MultiLinestring const& multilinestring, Strategy const& strategy)
0151         : m_multilinestring(multilinestring)
0152         , m_strategy(strategy)
0153     {}
0154 
0155     template <typename Turn>
0156     inline bool apply(Turn const& turn) const
0157     {
0158         typedef typename boost::range_value<MultiLinestring>::type linestring_type;
0159 
0160         linestring_type const& ls1 =
0161             range::at(m_multilinestring, turn.operations[0].seg_id.multi_index);
0162 
0163         linestring_type const& ls2 =
0164             range::at(m_multilinestring, turn.operations[1].seg_id.multi_index);
0165 
0166         if (turn.operations[0].seg_id.multi_index
0167             == turn.operations[1].seg_id.multi_index)
0168         {
0169             return is_closing_point_of(turn, ls1);
0170         }
0171 
0172         return
0173             is_boundary_point_of(turn.point, ls1)
0174             && is_boundary_point_of(turn.point, ls2)
0175             &&
0176             ( boost::size(ls1) != 2
0177               || boost::size(ls2) != 2
0178               || ! have_same_boundary_points(ls1, ls2) );
0179     }
0180 
0181 private:
0182     MultiLinestring const& m_multilinestring;
0183     Strategy const& m_strategy;
0184 };
0185 
0186 
0187 template <typename Linear, typename Strategy>
0188 inline bool has_self_intersections(Linear const& linear, Strategy const& strategy)
0189 {
0190     using point_type = point_type_t<Linear>;
0191     using turn_info = detail::overlay::turn_info<point_type>;
0192     using turn_policy = detail::overlay::get_turn_info
0193         <
0194             detail::disjoint::assign_disjoint_policy
0195         >;
0196     using is_acceptable_turn_type = is_acceptable_turn
0197         <
0198             Linear, Strategy
0199         >;
0200 
0201     // Compute self turns
0202     std::deque<turn_info> turns;
0203 
0204     is_acceptable_turn_type predicate(linear, strategy);
0205     detail::overlay::predicate_based_interrupt_policy
0206         <
0207             is_acceptable_turn_type
0208         > interrupt_policy(predicate);
0209 
0210     // TODO: skip_adjacent should be set to false
0211     detail::self_get_turn_points::get_turns
0212         <
0213             false, turn_policy
0214         >::apply(linear,
0215                  strategy,
0216                  turns,
0217                  interrupt_policy, 0, true);
0218 
0219     detail::is_valid::debug_print_turns(turns.begin(), turns.end());
0220     debug_print_boundary_points(linear);
0221 
0222     return interrupt_policy.has_intersections;
0223 }
0224 
0225 
0226 template <typename Linestring, bool CheckSelfIntersections = true>
0227 struct is_simple_linestring
0228 {
0229     template <typename Strategy>
0230     static inline bool apply(Linestring const& linestring,
0231                              Strategy const& strategy)
0232     {
0233         simplicity_failure_policy policy;
0234         return ! boost::empty(linestring)
0235             && ! detail::is_valid::has_duplicates<Linestring>::apply(linestring, policy, strategy)
0236             && ! detail::is_valid::has_spikes<Linestring>::apply(linestring, policy, strategy);
0237     }
0238 };
0239 
0240 template <typename Linestring>
0241 struct is_simple_linestring<Linestring, true>
0242 {
0243     template <typename Strategy>
0244     static inline bool apply(Linestring const& linestring,
0245                              Strategy const& strategy)
0246     {
0247         return is_simple_linestring<Linestring, false>::apply(linestring, strategy)
0248             && ! has_self_intersections(linestring, strategy);
0249     }
0250 };
0251 
0252 
0253 template <typename MultiLinestring>
0254 struct is_simple_multilinestring
0255 {
0256 private:
0257     template <typename Strategy>
0258     struct not_simple
0259     {
0260         not_simple(Strategy const& strategy)
0261             : m_strategy(strategy)
0262         {}
0263 
0264         template <typename Linestring>
0265         inline bool operator()(Linestring const& linestring) const
0266         {
0267             return ! detail::is_simple::is_simple_linestring
0268                 <
0269                     Linestring,
0270                     false // do not compute self-intersections
0271                 >::apply(linestring, m_strategy);
0272         }
0273 
0274         Strategy const& m_strategy;
0275     };
0276 
0277 public:
0278     template <typename Strategy>
0279     static inline bool apply(MultiLinestring const& multilinestring,
0280                              Strategy const& strategy)
0281     {
0282         // check each of the linestrings for simplicity
0283         // but do not compute self-intersections yet; these will be
0284         // computed for the entire multilinestring
0285         // return true for empty multilinestring
0286 
0287         using not_simple = not_simple<Strategy>; // do not compute self-intersections
0288 
0289         if (std::any_of(boost::begin(multilinestring),
0290                         boost::end(multilinestring),
0291                         not_simple(strategy)))
0292         {
0293             return false;
0294         }
0295 
0296         return ! has_self_intersections(multilinestring, strategy);
0297     }
0298 };
0299 
0300 
0301 
0302 }} // namespace detail::is_simple
0303 #endif // DOXYGEN_NO_DETAIL
0304 
0305 
0306 
0307 #ifndef DOXYGEN_NO_DISPATCH
0308 namespace dispatch
0309 {
0310 
0311 // A linestring is a curve.
0312 // A curve is simple if it does not pass through the same point twice,
0313 // with the possible exception of its two endpoints
0314 //
0315 // Reference: OGC 06-103r4 (6.1.6.1)
0316 template <typename Linestring>
0317 struct is_simple<Linestring, linestring_tag>
0318     : detail::is_simple::is_simple_linestring<Linestring>
0319 {};
0320 
0321 
0322 // A MultiLinestring is a MultiCurve
0323 // A MultiCurve is simple if all of its elements are simple and the
0324 // only intersections between any two elements occur at Points that
0325 // are on the boundaries of both elements.
0326 //
0327 // Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
0328 template <typename MultiLinestring>
0329 struct is_simple<MultiLinestring, multi_linestring_tag>
0330     : detail::is_simple::is_simple_multilinestring<MultiLinestring>
0331 {};
0332 
0333 
0334 } // namespace dispatch
0335 #endif // DOXYGEN_NO_DISPATCH
0336 
0337 
0338 }} // namespace boost::geometry
0339 
0340 
0341 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP