distance_segment_box.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2018-2021 Oracle and/or its affiliates.
  3. // Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
  4. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP
  9. #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP
  10. #include <type_traits>
  11. #include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
  12. #include <boost/geometry/algorithms/envelope.hpp>
  13. #include <boost/geometry/strategies/distance.hpp>
  14. #include <boost/geometry/strategies/normalize.hpp>
  15. #include <boost/geometry/strategies/spherical/disjoint_box_box.hpp>
  16. #include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
  17. #include <boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp>
  18. #include <boost/geometry/strategies/spherical/point_in_point.hpp>
  19. #include <boost/geometry/strategies/cartesian/point_in_box.hpp> // spherical
  20. #include <boost/geometry/strategies/spherical/ssf.hpp>
  21. #include <boost/geometry/util/numeric_cast.hpp>
  22. namespace boost { namespace geometry
  23. {
  24. namespace strategy { namespace distance
  25. {
  26. struct generic_segment_box
  27. {
  28. template
  29. <
  30. typename LessEqual,
  31. typename ReturnType,
  32. typename SegmentPoint,
  33. typename BoxPoint,
  34. typename Strategies
  35. >
  36. static inline ReturnType segment_below_of_box(
  37. SegmentPoint const& p0,
  38. SegmentPoint const& p1,
  39. BoxPoint const&,
  40. BoxPoint const& top_right,
  41. BoxPoint const& bottom_left,
  42. BoxPoint const& bottom_right,
  43. Strategies const& strategies)
  44. {
  45. ReturnType result;
  46. typename LessEqual::other less_equal;
  47. typedef geometry::model::segment<SegmentPoint> segment_type;
  48. // if cs_tag is spherical_tag check segment's cs_tag with spherical_equatorial_tag as default
  49. typedef std::conditional_t
  50. <
  51. std::is_same<typename Strategies::cs_tag, spherical_tag>::value,
  52. std::conditional_t
  53. <
  54. std::is_same
  55. <
  56. typename geometry::cs_tag<segment_type>::type,
  57. spherical_polar_tag
  58. >::value,
  59. spherical_polar_tag, spherical_equatorial_tag
  60. >,
  61. typename Strategies::cs_tag
  62. > cs_tag;
  63. typedef geometry::detail::disjoint::
  64. disjoint_segment_box_sphere_or_spheroid<cs_tag>
  65. disjoint_sb;
  66. typedef typename disjoint_sb::disjoint_info disjoint_info_type;
  67. segment_type seg(p0, p1);
  68. geometry::model::box<BoxPoint> input_box;
  69. geometry::set_from_radian<geometry::min_corner, 0>
  70. (input_box, geometry::get_as_radian<0>(bottom_left));
  71. geometry::set_from_radian<geometry::min_corner, 1>
  72. (input_box, geometry::get_as_radian<1>(bottom_left));
  73. geometry::set_from_radian<geometry::max_corner, 0>
  74. (input_box, geometry::get_as_radian<0>(top_right));
  75. geometry::set_from_radian<geometry::max_corner, 1>
  76. (input_box, geometry::get_as_radian<1>(top_right));
  77. SegmentPoint p_max;
  78. // TODO: Think about rewriting this and simply passing strategies
  79. // The problem is that this algorithm is called by disjoint(S/B) strategies.
  80. disjoint_info_type disjoint_result = disjoint_sb::
  81. apply(seg, input_box, p_max,
  82. strategies.azimuth(),
  83. strategies.normalize(p0),
  84. strategies.covered_by(p0, input_box), // disjoint
  85. strategies.disjoint(input_box, input_box));
  86. if (disjoint_result == disjoint_info_type::intersect) //intersect
  87. {
  88. return 0;
  89. }
  90. // disjoint but vertex not computed
  91. if (disjoint_result == disjoint_info_type::disjoint_no_vertex)
  92. {
  93. typedef typename coordinate_type<SegmentPoint>::type CT;
  94. geometry::model::box<SegmentPoint> mbr;
  95. geometry::envelope(seg, mbr, strategies);
  96. CT lon1 = geometry::get_as_radian<0>(p0);
  97. CT lat1 = geometry::get_as_radian<1>(p0);
  98. CT lon2 = geometry::get_as_radian<0>(p1);
  99. CT lat2 = geometry::get_as_radian<1>(p1);
  100. if (lon1 > lon2)
  101. {
  102. std::swap(lon1, lon2);
  103. std::swap(lat1, lat2);
  104. }
  105. CT vertex_lat;
  106. CT lat_sum = lat1 + lat2;
  107. if (lat_sum > CT(0))
  108. {
  109. vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(mbr);
  110. } else {
  111. vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(mbr);
  112. }
  113. CT alp1;
  114. strategies.azimuth().apply(lon1, lat1, lon2, lat2, alp1);
  115. // TODO: formula should not call strategy!
  116. CT vertex_lon = geometry::formula::vertex_longitude
  117. <
  118. CT,
  119. cs_tag
  120. >::apply(lon1, lat1, lon2, lat2,
  121. vertex_lat, alp1, strategies.azimuth());
  122. geometry::set_from_radian<0>(p_max, vertex_lon);
  123. geometry::set_from_radian<1>(p_max, vertex_lat);
  124. }
  125. //otherwise disjoint and vertex computed inside disjoint
  126. if (less_equal(geometry::get_as_radian<0>(bottom_left),
  127. geometry::get_as_radian<0>(p_max)))
  128. {
  129. result = util::numeric_cast<ReturnType>(
  130. strategies.distance(bottom_left, seg).apply(bottom_left, p0, p1));
  131. }
  132. else
  133. {
  134. // TODO: The strategy should not call the algorithm like that
  135. result = geometry::detail::distance::segment_to_box_2D
  136. <
  137. ReturnType,
  138. SegmentPoint,
  139. BoxPoint,
  140. Strategies
  141. >::template call_above_of_box
  142. <
  143. typename LessEqual::other
  144. >(p1, p0, p_max, bottom_right, strategies);
  145. }
  146. return result;
  147. }
  148. template <typename SPoint, typename BPoint>
  149. static void mirror(SPoint& p0,
  150. SPoint& p1,
  151. BPoint& bottom_left,
  152. BPoint& bottom_right,
  153. BPoint& top_left,
  154. BPoint& top_right)
  155. {
  156. //if segment's vertex is the southest point then mirror geometries
  157. if (geometry::get<1>(p0) + geometry::get<1>(p1) < 0)
  158. {
  159. BPoint bl = bottom_left;
  160. BPoint br = bottom_right;
  161. geometry::set<1>(p0, geometry::get<1>(p0) * -1);
  162. geometry::set<1>(p1, geometry::get<1>(p1) * -1);
  163. geometry::set<1>(bottom_left, geometry::get<1>(top_left) * -1);
  164. geometry::set<1>(top_left, geometry::get<1>(bl) * -1);
  165. geometry::set<1>(bottom_right, geometry::get<1>(top_right) * -1);
  166. geometry::set<1>(top_right, geometry::get<1>(br) * -1);
  167. }
  168. }
  169. };
  170. //===========================================================================
  171. template
  172. <
  173. typename CalculationType = void,
  174. typename Strategy = haversine<double, CalculationType>
  175. >
  176. struct spherical_segment_box
  177. {
  178. template <typename PointOfSegment, typename PointOfBox>
  179. struct calculation_type
  180. : promote_floating_point
  181. <
  182. typename strategy::distance::services::return_type
  183. <
  184. Strategy,
  185. PointOfSegment,
  186. PointOfBox
  187. >::type
  188. >
  189. {};
  190. typedef spherical_tag cs_tag;
  191. // constructors
  192. inline spherical_segment_box()
  193. {}
  194. explicit inline spherical_segment_box(typename Strategy::radius_type const& r)
  195. : m_strategy(r)
  196. {}
  197. inline spherical_segment_box(Strategy const& s)
  198. : m_strategy(s)
  199. {}
  200. typename Strategy::radius_type radius() const
  201. {
  202. return m_strategy.radius();
  203. }
  204. // methods
  205. template
  206. <
  207. typename LessEqual, typename ReturnType,
  208. typename SegmentPoint, typename BoxPoint,
  209. typename Strategies
  210. >
  211. inline ReturnType segment_below_of_box(SegmentPoint const& p0,
  212. SegmentPoint const& p1,
  213. BoxPoint const& top_left,
  214. BoxPoint const& top_right,
  215. BoxPoint const& bottom_left,
  216. BoxPoint const& bottom_right,
  217. Strategies const& strategies) const
  218. {
  219. return generic_segment_box::segment_below_of_box
  220. <
  221. LessEqual,
  222. ReturnType
  223. >(p0,p1,top_left,top_right,bottom_left,bottom_right,
  224. strategies);
  225. }
  226. template <typename SPoint, typename BPoint>
  227. static void mirror(SPoint& p0,
  228. SPoint& p1,
  229. BPoint& bottom_left,
  230. BPoint& bottom_right,
  231. BPoint& top_left,
  232. BPoint& top_right)
  233. {
  234. generic_segment_box::mirror(p0, p1,
  235. bottom_left, bottom_right,
  236. top_left, top_right);
  237. }
  238. private:
  239. Strategy m_strategy;
  240. };
  241. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  242. namespace services
  243. {
  244. template <typename CalculationType, typename Strategy>
  245. struct tag<spherical_segment_box<CalculationType, Strategy> >
  246. {
  247. typedef strategy_tag_distance_segment_box type;
  248. };
  249. template <typename CalculationType, typename Strategy, typename PS, typename PB>
  250. struct return_type<spherical_segment_box<CalculationType, Strategy>, PS, PB>
  251. : spherical_segment_box<CalculationType, Strategy>::template calculation_type<PS, PB>
  252. {};
  253. template <typename CalculationType, typename Strategy>
  254. struct comparable_type<spherical_segment_box<CalculationType, Strategy> >
  255. {
  256. // Define a cartesian_segment_box strategy with its underlying point-segment
  257. // strategy being comparable
  258. typedef spherical_segment_box
  259. <
  260. CalculationType,
  261. typename comparable_type<Strategy>::type
  262. > type;
  263. };
  264. template <typename CalculationType, typename Strategy>
  265. struct get_comparable<spherical_segment_box<CalculationType, Strategy> >
  266. {
  267. typedef typename comparable_type
  268. <
  269. spherical_segment_box<CalculationType, Strategy>
  270. >::type comparable_type;
  271. public :
  272. static inline comparable_type apply(spherical_segment_box<CalculationType, Strategy> const& )
  273. {
  274. return comparable_type();
  275. }
  276. };
  277. template <typename CalculationType, typename Strategy, typename PS, typename PB>
  278. struct result_from_distance<spherical_segment_box<CalculationType, Strategy>, PS, PB>
  279. {
  280. private :
  281. typedef typename return_type<
  282. spherical_segment_box
  283. <
  284. CalculationType,
  285. Strategy
  286. >,
  287. PS,
  288. PB
  289. >::type return_type;
  290. public :
  291. template <typename T>
  292. static inline return_type apply(spherical_segment_box<CalculationType,
  293. Strategy> const& ,
  294. T const& value)
  295. {
  296. Strategy s;
  297. return result_from_distance<Strategy, PS, PB>::apply(s, value);
  298. }
  299. };
  300. template <typename Segment, typename Box>
  301. struct default_strategy
  302. <
  303. segment_tag, box_tag, Segment, Box,
  304. spherical_equatorial_tag, spherical_equatorial_tag
  305. >
  306. {
  307. typedef spherical_segment_box<> type;
  308. };
  309. template <typename Box, typename Segment>
  310. struct default_strategy
  311. <
  312. box_tag, segment_tag, Box, Segment,
  313. spherical_equatorial_tag, spherical_equatorial_tag
  314. >
  315. {
  316. typedef typename default_strategy
  317. <
  318. segment_tag, box_tag, Segment, Box,
  319. spherical_equatorial_tag, spherical_equatorial_tag
  320. >::type type;
  321. };
  322. }
  323. #endif
  324. }} // namespace strategy::distance
  325. }} // namespace boost::geometry
  326. #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP