expand_point.hpp 8.0 KB

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