expand_point.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. typedef typename point_type<Box>::type box_point_type;
  49. typedef typename coordinate_type<Box>::type box_coordinate_type;
  50. typedef typename geometry::detail::cs_angular_units<Box>::type units_type;
  51. typedef math::detail::constants_on_spheroid
  52. <
  53. box_coordinate_type,
  54. units_type
  55. > constants;
  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. typename coordinate_type<Box>::type
  73. b_lon_min = geometry::get<min_corner, 0>(box),
  74. b_lat_min = geometry::get<min_corner, 1>(box),
  75. b_lon_max = geometry::get<max_corner, 0>(box),
  76. b_lat_max = geometry::get<max_corner, 1>(box);
  77. if (math::is_latitude_pole<units_type, IsEquatorial>(p_lat))
  78. {
  79. // the point of expansion is the either the north or the
  80. // south pole; the only important coordinate here is the
  81. // pole's latitude, as the longitude can be anything;
  82. // we, thus, take into account the point's latitude only and return
  83. geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
  84. geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
  85. return;
  86. }
  87. if (math::equals(b_lat_min, b_lat_max)
  88. && math::is_latitude_pole<units_type, IsEquatorial>(b_lat_min))
  89. {
  90. // the box degenerates to either the north or the south pole;
  91. // the only important coordinate here is the pole's latitude,
  92. // as the longitude can be anything;
  93. // we thus take into account the box's latitude only and return
  94. geometry::set<min_corner, 0>(box, p_lon);
  95. geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
  96. geometry::set<max_corner, 0>(box, p_lon);
  97. geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
  98. return;
  99. }
  100. // update latitudes
  101. b_lat_min = (std::min)(b_lat_min, p_lat);
  102. b_lat_max = (std::max)(b_lat_max, p_lat);
  103. // update longitudes
  104. if (math::smaller(p_lon, b_lon_min))
  105. {
  106. box_coordinate_type p_lon_shifted = p_lon + constants::period();
  107. if (math::larger(p_lon_shifted, b_lon_max))
  108. {
  109. // here we could check using: ! math::larger(.., ..)
  110. if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max))
  111. {
  112. b_lon_min = p_lon;
  113. }
  114. else
  115. {
  116. b_lon_max = p_lon_shifted;
  117. }
  118. }
  119. }
  120. else if (math::larger(p_lon, b_lon_max))
  121. {
  122. // in this case, and since p_lon is normalized in the range
  123. // (-180, 180], we must have that b_lon_max <= 180
  124. if (b_lon_min < 0
  125. && math::larger(p_lon - b_lon_max,
  126. constants::period() - p_lon + b_lon_min))
  127. {
  128. b_lon_min = p_lon;
  129. b_lon_max += constants::period();
  130. }
  131. else
  132. {
  133. b_lon_max = p_lon;
  134. }
  135. }
  136. geometry::set<min_corner, 0>(box, b_lon_min);
  137. geometry::set<min_corner, 1>(box, b_lat_min);
  138. geometry::set<max_corner, 0>(box, b_lon_max);
  139. geometry::set<max_corner, 1>(box, b_lat_max);
  140. }
  141. point_loop
  142. <
  143. 2, DimensionCount
  144. >::apply(box, point);
  145. }
  146. };
  147. } // namespace detail
  148. #endif // DOXYGEN_NO_DETAIL
  149. struct spherical_point
  150. {
  151. template <typename Box, typename Point>
  152. static void apply(Box & box, Point const& point)
  153. {
  154. expand::detail::point_loop_on_spheroid
  155. <
  156. dimension<Point>::value,
  157. ! std::is_same<typename cs_tag<Point>::type, spherical_polar_tag>::value
  158. >::apply(box, point);
  159. }
  160. };
  161. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  162. namespace services
  163. {
  164. template <typename CalculationType>
  165. struct default_strategy<point_tag, spherical_equatorial_tag, CalculationType>
  166. {
  167. typedef spherical_point type;
  168. };
  169. template <typename CalculationType>
  170. struct default_strategy<point_tag, spherical_polar_tag, CalculationType>
  171. {
  172. typedef spherical_point type;
  173. };
  174. template <typename CalculationType>
  175. struct default_strategy<point_tag, geographic_tag, CalculationType>
  176. {
  177. typedef spherical_point type;
  178. };
  179. } // namespace services
  180. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  181. }} // namespace strategy::expand
  182. }} // namespace boost::geometry
  183. #endif // BOOST_GEOMETRY_STRATEGY_SPHERICAL_EXPAND_POINT_HPP