123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- #ifndef BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
- #define BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
- #include <boost/math/constants/constants.hpp>
- #include <boost/math/special_functions/hypot.hpp>
- #include <boost/geometry/formulas/flattening.hpp>
- #include <boost/geometry/formulas/result_direct.hpp>
- #include <boost/geometry/util/constexpr.hpp>
- #include <boost/geometry/util/math.hpp>
- #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
- #include <boost/geometry/util/series_expansion.hpp>
- namespace boost { namespace geometry { namespace formula
- {
- namespace se = series_expansion;
- template <
- typename CT,
- bool EnableCoordinates = true,
- bool EnableReverseAzimuth = false,
- bool EnableReducedLength = false,
- bool EnableGeodesicScale = false,
- size_t SeriesOrder = 8
- >
- class karney_direct
- {
- static const bool CalcQuantities = EnableReducedLength || EnableGeodesicScale;
- static const bool CalcCoordinates = EnableCoordinates || CalcQuantities;
- static const bool CalcRevAzimuth = EnableReverseAzimuth || CalcCoordinates || CalcQuantities;
- public:
- typedef result_direct<CT> result_type;
- template <typename T, typename Dist, typename Azi, typename Spheroid>
- static inline result_type apply(T const& lo1,
- T const& la1,
- Dist const& distance,
- Azi const& azimuth12,
- Spheroid const& spheroid)
- {
- result_type result;
- CT lon1 = lo1 * math::r2d<CT>();
- CT const lat1 = la1 * math::r2d<CT>();
- Azi azi12 = azimuth12 * math::r2d<CT>();
- math::normalize_azimuth<degree, Azi>(azi12);
- CT const c0 = 0;
- CT const c1 = 1;
- CT const c2 = 2;
- CT const b = CT(get_radius<2>(spheroid));
- CT const f = formula::flattening<CT>(spheroid);
- CT const one_minus_f = c1 - f;
- CT const two_minus_f = c2 - f;
- CT const n = f / two_minus_f;
- CT const e2 = f * two_minus_f;
- CT const ep2 = e2 / math::sqr(one_minus_f);
- CT sin_alpha1, cos_alpha1;
- math::sin_cos_degrees<CT>(azi12, sin_alpha1, cos_alpha1);
-
- CT sin_beta1, cos_beta1;
- math::sin_cos_degrees<CT>(lat1, sin_beta1, cos_beta1);
- sin_beta1 *= one_minus_f;
- math::normalize_unit_vector<CT>(sin_beta1, cos_beta1);
- cos_beta1 = (std::max)(c0, cos_beta1);
-
- CT const sin_alpha0 = sin_alpha1 * cos_beta1;
- CT const cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);
- CT const k2 = math::sqr(cos_alpha0) * ep2;
- CT const epsilon = k2 / (c2 * (c1 + math::sqrt(c1 + k2)) + k2);
-
-
- CT const expansion_A1 = se::evaluate_A1<SeriesOrder>(epsilon);
-
- se::coeffs_C1<SeriesOrder, CT> const coeffs_C1(epsilon);
-
- CT const tau12 = distance / (b * (c1 + expansion_A1));
- CT const sin_tau12 = sin(tau12);
- CT const cos_tau12 = cos(tau12);
- CT sin_sigma1 = sin_beta1;
- CT sin_omega1 = sin_alpha0 * sin_beta1;
- CT cos_sigma1, cos_omega1;
- cos_sigma1 = cos_omega1 = sin_beta1 != c0 || cos_alpha1 != c0 ? cos_beta1 * cos_alpha1 : c1;
- math::normalize_unit_vector<CT>(sin_sigma1, cos_sigma1);
- CT const B11 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
- CT const sin_B11 = sin(B11);
- CT const cos_B11 = cos(B11);
- CT const sin_tau1 = sin_sigma1 * cos_B11 + cos_sigma1 * sin_B11;
- CT const cos_tau1 = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;
-
- se::coeffs_C1p<SeriesOrder, CT> const coeffs_C1p(epsilon);
- CT const B12 = - se::sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
- cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
- coeffs_C1p);
- CT const sigma12 = tau12 - (B12 - B11);
- CT const sin_sigma12 = sin(sigma12);
- CT const cos_sigma12 = cos(sigma12);
- CT const sin_sigma2 = sin_sigma1 * cos_sigma12 + cos_sigma1 * sin_sigma12;
- CT const cos_sigma2 = cos_sigma1 * cos_sigma12 - sin_sigma1 * sin_sigma12;
- if BOOST_GEOMETRY_CONSTEXPR (CalcRevAzimuth)
- {
- CT const sin_alpha2 = sin_alpha0;
- CT const cos_alpha2 = cos_alpha0 * cos_sigma2;
- result.reverse_azimuth = atan2(sin_alpha2, cos_alpha2);
- }
- if BOOST_GEOMETRY_CONSTEXPR (CalcCoordinates)
- {
-
- CT const sin_beta2 = cos_alpha0 * sin_sigma2;
- CT const cos_beta2 = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);
- result.lat2 = atan2(sin_beta2, one_minus_f * cos_beta2);
-
- CT const sin_omega2 = sin_alpha0 * sin_sigma2;
- CT const cos_omega2 = cos_sigma2;
- CT const omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
- cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);
- se::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);
- CT const A3 = math::horner_evaluate(epsilon, coeffs_A3.begin(), coeffs_A3.end());
- CT const A3c = -f * sin_alpha0 * A3;
- se::coeffs_C3<SeriesOrder, CT> const coeffs_C3(n, epsilon);
- CT const B31 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
- CT const sin_cos_res = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C3);
- CT const lam12 = omega12 + A3c * (sigma12 + (sin_cos_res - B31));
-
- CT lon12 = lam12 * math::r2d<CT>();
-
-
- math::normalize_longitude<degree, CT>(lon1);
- math::normalize_longitude<degree, CT>(lon12);
- result.lon2 = lon1 + lon12;
-
-
-
-
-
- math::normalize_longitude<degree, CT>(result.lon2);
- result.lon2 *= math::d2r<CT>();
- }
- if BOOST_GEOMETRY_CONSTEXPR (CalcQuantities)
- {
-
-
- se::coeffs_C2<SeriesOrder, CT> const coeffs_C2(epsilon);
- CT const B21 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
- CT const B22 = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);
-
-
- CT const expansion_A2 = se::evaluate_A2<SeriesOrder>(epsilon);
- CT const AB1 = (c1 + expansion_A1) * (B12 - B11);
- CT const AB2 = (c1 + expansion_A2) * (B22 - B21);
- CT const J12 = (expansion_A1 - expansion_A2) * sigma12 + (AB1 - AB2);
- CT const dn1 = math::sqrt(c1 + ep2 * math::sqr(sin_beta1));
- CT const dn2 = math::sqrt(c1 + k2 * math::sqr(sin_sigma2));
-
- result.reduced_length = b * ((dn2 * (cos_sigma1 * sin_sigma2) -
- dn1 * (sin_sigma1 * cos_sigma2)) -
- cos_sigma1 * cos_sigma2 * J12);
-
- CT const t = k2 * (sin_sigma2 - sin_sigma1) * (sin_sigma2 + sin_sigma1) / (dn1 + dn2);
- result.geodesic_scale = cos_sigma12 + (t * sin_sigma2 - cos_sigma2 * J12) *
- sin_sigma1 / dn1;
- }
- return result;
- }
- };
- }}}
- #endif
|