File indexing completed on 2025-01-18 09:35:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_GEOMETRY_FORMULAS_MAXIMUM_LONGITUDE_HPP
0013 #define BOOST_GEOMETRY_FORMULAS_MAXIMUM_LONGITUDE_HPP
0014
0015
0016 #include <boost/geometry/core/static_assert.hpp>
0017 #include <boost/geometry/formulas/spherical.hpp>
0018 #include <boost/geometry/formulas/flattening.hpp>
0019
0020 #include <boost/math/special_functions/hypot.hpp>
0021
0022 namespace boost { namespace geometry { namespace formula
0023 {
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 template <typename CT>
0034 class vertex_longitude_on_sphere
0035 {
0036
0037 public:
0038
0039 template <typename T>
0040 static inline CT apply(T const& lat1,
0041 T const& lat2,
0042 T const& lat3,
0043 T const& sin_l12,
0044 T const& cos_l12)
0045 {
0046
0047 CT const A = sin(lat1) * cos(lat2) * cos(lat3) * sin_l12;
0048 CT const B = sin(lat1) * cos(lat2) * cos(lat3) * cos_l12
0049 - cos(lat1) * sin(lat2) * cos(lat3);
0050 CT lon = atan2(B, A);
0051 return lon + math::pi<CT>();
0052 }
0053 };
0054
0055 template <typename CT>
0056 class vertex_longitude_on_spheroid
0057 {
0058 template<typename T>
0059 static inline void normalize(T& x, T& y)
0060 {
0061 T h = boost::math::hypot(x, y);
0062 x /= h;
0063 y /= h;
0064 }
0065
0066 public:
0067
0068 template <typename T, typename Spheroid>
0069 static inline CT apply(T const& lat1,
0070 T const& lat2,
0071 T const& lat3,
0072 T& alp1,
0073 Spheroid const& spheroid)
0074 {
0075
0076
0077
0078
0079 CT const c0 = 0;
0080 CT const c2 = 2;
0081 CT const half_pi = math::pi<CT>() / c2;
0082 if (math::equals(lat1, half_pi)
0083 || math::equals(lat2, half_pi)
0084 || math::equals(lat1, -half_pi)
0085 || math::equals(lat2, -half_pi))
0086 {
0087
0088 return c0;
0089 }
0090
0091
0092 CT const f = flattening<CT>(spheroid);
0093 CT const pi = math::pi<CT>();
0094 CT const c1 = 1;
0095 CT const cminus1 = -1;
0096
0097
0098
0099 CT const one_minus_f = c1 - f;
0100 CT const bet1 = atan(one_minus_f * tan(lat1));
0101 CT const bet2 = atan(one_minus_f * tan(lat2));
0102 CT const bet3 = atan(one_minus_f * tan(lat3));
0103
0104 CT cos_bet1 = cos(bet1);
0105 CT cos_bet2 = cos(bet2);
0106 CT const sin_bet1 = sin(bet1);
0107 CT const sin_bet2 = sin(bet2);
0108 CT const sin_bet3 = sin(bet3);
0109
0110 CT omg12 = 0;
0111
0112 if (bet1 < c0)
0113 {
0114 cos_bet1 *= cminus1;
0115 omg12 += pi;
0116 }
0117 if (bet2 < c0)
0118 {
0119 cos_bet2 *= cminus1;
0120 omg12 += pi;
0121 }
0122
0123 CT const sin_alp1 = sin(alp1);
0124 CT const cos_alp1 = math::sqrt(c1 - math::sqr(sin_alp1));
0125
0126 CT const norm = math::sqrt(math::sqr(cos_alp1) + math::sqr(sin_alp1 * sin_bet1));
0127 CT const sin_alp0 = sin(atan2(sin_alp1 * cos_bet1, norm));
0128
0129 BOOST_ASSERT(cos_bet2 != c0);
0130 CT const sin_alp2 = sin_alp1 * cos_bet1 / cos_bet2;
0131
0132 CT const cos_alp0 = math::sqrt(c1 - math::sqr(sin_alp0));
0133 CT const cos_alp2 = math::sqrt(c1 - math::sqr(sin_alp2));
0134
0135 CT const sig1 = atan2(sin_bet1, cos_alp1 * cos_bet1);
0136 CT const sig2 = atan2(sin_bet2, -cos_alp2 * cos_bet2);
0137
0138 CT const cos_sig1 = cos(sig1);
0139 CT const sin_sig1 = math::sqrt(c1 - math::sqr(cos_sig1));
0140
0141 CT const cos_sig2 = cos(sig2);
0142 CT const sin_sig2 = math::sqrt(c1 - math::sqr(cos_sig2));
0143
0144 CT const omg1 = atan2(sin_alp0 * sin_sig1, cos_sig1);
0145 CT const omg2 = atan2(sin_alp0 * sin_sig2, cos_sig2);
0146
0147 omg12 += omg1 - omg2;
0148
0149 CT const sin_omg12 = sin(omg12);
0150 CT const cos_omg12 = cos(omg12);
0151
0152 CT omg13 = geometry::formula::vertex_longitude_on_sphere<CT>
0153 ::apply(bet1, bet2, bet3, sin_omg12, cos_omg12);
0154
0155 if (lat1 * lat2 < c0)
0156 {
0157 if ((lat2 - lat1) * lat3 > c0)
0158 {
0159 omg13 = pi - omg13;
0160 }
0161 }
0162
0163
0164
0165 CT const e2 = f * (c2 - f);
0166 CT const ep = math::sqrt(e2 / (c1 - e2));
0167 CT const k2 = math::sqr(ep * cos_alp0);
0168 CT const sqrt_k2_plus_one = math::sqrt(c1 + k2);
0169 CT const eps = (sqrt_k2_plus_one - c1) / (sqrt_k2_plus_one + c1);
0170 CT const eps2 = eps * eps;
0171 CT const n = f / (c2 - f);
0172
0173
0174 CT sig3;
0175 if(sin_bet3 > c0)
0176 {
0177 sig3 = half_pi;
0178 } else {
0179 sig3 = -half_pi;
0180 }
0181 CT const cos_sig3 = 0;
0182 CT const sin_sig3 = 1;
0183
0184 CT sig13 = sig3 - sig1;
0185 if (sig13 > pi)
0186 {
0187 sig13 -= 2 * pi;
0188 }
0189
0190
0191 CT const c1over2 = 0.5;
0192 CT const c1over4 = 0.25;
0193 CT const c1over8 = 0.125;
0194 CT const c1over16 = 0.0625;
0195 CT const c4 = 4;
0196 CT const c8 = 8;
0197
0198 CT const A3 = 1 - (c1over2 - c1over2 * n) * eps - c1over4 * eps2;
0199 CT const C31 = (c1over4 - c1over4 * n) * eps + c1over8 * eps2;
0200 CT const C32 = c1over16 * eps2;
0201
0202 CT const sin2_sig3 = c2 * cos_sig3 * sin_sig3;
0203 CT const sin4_sig3 = sin_sig3 * (-c4 * cos_sig3
0204 + c8 * cos_sig3 * cos_sig3 * cos_sig3);
0205 CT const sin2_sig1 = c2 * cos_sig1 * sin_sig1;
0206 CT const sin4_sig1 = sin_sig1 * (-c4 * cos_sig1
0207 + c8 * cos_sig1 * cos_sig1 * cos_sig1);
0208 CT const I3 = A3 * (sig13
0209 + C31 * (sin2_sig3 - sin2_sig1)
0210 + C32 * (sin4_sig3 - sin4_sig1));
0211
0212 CT const sign = bet3 >= c0
0213 ? c1
0214 : cminus1;
0215
0216 CT const dlon_max = omg13 - sign * f * sin_alp0 * I3;
0217
0218 return dlon_max;
0219 }
0220 };
0221
0222
0223
0224 template <typename CT, typename CS_Tag>
0225 struct compute_vertex_lon
0226 {
0227 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
0228 "Not implemented for this coordinate system.",
0229 CT, CS_Tag);
0230 };
0231
0232 template <typename CT>
0233 struct compute_vertex_lon<CT, spherical_equatorial_tag>
0234 {
0235 template <typename Strategy>
0236 static inline CT apply(CT const& lat1,
0237 CT const& lat2,
0238 CT const& vertex_lat,
0239 CT const& sin_l12,
0240 CT const& cos_l12,
0241 CT,
0242 Strategy)
0243 {
0244 return vertex_longitude_on_sphere<CT>
0245 ::apply(lat1,
0246 lat2,
0247 vertex_lat,
0248 sin_l12,
0249 cos_l12);
0250 }
0251 };
0252
0253 template <typename CT>
0254 struct compute_vertex_lon<CT, geographic_tag>
0255 {
0256 template <typename Strategy>
0257 static inline CT apply(CT const& lat1,
0258 CT const& lat2,
0259 CT const& vertex_lat,
0260 CT,
0261 CT,
0262 CT& alp1,
0263 Strategy const& azimuth_strategy)
0264 {
0265 return vertex_longitude_on_spheroid<CT>
0266 ::apply(lat1,
0267 lat2,
0268 vertex_lat,
0269 alp1,
0270 azimuth_strategy.model());
0271 }
0272 };
0273
0274
0275
0276
0277 template <typename CT, typename CS_Tag>
0278 class vertex_longitude
0279 {
0280 public :
0281 template <typename Strategy>
0282 static inline CT apply(CT& lon1,
0283 CT& lat1,
0284 CT& lon2,
0285 CT& lat2,
0286 CT const& vertex_lat,
0287 CT& alp1,
0288 Strategy const& azimuth_strategy)
0289 {
0290 CT const c0 = 0;
0291 CT pi = math::pi<CT>();
0292
0293
0294 if (math::equals(vertex_lat, lat1))
0295 {
0296 return lon1;
0297 }
0298 if (math::equals(vertex_lat, lat2))
0299 {
0300 return lon2;
0301 }
0302
0303
0304 if (math::equals(lon1, lon2))
0305 {
0306 return (std::max)(lat1, lat2);
0307 }
0308 BOOST_ASSERT(lon1 < lon2);
0309
0310 CT dlon = compute_vertex_lon<CT, CS_Tag>::apply(lat1, lat2,
0311 vertex_lat,
0312 sin(lon1 - lon2),
0313 cos(lon1 - lon2),
0314 alp1,
0315 azimuth_strategy);
0316
0317 CT vertex_lon = std::fmod(lon1 + dlon, 2 * pi);
0318
0319 if (vertex_lat < c0)
0320 {
0321 vertex_lon -= pi;
0322 }
0323
0324 if (std::abs(lon1 - lon2) > pi)
0325 {
0326 vertex_lon -= pi;
0327 }
0328
0329 return vertex_lon;
0330 }
0331 };
0332
0333 template <typename CT>
0334 class vertex_longitude<CT, cartesian_tag>
0335 {
0336 public :
0337 template <typename Strategy>
0338 static inline CT apply(CT& ,
0339 CT& ,
0340 CT& lon2,
0341 CT& ,
0342 CT const& ,
0343 CT& ,
0344 Strategy const& )
0345 {
0346 return lon2;
0347 }
0348 };
0349
0350 }}}
0351 #endif
0352