File indexing completed on 2025-09-18 08:42:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
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
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
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
0283
0284
0285
0286
0287 using not_simple = not_simple<Strategy>;
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 }}
0303 #endif
0304
0305
0306
0307 #ifndef DOXYGEN_NO_DISPATCH
0308 namespace dispatch
0309 {
0310
0311
0312
0313
0314
0315
0316 template <typename Linestring>
0317 struct is_simple<Linestring, linestring_tag>
0318 : detail::is_simple::is_simple_linestring<Linestring>
0319 {};
0320
0321
0322
0323
0324
0325
0326
0327
0328 template <typename MultiLinestring>
0329 struct is_simple<MultiLinestring, multi_linestring_tag>
0330 : detail::is_simple::is_simple_multilinestring<MultiLinestring>
0331 {};
0332
0333
0334 }
0335 #endif
0336
0337
0338 }}
0339
0340
0341 #endif