segment_box.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2013-2019.
  7. // Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
  8. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  9. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  10. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  11. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  12. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  13. // Use, modification and distribution is subject to the Boost Software License,
  14. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  15. // http://www.boost.org/LICENSE_1_0.txt)
  16. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
  17. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
  18. #include <cstddef>
  19. #include <boost/geometry/core/tags.hpp>
  20. #include <boost/geometry/core/radian_access.hpp>
  21. #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
  22. #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
  23. #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
  24. #include <boost/geometry/algorithms/detail/envelope/segment.hpp>
  25. #include <boost/geometry/algorithms/detail/normalize.hpp>
  26. #include <boost/geometry/algorithms/dispatch/disjoint.hpp>
  27. #include <boost/geometry/algorithms/envelope.hpp>
  28. #include <boost/geometry/formulas/vertex_longitude.hpp>
  29. #include <boost/geometry/geometries/box.hpp>
  30. // Temporary, for envelope_segment_impl
  31. #include <boost/geometry/strategies/spherical/envelope_segment.hpp>
  32. namespace boost { namespace geometry
  33. {
  34. #ifndef DOXYGEN_NO_DETAIL
  35. namespace detail { namespace disjoint
  36. {
  37. template <typename CS_Tag>
  38. struct disjoint_segment_box_sphere_or_spheroid
  39. {
  40. struct disjoint_info
  41. {
  42. enum type
  43. {
  44. intersect,
  45. disjoint_no_vertex,
  46. disjoint_vertex
  47. };
  48. disjoint_info(type t) : m_(t){}
  49. operator type () const {return m_;}
  50. type m_;
  51. private :
  52. //prevent automatic conversion for any other built-in types
  53. template <typename T>
  54. operator T () const;
  55. };
  56. template
  57. <
  58. typename Segment, typename Box,
  59. typename AzimuthStrategy,
  60. typename NormalizeStrategy,
  61. typename DisjointPointBoxStrategy,
  62. typename DisjointBoxBoxStrategy
  63. >
  64. static inline bool apply(Segment const& segment,
  65. Box const& box,
  66. AzimuthStrategy const& azimuth_strategy,
  67. NormalizeStrategy const& normalize_strategy,
  68. DisjointPointBoxStrategy const& disjoint_point_box_strategy,
  69. DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
  70. {
  71. typedef typename point_type<Segment>::type segment_point;
  72. segment_point vertex;
  73. return apply(segment, box, vertex,
  74. azimuth_strategy,
  75. normalize_strategy,
  76. disjoint_point_box_strategy,
  77. disjoint_box_box_strategy) != disjoint_info::intersect;
  78. }
  79. template
  80. <
  81. typename Segment, typename Box,
  82. typename P,
  83. typename AzimuthStrategy,
  84. typename NormalizeStrategy,
  85. typename DisjointPointBoxStrategy,
  86. typename DisjointBoxBoxStrategy
  87. >
  88. static inline disjoint_info apply(Segment const& segment,
  89. Box const& box,
  90. P& vertex,
  91. AzimuthStrategy const& azimuth_strategy,
  92. NormalizeStrategy const& ,
  93. DisjointPointBoxStrategy const& disjoint_point_box_strategy,
  94. DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
  95. {
  96. assert_dimension_equal<Segment, Box>();
  97. typedef typename point_type<Segment>::type segment_point_type;
  98. segment_point_type p0, p1;
  99. geometry::detail::assign_point_from_index<0>(segment, p0);
  100. geometry::detail::assign_point_from_index<1>(segment, p1);
  101. //vertex not computed here
  102. disjoint_info disjoint_return_value = disjoint_info::disjoint_no_vertex;
  103. // Simplest cases first
  104. // Case 1: if box contains one of segment's endpoints then they are not disjoint
  105. if ( ! disjoint_point_box(p0, box, disjoint_point_box_strategy)
  106. || ! disjoint_point_box(p1, box, disjoint_point_box_strategy) )
  107. {
  108. return disjoint_info::intersect;
  109. }
  110. // Case 2: disjoint if bounding boxes are disjoint
  111. typedef typename coordinate_type<segment_point_type>::type CT;
  112. segment_point_type p0_normalized;
  113. NormalizeStrategy::apply(p0, p0_normalized);
  114. segment_point_type p1_normalized;
  115. NormalizeStrategy::apply(p1, p1_normalized);
  116. CT lon1 = geometry::get_as_radian<0>(p0_normalized);
  117. CT lat1 = geometry::get_as_radian<1>(p0_normalized);
  118. CT lon2 = geometry::get_as_radian<0>(p1_normalized);
  119. CT lat2 = geometry::get_as_radian<1>(p1_normalized);
  120. if (lon1 > lon2)
  121. {
  122. std::swap(lon1, lon2);
  123. std::swap(lat1, lat2);
  124. }
  125. geometry::model::box<segment_point_type> box_seg;
  126. strategy::envelope::detail::envelope_segment_impl
  127. <
  128. CS_Tag
  129. >::template apply<geometry::radian>(lon1, lat1,
  130. lon2, lat2,
  131. box_seg,
  132. azimuth_strategy);
  133. if (disjoint_box_box(box, box_seg, disjoint_box_box_strategy))
  134. {
  135. return disjoint_return_value;
  136. }
  137. // Case 3: test intersection by comparing angles
  138. CT alp1, a_b0, a_b1, a_b2, a_b3;
  139. CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box);
  140. CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box);
  141. CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box);
  142. CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box);
  143. azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1);
  144. azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0);
  145. azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1);
  146. azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2);
  147. azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3);
  148. bool b0 = formula::azimuth_side_value(alp1, a_b0) > 0;
  149. bool b1 = formula::azimuth_side_value(alp1, a_b1) > 0;
  150. bool b2 = formula::azimuth_side_value(alp1, a_b2) > 0;
  151. bool b3 = formula::azimuth_side_value(alp1, a_b3) > 0;
  152. if (!(b0 && b1 && b2 && b3) && (b0 || b1 || b2 || b3))
  153. {
  154. return disjoint_info::intersect;
  155. }
  156. // Case 4: The only intersection case not covered above is when all four
  157. // points of the box are above (below) the segment in northern (southern)
  158. // hemisphere. Then we have to compute the vertex of the segment
  159. CT vertex_lat;
  160. CT lat_sum = lat1 + lat2;
  161. if ((lat1 < b_lat_min && lat_sum > CT(0))
  162. || (lat1 > b_lat_max && lat_sum < CT(0)))
  163. {
  164. CT b_lat_below; //latitude of box closest to equator
  165. if (lat_sum > CT(0))
  166. {
  167. vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
  168. b_lat_below = b_lat_min;
  169. } else {
  170. vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg);
  171. b_lat_below = b_lat_max;
  172. }
  173. //optimization TODO: computing the spherical longitude should suffice for
  174. // the majority of cases
  175. CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag>
  176. ::apply(lon1, lat1,
  177. lon2, lat2,
  178. vertex_lat,
  179. alp1,
  180. azimuth_strategy);
  181. geometry::set_from_radian<0>(vertex, vertex_lon);
  182. geometry::set_from_radian<1>(vertex, vertex_lat);
  183. disjoint_return_value = disjoint_info::disjoint_vertex; //vertex_computed
  184. // Check if the vertex point is within the band defined by the
  185. // minimum and maximum longitude of the box; if yes, then return
  186. // false if the point is above the min latitude of the box; return
  187. // true in all other cases
  188. if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max
  189. && std::abs(vertex_lat) > std::abs(b_lat_below))
  190. {
  191. return disjoint_info::intersect;
  192. }
  193. }
  194. return disjoint_return_value;
  195. }
  196. };
  197. struct disjoint_segment_box
  198. {
  199. template <typename Segment, typename Box, typename Strategy>
  200. static inline bool apply(Segment const& segment,
  201. Box const& box,
  202. Strategy const& strategy)
  203. {
  204. return strategy.apply(segment, box);
  205. }
  206. };
  207. }} // namespace detail::disjoint
  208. #endif // DOXYGEN_NO_DETAIL
  209. #ifndef DOXYGEN_NO_DISPATCH
  210. namespace dispatch
  211. {
  212. template <typename Segment, typename Box, std::size_t DimensionCount>
  213. struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
  214. : detail::disjoint::disjoint_segment_box
  215. {};
  216. } // namespace dispatch
  217. #endif // DOXYGEN_NO_DISPATCH
  218. }} // namespace boost::geometry
  219. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP