less_by_segment_ratio.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2017.
  4. // Modifications copyright (c) 2017 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_ON_SEGMENT_RATIO_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_ON_SEGMENT_RATIO_HPP
  11. #include <cstddef>
  12. #include <algorithm>
  13. #include <map>
  14. #include <set>
  15. #include <vector>
  16. #include <boost/range.hpp>
  17. #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
  18. #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
  19. #include <boost/geometry/strategies/side.hpp>
  20. namespace boost { namespace geometry
  21. {
  22. #ifndef DOXYGEN_NO_DETAIL
  23. namespace detail { namespace overlay
  24. {
  25. // Wraps "turn_operation" from turn_info.hpp,
  26. // giving it extra information, necessary for sorting
  27. template <typename TurnOperation>
  28. struct indexed_turn_operation
  29. {
  30. typedef TurnOperation type;
  31. std::size_t turn_index;
  32. std::size_t operation_index;
  33. bool skip;
  34. // use pointers to avoid copies, const& is not possible because of usage in vector
  35. segment_identifier const* other_seg_id; // segment id of other segment of intersection of two segments
  36. TurnOperation const* subject;
  37. inline indexed_turn_operation(std::size_t ti, std::size_t oi,
  38. TurnOperation const& sub,
  39. segment_identifier const& oid)
  40. : turn_index(ti)
  41. , operation_index(oi)
  42. , skip(false)
  43. , other_seg_id(&oid)
  44. , subject(boost::addressof(sub))
  45. {}
  46. };
  47. template
  48. <
  49. typename Turns,
  50. typename Indexed,
  51. typename Geometry1, typename Geometry2,
  52. typename RobustPolicy,
  53. typename SideStrategy,
  54. bool Reverse1, bool Reverse2
  55. >
  56. struct less_by_segment_ratio
  57. {
  58. inline less_by_segment_ratio(Turns const& turns
  59. , Geometry1 const& geometry1
  60. , Geometry2 const& geometry2
  61. , RobustPolicy const& robust_policy
  62. , SideStrategy const& strategy)
  63. : m_turns(turns)
  64. , m_geometry1(geometry1)
  65. , m_geometry2(geometry2)
  66. , m_robust_policy(robust_policy)
  67. , m_strategy(strategy)
  68. {
  69. }
  70. private :
  71. Turns const& m_turns;
  72. Geometry1 const& m_geometry1;
  73. Geometry2 const& m_geometry2;
  74. RobustPolicy const& m_robust_policy;
  75. SideStrategy const& m_strategy;
  76. typedef typename geometry::point_type<Geometry1>::type point_type;
  77. inline bool default_order(Indexed const& left, Indexed const& right) const
  78. {
  79. // We've nothing to sort on. Take the indexes
  80. return left.turn_index < right.turn_index;
  81. }
  82. inline bool consider_relative_order(Indexed const& left,
  83. Indexed const& right) const
  84. {
  85. point_type pi, pj, ri, rj, si, sj;
  86. geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
  87. left.subject->seg_id,
  88. pi, pj);
  89. geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
  90. *left.other_seg_id,
  91. ri, rj);
  92. geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
  93. *right.other_seg_id,
  94. si, sj);
  95. int const side_rj_p = m_strategy.apply(pi, pj, rj);
  96. int const side_sj_p = m_strategy.apply(pi, pj, sj);
  97. // Put the one turning left (1; right == -1) as last
  98. if (side_rj_p != side_sj_p)
  99. {
  100. return side_rj_p < side_sj_p;
  101. }
  102. int const side_sj_r = m_strategy.apply(ri, rj, sj);
  103. int const side_rj_s = m_strategy.apply(si, sj, rj);
  104. // If they both turn left: the most left as last
  105. // If they both turn right: this is not relevant, but take also here most left
  106. if (side_rj_s != side_sj_r)
  107. {
  108. return side_rj_s < side_sj_r;
  109. }
  110. return default_order(left, right);
  111. }
  112. public :
  113. // Note that left/right do NOT correspond to m_geometry1/m_geometry2
  114. // but to the "indexed_turn_operation"
  115. inline bool operator()(Indexed const& left, Indexed const& right) const
  116. {
  117. if (! (left.subject->seg_id == right.subject->seg_id))
  118. {
  119. return left.subject->seg_id < right.subject->seg_id;
  120. }
  121. // Both left and right are located on the SAME segment.
  122. if (! (left.subject->fraction == right.subject->fraction))
  123. {
  124. return left.subject->fraction < right.subject->fraction;
  125. }
  126. typedef typename boost::range_value<Turns>::type turn_type;
  127. turn_type const& left_turn = m_turns[left.turn_index];
  128. turn_type const& right_turn = m_turns[right.turn_index];
  129. // First check "real" intersection (crosses)
  130. // -> distance zero due to precision, solve it by sorting
  131. if (left_turn.method == method_crosses
  132. && right_turn.method == method_crosses)
  133. {
  134. return consider_relative_order(left, right);
  135. }
  136. bool const left_both_xx = left_turn.both(operation_blocked);
  137. bool const right_both_xx = right_turn.both(operation_blocked);
  138. if (left_both_xx && ! right_both_xx)
  139. {
  140. return true;
  141. }
  142. if (! left_both_xx && right_both_xx)
  143. {
  144. return false;
  145. }
  146. bool const left_both_uu = left_turn.both(operation_union);
  147. bool const right_both_uu = right_turn.both(operation_union);
  148. if (left_both_uu && ! right_both_uu)
  149. {
  150. return true;
  151. }
  152. if (! left_both_uu && right_both_uu)
  153. {
  154. return false;
  155. }
  156. return default_order(left, right);
  157. }
  158. };
  159. }} // namespace detail::overlay
  160. #endif //DOXYGEN_NO_DETAIL
  161. }} // namespace boost::geometry
  162. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_ON_SEGMENT_RATIO_HPP