File indexing completed on 2025-10-31 08:39:52
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