distance_segment_box.hpp 13 KB

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