distance_segment_box.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2018-2019 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 <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
  11. #include <boost/geometry/strategies/distance.hpp>
  12. #include <boost/geometry/strategies/normalize.hpp>
  13. #include <boost/geometry/strategies/spherical/disjoint_box_box.hpp>
  14. #include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
  15. #include <boost/geometry/strategies/spherical/point_in_point.hpp>
  16. #include <boost/geometry/strategies/cartesian/point_in_box.hpp> // spherical
  17. #include <boost/geometry/strategies/spherical/ssf.hpp>
  18. namespace boost { namespace geometry
  19. {
  20. namespace strategy { namespace distance
  21. {
  22. struct generic_segment_box
  23. {
  24. template
  25. <
  26. typename LessEqual,
  27. typename ReturnType,
  28. typename SegmentPoint,
  29. typename BoxPoint,
  30. typename SegmentBoxStrategy,
  31. typename AzimuthStrategy,
  32. typename EnvelopeSegmentStrategy,
  33. typename NormalizePointStrategy,
  34. typename DisjointPointBoxStrategy,
  35. typename DisjointBoxBoxStrategy
  36. >
  37. static inline ReturnType segment_below_of_box(
  38. SegmentPoint const& p0,
  39. SegmentPoint const& p1,
  40. BoxPoint const&,
  41. BoxPoint const& top_right,
  42. BoxPoint const& bottom_left,
  43. BoxPoint const& bottom_right,
  44. SegmentBoxStrategy const& sb_strategy,
  45. AzimuthStrategy const& az_strategy,
  46. EnvelopeSegmentStrategy const& es_strategy,
  47. NormalizePointStrategy const& np_strategy,
  48. DisjointPointBoxStrategy const& dpb_strategy,
  49. DisjointBoxBoxStrategy const& dbb_strategy)
  50. {
  51. ReturnType result;
  52. typename LessEqual::other less_equal;
  53. typedef geometry::model::segment<SegmentPoint> segment_type;
  54. // if cs_tag is spherical_tag check segment's cs_tag with spherical_equatorial_tag as default
  55. typedef typename boost::mpl::if_c
  56. <
  57. boost::is_same<typename SegmentBoxStrategy::cs_tag, spherical_tag>::value,
  58. typename boost::mpl::if_c
  59. <
  60. boost::is_same
  61. <
  62. typename geometry::cs_tag<segment_type>::type,
  63. spherical_polar_tag
  64. >::value,
  65. spherical_polar_tag, spherical_equatorial_tag
  66. >::type,
  67. typename SegmentBoxStrategy::cs_tag
  68. >::type cs_tag;
  69. typedef geometry::detail::disjoint::
  70. disjoint_segment_box_sphere_or_spheroid<cs_tag>
  71. disjoint_sb;
  72. typedef typename disjoint_sb::disjoint_info disjoint_info_type;
  73. segment_type seg(p0, p1);
  74. geometry::model::box<BoxPoint> input_box;
  75. geometry::set_from_radian<geometry::min_corner, 0>
  76. (input_box, geometry::get_as_radian<0>(bottom_left));
  77. geometry::set_from_radian<geometry::min_corner, 1>
  78. (input_box, geometry::get_as_radian<1>(bottom_left));
  79. geometry::set_from_radian<geometry::max_corner, 0>
  80. (input_box, geometry::get_as_radian<0>(top_right));
  81. geometry::set_from_radian<geometry::max_corner, 1>
  82. (input_box, geometry::get_as_radian<1>(top_right));
  83. SegmentPoint p_max;
  84. disjoint_info_type disjoint_result = disjoint_sb::
  85. apply(seg, input_box, p_max,
  86. az_strategy, np_strategy, dpb_strategy, dbb_strategy);
  87. if (disjoint_result == disjoint_info_type::intersect) //intersect
  88. {
  89. return 0;
  90. }
  91. // disjoint but vertex not computed
  92. if (disjoint_result == disjoint_info_type::disjoint_no_vertex)
  93. {
  94. typedef typename coordinate_type<SegmentPoint>::type CT;
  95. geometry::model::box<SegmentPoint> mbr;
  96. geometry::envelope(seg, mbr, es_strategy);
  97. CT lon1 = geometry::get_as_radian<0>(p0);
  98. CT lat1 = geometry::get_as_radian<1>(p0);
  99. CT lon2 = geometry::get_as_radian<0>(p1);
  100. CT lat2 = geometry::get_as_radian<1>(p1);
  101. if (lon1 > lon2)
  102. {
  103. std::swap(lon1, lon2);
  104. std::swap(lat1, lat2);
  105. }
  106. CT vertex_lat;
  107. CT lat_sum = lat1 + lat2;
  108. if (lat_sum > CT(0))
  109. {
  110. vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(mbr);
  111. } else {
  112. vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(mbr);
  113. }
  114. CT alp1;
  115. az_strategy.apply(lon1, lat1, lon2, lat2, alp1);
  116. CT vertex_lon = geometry::formula::vertex_longitude
  117. <
  118. CT,
  119. cs_tag
  120. >::apply(lon1, lat1, lon2, lat2,
  121. vertex_lat, alp1, az_strategy);
  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 = boost::numeric_cast<ReturnType>(typename
  130. SegmentBoxStrategy::distance_ps_strategy::type().apply(bottom_left, p0, p1));
  131. }
  132. else
  133. {
  134. result = geometry::detail::distance::segment_to_box_2D
  135. <
  136. ReturnType,
  137. SegmentPoint,
  138. BoxPoint,
  139. SegmentBoxStrategy
  140. >::template call_above_of_box
  141. <
  142. typename LessEqual::other
  143. >(p1, p0, p_max, bottom_right, sb_strategy);
  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. // strategy getters
  191. // point-point strategy getters
  192. struct distance_pp_strategy
  193. {
  194. typedef Strategy type;
  195. };
  196. inline typename distance_pp_strategy::type get_distance_pp_strategy() const
  197. {
  198. return typename distance_pp_strategy::type();
  199. }
  200. // point-segment strategy getters
  201. struct distance_ps_strategy
  202. {
  203. typedef cross_track<CalculationType, Strategy> type;
  204. };
  205. inline typename distance_ps_strategy::type get_distance_ps_strategy() const
  206. {
  207. return typename distance_ps_strategy::type();
  208. }
  209. struct distance_pb_strategy
  210. {
  211. typedef cross_track_point_box<CalculationType, Strategy> type;
  212. };
  213. inline typename distance_pb_strategy::type get_distance_pb_strategy() const
  214. {
  215. return typename distance_pb_strategy::type();
  216. }
  217. // TODO: why is the Radius not propagated above?
  218. typedef side::spherical_side_formula<CalculationType> side_strategy_type;
  219. static inline side_strategy_type get_side_strategy()
  220. {
  221. return side_strategy_type();
  222. }
  223. typedef within::spherical_point_point equals_point_point_strategy_type;
  224. static inline equals_point_point_strategy_type get_equals_point_point_strategy()
  225. {
  226. return equals_point_point_strategy_type();
  227. }
  228. // methods
  229. template <typename LessEqual, typename ReturnType,
  230. typename SegmentPoint, typename BoxPoint>
  231. inline ReturnType segment_below_of_box(SegmentPoint const& p0,
  232. SegmentPoint const& p1,
  233. BoxPoint const& top_left,
  234. BoxPoint const& top_right,
  235. BoxPoint const& bottom_left,
  236. BoxPoint const& bottom_right) const
  237. {
  238. typedef typename azimuth::spherical<CalculationType> azimuth_strategy_type;
  239. azimuth_strategy_type az_strategy;
  240. typedef typename envelope::spherical_segment<CalculationType>
  241. envelope_segment_strategy_type;
  242. envelope_segment_strategy_type es_strategy;
  243. return generic_segment_box::segment_below_of_box
  244. <
  245. LessEqual,
  246. ReturnType
  247. >(p0,p1,top_left,top_right,bottom_left,bottom_right,
  248. spherical_segment_box<CalculationType>(),
  249. az_strategy, es_strategy,
  250. normalize::spherical_point(),
  251. covered_by::spherical_point_box(),
  252. disjoint::spherical_box_box());
  253. }
  254. template <typename SPoint, typename BPoint>
  255. static void mirror(SPoint& p0,
  256. SPoint& p1,
  257. BPoint& bottom_left,
  258. BPoint& bottom_right,
  259. BPoint& top_left,
  260. BPoint& top_right)
  261. {
  262. generic_segment_box::mirror(p0, p1,
  263. bottom_left, bottom_right,
  264. top_left, top_right);
  265. }
  266. };
  267. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  268. namespace services
  269. {
  270. template <typename CalculationType, typename Strategy>
  271. struct tag<spherical_segment_box<CalculationType, Strategy> >
  272. {
  273. typedef strategy_tag_distance_segment_box type;
  274. };
  275. template <typename CalculationType, typename Strategy, typename PS, typename PB>
  276. struct return_type<spherical_segment_box<CalculationType, Strategy>, PS, PB>
  277. : spherical_segment_box<CalculationType, Strategy>::template calculation_type<PS, PB>
  278. {};
  279. template <typename CalculationType, typename Strategy>
  280. struct comparable_type<spherical_segment_box<CalculationType, Strategy> >
  281. {
  282. // Define a cartesian_segment_box strategy with its underlying point-segment
  283. // strategy being comparable
  284. typedef spherical_segment_box
  285. <
  286. CalculationType,
  287. typename comparable_type<Strategy>::type
  288. > type;
  289. };
  290. template <typename CalculationType, typename Strategy>
  291. struct get_comparable<spherical_segment_box<CalculationType, Strategy> >
  292. {
  293. typedef typename comparable_type
  294. <
  295. spherical_segment_box<CalculationType, Strategy>
  296. >::type comparable_type;
  297. public :
  298. static inline comparable_type apply(spherical_segment_box<CalculationType, Strategy> const& )
  299. {
  300. return comparable_type();
  301. }
  302. };
  303. template <typename CalculationType, typename Strategy, typename PS, typename PB>
  304. struct result_from_distance<spherical_segment_box<CalculationType, Strategy>, PS, PB>
  305. {
  306. private :
  307. typedef typename return_type<
  308. spherical_segment_box
  309. <
  310. CalculationType,
  311. Strategy
  312. >,
  313. PS,
  314. PB
  315. >::type return_type;
  316. public :
  317. template <typename T>
  318. static inline return_type apply(spherical_segment_box<CalculationType,
  319. Strategy> const& ,
  320. T const& value)
  321. {
  322. Strategy s;
  323. return result_from_distance<Strategy, PS, PB>::apply(s, value);
  324. }
  325. };
  326. template <typename Segment, typename Box>
  327. struct default_strategy
  328. <
  329. segment_tag, box_tag, Segment, Box,
  330. spherical_equatorial_tag, spherical_equatorial_tag
  331. >
  332. {
  333. typedef spherical_segment_box<> type;
  334. };
  335. template <typename Box, typename Segment>
  336. struct default_strategy
  337. <
  338. box_tag, segment_tag, Box, Segment,
  339. spherical_equatorial_tag, spherical_equatorial_tag
  340. >
  341. {
  342. typedef typename default_strategy
  343. <
  344. segment_tag, box_tag, Segment, Box,
  345. spherical_equatorial_tag, spherical_equatorial_tag
  346. >::type type;
  347. };
  348. }
  349. #endif
  350. }} // namespace strategy::distance
  351. }} // namespace boost::geometry
  352. #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP