annotate DEPENDENCIES/generic/include/boost/geometry/algorithms/detail/overlay/follow.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // Boost.Geometry (aka GGL, Generic Geometry Library)
Chris@16 2
Chris@101 3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
Chris@101 4
Chris@101 5 // This file was modified by Oracle on 2014.
Chris@101 6 // Modifications copyright (c) 2014 Oracle and/or its affiliates.
Chris@101 7
Chris@101 8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
Chris@16 9
Chris@16 10 // Use, modification and distribution is subject to the Boost Software License,
Chris@16 11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 12 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 13
Chris@16 14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
Chris@16 15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
Chris@16 16
Chris@16 17 #include <cstddef>
Chris@16 18
Chris@16 19 #include <boost/range.hpp>
Chris@16 20 #include <boost/mpl/assert.hpp>
Chris@16 21
Chris@16 22 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
Chris@16 23 #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
Chris@16 24 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
Chris@16 25 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
Chris@16 26
Chris@16 27 #include <boost/geometry/algorithms/covered_by.hpp>
Chris@101 28 #include <boost/geometry/algorithms/clear.hpp>
Chris@16 29
Chris@16 30
Chris@16 31 namespace boost { namespace geometry
Chris@16 32 {
Chris@16 33
Chris@16 34
Chris@16 35 #ifndef DOXYGEN_NO_DETAIL
Chris@16 36 namespace detail { namespace overlay
Chris@16 37 {
Chris@16 38
Chris@16 39 namespace following
Chris@16 40 {
Chris@101 41
Chris@16 42 template <typename Turn, typename Operation>
Chris@16 43 static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
Chris@16 44 {
Chris@16 45 // (Blocked means: blocked for polygon/polygon intersection, because
Chris@16 46 // they are reversed. But for polygon/line it is similar to continue)
Chris@16 47 return op.operation == operation_intersection
Chris@16 48 || op.operation == operation_continue
Chris@16 49 || op.operation == operation_blocked
Chris@16 50 ;
Chris@16 51 }
Chris@16 52
Chris@101 53 template
Chris@16 54 <
Chris@101 55 typename Turn,
Chris@101 56 typename Operation,
Chris@101 57 typename LineString,
Chris@16 58 typename Polygon
Chris@16 59 >
Chris@101 60 static inline bool last_covered_by(Turn const& turn, Operation const& op,
Chris@16 61 LineString const& linestring, Polygon const& polygon)
Chris@16 62 {
Chris@101 63 // Check any point between the this one and the first IP
Chris@16 64 typedef typename geometry::point_type<LineString>::type point_type;
Chris@16 65 point_type point_in_between;
Chris@16 66 detail::point_on_border::midpoint_helper
Chris@16 67 <
Chris@16 68 point_type,
Chris@16 69 0, dimension<point_type>::value
Chris@101 70 >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
Chris@16 71
Chris@16 72 return geometry::covered_by(point_in_between, polygon);
Chris@16 73 }
Chris@16 74
Chris@16 75
Chris@101 76 template
Chris@16 77 <
Chris@101 78 typename Turn,
Chris@101 79 typename Operation,
Chris@101 80 typename LineString,
Chris@16 81 typename Polygon
Chris@16 82 >
Chris@101 83 static inline bool is_leaving(Turn const& turn, Operation const& op,
Chris@101 84 bool entered, bool first,
Chris@16 85 LineString const& linestring, Polygon const& polygon)
Chris@16 86 {
Chris@16 87 if (op.operation == operation_union)
Chris@16 88 {
Chris@101 89 return entered
Chris@16 90 || turn.method == method_crosses
Chris@16 91 || (first && last_covered_by(turn, op, linestring, polygon))
Chris@16 92 ;
Chris@16 93 }
Chris@16 94 return false;
Chris@16 95 }
Chris@16 96
Chris@16 97
Chris@101 98 template
Chris@16 99 <
Chris@101 100 typename Turn,
Chris@101 101 typename Operation,
Chris@101 102 typename LineString,
Chris@16 103 typename Polygon
Chris@16 104 >
Chris@101 105 static inline bool is_staying_inside(Turn const& turn, Operation const& op,
Chris@101 106 bool entered, bool first,
Chris@16 107 LineString const& linestring, Polygon const& polygon)
Chris@16 108 {
Chris@16 109 if (turn.method == method_crosses)
Chris@16 110 {
Chris@101 111 // The normal case, this is completely covered with entering/leaving
Chris@16 112 // so stay out of this time consuming "covered_by"
Chris@16 113 return false;
Chris@16 114 }
Chris@16 115
Chris@16 116 if (is_entering(turn, op))
Chris@16 117 {
Chris@16 118 return entered || (first && last_covered_by(turn, op, linestring, polygon));
Chris@16 119 }
Chris@16 120
Chris@16 121 return false;
Chris@16 122 }
Chris@16 123
Chris@101 124 template
Chris@16 125 <
Chris@101 126 typename Turn,
Chris@101 127 typename Operation,
Chris@101 128 typename Linestring,
Chris@16 129 typename Polygon
Chris@16 130 >
Chris@16 131 static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
Chris@16 132 Linestring const& linestring, Polygon const& polygon)
Chris@16 133 {
Chris@16 134 if (first && (turn.method == method_collinear || turn.method == method_equal))
Chris@16 135 {
Chris@16 136 return last_covered_by(turn, op, linestring, polygon);
Chris@16 137 }
Chris@16 138 return false;
Chris@16 139 }
Chris@16 140
Chris@16 141
Chris@16 142 // Template specialization structure to call the right actions for the right type
Chris@101 143 template <overlay_type OverlayType, bool RemoveSpikes = true>
Chris@16 144 struct action_selector
Chris@16 145 {
Chris@16 146 // If you get here the overlay type is not intersection or difference
Chris@16 147 // BOOST_MPL_ASSERT(false);
Chris@16 148 };
Chris@16 149
Chris@16 150 // Specialization for intersection, containing the implementation
Chris@101 151 template <bool RemoveSpikes>
Chris@101 152 struct action_selector<overlay_intersection, RemoveSpikes>
Chris@16 153 {
Chris@16 154 template
Chris@16 155 <
Chris@101 156 typename OutputIterator,
Chris@101 157 typename LineStringOut,
Chris@101 158 typename LineString,
Chris@101 159 typename Point,
Chris@101 160 typename Operation,
Chris@101 161 typename RobustPolicy
Chris@16 162 >
Chris@16 163 static inline void enter(LineStringOut& current_piece,
Chris@101 164 LineString const& ,
Chris@16 165 segment_identifier& segment_id,
Chris@101 166 signed_index_type , Point const& point,
Chris@101 167 Operation const& operation,
Chris@101 168 RobustPolicy const& ,
Chris@101 169 OutputIterator& )
Chris@16 170 {
Chris@16 171 // On enter, append the intersection point and remember starting point
Chris@101 172 // TODO: we don't check on spikes for linestrings (?). Consider this.
Chris@16 173 detail::overlay::append_no_duplicates(current_piece, point);
Chris@16 174 segment_id = operation.seg_id;
Chris@16 175 }
Chris@16 176
Chris@16 177 template
Chris@16 178 <
Chris@101 179 typename OutputIterator,
Chris@101 180 typename LineStringOut,
Chris@101 181 typename LineString,
Chris@101 182 typename Point,
Chris@101 183 typename Operation,
Chris@101 184 typename RobustPolicy
Chris@16 185 >
Chris@16 186 static inline void leave(LineStringOut& current_piece,
Chris@16 187 LineString const& linestring,
Chris@16 188 segment_identifier& segment_id,
Chris@101 189 signed_index_type index, Point const& point,
Chris@101 190 Operation const& ,
Chris@101 191 RobustPolicy const& robust_policy,
Chris@101 192 OutputIterator& out)
Chris@16 193 {
Chris@16 194 // On leave, copy all segments from starting point, append the intersection point
Chris@16 195 // and add the output piece
Chris@101 196 detail::copy_segments::copy_segments_linestring
Chris@101 197 <
Chris@101 198 false, RemoveSpikes
Chris@101 199 >::apply(linestring, segment_id, index, robust_policy, current_piece);
Chris@16 200 detail::overlay::append_no_duplicates(current_piece, point);
Chris@101 201 if (::boost::size(current_piece) > 1)
Chris@16 202 {
Chris@16 203 *out++ = current_piece;
Chris@16 204 }
Chris@101 205
Chris@101 206 geometry::clear(current_piece);
Chris@101 207 }
Chris@101 208
Chris@101 209 template
Chris@101 210 <
Chris@101 211 typename OutputIterator,
Chris@101 212 typename LineStringOut,
Chris@101 213 typename LineString,
Chris@101 214 typename Point,
Chris@101 215 typename Operation
Chris@101 216 >
Chris@101 217 static inline void isolated_point(LineStringOut&,
Chris@101 218 LineString const&,
Chris@101 219 segment_identifier&,
Chris@101 220 signed_index_type, Point const& point,
Chris@101 221 Operation const& , OutputIterator& out)
Chris@101 222 {
Chris@101 223 LineStringOut isolated_point_ls;
Chris@101 224 geometry::append(isolated_point_ls, point);
Chris@101 225
Chris@101 226 #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
Chris@101 227 geometry::append(isolated_point_ls, point);
Chris@101 228 #endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
Chris@101 229
Chris@101 230 *out++ = isolated_point_ls;
Chris@16 231 }
Chris@16 232
Chris@16 233 static inline bool is_entered(bool entered)
Chris@16 234 {
Chris@16 235 return entered;
Chris@16 236 }
Chris@16 237
Chris@101 238 template
Chris@101 239 <
Chris@101 240 typename Point,
Chris@101 241 typename Geometry,
Chris@101 242 typename RobustPolicy
Chris@101 243 >
Chris@101 244 static inline bool included(Point const& point,
Chris@101 245 Geometry const& geometry,
Chris@101 246 RobustPolicy const& )
Chris@16 247 {
Chris@16 248 return geometry::covered_by(point, geometry);
Chris@16 249 }
Chris@16 250
Chris@16 251 };
Chris@16 252
Chris@16 253 // Specialization for difference, which reverses these actions
Chris@101 254 template <bool RemoveSpikes>
Chris@101 255 struct action_selector<overlay_difference, RemoveSpikes>
Chris@16 256 {
Chris@101 257 typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
Chris@16 258
Chris@16 259 template
Chris@16 260 <
Chris@101 261 typename OutputIterator,
Chris@101 262 typename LineStringOut,
Chris@101 263 typename LineString,
Chris@101 264 typename Point,
Chris@101 265 typename Operation,
Chris@101 266 typename RobustPolicy
Chris@16 267 >
Chris@101 268 static inline void enter(LineStringOut& current_piece,
Chris@101 269 LineString const& linestring,
Chris@101 270 segment_identifier& segment_id,
Chris@101 271 signed_index_type index, Point const& point,
Chris@101 272 Operation const& operation,
Chris@101 273 RobustPolicy const& robust_policy,
Chris@101 274 OutputIterator& out)
Chris@16 275 {
Chris@101 276 normal_action::leave(current_piece, linestring, segment_id, index,
Chris@101 277 point, operation, robust_policy, out);
Chris@16 278 }
Chris@16 279
Chris@16 280 template
Chris@16 281 <
Chris@101 282 typename OutputIterator,
Chris@101 283 typename LineStringOut,
Chris@101 284 typename LineString,
Chris@101 285 typename Point,
Chris@101 286 typename Operation,
Chris@101 287 typename RobustPolicy
Chris@16 288 >
Chris@16 289 static inline void leave(LineStringOut& current_piece,
Chris@16 290 LineString const& linestring,
Chris@16 291 segment_identifier& segment_id,
Chris@101 292 signed_index_type index, Point const& point,
Chris@101 293 Operation const& operation,
Chris@101 294 RobustPolicy const& robust_policy,
Chris@101 295 OutputIterator& out)
Chris@16 296 {
Chris@16 297 normal_action::enter(current_piece, linestring, segment_id, index,
Chris@101 298 point, operation, robust_policy, out);
Chris@101 299 }
Chris@101 300
Chris@101 301 template
Chris@101 302 <
Chris@101 303 typename OutputIterator,
Chris@101 304 typename LineStringOut,
Chris@101 305 typename LineString,
Chris@101 306 typename Point,
Chris@101 307 typename Operation
Chris@101 308 >
Chris@101 309 static inline void isolated_point(LineStringOut&,
Chris@101 310 LineString const&,
Chris@101 311 segment_identifier&,
Chris@101 312 signed_index_type, Point const&,
Chris@101 313 Operation const&, OutputIterator&)
Chris@101 314 {
Chris@16 315 }
Chris@16 316
Chris@16 317 static inline bool is_entered(bool entered)
Chris@16 318 {
Chris@16 319 return ! normal_action::is_entered(entered);
Chris@16 320 }
Chris@16 321
Chris@101 322 template
Chris@101 323 <
Chris@101 324 typename Point,
Chris@101 325 typename Geometry,
Chris@101 326 typename RobustPolicy
Chris@101 327 >
Chris@101 328 static inline bool included(Point const& point,
Chris@101 329 Geometry const& geometry,
Chris@101 330 RobustPolicy const& robust_policy)
Chris@16 331 {
Chris@101 332 return ! normal_action::included(point, geometry, robust_policy);
Chris@16 333 }
Chris@16 334
Chris@16 335 };
Chris@16 336
Chris@16 337 }
Chris@16 338
Chris@16 339 /*!
Chris@16 340 \brief Follows a linestring from intersection point to intersection point, outputting which
Chris@16 341 is inside, or outside, a ring or polygon
Chris@16 342 \ingroup overlay
Chris@16 343 */
Chris@16 344 template
Chris@16 345 <
Chris@16 346 typename LineStringOut,
Chris@16 347 typename LineString,
Chris@16 348 typename Polygon,
Chris@101 349 overlay_type OverlayType,
Chris@101 350 bool RemoveSpikes = true
Chris@16 351 >
Chris@16 352 class follow
Chris@16 353 {
Chris@16 354
Chris@101 355 template <typename Turn>
Chris@16 356 struct sort_on_segment
Chris@16 357 {
Chris@16 358 // In case of turn point at the same location, we want to have continue/blocked LAST
Chris@16 359 // because that should be followed (intersection) or skipped (difference).
Chris@16 360 inline int operation_order(Turn const& turn) const
Chris@16 361 {
Chris@16 362 operation_type const& operation = turn.operations[0].operation;
Chris@16 363 switch(operation)
Chris@16 364 {
Chris@16 365 case operation_opposite : return 0;
Chris@16 366 case operation_none : return 0;
Chris@16 367 case operation_union : return 1;
Chris@16 368 case operation_intersection : return 2;
Chris@16 369 case operation_blocked : return 3;
Chris@16 370 case operation_continue : return 4;
Chris@16 371 }
Chris@16 372 return -1;
Chris@16 373 };
Chris@16 374
Chris@16 375 inline bool use_operation(Turn const& left, Turn const& right) const
Chris@16 376 {
Chris@101 377 // If they are the same, OK.
Chris@16 378 return operation_order(left) < operation_order(right);
Chris@16 379 }
Chris@16 380
Chris@16 381 inline bool use_distance(Turn const& left, Turn const& right) const
Chris@16 382 {
Chris@101 383 return left.operations[0].fraction == right.operations[0].fraction
Chris@16 384 ? use_operation(left, right)
Chris@101 385 : left.operations[0].fraction < right.operations[0].fraction
Chris@16 386 ;
Chris@16 387 }
Chris@16 388
Chris@16 389 inline bool operator()(Turn const& left, Turn const& right) const
Chris@16 390 {
Chris@16 391 segment_identifier const& sl = left.operations[0].seg_id;
Chris@16 392 segment_identifier const& sr = right.operations[0].seg_id;
Chris@16 393
Chris@16 394 return sl == sr
Chris@16 395 ? use_distance(left, right)
Chris@16 396 : sl < sr
Chris@16 397 ;
Chris@16 398
Chris@16 399 }
Chris@16 400 };
Chris@16 401
Chris@16 402
Chris@16 403
Chris@16 404 public :
Chris@16 405
Chris@101 406 template
Chris@101 407 <
Chris@101 408 typename Point,
Chris@101 409 typename Geometry,
Chris@101 410 typename RobustPolicy
Chris@101 411 >
Chris@101 412 static inline bool included(Point const& point,
Chris@101 413 Geometry const& geometry,
Chris@101 414 RobustPolicy const& robust_policy)
Chris@16 415 {
Chris@101 416 return following::action_selector
Chris@101 417 <
Chris@101 418 OverlayType, RemoveSpikes
Chris@101 419 >::included(point, geometry, robust_policy);
Chris@16 420 }
Chris@16 421
Chris@101 422 template
Chris@101 423 <
Chris@101 424 typename Turns,
Chris@101 425 typename OutputIterator,
Chris@101 426 typename RobustPolicy
Chris@101 427 >
Chris@16 428 static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
Chris@16 429 detail::overlay::operation_type , // TODO: this parameter might be redundant
Chris@101 430 Turns& turns,
Chris@101 431 RobustPolicy const& robust_policy,
Chris@101 432 OutputIterator out)
Chris@16 433 {
Chris@16 434 typedef typename boost::range_iterator<Turns>::type turn_iterator;
Chris@16 435 typedef typename boost::range_value<Turns>::type turn_type;
Chris@16 436 typedef typename boost::range_iterator
Chris@16 437 <
Chris@16 438 typename turn_type::container_type
Chris@16 439 >::type turn_operation_iterator_type;
Chris@16 440
Chris@101 441 typedef following::action_selector<OverlayType, RemoveSpikes> action;
Chris@16 442
Chris@16 443 // Sort intersection points on segments-along-linestring, and distance
Chris@16 444 // (like in enrich is done for poly/poly)
Chris@16 445 std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
Chris@16 446
Chris@16 447 LineStringOut current_piece;
Chris@16 448 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
Chris@16 449
Chris@16 450 // Iterate through all intersection points (they are ordered along the line)
Chris@16 451 bool entered = false;
Chris@16 452 bool first = true;
Chris@16 453 for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
Chris@16 454 {
Chris@16 455 turn_operation_iterator_type iit = boost::begin(it->operations);
Chris@16 456
Chris@16 457 if (following::was_entered(*it, *iit, first, linestring, polygon))
Chris@16 458 {
Chris@16 459 debug_traverse(*it, *iit, "-> Was entered");
Chris@16 460 entered = true;
Chris@16 461 }
Chris@16 462
Chris@16 463 if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
Chris@16 464 {
Chris@16 465 debug_traverse(*it, *iit, "-> Staying inside");
Chris@16 466
Chris@16 467 entered = true;
Chris@16 468 }
Chris@16 469 else if (following::is_entering(*it, *iit))
Chris@16 470 {
Chris@16 471 debug_traverse(*it, *iit, "-> Entering");
Chris@16 472
Chris@16 473 entered = true;
Chris@101 474 action::enter(current_piece, linestring, current_segment_id,
Chris@101 475 iit->seg_id.segment_index, it->point, *iit,
Chris@101 476 robust_policy,
Chris@101 477 out);
Chris@16 478 }
Chris@16 479 else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
Chris@16 480 {
Chris@16 481 debug_traverse(*it, *iit, "-> Leaving");
Chris@16 482
Chris@16 483 entered = false;
Chris@101 484 action::leave(current_piece, linestring, current_segment_id,
Chris@101 485 iit->seg_id.segment_index, it->point, *iit,
Chris@101 486 robust_policy,
Chris@101 487 out);
Chris@16 488 }
Chris@16 489 first = false;
Chris@16 490 }
Chris@16 491
Chris@16 492 if (action::is_entered(entered))
Chris@16 493 {
Chris@101 494 detail::copy_segments::copy_segments_linestring
Chris@101 495 <
Chris@101 496 false, RemoveSpikes
Chris@101 497 >::apply(linestring,
Chris@101 498 current_segment_id,
Chris@101 499 static_cast<signed_index_type>(boost::size(linestring) - 1),
Chris@101 500 robust_policy,
Chris@101 501 current_piece);
Chris@16 502 }
Chris@16 503
Chris@16 504 // Output the last one, if applicable
Chris@101 505 if (::boost::size(current_piece) > 1)
Chris@16 506 {
Chris@16 507 *out++ = current_piece;
Chris@16 508 }
Chris@16 509 return out;
Chris@16 510 }
Chris@16 511
Chris@16 512 };
Chris@16 513
Chris@16 514
Chris@16 515 }} // namespace detail::overlay
Chris@16 516 #endif // DOXYGEN_NO_DETAIL
Chris@16 517
Chris@16 518
Chris@16 519 }} // namespace boost::geometry
Chris@16 520
Chris@16 521
Chris@16 522 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP