File indexing completed on 2025-09-18 08:44:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #ifndef BOOST_GEOMETRY_STRATEGY_SPHERICAL_EXPAND_POINT_HPP
0023 #define BOOST_GEOMETRY_STRATEGY_SPHERICAL_EXPAND_POINT_HPP
0024
0025 #include <algorithm>
0026 #include <cstddef>
0027 #include <functional>
0028 #include <type_traits>
0029
0030 #include <boost/geometry/core/access.hpp>
0031 #include <boost/geometry/core/coordinate_dimension.hpp>
0032 #include <boost/geometry/core/coordinate_system.hpp>
0033 #include <boost/geometry/core/coordinate_type.hpp>
0034 #include <boost/geometry/core/tags.hpp>
0035
0036 #include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp>
0037 #include <boost/geometry/util/math.hpp>
0038 #include <boost/geometry/util/select_coordinate_type.hpp>
0039
0040 #include <boost/geometry/algorithms/detail/normalize.hpp>
0041 #include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
0042
0043 #include <boost/geometry/strategy/expand.hpp>
0044 #include <boost/geometry/strategy/cartesian/expand_point.hpp>
0045
0046
0047 namespace boost { namespace geometry
0048 {
0049
0050 namespace strategy { namespace expand
0051 {
0052
0053 #ifndef DOXYGEN_NO_DETAIL
0054 namespace detail
0055 {
0056
0057
0058 template <std::size_t DimensionCount, bool IsEquatorial>
0059 struct point_loop_on_spheroid
0060 {
0061 template <typename Box, typename Point>
0062 static inline void apply(Box& box, Point const& point)
0063 {
0064 using box_point_type = point_type_t<Box>;
0065 using box_coordinate_type = coordinate_type_t<Box>;
0066 using units_type = typename geometry::detail::cs_angular_units<Box>::type;
0067 using constants = math::detail::constants_on_spheroid
0068 <
0069 box_coordinate_type,
0070 units_type
0071 >;
0072
0073
0074 Point p_normalized;
0075 strategy::normalize::spherical_point::apply(point, p_normalized);
0076
0077
0078 box_point_type box_point;
0079 geometry::detail::envelope::transform_units(p_normalized, box_point);
0080
0081 if (is_inverse_spheroidal_coordinates(box))
0082 {
0083 geometry::set_from_radian<min_corner, 0>(box, geometry::get_as_radian<0>(p_normalized));
0084 geometry::set_from_radian<min_corner, 1>(box, geometry::get_as_radian<1>(p_normalized));
0085 geometry::set_from_radian<max_corner, 0>(box, geometry::get_as_radian<0>(p_normalized));
0086 geometry::set_from_radian<max_corner, 1>(box, geometry::get_as_radian<1>(p_normalized));
0087
0088 } else {
0089
0090 strategy::normalize::spherical_box::apply(box, box);
0091
0092 box_coordinate_type p_lon = geometry::get<0>(box_point);
0093 box_coordinate_type p_lat = geometry::get<1>(box_point);
0094
0095 box_coordinate_type b_lon_min = geometry::get<min_corner, 0>(box);
0096 box_coordinate_type b_lat_min = geometry::get<min_corner, 1>(box);
0097 box_coordinate_type b_lon_max = geometry::get<max_corner, 0>(box);
0098 box_coordinate_type b_lat_max = geometry::get<max_corner, 1>(box);
0099
0100 if (math::is_latitude_pole<units_type, IsEquatorial>(p_lat))
0101 {
0102
0103
0104
0105
0106 geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
0107 geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
0108 return;
0109 }
0110
0111 if (math::equals(b_lat_min, b_lat_max)
0112 && math::is_latitude_pole<units_type, IsEquatorial>(b_lat_min))
0113 {
0114
0115
0116
0117
0118 geometry::set<min_corner, 0>(box, p_lon);
0119 geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
0120 geometry::set<max_corner, 0>(box, p_lon);
0121 geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
0122 return;
0123 }
0124
0125
0126 b_lat_min = (std::min)(b_lat_min, p_lat);
0127 b_lat_max = (std::max)(b_lat_max, p_lat);
0128
0129
0130 if (math::smaller(p_lon, b_lon_min))
0131 {
0132 box_coordinate_type p_lon_shifted = p_lon + constants::period();
0133
0134 if (math::larger(p_lon_shifted, b_lon_max))
0135 {
0136
0137 if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max))
0138 {
0139 b_lon_min = p_lon;
0140 }
0141 else
0142 {
0143 b_lon_max = p_lon_shifted;
0144 }
0145 }
0146 }
0147 else if (math::larger(p_lon, b_lon_max))
0148 {
0149
0150
0151 if (b_lon_min < 0
0152 && math::larger(p_lon - b_lon_max,
0153 constants::period() - p_lon + b_lon_min))
0154 {
0155 b_lon_min = p_lon;
0156 b_lon_max += constants::period();
0157 }
0158 else
0159 {
0160 b_lon_max = p_lon;
0161 }
0162 }
0163
0164 geometry::set<min_corner, 0>(box, b_lon_min);
0165 geometry::set<min_corner, 1>(box, b_lat_min);
0166 geometry::set<max_corner, 0>(box, b_lon_max);
0167 geometry::set<max_corner, 1>(box, b_lat_max);
0168 }
0169
0170 point_loop
0171 <
0172 2, DimensionCount
0173 >::apply(box, point);
0174 }
0175 };
0176
0177
0178 }
0179 #endif
0180
0181
0182 struct spherical_point
0183 {
0184 template <typename Box, typename Point>
0185 static void apply(Box & box, Point const& point)
0186 {
0187 expand::detail::point_loop_on_spheroid
0188 <
0189 dimension<Point>::value,
0190 ! std::is_same<cs_tag_t<Point>, spherical_polar_tag>::value
0191 >::apply(box, point);
0192 }
0193 };
0194
0195
0196 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
0197
0198 namespace services
0199 {
0200
0201 template <typename CalculationType>
0202 struct default_strategy<point_tag, spherical_equatorial_tag, CalculationType>
0203 {
0204 typedef spherical_point type;
0205 };
0206
0207 template <typename CalculationType>
0208 struct default_strategy<point_tag, spherical_polar_tag, CalculationType>
0209 {
0210 typedef spherical_point type;
0211 };
0212
0213 template <typename CalculationType>
0214 struct default_strategy<point_tag, geographic_tag, CalculationType>
0215 {
0216 typedef spherical_point type;
0217 };
0218
0219
0220 }
0221
0222 #endif
0223
0224
0225 }}
0226
0227 }}
0228
0229 #endif