expand_point.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
  6. // This file was modified by Oracle on 2015-2020.
  7. // Modifications copyright (c) 2015-2020, 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. // Distributed under the Boost Software License, Version 1.0.
  14. // (See accompanying file LICENSE_1_0.txt or copy at
  15. // http://www.boost.org/LICENSE_1_0.txt)
  16. #ifndef BOOST_GEOMETRY_STRATEGY_SPHERICAL_EXPAND_POINT_HPP
  17. #define BOOST_GEOMETRY_STRATEGY_SPHERICAL_EXPAND_POINT_HPP
  18. #include <algorithm>
  19. #include <cstddef>
  20. #include <functional>
  21. #include <type_traits>
  22. #include <boost/geometry/core/access.hpp>
  23. #include <boost/geometry/core/coordinate_dimension.hpp>
  24. #include <boost/geometry/core/coordinate_system.hpp>
  25. #include <boost/geometry/core/coordinate_type.hpp>
  26. #include <boost/geometry/core/tags.hpp>
  27. #include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp>
  28. #include <boost/geometry/util/math.hpp>
  29. #include <boost/geometry/util/select_coordinate_type.hpp>
  30. #include <boost/geometry/algorithms/detail/normalize.hpp>
  31. #include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
  32. #include <boost/geometry/strategy/expand.hpp>
  33. #include <boost/geometry/strategy/cartesian/expand_point.hpp>
  34. namespace boost { namespace geometry
  35. {
  36. namespace strategy { namespace expand
  37. {
  38. #ifndef DOXYGEN_NO_DETAIL
  39. namespace detail
  40. {
  41. // implementation for the spherical and geographic coordinate systems
  42. template <std::size_t DimensionCount, bool IsEquatorial>
  43. struct point_loop_on_spheroid
  44. {
  45. template <typename Box, typename Point>
  46. static inline void apply(Box& box, Point const& point)
  47. {
  48. using box_point_type = point_type_t<Box>;
  49. using box_coordinate_type = coordinate_type_t<Box>;
  50. using units_type = typename geometry::detail::cs_angular_units<Box>::type;
  51. using constants = math::detail::constants_on_spheroid
  52. <
  53. box_coordinate_type,
  54. units_type
  55. >;
  56. // normalize input point and input box
  57. Point p_normalized;
  58. strategy::normalize::spherical_point::apply(point, p_normalized);
  59. // transform input point to be of the same type as the box point
  60. box_point_type box_point;
  61. geometry::detail::envelope::transform_units(p_normalized, box_point);
  62. if (is_inverse_spheroidal_coordinates(box))
  63. {
  64. geometry::set_from_radian<min_corner, 0>(box, geometry::get_as_radian<0>(p_normalized));
  65. geometry::set_from_radian<min_corner, 1>(box, geometry::get_as_radian<1>(p_normalized));
  66. geometry::set_from_radian<max_corner, 0>(box, geometry::get_as_radian<0>(p_normalized));
  67. geometry::set_from_radian<max_corner, 1>(box, geometry::get_as_radian<1>(p_normalized));
  68. } else {
  69. strategy::normalize::spherical_box::apply(box, box);
  70. box_coordinate_type p_lon = geometry::get<0>(box_point);
  71. box_coordinate_type p_lat = geometry::get<1>(box_point);
  72. box_coordinate_type b_lon_min = geometry::get<min_corner, 0>(box);
  73. box_coordinate_type b_lat_min = geometry::get<min_corner, 1>(box);
  74. box_coordinate_type b_lon_max = geometry::get<max_corner, 0>(box);
  75. box_coordinate_type b_lat_max = geometry::get<max_corner, 1>(box);
  76. if (math::is_latitude_pole<units_type, IsEquatorial>(p_lat))
  77. {
  78. // the point of expansion is the either the north or the
  79. // south pole; the only important coordinate here is the
  80. // pole's latitude, as the longitude can be anything;
  81. // we, thus, take into account the point's latitude only and return
  82. geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
  83. geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
  84. return;
  85. }
  86. if (math::equals(b_lat_min, b_lat_max)
  87. && math::is_latitude_pole<units_type, IsEquatorial>(b_lat_min))
  88. {
  89. // the box degenerates to either the north or the south pole;
  90. // the only important coordinate here is the pole's latitude,
  91. // as the longitude can be anything;
  92. // we thus take into account the box's latitude only and return
  93. geometry::set<min_corner, 0>(box, p_lon);
  94. geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
  95. geometry::set<max_corner, 0>(box, p_lon);
  96. geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
  97. return;
  98. }
  99. // update latitudes
  100. b_lat_min = (std::min)(b_lat_min, p_lat);
  101. b_lat_max = (std::max)(b_lat_max, p_lat);
  102. // update longitudes
  103. if (math::smaller(p_lon, b_lon_min))
  104. {
  105. box_coordinate_type p_lon_shifted = p_lon + constants::period();
  106. if (math::larger(p_lon_shifted, b_lon_max))
  107. {
  108. // here we could check using: ! math::larger(.., ..)
  109. if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max))
  110. {
  111. b_lon_min = p_lon;
  112. }
  113. else
  114. {
  115. b_lon_max = p_lon_shifted;
  116. }
  117. }
  118. }
  119. else if (math::larger(p_lon, b_lon_max))
  120. {
  121. // in this case, and since p_lon is normalized in the range
  122. // (-180, 180], we must have that b_lon_max <= 180
  123. if (b_lon_min < 0
  124. && math::larger(p_lon - b_lon_max,
  125. constants::period() - p_lon + b_lon_min))
  126. {
  127. b_lon_min = p_lon;
  128. b_lon_max += constants::period();
  129. }
  130. else
  131. {
  132. b_lon_max = p_lon;
  133. }
  134. }
  135. geometry::set<min_corner, 0>(box, b_lon_min);
  136. geometry::set<min_corner, 1>(box, b_lat_min);
  137. geometry::set<max_corner, 0>(box, b_lon_max);
  138. geometry::set<max_corner, 1>(box, b_lat_max);
  139. }
  140. point_loop
  141. <
  142. 2, DimensionCount
  143. >::apply(box, point);
  144. }
  145. };
  146. } // namespace detail
  147. #endif // DOXYGEN_NO_DETAIL
  148. struct spherical_point
  149. {
  150. template <typename Box, typename Point>
  151. static void apply(Box & box, Point const& point)
  152. {
  153. expand::detail::point_loop_on_spheroid
  154. <
  155. dimension<Point>::value,
  156. ! std::is_same<cs_tag_t<Point>, spherical_polar_tag>::value
  157. >::apply(box, point);
  158. }
  159. };
  160. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  161. namespace services
  162. {
  163. template <typename CalculationType>
  164. struct default_strategy<point_tag, spherical_equatorial_tag, CalculationType>
  165. {
  166. typedef spherical_point type;
  167. };
  168. template <typename CalculationType>
  169. struct default_strategy<point_tag, spherical_polar_tag, CalculationType>
  170. {
  171. typedef spherical_point type;
  172. };
  173. template <typename CalculationType>
  174. struct default_strategy<point_tag, geographic_tag, CalculationType>
  175. {
  176. typedef spherical_point type;
  177. };
  178. } // namespace services
  179. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  180. }} // namespace strategy::expand
  181. }} // namespace boost::geometry
  182. #endif // BOOST_GEOMETRY_STRATEGY_SPHERICAL_EXPAND_POINT_HPP