File indexing completed on 2025-01-18 09:35:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_GEOMETRY_FORMULAS_SPHERICAL_HPP
0012 #define BOOST_GEOMETRY_FORMULAS_SPHERICAL_HPP
0013
0014 #include <boost/geometry/core/coordinate_system.hpp>
0015 #include <boost/geometry/core/coordinate_type.hpp>
0016 #include <boost/geometry/core/cs.hpp>
0017 #include <boost/geometry/core/access.hpp>
0018 #include <boost/geometry/core/radian_access.hpp>
0019 #include <boost/geometry/core/radius.hpp>
0020
0021
0022 #include <boost/geometry/arithmetic/cross_product.hpp>
0023 #include <boost/geometry/arithmetic/dot_product.hpp>
0024
0025 #include <boost/geometry/util/math.hpp>
0026 #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
0027 #include <boost/geometry/util/select_coordinate_type.hpp>
0028
0029 #include <boost/geometry/formulas/result_direct.hpp>
0030
0031 namespace boost { namespace geometry {
0032
0033 namespace formula {
0034
0035 template <typename T>
0036 struct result_spherical
0037 {
0038 result_spherical()
0039 : azimuth(0)
0040 , reverse_azimuth(0)
0041 {}
0042
0043 T azimuth;
0044 T reverse_azimuth;
0045 };
0046
0047 template <typename T>
0048 static inline void sph_to_cart3d(T const& lon, T const& lat, T & x, T & y, T & z)
0049 {
0050 T const cos_lat = cos(lat);
0051 x = cos_lat * cos(lon);
0052 y = cos_lat * sin(lon);
0053 z = sin(lat);
0054 }
0055
0056 template <typename Point3d, typename PointSph>
0057 static inline Point3d sph_to_cart3d(PointSph const& point_sph)
0058 {
0059 typedef typename coordinate_type<Point3d>::type calc_t;
0060
0061 calc_t const lon = get_as_radian<0>(point_sph);
0062 calc_t const lat = get_as_radian<1>(point_sph);
0063 calc_t x, y, z;
0064 sph_to_cart3d(lon, lat, x, y, z);
0065
0066 Point3d res;
0067 set<0>(res, x);
0068 set<1>(res, y);
0069 set<2>(res, z);
0070
0071 return res;
0072 }
0073
0074 template <typename T>
0075 static inline void cart3d_to_sph(T const& x, T const& y, T const& z, T & lon, T & lat)
0076 {
0077 lon = atan2(y, x);
0078 lat = asin(z);
0079 }
0080
0081 template <typename PointSph, typename Point3d>
0082 static inline PointSph cart3d_to_sph(Point3d const& point_3d)
0083 {
0084 typedef typename coordinate_type<PointSph>::type coord_t;
0085 typedef typename coordinate_type<Point3d>::type calc_t;
0086
0087 calc_t const x = get<0>(point_3d);
0088 calc_t const y = get<1>(point_3d);
0089 calc_t const z = get<2>(point_3d);
0090 calc_t lonr, latr;
0091 cart3d_to_sph(x, y, z, lonr, latr);
0092
0093 PointSph res;
0094 set_from_radian<0>(res, lonr);
0095 set_from_radian<1>(res, latr);
0096
0097 coord_t lon = get<0>(res);
0098 coord_t lat = get<1>(res);
0099
0100 math::normalize_spheroidal_coordinates
0101 <
0102 typename geometry::detail::cs_angular_units<PointSph>::type,
0103 coord_t
0104 >(lon, lat);
0105
0106 set<0>(res, lon);
0107 set<1>(res, lat);
0108
0109 return res;
0110 }
0111
0112
0113
0114
0115 template <typename Point3d1, typename Point3d2>
0116 static inline int sph_side_value(Point3d1 const& norm, Point3d2 const& pt)
0117 {
0118 typedef typename select_coordinate_type<Point3d1, Point3d2>::type calc_t;
0119 calc_t c0 = 0;
0120 calc_t d = dot_product(norm, pt);
0121 return math::equals(d, c0) ? 0
0122 : d > c0 ? 1
0123 : -1;
0124 }
0125
0126 template <typename CT, bool ReverseAzimuth, typename T1, typename T2>
0127 static inline result_spherical<CT> spherical_azimuth(T1 const& lon1,
0128 T1 const& lat1,
0129 T2 const& lon2,
0130 T2 const& lat2)
0131 {
0132 typedef result_spherical<CT> result_type;
0133 result_type result;
0134
0135
0136
0137 CT dlon = lon2 - lon1;
0138
0139
0140
0141
0142
0143
0144
0145
0146 CT const cos_dlon = cos(dlon);
0147 CT const sin_dlon = sin(dlon);
0148 CT const cos_lat1 = cos(lat1);
0149 CT const cos_lat2 = cos(lat2);
0150 CT const sin_lat1 = sin(lat1);
0151 CT const sin_lat2 = sin(lat2);
0152
0153 {
0154
0155
0156 CT const y = sin_dlon * cos_lat2;
0157 CT const x = cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon;
0158 result.azimuth = atan2(y, x);
0159 }
0160
0161 if (ReverseAzimuth)
0162 {
0163 CT const y = sin_dlon * cos_lat1;
0164 CT const x = sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1;
0165 result.reverse_azimuth = atan2(y, x);
0166 }
0167
0168 return result;
0169 }
0170
0171 template <typename ReturnType, typename T1, typename T2>
0172 inline ReturnType spherical_azimuth(T1 const& lon1, T1 const& lat1,
0173 T2 const& lon2, T2 const& lat2)
0174 {
0175 return spherical_azimuth<ReturnType, false>(lon1, lat1, lon2, lat2).azimuth;
0176 }
0177
0178 template <typename T>
0179 inline T spherical_azimuth(T const& lon1, T const& lat1, T const& lon2, T const& lat2)
0180 {
0181 return spherical_azimuth<T, false>(lon1, lat1, lon2, lat2).azimuth;
0182 }
0183
0184 template <typename T>
0185 inline int azimuth_side_value(T const& azi_a1_p, T const& azi_a1_a2)
0186 {
0187 T const c0 = 0;
0188 T const pi = math::pi<T>();
0189
0190
0191
0192
0193 T a_diff = azi_a1_p - azi_a1_a2;
0194
0195 math::detail::normalize_angle_loop<radian>(a_diff);
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214 return math::equals(a_diff, c0)
0215 || math::equals(a_diff, pi)
0216 || math::equals(a_diff, -pi) ? 0
0217 : a_diff > 0 ? -1
0218 : 1;
0219 }
0220
0221 template
0222 <
0223 bool Coordinates,
0224 bool ReverseAzimuth,
0225 typename CT,
0226 typename Sphere
0227 >
0228 inline result_direct<CT> spherical_direct(CT const& lon1,
0229 CT const& lat1,
0230 CT const& sig12,
0231 CT const& alp1,
0232 Sphere const& sphere)
0233 {
0234 result_direct<CT> result;
0235
0236 CT const sin_alp1 = sin(alp1);
0237 CT const sin_lat1 = sin(lat1);
0238 CT const cos_alp1 = cos(alp1);
0239 CT const cos_lat1 = cos(lat1);
0240
0241 CT const norm = math::sqrt(cos_alp1 * cos_alp1 + sin_alp1 * sin_alp1
0242 * sin_lat1 * sin_lat1);
0243 CT const alp0 = atan2(sin_alp1 * cos_lat1, norm);
0244 CT const sig1 = atan2(sin_lat1, cos_alp1 * cos_lat1);
0245 CT const sig2 = sig1 + sig12 / get_radius<0>(sphere);
0246
0247 CT const cos_sig2 = cos(sig2);
0248 CT const sin_alp0 = sin(alp0);
0249 CT const cos_alp0 = cos(alp0);
0250
0251 if (Coordinates)
0252 {
0253 CT const sin_sig2 = sin(sig2);
0254 CT const sin_sig1 = sin(sig1);
0255 CT const cos_sig1 = cos(sig1);
0256
0257 CT const norm2 = math::sqrt(cos_alp0 * cos_alp0 * cos_sig2 * cos_sig2
0258 + sin_alp0 * sin_alp0);
0259 CT const lat2 = atan2(cos_alp0 * sin_sig2, norm2);
0260
0261 CT const omg1 = atan2(sin_alp0 * sin_sig1, cos_sig1);
0262 CT const lon2 = atan2(sin_alp0 * sin_sig2, cos_sig2);
0263
0264 result.lon2 = lon1 + lon2 - omg1;
0265 result.lat2 = lat2;
0266
0267
0268
0269 math::detail::normalize_angle_cond<radian>(result.lon2);
0270 }
0271
0272 if (ReverseAzimuth)
0273 {
0274 CT const alp2 = atan2(sin_alp0, cos_alp0 * cos_sig2);
0275 result.reverse_azimuth = alp2;
0276 }
0277
0278 return result;
0279 }
0280
0281 }
0282
0283 }}
0284
0285 #endif