/home/adeel

Google Summer of Code 2018 final evaluation report

Link to GitHub repository: https://github.com/BoostGSoC18/geometry

The work is present under the following branches:

Summary

The goal of this project was to implement the direct and inverse geodesic algorithms in the Boost Geometry library. These methods were proposed by Charles Karney in his paper in 2011.

In a previous blog post, the inaccuracy of the existing methods was discussed, which provided inconsistent results for nearly antipodal points. To monitor the progress, a weekly report was provided through GitHub, which summarized the work done. Finally, benchmarks were performed against existing methods in Boost Geometry. The performance metric used was execution time and accuracy.

Additional material, such as utility scripts for parsing the test data is present at: https://github.com/adl1995/boost-geometry-extra

The programming competency task for this project is present at: https://github.com/adl1995/geolib

List of pull requests

List of commits

List of commit diffs

commit 5718b62405773a7b901dc30e06d734a9481761dc
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jul 26 16:27:59 2018 +0500

    [example] Add example on distance formula

    The formula used is Karney's direct method.

diff --git a/example/ml03_distance_formula.cpp b/example/ml03_distance_formula.cpp
new file mode 100644
index 0000000..6ddd9fc
--- /dev/null
+++ b/example/ml03_distance_formula.cpp
@@ -0,0 +1,37 @@
+// Boost.Geometry
+
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Formula example - Show how to use Karney's direct method.
+
+#include <boost/geometry.hpp>
+#include <boost/geometry/formulas/karney_direct.hpp>
+
+using namespace boost::geometry;
+
+int main()
+{
+    double lon1_deg = 0.;
+    double lat1_deg = 73.114273316483;
+    double distance_m = 19992866.6147806;
+    double azi12_deg = 78.154765899661;
+
+    // Create an alias of the formula.
+    typedef formula::karney_direct<double, true, true, true, true, 8> karney_direct;
+
+    // Structure to hold the resulting values.
+    formula::result_direct<double> result;
+
+    // WGS-84 spheroid.
+    srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);
+
+    result = karney_direct::apply(lon1_deg, lat1_deg, distance_m, azi12_deg, spheroid);
+
+    return 0;
+}

commit 1bfeba16aa7c7e3db6a753ecf74a299244ab7014
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jul 20 13:52:20 2018 +0500

    [strategies] Add distance strategy for Karney's inverse formula

diff --git a/include/boost/geometry/strategies/geographic/distance_karney.hpp b/include/boost/geometry/strategies/geographic/distance_karney.hpp
new file mode 100644
index 0000000..2391496
--- /dev/null
+++ b/include/boost/geometry/strategies/geographic/distance_karney.hpp
@@ -0,0 +1,116 @@
+// Boost.Geometry
+
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_KARNEY_HPP
+#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_KARNEY_HPP
+
+
+#include <boost/geometry/strategies/geographic/distance.hpp>
+#include <boost/geometry/strategies/geographic/parameters.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace distance
+{
+
+/*!
+\brief The solution of the inverse problem of geodesics on latlong coordinates,
+       after Karney (2011).
+\ingroup distance
+\tparam Spheroid The reference spheroid model
+\tparam CalculationType \tparam_calculation
+\author See
+- Charles F.F Karney, Algorithms for geodesics, 2011
+https://arxiv.org/pdf/1109.4448.pdf
+*/
+template
+<
+    typename Spheroid = srs::spheroid<double>,
+    typename CalculationType = void
+>
+class karney
+    : public strategy::distance::geographic
+        <
+            strategy::karney, Spheroid, CalculationType
+        >
+{
+    typedef strategy::distance::geographic
+        <
+            strategy::karney, Spheroid, CalculationType
+        > base_type;
+
+public:
+    inline karney()
+        : base_type()
+    {}
+
+    explicit inline karney(Spheroid const& spheroid)
+        : base_type(spheroid)
+    {}
+};
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+template <typename Spheroid, typename CalculationType>
+struct tag<karney<Spheroid, CalculationType> >
+{
+    typedef strategy_tag_distance_point_point type;
+};
+
+
+template <typename Spheroid, typename CalculationType, typename P1, typename P2>
+struct return_type<karney<Spheroid, CalculationType>, P1, P2>
+    : karney<Spheroid, CalculationType>::template calculation_type<P1, P2>
+{};
+
+
+template <typename Spheroid, typename CalculationType>
+struct comparable_type<karney<Spheroid, CalculationType> >
+{
+    typedef karney<Spheroid, CalculationType> type;
+};
+
+
+template <typename Spheroid, typename CalculationType>
+struct get_comparable<karney<Spheroid, CalculationType> >
+{
+    static inline karney<Spheroid, CalculationType> apply(karney<Spheroid, CalculationType> const& input)
+    {
+        return input;
+    }
+};
+
+template <typename Spheroid, typename CalculationType, typename P1, typename P2>
+struct result_from_distance<karney<Spheroid, CalculationType>, P1, P2 >
+{
+    template <typename T>
+    static inline typename return_type<karney<Spheroid, CalculationType>, P1, P2>::type
+        apply(karney<Spheroid, CalculationType> const& , T const& value)
+    {
+        return value;
+    }
+};
+
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+}} // namespace strategy::distance
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_KARNEY_HPP
diff --git a/include/boost/geometry/strategies/geographic/parameters.hpp b/include/boost/geometry/strategies/geographic/parameters.hpp
index 92ebe08..7c82902 100644
--- a/include/boost/geometry/strategies/geographic/parameters.hpp
+++ b/include/boost/geometry/strategies/geographic/parameters.hpp
@@ -15,6 +15,8 @@
 #include <boost/geometry/formulas/thomas_inverse.hpp>
 #include <boost/geometry/formulas/vincenty_direct.hpp>
 #include <boost/geometry/formulas/vincenty_inverse.hpp>
+#include <boost/geometry/formulas/karney_direct.hpp>
+#include <boost/geometry/formulas/karney_inverse.hpp>

 #include <boost/mpl/assert.hpp>
 #include <boost/mpl/integral_c.hpp>
@@ -136,6 +138,46 @@ struct vincenty
     {};
 };

+struct karney
+{
+    template
+    <
+        typename CT,
+        bool EnableCoordinates = true,
+        bool EnableReverseAzimuth = false,
+        bool EnableReducedLength = false,
+        bool EnableGeodesicScale = false,
+        size_t SeriesOrder = 8
+    >
+    struct direct
+            : formula::karney_direct
+              <
+                  CT, EnableCoordinates, EnableReverseAzimuth,
+                  EnableReducedLength, EnableGeodesicScale,
+                  SeriesOrder
+              >
+    {};
+
+    template
+    <
+        typename CT,
+        bool EnableDistance,
+        bool EnableAzimuth,
+        bool EnableReverseAzimuth = false,
+        bool EnableReducedLength = false,
+        bool EnableGeodesicScale = false,
+        size_t SeriesOrder = 8
+    >
+    struct inverse
+        : formula::karney_inverse
+            <
+                CT, EnableDistance,
+                EnableAzimuth, EnableReverseAzimuth,
+                EnableReducedLength, EnableGeodesicScale,
+                SeriesOrder
+            >
+    {};
+};

 template <typename FormulaPolicy>
 struct default_order
@@ -162,6 +204,11 @@ struct default_order<vincenty>
     : boost::mpl::integral_c<unsigned int, 4>
 {};

+template<>
+struct default_order<karney>
+    : boost::mpl::integral_c<unsigned int, 8>
+{};
+
 }}} // namespace boost::geometry::strategy


diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp
index 7d6cb61..11019bd 100644
--- a/include/boost/geometry/strategies/strategies.hpp
+++ b/include/boost/geometry/strategies/strategies.hpp
@@ -96,6 +96,7 @@
 #include <boost/geometry/strategies/geographic/distance_cross_track_point_box.hpp>
 #include <boost/geometry/strategies/geographic/distance_thomas.hpp>
 #include <boost/geometry/strategies/geographic/distance_vincenty.hpp>
+#include <boost/geometry/strategies/geographic/distance_karney.hpp>
 #include <boost/geometry/strategies/geographic/envelope_segment.hpp>
 #include <boost/geometry/strategies/geographic/intersection.hpp>
 //#include <boost/geometry/strategies/geographic/intersection_elliptic.hpp>

commit 2ff18246838d2b6a4fe2db549f26581ec3e5cb6b
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jul 16 19:06:20 2018 +0500

    [formulas][test] Update copyright information

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 28cdae7..01fea66 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -1,11 +1,26 @@
 // Boost.Geometry

-// Contributed and/or modified by Adeel Ahmad.
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt)

+// This file is converted from GeographicLib, https://geographiclib.sourceforge.io
+// GeographicLib is originally written by Charles Karney.
+
+// Author: Charles Karney (2008-2017)
+
+// Last updated version of GeographicLib: 1.49
+
+// Original copyright notice:
+
+// Copyright (c) Charles Karney (2008-2017) <charles@karney.com> and licensed
+// under the MIT/X11 License. For more information, see
+// https://geographiclib.sourceforge.io
+
 #ifndef BOOST_GEOMETRY_FORMULAS_KARNEY_INVERSE_HPP
 #define BOOST_GEOMETRY_FORMULAS_KARNEY_INVERSE_HPP

diff --git a/test/formulas/inverse.cpp b/test/formulas/inverse.cpp
index 07c0fbc..d9617b5 100644
--- a/test/formulas/inverse.cpp
+++ b/test/formulas/inverse.cpp
@@ -4,7 +4,7 @@
 // Copyright (c) 2016-2017 Oracle and/or its affiliates.

 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at

commit b44e3aed599061be89f8b314446fe02b9345fb2f
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jul 13 12:15:35 2018 +0500

    [formulas] Remove unused variable a12 in karney_inverse

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 8c509af..28cdae7 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -196,7 +196,7 @@ public:
         CT const dn1 = sqrt(c1 + ep2 * math::sqr(sin_beta1));
         CT const dn2 = sqrt(c1 + ep2 * math::sqr(sin_beta2));

-        CT a12, sigma12;
+        CT sigma12;
         CT m12x, s12x, M21;

         // Index zero element of coeffs_C1 is unused.
@@ -244,7 +244,6 @@ public:

                 m12x *= b;
                 s12x *= b;
-                a12 = sigma12 / math::d2r<CT>();
             }
             else
             {
@@ -270,7 +269,6 @@ public:
             {
                 result.geodesic_scale = cos(sigma12);
             }
-            a12 = lon12 / one_minus_f;
         }
         else if (!meridian)
         {
@@ -299,7 +297,6 @@ public:
                 }

                 // Convert to radians.
-                a12 = sigma12 / math::d2r<CT>();
                 omega12 = lam12 / (one_minus_f * dnm);
             }
             else
@@ -403,7 +400,6 @@ public:

                 m12x *= b;
                 s12x *= b;
-                a12 = sigma12 / math::d2r<CT>();
             }
         }


commit 55c1691ddc0852613bc37bedc935be308913e3f7
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jul 13 12:08:00 2018 +0500

    [formulas] Fix incorrect argument to meridian_length() function

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index ae0a368..8c509af 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -235,7 +235,6 @@ public:
                                              m12x, dummy, result.geodesic_scale,
                                              M21, coeffs_C1);

-
             if (sigma12 < c1 || m12x >= c0)
             {
                 if (sigma12 < c3 * tiny)
@@ -254,7 +253,7 @@ public:
             }
         }

-        CT omega12, sin_omega12, cos_omega12;
+        CT omega12;

         if (!meridian && sin_beta1 == c0 &&
             (f <= c0 || lon12_error >= f * c180))
@@ -273,7 +272,6 @@ public:
             }
             a12 = lon12 / one_minus_f;
         }
-
         else if (!meridian)
         {
             // If point1 and point2 belong within a hemisphere bounded by a
@@ -352,6 +350,7 @@ public:
                         sin_alpha1a = sin_alpha1;
                         cos_alpha1a = cos_alpha1;
                     }
+
                     if (iteration < max_iterations && dv > c0)
                     {
                         CT diff_alpha1 = -v / dv;
@@ -390,17 +389,17 @@ public:
                     tripn = false;
                     tripb = (std::abs(sin_alpha1a - sin_alpha1) + (cos_alpha1a - cos_alpha1) < tol_bisection ||
                              std::abs(sin_alpha1 - sin_alpha1b) + (cos_alpha1 - cos_alpha1b) < tol_bisection);
-
                 }

                 CT dummy;
+                se::coeffs_C1<SeriesOrder, CT> const coeffs_C1_eps(eps);
                 // Ensure that the reduced length and geodesic scale are computed in
                 // a "canonical" way, with the I2 integral.
-                meridian_length(n, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
-                                                 sin_sigma2, cos_sigma2, dn2,
-                                                 cos_beta1, cos_beta2, s12x,
-                                                 m12x, dummy, result.geodesic_scale,
-                                                 M21, coeffs_C1);
+                meridian_length(eps, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
+                                                   sin_sigma2, cos_sigma2, dn2,
+                                                   cos_beta1, cos_beta2, s12x,
+                                                   m12x, dummy, result.geodesic_scale,
+                                                   M21, coeffs_C1_eps);

                 m12x *= b;
                 s12x *= b;
@@ -874,11 +873,11 @@ public:
             else
             {
                 CT dummy;
-                meridian_length(n, eps, sigma12, sin_sigma1, cos_sigma1, dn1,
-                                                 sin_sigma2, cos_sigma2, dn2,
-                                                 cos_beta1, cos_beta2, dummy,
-                                                 diff_lam12, dummy, dummy,
-                                                 dummy, coeffs_C1);
+                meridian_length(eps, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
+                                                   sin_sigma2, cos_sigma2, dn2,
+                                                   cos_beta1, cos_beta2, dummy,
+                                                   diff_lam12, dummy, dummy,
+                                                   dummy, coeffs_C1);

                 diff_lam12 *= one_minus_f / (cos_alpha2 * cos_beta2);
             }

commit daf03b488898f4aca65379e8982833f9c8cf1ba3
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jul 10 11:52:20 2018 +0500

    [formulas] Use namespace alias se for series_expansion in karney_inverse

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 6b6a3b5..ae0a368 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -24,6 +24,7 @@
 namespace boost { namespace geometry { namespace formula
 {

+namespace se = series_expansion;

 /*!
 \brief The solution of the inverse problem of geodesics on latlong coordinates,
@@ -199,7 +200,7 @@ public:
         CT m12x, s12x, M21;

         // Index zero element of coeffs_C1 is unused.
-        series_expansion::coeffs_C1<SeriesOrder, CT> const coeffs_C1(n);
+        se::coeffs_C1<SeriesOrder, CT> const coeffs_C1(n);

         bool meridian = lat1 == -90 || sin_lam12 == 0;

@@ -459,7 +460,7 @@ public:
         CT expansion_A1, expansion_A2;

         // Evaluate the coefficients for C2.
-        series_expansion::coeffs_C2<SeriesOrder, CT> coeffs_C2(epsilon);
+        se::coeffs_C2<SeriesOrder, CT> coeffs_C2(epsilon);

         if (BOOST_GEOMETRY_CONDITION(EnableDistance) ||
             BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
@@ -467,14 +468,14 @@ public:
         {
             // Find the coefficients for A1 by computing the
             // series expansion using Horner scehme.
-            expansion_A1 = series_expansion::evaluate_A1<SeriesOrder>(epsilon);
+            expansion_A1 = se::evaluate_A1<SeriesOrder>(epsilon);

             if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
                 BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
             {
                 // Find the coefficients for A2 by computing the
                 // series expansion using Horner scehme.
-                expansion_A2 = series_expansion::evaluate_A2<SeriesOrder>(epsilon);
+                expansion_A2 = se::evaluate_A2<SeriesOrder>(epsilon);

                 A12x = expansion_A1 - expansion_A2;
                 expansion_A2 += c1;
@@ -484,16 +485,16 @@ public:

         if (BOOST_GEOMETRY_CONDITION(EnableDistance))
         {
-            CT B1 = series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C1)
-                  - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
+            CT B1 = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C1)
+                  - se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);

             s12x = expansion_A1 * (sigma12 + B1);

             if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
                 BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
             {
-                CT B2 = series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2)
-                      - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
+                CT B2 = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2)
+                      - se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);

                 J12 = A12x * sigma12 + (expansion_A1 * B1 - expansion_A2 * B2);
             }
@@ -508,8 +509,8 @@ public:
             }

             J12 = A12x * sigma12 +
-                   (series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2)
-                  - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2));
+                   (se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2)
+                  - se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2));
         }

         if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
@@ -627,7 +628,7 @@ public:
                 CT k2 = math::sqr(sin_beta1) * ep2;
                 CT eps = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);

-                series_expansion::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);
+                se::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);

                 CT const A3 = math::horner_evaluate(eps, coeffs_A3.begin(), coeffs_A3.end());

@@ -852,12 +853,12 @@ public:

         eps = k2 / (c2 * (c1 + std::sqrt(c1 + k2)) + k2);

-        series_expansion::coeffs_C3<SeriesOrder, CT> const coeffs_C3(n, eps);
+        se::coeffs_C3<SeriesOrder, CT> const coeffs_C3(n, eps);

-        B312 = series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C3)
-             - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
+        B312 = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C3)
+             - se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);

-        series_expansion::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);
+        se::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);

         CT const A3 = math::horner_evaluate(eps, coeffs_A3.begin(), coeffs_A3.end());


commit 6432dfe96c0141dca0c619dba130c94cd6dc9304
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jul 10 11:36:33 2018 +0500

    [formulas][util] Reformat code in karney_inverse to use coefficient containers

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 691c111..6b6a3b5 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -161,14 +161,14 @@ public:
         math::sin_cos_degrees(lat1, sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

-        math::normalize_values<CT>(sin_beta1, cos_beta1);
+        math::normalize_unit_vector<CT>(sin_beta1, cos_beta1);
         cos_beta1 = std::max(tiny, cos_beta1);

         CT sin_beta2, cos_beta2;
         math::sin_cos_degrees(lat2, sin_beta2, cos_beta2);
         sin_beta2 *= one_minus_f;

-        math::normalize_values<CT>(sin_beta2, cos_beta2);
+        math::normalize_unit_vector<CT>(sin_beta2, cos_beta2);
         cos_beta2 = std::max(tiny, cos_beta2);

         // If cos_beta1 < -sin_beta1, then cos_beta2 - cos_beta1 is a
@@ -181,8 +181,7 @@ public:
         {
             if (cos_beta1 == cos_beta2)
             {
-                sin_beta2 = sin_beta2 < 0 ? sin_beta1 :
-                                            -sin_beta1;
+                sin_beta2 = sin_beta2 < 0 ? sin_beta1 : -sin_beta1;
             }
         }
         else
@@ -200,7 +199,7 @@ public:
         CT m12x, s12x, M21;

         // Index zero element of coeffs_C1 is unused.
-        CT coeffs_C1[SeriesOrder + 1];
+        series_expansion::coeffs_C1<SeriesOrder, CT> const coeffs_C1(n);

         bool meridian = lat1 == -90 || sin_lam12 == 0;

@@ -292,7 +291,7 @@ public:

             if (sigma12 >= c0)
             {
-                // Short lines case (newton_start sets sin_alpha2, cos_alpha2, dnm)
+                // Short lines case (newton_start sets sin_alpha2, cos_alpha2, dnm).
                 s12x = sigma12 * b * dnm;
                 m12x = math::sqr(dnm) * b * sin(sigma12 / dnm);
                 if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
@@ -366,7 +365,7 @@ public:
                         {
                             cos_alpha1 = cos_alpha1 * cos_diff_alpha1 - sin_alpha1 * sin_diff_alpha1;
                             sin_alpha1 = nsin_alpha1;
-                            math::normalize_values<CT>(sin_alpha1, cos_alpha1);
+                            math::normalize_unit_vector<CT>(sin_alpha1, cos_alpha1);

                             // In some regimes we don't get quadratic convergence because
                             // slope -> 0. So use convergence conditions based on epsilon
@@ -386,7 +385,7 @@ public:
                     // WGS84 and random input: mean = 4.74, sd = 0.99
                     sin_alpha1 = (sin_alpha1a + sin_alpha1b) / c2;
                     cos_alpha1 = (cos_alpha1a + cos_alpha1b) / c2;
-                    math::normalize_values<CT>(sin_alpha1, cos_alpha1);
+                    math::normalize_unit_vector<CT>(sin_alpha1, cos_alpha1);
                     tripn = false;
                     tripb = (std::abs(sin_alpha1a - sin_alpha1) + (cos_alpha1a - cos_alpha1) < tol_bisection ||
                              std::abs(sin_alpha1 - sin_alpha1b) + (cos_alpha1 - cos_alpha1b) < tol_bisection);
@@ -447,18 +446,20 @@ public:
         return result;
     }

+    template <typename CoeffsC1>
     static inline void meridian_length(CT epsilon, CT ep2, CT sigma12,
                                        CT sin_sigma1, CT cos_sigma1, CT dn1,
                                        CT sin_sigma2, CT cos_sigma2, CT dn2,
                                        CT cos_beta1, CT cos_beta2,
                                        CT& s12x, CT& m12x, CT& m0,
-                                       CT& M12, CT& M21, CT coeffs_C1[])
+                                       CT& M12, CT& M21,
+                                       CoeffsC1 coeffs_C1)
     {
         CT A12x = 0, J12 = 0;
         CT expansion_A1, expansion_A2;

-        // Index zero element of coeffs_C2 is unused.
-        CT coeffs_C2[SeriesOrder + 1];
+        // Evaluate the coefficients for C2.
+        series_expansion::coeffs_C2<SeriesOrder, CT> coeffs_C2(epsilon);

         if (BOOST_GEOMETRY_CONDITION(EnableDistance) ||
             BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
@@ -466,20 +467,14 @@ public:
         {
             // Find the coefficients for A1 by computing the
             // series expansion using Horner scehme.
-            expansion_A1 = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);
-
-            // Evaluate the coefficients for C1.
-            series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);
+            expansion_A1 = series_expansion::evaluate_A1<SeriesOrder>(epsilon);

             if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
                 BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
             {
                 // Find the coefficients for A2 by computing the
                 // series expansion using Horner scehme.
-                expansion_A2 = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);
-
-                // Evaluate the coefficients for C2.
-                series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);
+                expansion_A2 = series_expansion::evaluate_A2<SeriesOrder>(epsilon);

                 A12x = expansion_A1 - expansion_A2;
                 expansion_A2 += c1;
@@ -489,23 +484,18 @@ public:

         if (BOOST_GEOMETRY_CONDITION(EnableDistance))
         {
-            CT B1 = series_expansion::sin_cos_series<CT, SeriesOrder>
-                                      (sin_sigma2, cos_sigma2, coeffs_C1)
-                  - series_expansion::sin_cos_series<CT, SeriesOrder>
-                                      (sin_sigma1, cos_sigma1, coeffs_C1);
+            CT B1 = series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C1)
+                  - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);

             s12x = expansion_A1 * (sigma12 + B1);

             if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
                 BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
             {
-                CT B2 = series_expansion::sin_cos_series<CT, SeriesOrder>
-                                          (sin_sigma2, cos_sigma2, coeffs_C2)
-                      - series_expansion::sin_cos_series<CT, SeriesOrder>
-                                          (sin_sigma1, cos_sigma1, coeffs_C2);
+                CT B2 = series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2)
+                      - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);

-                J12 = A12x * sigma12 + (expansion_A1 * B1 -
-                                        expansion_A2 * B2);
+                J12 = A12x * sigma12 + (expansion_A1 * B1 - expansion_A2 * B2);
             }
         }
         else if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
@@ -518,14 +508,8 @@ public:
             }

             J12 = A12x * sigma12 +
-                   (series_expansion::sin_cos_series<CT, SeriesOrder>
-                                      (sin_sigma2,
-                                       cos_sigma2,
-                                       coeffs_C2)
-                  - series_expansion::sin_cos_series<CT, SeriesOrder>
-                                      (sin_sigma1,
-                                       cos_sigma1,
-                                       coeffs_C2));
+                   (series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2)
+                  - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2));
         }

         if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
@@ -554,12 +538,13 @@ public:
      doesn't need to be used, return also sin_alpha2 and
      cos_alpha2 and function value is sig12.
     */
+    template <typename CoeffsC1>
     static inline CT newton_start(CT sin_beta1, CT cos_beta1, CT dn1,
                                   CT sin_beta2, CT cos_beta2, CT dn2,
                                   CT lam12, CT sin_lam12, CT cos_lam12,
                                   CT& sin_alpha1, CT& cos_alpha1,
                                   CT& sin_alpha2, CT& cos_alpha2,
-                                  CT& dnm, CT coeffs_C1[], CT ep2,
+                                  CT& dnm, CoeffsC1 coeffs_C1, CT ep2,
                                   CT tol1, CT tol2, CT etol2, CT n, CT f)
     {
         CT const one_minus_f = c1 - f;
@@ -615,7 +600,7 @@ public:
                 (cos_omega12 >= c0 ? math::sqr(sin_omega12) /
                 (c1 + cos_omega12) : c1 - cos_omega12);

-            math::normalize_values<CT>(sin_alpha2, cos_alpha2);
+            math::normalize_unit_vector<CT>(sin_alpha2, cos_alpha2);
             // Set return value.
             sig12 = atan2(sin_sigma12, cos_sigma12);
         }
@@ -642,10 +627,9 @@ public:
                 CT k2 = math::sqr(sin_beta1) * ep2;
                 CT eps = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);

-                CT coeffs_A3[SeriesOrder];
-                series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
+                series_expansion::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);

-                CT const A3 = math::horner_evaluate(eps, coeffs_A3, coeffs_A3 + SeriesOrder);
+                CT const A3 = math::horner_evaluate(eps, coeffs_A3.begin(), coeffs_A3.end());

                 lambda_scale = f * cos_beta1 * A3 * math::pi<CT>();
                 beta_scale = lambda_scale * cos_beta1;
@@ -708,7 +692,7 @@ public:
         // Sanity check on starting guess. Backwards check allows NaN through.
         if (!(sin_alpha1 <= c0))
         {
-            math::normalize_values<CT>(sin_alpha1, cos_alpha1);
+            math::normalize_unit_vector<CT>(sin_alpha1, cos_alpha1);
         }
         else
         {
@@ -791,6 +775,7 @@ public:
         return k;
     }

+    template <typename CoeffsC1>
     static inline CT lambda12(CT sin_beta1, CT cos_beta1, CT dn1,
                               CT sin_beta2, CT cos_beta2, CT dn2,
                               CT sin_alpha1, CT cos_alpha1,
@@ -802,7 +787,7 @@ public:
                               CT& eps, CT& diff_omega12,
                               bool diffp, CT& diff_lam12,
                               CT f, CT n, CT ep2, CT tiny,
-                              CT coeffs_C1[])
+                              CoeffsC1 coeffs_C1)
     {
         CT const one_minus_f = c1 - f;

@@ -826,7 +811,7 @@ public:

         cos_sigma1 = cos_omega1 = cos_alpha1 * cos_beta1;

-        math::normalize_values<CT>(sin_sigma1, cos_sigma1);
+        math::normalize_unit_vector<CT>(sin_sigma1, cos_sigma1);

         // Enforce symmetries in the case abs(beta2) = -beta1.
         // Otherwise, this can yield singularities in the Newton iteration.
@@ -848,7 +833,7 @@ public:
         cos_sigma2 = cos_omega2 =
             cos_alpha2 * cos_beta2;

-        math::normalize_values<CT>(sin_sigma2, cos_sigma2);
+        math::normalize_unit_vector<CT>(sin_sigma2, cos_sigma2);

         // sig12 = sig2 - sig1, limit to [0, pi].
         sigma12 = atan2(std::max(CT(0), cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
@@ -867,24 +852,14 @@ public:

         eps = k2 / (c2 * (c1 + std::sqrt(c1 + k2)) + k2);

-        // Compute the size of coefficient array.
-        size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
-        CT coeffs_C3x[coeffs_C3_size];
-        series_expansion::evaluate_coeffs_C3x<CT, SeriesOrder>(n, coeffs_C3x);
-
-        // Evaluate C3 coefficients.
-        CT coeffs_C3[SeriesOrder];
-        series_expansion::evaluate_coeffs_C3<CT, SeriesOrder>(eps, coeffs_C3, coeffs_C3x);
+        series_expansion::coeffs_C3<SeriesOrder, CT> const coeffs_C3(n, eps);

-        B312 = series_expansion::sin_cos_series<CT, SeriesOrder>
-                   (sin_sigma2, cos_sigma2, coeffs_C3) -
-               series_expansion::sin_cos_series<CT, SeriesOrder>
-                   (sin_sigma1, cos_sigma1, coeffs_C3);
+        B312 = series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C3)
+             - series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);

-        CT coeffs_A3[SeriesOrder];
-        series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
+        series_expansion::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);

-        CT const A3 = math::horner_evaluate(eps, coeffs_A3, coeffs_A3 + SeriesOrder);
+        CT const A3 = math::horner_evaluate(eps, coeffs_A3.begin(), coeffs_A3.end());

         diff_omega12 = -f * A3 * sin_alpha0 * (sigma12 + B312);
         lam12 = eta + diff_omega12;
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 175b96f..6304484 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -387,7 +387,7 @@ inline T difference_angle(T x, T y, T& e)
 {
     T t, d = math::sum_error(std::remainder(-x, T(360)), std::remainder(y, T(360)), t);

-    normalize_angle<degree, T>(d);
+    normalize_azimuth<degree, T>(d);

     // Here y - x = d + t (mod 360), exactly, where d is in (-180,180] and
     // abs(t) <= eps (eps = 2^-45 for doubles).  The only case where the

commit 73a2e2b8a4f47ea87fd63dc4de03b4e3dd797835
Merge: 1a52eac 687df8e
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jul 9 16:15:41 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

commit 1a52eaca9c35791984d2d3ba4ed0f5df2c963a23
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jul 6 18:27:49 2018 +0500

    [formulas] Resolve inaccuracy in starting point for Newton's method

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 3864fb1..691c111 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -102,7 +102,6 @@ public:

         CT tiny = std::sqrt(std::numeric_limits<CT>::min());

-
         CT const n = f / two_minus_f;
         CT const e2 = f * two_minus_f;
         CT const ep2 = e2 / math::sqr(one_minus_f);
@@ -293,7 +292,7 @@ public:

             if (sigma12 >= c0)
             {
-                // Short lines case (newton_start sets salp2, calp2, dnm)
+                // Short lines case (newton_start sets sin_alpha2, cos_alpha2, dnm)
                 s12x = sigma12 * b * dnm;
                 m12x = math::sqr(dnm) * b * sin(sigma12 / dnm);
                 if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
@@ -361,7 +360,7 @@ public:
                         CT cos_diff_alpha1 = cos(diff_alpha1);

                         CT nsin_alpha1 = sin_alpha1 * cos_diff_alpha1 +
-                                        cos_alpha1 * sin_diff_alpha1;
+                            cos_alpha1 * sin_diff_alpha1;

                         if (nsin_alpha1 > c0 && std::abs(diff_alpha1) < math::pi<CT>())
                         {
@@ -565,15 +564,21 @@ public:
     {
         CT const one_minus_f = c1 - f;
         CT const x_thresh = c1000 * tol2;
+
+        // Return a starting point for Newton's method in sin_alpha1
+        // and cos_alpha1 (function value is -1). If Newton's method
+        // doesn't need to be used, return also sin_alpha2 and
+        // cos_alpha2 and function value is sig12.
         CT sig12 = -c1;

+        // bet12 = bet2 - bet1 in [0, pi); beta12a = bet2 + bet1 in (-pi, 0]
         CT sin_beta12 = sin_beta2 * cos_beta1 - cos_beta2 * sin_beta1;
         CT cos_beta12 = cos_beta2 * cos_beta1 + sin_beta2 * sin_beta1;

         CT sin_beta12a = sin_beta2 * cos_beta1 + cos_beta2 * sin_beta1;

         bool shortline = cos_beta12 >= c0 && sin_beta12 < c0_5 &&
-                         cos_beta2 * lam12 < c0_5;
+            cos_beta2 * lam12 < c0_5;

         CT sin_omega12, cos_omega12;

@@ -609,6 +614,10 @@ public:
             cos_alpha2 = sin_beta12 - cos_beta1 * sin_beta2 *
                 (cos_omega12 >= c0 ? math::sqr(sin_omega12) /
                 (c1 + cos_omega12) : c1 - cos_omega12);
+
+            math::normalize_values<CT>(sin_alpha2, cos_alpha2);
+            // Set return value.
+            sig12 = atan2(sin_sigma12, cos_sigma12);
         }
         // Skip astroid calculation if too eccentric.
         else if (std::abs(n) > c0_1 ||
@@ -616,11 +625,11 @@ public:
                  sin_sigma12 >= c6 * std::abs(n) * math::pi<CT>() *
                  math::sqr(cos_beta1))
         {
-            // Nothing to do.
+            // Nothing to do, zeroth order spherical approximation will do.
         }
         else
         {
-            // Scale lam12 and beta2 to x, y coordinate system where antipodal
+            // Scale lam12 and bet2 to x, y coordinate system where antipodal
             // point is at origin and singular point is at y = 0, x = -1.
             CT lambda_scale, beta_scale;

@@ -628,18 +637,17 @@ public:
             volatile CT x;

             CT lam12x = atan2(-sin_lam12, -cos_lam12);
-            if (f >= 0)
+            if (f >= c0)
             {
                 CT k2 = math::sqr(sin_beta1) * ep2;
-                CT epsilon = k2 / (c2 * (c1 * sqrt(c1 + k2)) + k2);
+                CT eps = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);

                 CT coeffs_A3[SeriesOrder];
                 series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);

-                CT const A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
+                CT const A3 = math::horner_evaluate(eps, coeffs_A3, coeffs_A3 + SeriesOrder);

                 lambda_scale = f * cos_beta1 * A3 * math::pi<CT>();
-
                 beta_scale = lambda_scale * cos_beta1;

                 x = lam12x / lambda_scale;
@@ -671,12 +679,12 @@ public:
                 if (f >= c0)
                 {
                     sin_alpha1 = std::min(CT(1), -CT(x));
-                    cos_alpha1 = - std::sqrt(CT(1) - math::sqr(sin_alpha1));
+                    cos_alpha1 = - math::sqrt(c1 - math::sqr(sin_alpha1));
                 }
                 else
                 {
-                    cos_alpha1 = std::max(x > -tol1 ? c0 : -c1, CT(x));
-                    sin_alpha1 = std::sqrt(c1 - math::sqr(cos_alpha1));
+                    cos_alpha1 = std::max(CT(x > -tol1 ? c0 : -c1), CT(x));
+                    sin_alpha1 = math::sqrt(c1 - math::sqr(cos_alpha1));
                 }
             }
             else
@@ -687,8 +695,8 @@ public:
                 CT omega12a = lambda_scale * (f >= c0 ? -x * k /
                     (c1 + k) : -y * (c1 + k) / k);

-                CT sin_omega12 = sin(omega12a);
-                CT cos_omega12 = -cos(omega12a);
+                sin_omega12 = sin(omega12a);
+                cos_omega12 = -cos(omega12a);

                 // Update spherical estimate of alpha1 using omgega12 instead of lam12.
                 sin_alpha1 = cos_beta2 * sin_omega12;
@@ -697,15 +705,15 @@ public:
             }
         }

-        // Apply sanity check on starting guess. Backwards check allows NaN through.
+        // Sanity check on starting guess. Backwards check allows NaN through.
         if (!(sin_alpha1 <= c0))
         {
-          math::normalize_values<CT>(sin_alpha1, cos_alpha1);
+            math::normalize_values<CT>(sin_alpha1, cos_alpha1);
         }
         else
         {
-          sin_alpha1 = c1;
-          cos_alpha1 = c0;
+            sin_alpha1 = c1;
+            cos_alpha1 = c0;
         }

         return sig12;

commit 535ae96a8682fcc068016db212585e2c5994827a
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jul 3 11:11:41 2018 +0500

    [test] Add nearly antipodal points dataset for inverse geodesic problem

    These values are collected from GeodTest which is associated
    with GeographicLib:
    https://zenodo.org/record/32156

    The conversion to C++ array format is done using this Python script:
    https://github.com/adl1995/boost-geometry-extra/blob/master/geographiclib-dataset-parse-inverse.py

    Geodesic scale (M12) is absent from the GeodTest dataset, so it is
    manually generated using GeographicLib using this C++ script:
    https://github.com/adl1995/boost-geometry-extra/blob/master/geographicLib-direct-antipodal.cpp

diff --git a/test/formulas/inverse.cpp b/test/formulas/inverse.cpp
index 8e7ad03..07c0fbc 100644
--- a/test/formulas/inverse.cpp
+++ b/test/formulas/inverse.cpp
@@ -4,6 +4,7 @@
 // Copyright (c) 2016-2017 Oracle and/or its affiliates.

 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -14,6 +15,7 @@

 #include "test_formula.hpp"
 #include "inverse_cases.hpp"
+#include "inverse_cases_antipodal.hpp"

 #include <boost/geometry/formulas/vincenty_inverse.hpp>
 #include <boost/geometry/formulas/thomas_inverse.hpp>
@@ -22,8 +24,9 @@

 #include <boost/geometry/srs/spheroid.hpp>

+template <typename Result>
 void check_inverse(std::string const& name,
-                   expected_results const& results,
+                   Result const& results,
                    bg::formula::result_inverse<double> const& result,
                    expected_result const& expected,
                    expected_result const& reference,
@@ -87,6 +90,23 @@ void test_all(expected_results const& results)
     check_inverse("karney", results, result_k, results.vincenty, results.reference, 0.0000001);
 }

+void test_karney_antipodal(expected_results_antipodal const& results)
+{
+    double lon1d = results.p1.lon;
+    double lat1d = results.p1.lat;
+    double lon2d = results.p2.lon;
+    double lat2d = results.p2.lat;
+
+    // WGS84
+    bg::srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);
+
+    bg::formula::result_inverse<double> result;
+
+    typedef bg::formula::karney_inverse<double, true, true, true, true, true, 8> ka_t;
+    result = ka_t::apply(lon1d, lat1d, lon2d, lat2d, spheroid);
+    check_inverse("karney", results, result, results.karney, results.karney, 0.0000001);
+}
+
 int test_main(int, char*[])
 {
     for (size_t i = 0; i < expected_size; ++i)
@@ -94,5 +114,10 @@ int test_main(int, char*[])
         test_all(expected[i]);
     }

+    for (size_t i = 0; i < expected_size_antipodal; ++i)
+    {
+        test_karney_antipodal(expected_antipodal[i]);
+    }
+
     return 0;
 }
diff --git a/test/formulas/inverse_cases_antipodal.hpp b/test/formulas/inverse_cases_antipodal.hpp
new file mode 100644
index 0000000..e66046d
--- /dev/null
+++ b/test/formulas/inverse_cases_antipodal.hpp
@@ -0,0 +1,342 @@
+// Boost.Geometry
+// Unit Test
+
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_TEST_INVERSE_CASES_ANTIPODAL_HPP
+#define BOOST_GEOMETRY_TEST_INVERSE_CASES_ANTIPODAL_HPP
+
+#include "inverse_cases.hpp"
+
+struct expected_results_antipodal
+{
+    coordinates p1;
+    coordinates p2;
+    expected_result karney;
+};
+
+/*
+ These values are collected from GeodTest which is associated with GeographicLib:
+     https://zenodo.org/record/32156
+
+ The conversion to C++ array format is done using this Python script:
+     https://github.com/adl1995/boost-geometry-extra/blob/master/geographiclib-dataset-parse-inverse.py
+
+ Geodesic scale (M12) is absent from the GeodTest dataset, so it is manually generated
+ using GeographicLib using this C++ script:
+     https://github.com/adl1995/boost-geometry-extra/blob/master/geographicLib-direct-antipodal.cpp
+*/
+expected_results_antipodal expected_antipodal[] =
+{
+    {
+        { 0, 31.394417440639 }, { 179.615601631202912322, -31.275540610835465807 },
+        { 19980218.4055399, 34.266322930672, 145.782701113414306756, 49490.8807994496209, -0.996116451012525883079717914370121434 }
+    },{
+        { 0, 29.788792273749 }, { 178.569451327813675741, -29.558013672069422725 },
+        { 19887224.5407334, 74.302205994192, 106.156240654579267308, 97043.7545600593058, -0.998624031147844926081802441331092268 }
+    },{
+        { 0, 46.471843094141 }, { 179.083144618009561276, -46.284166405924629853 },
+        { 19944337.8863917, 63.693680310665, 116.699978859005570535, 53139.140576552365, -0.997597309645591900917338534782174975 }
+    },{
+        { 0, 63.016506345929 }, { 179.862869954071637855, -63.02943882703369735 },
+        { 20000925.7533636, 153.393656073038, 26.619056019474552953, 12713.9284725111772, -1.00381317792143387457315384381217882 }
+    },{
+        { 0, 19.796231412719 }, { 179.546498474461283862, -19.470586923091672503 },
+        { 19956338.1330537, 28.272934411318, 151.789094611690988249, 87191.1749625132931, -0.997015409027664833985227232915349305 }
+    },{
+        { 0, 6.373459459035 }, { 179.240009269347556917, -6.204887833274217382 },
+        { 19946581.6983394, 56.859050230583, 123.169200847008284851, 53958.8698005263939, -0.999349049081101004077254401636309922 }
+    },{
+        { 0, 66.380766469414 }, { 179.632633596894388233, -66.27177494016956425 },
+        { 19986277.7696849, 38.646950203356, 141.550919825824399405, 22198.215635049214, -0.996949176054954366854587988200364634 }
+    },{
+        { 0, 16.483421185231 }, { 179.731567273052604726, -16.818424446748042212 },
+        { 19962737.9842573, 163.431254767325, 16.598399455529231288, 95318.4104529881431, -1.00272210232979741562076014815829694 }
+    },{
+        { 0, 4.215702155486 }, { 179.093771177769992874, -4.051917290690976764 },
+        { 19932517.393764, 65.543168480886, 114.482669479963380006, 55205.4553703842317, -0.999655858425056553784315838129259646 }
+    },{
+        { 0, 40.71372085907 }, { 179.404612926861498984, -41.047052242159400671 },
+        { 19951133.3595356, 143.672151631634, 36.54002600969304553, 70931.1530155553621, -1.00414169574077272173440178448799998 }
+    },{
+        { 0, 15.465481491654 }, { 179.020726605204181801, -14.622355549425900341 },
+        { 19877383.8879911, 36.289185640976, 143.875673907461159912, 156419.0806764376957, -0.997639074397169589580869342171354219 }
+    },{
+        { 0, 17.586197343531 }, { 179.722490735835379144, -17.731394230364437075 },
+        { 19982280.4639115, 157.929615091529, 22.089021105298661023, 69727.5357849255557, -1.00280451698301242835498214844847098 }
+    },{
+        { 0, 5.7442768247 }, { 178.85894724576868462, -6.039853564481335581 },
+        { 19902873.7431814, 116.146983678305, 63.91482549951374061, 87149.6188944111673, -1.00039332893096744037109147029696032 }
+    },{
+        { 0, 32.002904282111 }, { 179.744925422107715439, -32.297934520693132807 },
+        { 19967670.3104795, 163.052160078191, 17.004175883388454943, 78311.3164829640582, -1.00449903445302446414189034840092063 }
+    },{
+        { 0, 55.902716926362 }, { 179.300685189522463007, -55.934320218634018206 },
+        { 19970525.337607, 98.927641063414, 81.374264168520557301, 23554.0093185709067, -1.00072788779083454713259015989024192 }
+    },{
+        { 0, 22.69939784398 }, { 179.294173474584020749, -22.654875407651067149 },
+        { 19959286.1903172, 74.253870776761, 105.811588890213155275, 22369.7179951557679, -0.998972181419003457669703038845909759 }
+    },{
+        { 0, 41.312328471121 }, { 179.817186837717804928, -40.954523601529804886 },
+        { 19962690.5721867, 11.277616109847, 168.784288786443902199, 77252.6121237260201, -0.994825151471527391322524636052548885 }
+    },{
+        { 0, 27.927415327453 }, { 179.636508875679110143, -27.607314264234172721 },
+        { 19961296.8828333, 23.166421459647, 156.905194492817275222, 83096.5801709291101, -0.995959692767656723511038308060960844 }
+    },{
+        { 0, 41.567228741451 }, { 179.931812964300204608, -42.103039532074194347 },
+        { 19944253.4454809, 176.66609526064, 3.361859685835349219, 96859.08180779197, -1.00513607140487626345759508694754913 }
+    },{
+        { 0, 37.384208978567 }, { 179.225180174670992261, -36.916085670712060029 },
+        { 19928705.5911445, 39.072534864532, 141.212743814390850106, 92667.7834060578402, -0.995955516859159284415170532156480476 }
+    },{
+        { 0, 59.011868682852 }, { 179.424923485514312807, -58.82705468054708336 },
+        { 19970442.3788306, 44.970301291063, 135.333817989802309531, 38071.1136293083857, -0.996658942892707400140750451100757346 }
+    },{
+        { 0, 35.515406087737 }, { 179.50369572149476218, -35.119747127350258822 },
+        { 19948918.9139751, 28.528972431952, 151.622257906284404073, 84564.0387217601751, -0.995562861799169418475230486365035176 }
+    },{
+        { 0, 58.170252463184 }, { 179.254737571455023977, -58.372261836268550805 },
+        { 19961407.0813807, 128.021116291844, 52.399129705193347143, 43715.3070711393309, -1.00285273713280753682397516968194395 }
+    },{
+        { 0, 34.012183807959 }, { 179.83713352180447672, -34.29640782899529639 },
+        { 19970955.843065, 168.944519134772, 11.093048811826875835, 76493.5814538538151, -1.0047652354558671561335359001532197 }
+    },{
+        { 0, 45.510762948553 }, { 178.981682578823726535, -45.582753595227824235 },
+        { 19940248.3450143, 99.886784003837, 80.542330522982505877, 48555.1946627894972, -1.00083807750906350619857221317943186 }
+    },{
+        { 0, 4.19841765451 }, { 179.398024428225540172, -4.198416896099783242 },
+        { 19970496.5132933, 89.561550657928, 90.438456568689151881, 14.8790480103109, -0.999994104810285944218151144013972953 }
+    },{
+        { 0, 40.890119148103 }, { 179.6557148951668192, -41.553556264538302258 },
+        { 19926563.5817492, 165.437641169967, 14.713597527941311478, 111805.7305227545923, -1.00492294933406567380984597548376769 }
+    },{
+        { 0, 28.096672787686 }, { 178.606868012231657724, -28.472055035513955205 },
+        { 19883901.8482359, 115.174366374632, 65.257367020445564176, 107880.4353518862363, -1.00170803073331593502359737613005564 }
+    },{
+        { 0, 6.50572154271 }, { 178.926013840891647541, -6.411745140559297675 },
+        { 19917276.4101551, 79.069492719523, 100.985091481519557845, 57073.3242952680707, -0.999736666933808471036115861352300271 }
+    },{
+        { 0, .468835109567 }, { 178.325942223692180692, -.281751687044281805 },
+        { 19849380.7342734, 80.234636214474, 99.77243368342786593, 123845.4568822078908, -0.999801437209140719808431185811059549 }
+    },{
+        { 0, 1.682746325049 }, { 179.717131561406935483, -.677647430701204515 },
+        { 19890026.0274781, 10.076182752451, 169.927471515299313238, 177917.2104306563981, -0.999538055691262194990542866435134783 }
+    },{
+        { 0, 10.711305126218 }, { 179.874050163405229937, -10.349315378531556046 },
+        { 19962987.2134077, 7.528253696796, 172.480576051850009046, 104175.1095378254456, -0.998071853755238880268052525934763253 }
+    },{
+        { 0, 53.374321544652 }, { 179.729445806011012057, -53.196257519024042184 },
+        { 19980478.1457438, 23.324715976877, 156.777734080146664812, 41907.8869272231053, -0.995333596277707566279957518418086693 }
+    },{
+        { 0, 39.680221664519 }, { 179.87506206720154785, -39.256187213040660911 },
+        { 19956191.7841809, 7.075406493429, 172.967624741991546131, 86943.8110669895148, -0.994801087909667924868983845954062417 }
+    },{
+        { 0, 1.377666714083 }, { 178.994542525209058878, -1.415358715570225495 },
+        { 19925401.4931301, 95.29199069739, 84.7178724483824156, 45800.9140624827059, -0.99999803170512457928253979844157584 }
+    },{
+        { 0, 48.751426624188 }, { 179.661697715070846977, -48.688146707479475147 },
+        { 19988599.1160495, 40.252328570137, 139.808452951157199824, 26322.3790862461568, -0.995999245724129789181233718409202993 }
+    },{
+        { 0, 59.443039048494 }, { 179.247605418616998285, -59.454371825393424121 },
+        { 19969935.9534732, 93.052184108221, 87.331416513795326158, 25342.4691896499534, -1.00020727848897084122370415570912883 }
+    },{
+        { 0, 4.122408476235 }, { 179.749430572914989772, -4.689124208743755363 },
+        { 19938291.6332293, 167.73479753304, 12.274635577599782826, 127855.6475863583497, -1.00068600902837667732114823593292385 }
+    },{
+        { 0, 46.422470082432 }, { 178.857408435141563774, -46.390934261324541952 },
+        { 19931980.7029341, 86.67365350297, 93.852683224054943377, 56114.680046867064, -0.999607096116300386512421027873642743 }
+    },{
+        { 0, 32.614423729024 }, { 179.460593512880455451, -32.01874745886238612 },
+        { 19926887.3785175, 24.943814520557, 155.229917137448282531, 112355.3319340873104, -0.995562150676871926435751447570510209 }
+    },{
+        { 0, 3.242895277973 }, { 179.556428318080663113, -3.001106476068264917 },
+        { 19964490.4789049, 30.247458779683, 149.760178923092147784, 80929.0418317066044, -0.999474184270344845337774586369050667 }
+    },{
+        { 0, 6.29069210113 }, { 178.556859259685624933, -6.354208910915346725 },
+        { 19877160.8505733, 94.34299459284, 85.750059038253282986, 94127.1566760840083, -0.999976397350904933070125935046235099 }
+    },{
+        { 0, 18.232086569498 }, { 179.658073278238477245, -18.87394850776853555 },
+        { 19927978.7462175, 164.41905055334, 15.640779355822506503, 129771.1882449660559, -1.00293460439063886191490837518358603 }
+    },{
+        { 0, 12.049849333181 }, { 179.761046682699610657, -11.201990279782499264 },
+        { 19908004.4552909, 9.418096768309, 170.610608272305604585, 157761.5040571466343, -0.997761474497510958414636661473196 }
+    },{
+        { 0, 40.289465276136 }, { 179.644208494155329095, -40.370034926441385999 },
+        { 19985674.936106, 143.092606818963, 36.958610382613096419, 36200.8933724688593, -1.00414965876091266672176516294712201 }
+    },{
+        { 0, 2.197784650379 }, { 179.961199531084784854, -1.353440827124394777 },
+        { 19910509.7517973, 1.542117609437, 178.458582198505846426, 160403.6285079348996, -0.999488724639301051588802238256903365 }
+    },{
+        { 0, 1.966575272177 }, { 179.699817324905962184, -3.101125282483752618 },
+        { 19875595.6267266, 170.112968791865, 9.89572776349855838, 192355.7206665719908, -1.00015463589804554089823795948177576 }
+    },{
+        { 0, 25.078832492684 }, { 178.600804840925824646, -24.897833702325682511 },
+        { 19887997.7953866, 77.264585323781, 103.101167809583406892, 92442.9124509225839, -0.998981189838600847075156252685701475 }
+    },{
+        { 0, 31.740361941314 }, { 179.553485210731879874, -31.909206787477701871 },
+        { 19972325.3556069, 143.930820896999, 36.145242998351638503, 54883.4113710054145, -1.00379461628115951299378139083273709 }
+    },{
+        { 0, .05479250563 }, { 178.822647462220726609, .836079031223269324 },
+        { 19858049.4780499, 41.349430623518, 138.645259065012502544, 169078.442370111714, -0.9997793696948588104689292777038645 }
+    },{
+        { 0, 36.685139871608 }, { 179.366667224014334712, -36.6833040833258687 },
+        { 19968965.6773632, 89.167975517493, 90.921025521408327068, 13327.2156799476918, -0.999916537946348604748436628142371774 }
+    },{
+        { 0, 3.451199399671 }, { 179.107509334399258305, -3.459003521120242021 },
+        { 19938203.3838544, 91.541212417048, 88.476282464773035164, 32316.1747698810781, -1.00000397484395819880376166111091152 }
+    },{
+        { 0, 27.692898794247 }, { 178.512356615673144314, -27.666009301228316555 },
+        { 19883493.6699045, 88.406440883665, 92.036345087713397961, 94128.7880896190836, -0.999736458322951659916100197733612731 }
+    },{
+        { 0, 17.363238291869 }, { 179.567921315455829491, -17.288872648596950413 },
+        { 19980749.7638027, 39.697196316589, 140.321938237586060826, 46975.9359427664379, -0.997687691981715030209443284547887743 }
+    },{
+        { 0, 37.006775102539 }, { 179.191103068859169842, -37.156365616364686838 },
+        { 19949309.9180043, 116.455543532607, 63.771817992036617793, 45856.1961421018701, -1.00221962858918423044940482213860378 }
+    },{
+        { 0, 45.572883540957 }, { 179.224707765088686272, -45.94675931323086696 },
+        { 19940027.8586414, 137.627256708444, 42.723991162977357301, 74208.4359612889496, -1.00380887786447159371050474874209613 }
+    },{
+        { 0, 43.63393981955 }, { 178.878236417027994157, -43.642335115130514773 },
+        { 19931045.2914508, 91.203625101465, 89.268780774643462256, 55253.5406349861764, -1.00002974153150514524668324156664312 }
+    },{
+        { 0, 38.4995307019 }, { 179.143856004445269342, -39.042223438550921467 },
+        { 19918391.2222193, 141.232864609445, 39.117947060740562295, 102217.2563106863077, -1.00388164115732947401227193040540442 }
+    },{
+        { 0, 27.55015339382 }, { 179.596220103573824099, -27.587412128122249651 },
+        { 19986004.7358853, 137.025135713548, 42.992898351962011956, 33938.7346646670654, -1.00316044390281167153489150223322213 }
+    },{
+        { 0, 1.54507498314 }, { 179.567115633151308577, -1.448861185025252004 },
+        { 19978593.3191777, 36.816106412092, 143.185763012309022403, 56320.5800276739168, -0.999770499462467210349814195069484413 }
+    },{
+        { 0, 45.217063644222 }, { 179.807382581661125, -45.086424050571516283 },
+        { 19987042.0782465, 18.114645812265, 161.928120141429818658, 45544.2915061261936, -0.994974179414854997816064496873877943 }
+    },{
+        { 0, 13.473522450751 }, { 179.726941062277208626, -13.570372758027936877 },
+        { 19987364.078382, 156.839609002403, 23.170293747820406391, 65329.9068132034472, -1.00219093189506569530067281448282301 }
+    },{
+        { 0, 6.287741997374 }, { 179.071252372259552052, -6.743450924917895817 },
+        { 19912159.8245954, 132.954797451112, 47.100789519677419746, 104772.4027498097375, -1.00071252411103017720961361192166805 }
+    },{
+        { 0, 7.639709001531 }, { 179.616156296978583335, -7.48702643786017917 },
+        { 19976374.3699535, 29.731916588299, 150.279582966919438164, 69224.6591757209539, -0.998789792086741234911073661351110786 }
+    },{
+        { 0, 5.893688050348 }, { 179.586212000450856399, -4.888408917114795625 },
+        { 19886907.2520668, 14.653438882877, 165.371181401863458848, 177183.5330818593022, -0.998794647031120752522781458537792787 }
+    },{
+        { 0, 61.997076235476 }, { 179.605779116829636081, -62.19593758437129915 },
+        { 19976288.2901729, 149.562797049254, 30.65850204223272625, 36696.2853801462176, -1.00373071432437144245852778112748638 }
+    },{
+        { 0, 50.507637741656 }, { 179.893569206021038536, -50.721890799900161112 },
+        { 19979542.5263293, 171.564028344478, 8.4746613464253591, 50644.5234828162697, -1.00508881632281776852266830246662721 }
+    },{
+        { 0, 7.484475238477 }, { 178.638400003000590878, -6.926155588124333461 },
+        { 19867425.2906303, 57.020570370985, 123.087267812322270238, 132929.2775641349633, -0.999097042677338120775232255255104974 }
+    },{
+        { 0, 56.851165323215 }, { 179.587046628550073045, -56.875248360744638525 },
+        { 19988235.9960515, 112.345749045605, 67.744017057185404441, 9971.0934553515518, -1.00182859249871403228837607457535341 }
+    },{
+        { 0, 10.692273150738 }, { 178.709520715733071393, -10.851727623036704339 },
+        { 19893210.3050033, 102.824601316946, 77.308514969817191459, 83032.7122948051111, -1.00034345584508432835946223349310458 }
+    },{
+        { 0, 46.694739303788 }, { 179.926838145841924189, -46.948618153686522669 },
+        { 19975447.9283188, 174.663684259477, 5.361568174833475454, 59614.5876209460645, -1.00520484875201732144489596976200119 }
+    },{
+        { 0, 15.804386137005 }, { 178.367587635209819128, -15.522042847777054984 },
+        { 19855850.8800526, 74.932089158884, 105.357235560913450667, 123350.4326645237628, -0.999091578546475345135036150168161839 }
+    },{
+        { 0, 4.371450175299 }, { 179.780887420199549421, -4.566109732313098407 },
+        { 19979071.1035552, 164.163592252794, 15.840695025950408814, 84137.2115482558728, -1.00076323969894742660358133434783667 }
+    },{
+        { 0, 30.894388279688 }, { 179.375426183521944524, -30.871308884744172663 },
+        { 19968681.8321577, 77.35154610481, 102.709506078439532936, 14048.0277985734058, -0.998975176336422854284080585784977302 }
+    },{
+        { 0, 9.541166838639 }, { 178.432934555386452839, -10.09982228112793472 },
+        { 19848553.7844137, 118.441353539081, 61.736686215549403663, 144831.1911566651614, -1.00060548620110489892454097571317106 }
+    },{
+        { 0, 8.489292700054 }, { 179.906698338023119097, -8.559237750032113623 },
+        { 19995477.1669578, 171.963952699866, 8.037517851139094467, 72192.60793572974, -1.00152068486306466965629624610301107 }
+    },{
+        { 0, 19.562401114224 }, { 178.838724116996037606, -20.05038360490599475 },
+        { 19893208.1788508, 126.362762598128, 53.875560227496658204, 112181.7524188837615, -1.00185202668802775249901060306001455 }
+    },{
+        { 0, 42.260350252749 }, { 179.807860448877064601, -42.79985897702184353 },
+        { 19942715.0054774, 170.703419847646, 9.377654670896439828, 96336.3477142010769, -1.00508642406443549077721399953588843 }
+    },{
+        { 0, 24.511403144656 }, { 178.957598444862223515, -24.616808725039883945 },
+        { 19924809.5184876, 102.913211410163, 77.297538210434837096, 55403.453072179318, -1.0008408309188838725134473861544393 }
+    },{
+        { 0, 20.844284170708 }, { 179.069258863637226633, -20.321320573298341477 },
+        { 19909084.6340808, 44.172784008084, 136.01627115731728436, 111009.0987238994608, -0.997389183621778974142557672166731209 }
+    },{
+        { 0, 2.426010809098 }, { 178.236397468862000784, -2.513715200833756776 },
+        { 19840940.6924189, 94.315194952561, 85.734896842737189557, 130002.6104886615638, -0.999825249844991659209370027383556589 }
+    },{
+        { 0, 6.600682554664 }, { 179.646475458013797028, -7.699164822656561787 },
+        { 19878412.28273, 168.167678684515, 11.861035812918738552, 187426.3958525886692, -1.00098284856064978498579876031726599 }
+    },{
+        { 0, 23.372339802326 }, { 179.499422665106094027, -24.239465200482591299 },
+        { 19899498.4582543, 161.197647943542, 18.932355367478826536, 151863.2545535951091, -1.00347666868431395492677893344080076 }
+    },{
+        { 0, 16.194668264095 }, { 179.115193814080201851, -17.129419031459576897 },
+        { 19874825.6683239, 148.942349959054, 31.225656401221968078, 166033.3161394594622, -1.00222032222233647935638600756647065 }
+    },{
+        { 0, 1.528726471528 }, { 178.791047180477802091, -1.282203000582034597 },
+        { 19897803.9939987, 69.212891442493, 110.802928803578167132, 85252.8333849204133, -0.999827144228156883265512533398577943 }
+    },{
+        { 0, 6.297249676078 }, { 178.623258703845895437, -5.709470001196540278 },
+        { 19864042.0495193, 56.274639904925, 123.817184177744186806, 137475.1283083659258, -0.999190450178399580671850799262756482 }
+    },{
+        { 0, 17.393540327984 }, { 179.330156510680163326, -17.431100690958209424 },
+        { 19962624.6302607, 107.855062015266, 72.181322855288535245, 19320.5501845044839, -1.00091841779689127989172447996679693 }
+    },{
+        { 0, 46.284685151236 }, { 179.852534804091121255, -46.176234945675219984 },
+        { 19990422.3478916, 14.758013867151, 165.271681964991897184, 42614.1796365710104, -0.994894592261839960656288894824683666 }
+    },{
+        { 0, 14.924320176299 }, { 179.195663739713760883, -14.125476432252858442 },
+        { 19891861.8615337, 31.446544793174, 148.678916887199611191, 149419.6596309045804, -0.997620142585332936313591289945179597 }
+    },{
+        { 0, 23.668824656069 }, { 179.409875478773990359, -24.107855233601412399 },
+        { 19938736.4442268, 148.091483667618, 32.02919257641173958, 97771.7687385830819, -1.00323262872000595891108787327539176 }
+    },{
+        { 0, 46.986276695896 }, { 179.92040916864362177, -47.301644191214905832 },
+        { 19968596.0414782, 174.796708941456, 5.234240076649939638, 66113.7417494369769, -1.00519095452608087093437916337279603 }
+    },{
+        { 0, 65.946144289524 }, { 179.808282612725835525, -65.871840130833632868 },
+        { 19993734.5109736, 25.375428509648, 154.703163938350061652, 18355.2254271672769, -0.996436935914610577569305860379245132 }
+    },{
+        { 0, 10.950298933293 }, { 179.624609619829763098, -10.787771536605316781 },
+        { 19975919.5586889, 28.779018914489, 151.238005588662201946, 70291.1998404303581, -0.998272071834115148902810688014142215 }
+    },{
+        { 0, 13.609869340778 }, { 179.035623147420893383, -14.023624108675206222 },
+        { 19913213.8514358, 129.616021271129, 50.506400999466711623, 97596.7664002074776, -1.00146664642314031645753402699483559 }
+    },{
+        { 0, 48.701427557433 }, { 179.385565054218238481, -48.735316652259656533 },
+        { 19972955.2699173, 102.875149183407, 77.294384444682547869, 18461.7742226227697, -1.00114676855429074464609584538266063 }
+    },{
+        { 0, 31.519172055785 }, { 179.555251675378549409, -31.140142027808697534 },
+        { 19952318.3772514, 26.247105619999, 153.865822276646938125, 86354.7117605101002, -0.995739948399825047786748655198607594 }
+    },{
+        { 0, 31.863784754278 }, { 179.722489476483407524, -31.826935359797657785 },
+        { 19993324.8682601, 29.572313410211, 150.440607907359037187, 41427.6181613499234, -0.995888009001147267440501309465616941 }
+    },{
+        { 0, 76.434608546092 }, { 179.918287057674124459, -76.48787937532808951 },
+        { 19997750.023578, 167.428385412814, 12.621032110142724567, 9619.5267710862108, -1.00233963893091582164629471662919968 }
+    },{
+        { 0, 73.114273316483 }, { 179.576736605988553624, -73.098788070892914568 },
+        { 19992866.6147806, 78.154765899661, 102.085693546950923465, 8580.6475692800946, -0.999384143308475469957841141876997426 }
+    },{
+        { 0, 1.125639056292 }, { 178.426819580880619395, -.694775021853292564 },
+        { 19852573.5442848, 67.184842289382, 112.831314850896246589, 132932.8743502563937, -0.999732957962833457266071945923613384 }
+    }
+};
+
+size_t const expected_size_antipodal = sizeof(expected_antipodal) / sizeof(expected_results_antipodal);
+
+#endif // BOOST_GEOMETRY_TEST_INVERSE_CASES_ANTIPODAL_HPP

commit 4f0431085902aac5623fbf7db0909162a138a3f7
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jul 3 09:55:06 2018 +0500

    [formulas][test] Add Karney's inverse method in inverse test cases

    The compilation is successful with gcc version (7.2.0),
    but not with version (5.4.1). The accepted tolerance
    is set to (0.0000001). Currently, all tests are not
    passing, which indicates an error in the calculation.

    Additionally, some changes have been made in
    karney_inverse.hpp

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 517b966..3864fb1 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -98,7 +98,7 @@ public:
         CT const tol_bisection = tol0 * tol2;

         CT const etol2 = c0_1 * tol2 /
-            sqrt(std::max(c0_001, std::abs(f)) * std::min(c1, c1 - f / c2) / c2);
+            sqrt(std::max(CT(0.001), std::abs(f)) * std::min(CT(1), CT(1) - f / CT(2)) / c2);

         CT tiny = std::sqrt(std::numeric_limits<CT>::min());

@@ -226,8 +226,8 @@ public:
             CT sin_sigma2 = sin_beta2;
             CT cos_sigma2 = cos_alpha2 * cos_beta2;

-            CT sigma12 = std::atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
-                                                 cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);
+            CT sigma12 = std::atan2(std::max(CT(0), cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
+                                                    cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);

             CT dummy;
             meridian_length(n, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
@@ -670,8 +670,8 @@ public:
                 // Strip near cut.
                 if (f >= c0)
                 {
-                    sin_alpha1 = std::min(c1, -CT(x));
-                    cos_alpha1 = - std::sqrt(c1 - math::sqr(sin_alpha1));
+                    sin_alpha1 = std::min(CT(1), -CT(x));
+                    cos_alpha1 = - std::sqrt(CT(1) - math::sqr(sin_alpha1));
                 }
                 else
                 {
@@ -780,7 +780,6 @@ public:
             // For y small, positive root is k = abs(y)/sqrt(1-x^2).
             k = c0;
         }
-
         return k;
     }

@@ -844,11 +843,11 @@ public:
         math::normalize_values<CT>(sin_sigma2, cos_sigma2);

         // sig12 = sig2 - sig1, limit to [0, pi].
-        sigma12 = atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
-                                     cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);
+        sigma12 = atan2(std::max(CT(0), cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
+                                        cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);

         // omg12 = omg2 - omg1, limit to [0, pi].
-        sin_omega12 = std::max(c0, cos_omega1 * sin_omega2 - sin_omega1 * cos_omega2);
+        sin_omega12 = std::max(CT(0), cos_omega1 * sin_omega2 - sin_omega1 * cos_omega2);
         cos_omega12 = cos_omega1 * cos_omega2 + sin_omega1 * sin_omega2;

         // eta = omg12 - lam120.
@@ -900,7 +899,6 @@ public:
                 diff_lam12 *= one_minus_f / (cos_alpha2 * cos_beta2);
             }
         }
-
         return lam12;
     }

diff --git a/test/formulas/inverse.cpp b/test/formulas/inverse.cpp
index 59bb8b6..8e7ad03 100644
--- a/test/formulas/inverse.cpp
+++ b/test/formulas/inverse.cpp
@@ -18,6 +18,7 @@
 #include <boost/geometry/formulas/vincenty_inverse.hpp>
 #include <boost/geometry/formulas/thomas_inverse.hpp>
 #include <boost/geometry/formulas/andoyer_inverse.hpp>
+#include <boost/geometry/formulas/karney_inverse.hpp>

 #include <boost/geometry/srs/spheroid.hpp>

@@ -53,10 +54,15 @@ void test_all(expected_results const& results)
     double lon2r = results.p2.lon * d2r;
     double lat2r = results.p2.lat * d2r;

+    double lon1d = results.p1.lon;
+    double lat1d = results.p1.lat;
+    double lon2d = results.p2.lon;
+    double lat2d = results.p2.lat;
+
     // WGS84
     bg::srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);

-    bg::formula::result_inverse<double> result_v, result_t, result_a;
+    bg::formula::result_inverse<double> result_v, result_t, result_a, result_k;

     typedef bg::formula::vincenty_inverse<double, true, true, true, true, true> vi_t;
     result_v = vi_t::apply(lon1r, lat1r, lon2r, lat2r, spheroid);
@@ -75,6 +81,10 @@ void test_all(expected_results const& results)
     result_a.azimuth *= r2d;
     result_a.reverse_azimuth *= r2d;
     check_inverse("andoyer", results, result_a, results.andoyer, results.reference, 0.001);
+
+    typedef bg::formula::karney_inverse<double, true, true, true, true, true, 8> ka_t;
+    result_k = ka_t::apply(lon1d, lat1d, lon2d, lat2d, spheroid);
+    check_inverse("karney", results, result_k, results.vincenty, results.reference, 0.0000001);
 }

 int test_main(int, char*[])

commit 12bd41fd5db58d0f60d6544dafa981087f077aa5
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jul 2 13:47:58 2018 +0500

    [formulas] Store values from Karney's inverse method in result_inverse structure

    The computed values from inverse method include distance, azimuth,
    reverse_azimuth, reduced_length, and geodesic_scale.

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 5b6de69..517b966 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -133,8 +133,8 @@ public:
         }

         // Make points close to the equator to lie on it.
-        lat1 = std::abs(lat1) > 90 ? math::NaN<CT>() : lat1;
-        lat2 = std::abs(lat2) > 90 ? math::NaN<CT>() : lat2;
+        lat1 = std::abs(lat1) > c90 ? math::NaN<CT>() : lat1;
+        lat2 = std::abs(lat2) > c90 ? math::NaN<CT>() : lat2;

         lat1 = math::round_angle(lat1);
         lat2 = math::round_angle(lat2);
@@ -217,8 +217,8 @@ public:
             sin_alpha1 = sin_lam12;

             // Heading north at the target.
-            cos_alpha2 = 1;
-            sin_alpha2 = 0;
+            cos_alpha2 = c1;
+            sin_alpha2 = c0;

             CT sin_sigma1 = sin_beta1;
             CT cos_sigma1 = cos_alpha1 * cos_beta1;
@@ -227,7 +227,7 @@ public:
             CT cos_sigma2 = cos_alpha2 * cos_beta2;

             CT sigma12 = std::atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
-                                             cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);
+                                                 cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);

             CT dummy;
             meridian_length(n, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
@@ -257,8 +257,8 @@ public:

         CT omega12, sin_omega12, cos_omega12;

-        if (!meridian && sin_beta1 == 0 &&
-            (f <= 0 || lon12_error >= f * c180))
+        if (!meridian && sin_beta1 == c0 &&
+            (f <= c0 || lon12_error >= f * c180))
         {
             // Points lie on the equator.
             cos_alpha1 = cos_alpha2 = c0;
@@ -324,7 +324,6 @@ public:
                      ++iteration)
                 {
                     CT dv;
-
                     CT v = lambda12(sin_beta1, cos_beta1, dn1,
                                     sin_beta2, cos_beta2, dn2,
                                     sin_alpha1, cos_alpha1,
@@ -361,13 +360,13 @@ public:
                         CT sin_diff_alpha1 = sin(diff_alpha1);
                         CT cos_diff_alpha1 = cos(diff_alpha1);

-                        CT nsin_alpa1 = sin_alpha1 * cos_diff_alpha1 +
+                        CT nsin_alpha1 = sin_alpha1 * cos_diff_alpha1 +
                                         cos_alpha1 * sin_diff_alpha1;

-                        if (nsin_alpa1 > c0 && std::abs(diff_alpha1) < math::pi<CT>())
+                        if (nsin_alpha1 > c0 && std::abs(diff_alpha1) < math::pi<CT>())
                         {
                             cos_alpha1 = cos_alpha1 * cos_diff_alpha1 - sin_alpha1 * sin_diff_alpha1;
-                            sin_alpha1 = nsin_alpa1;
+                            sin_alpha1 = nsin_alpha1;
                             math::normalize_values<CT>(sin_alpha1, cos_alpha1);

                             // In some regimes we don't get quadratic convergence because
@@ -394,12 +393,6 @@ public:
                              std::abs(sin_alpha1 - sin_alpha1b) + (cos_alpha1 - cos_alpha1b) < tol_bisection);

                 }
-                // Store values in temporary vairables.
-                // bool enable_reduced_length = EnableReducedLength;
-                // bool enable_geodesic_scale = EnableGeodesicScale;
-
-                // EnableReducedLength = false;
-                // EnableGeodesicScale = false;

                 CT dummy;
                 // Ensure that the reduced length and geodesic scale are computed in
@@ -410,11 +403,49 @@ public:
                                                  m12x, dummy, result.geodesic_scale,
                                                  M21, coeffs_C1);

-                // Restore values to their previous state.
-                // EnableReducedLength = enable_reduced_length;
-                // EnableGeodesicScale = enable_geodesic_scale;
+                m12x *= b;
+                s12x *= b;
+                a12 = sigma12 / math::d2r<CT>();
+            }
+        }
+
+        if (swap_point < 0)
+        {
+            swap(sin_alpha1, sin_alpha2);
+            swap(cos_alpha1, cos_alpha2);
+            swap(result.geodesic_scale, M21);
+        }
+
+        sin_alpha1 *= swap_point * lon12_sign;
+        cos_alpha1 *= swap_point * lat_sign;
+
+        sin_alpha2 *= swap_point * lon12_sign;
+        cos_alpha2 *= swap_point * lat_sign;
+
+        if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
+        {
+            result.reduced_length = m12x;
+        }
+
+        if (BOOST_GEOMETRY_CONDITION(CalcAzimuths))
+        {
+            if (BOOST_GEOMETRY_CONDITION(CalcFwdAzimuth))
+            {
+                result.azimuth = atan2(sin_alpha1, cos_alpha1) * math::r2d<CT>();
+            }
+
+            if (BOOST_GEOMETRY_CONDITION(CalcRevAzimuth))
+            {
+                result.reverse_azimuth = atan2(sin_alpha2, cos_alpha2) * math::r2d<CT>();
             }
         }
+
+        if (BOOST_GEOMETRY_CONDITION(EnableDistance))
+        {
+            result.distance = s12x;
+        }
+
+        return result;
     }

     static inline void meridian_length(CT epsilon, CT ep2, CT sigma12,
@@ -436,8 +467,7 @@ public:
         {
             // Find the coefficients for A1 by computing the
             // series expansion using Horner scehme.
-            expansion_A1
-                = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);
+            expansion_A1 = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);

             // Evaluate the coefficients for C1.
             series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);
@@ -447,8 +477,7 @@ public:
             {
                 // Find the coefficients for A2 by computing the
                 // series expansion using Horner scehme.
-                expansion_A2
-                    = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);
+                expansion_A2 = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);

                 // Evaluate the coefficients for C2.
                 series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);
@@ -466,7 +495,7 @@ public:
                   - series_expansion::sin_cos_series<CT, SeriesOrder>
                                       (sin_sigma1, cos_sigma1, coeffs_C1);

-            m12x = expansion_A1 * (sigma12 + B1);
+            s12x = expansion_A1 * (sigma12 + B1);

             if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
                 BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
@@ -587,7 +616,7 @@ public:
                  sin_sigma12 >= c6 * std::abs(n) * math::pi<CT>() *
                  math::sqr(cos_beta1))
         {
-            // Nothing to do (?).
+            // Nothing to do.
         }
         else
         {
@@ -751,6 +780,7 @@ public:
             // For y small, positive root is k = abs(y)/sqrt(1-x^2).
             k = c0;
         }
+
         return k;
     }

@@ -787,8 +817,7 @@ public:
         sin_sigma1 = sin_beta1;
         sin_omega1 = sin_alpha0 * sin_beta1;

-        cos_sigma1 = cos_omega1 =
-            cos_alpha1 * cos_beta1;
+        cos_sigma1 = cos_omega1 = cos_alpha1 * cos_beta1;

         math::normalize_values<CT>(sin_sigma1, cos_sigma1);

@@ -816,7 +845,7 @@ public:

         // sig12 = sig2 - sig1, limit to [0, pi].
         sigma12 = atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
-                                cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);
+                                     cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);

         // omg12 = omg2 - omg1, limit to [0, pi].
         sin_omega12 = std::max(c0, cos_omega1 * sin_omega2 - sin_omega1 * cos_omega2);
@@ -871,6 +900,7 @@ public:
                 diff_lam12 *= one_minus_f / (cos_alpha2 * cos_beta2);
             }
         }
+
         return lam12;
     }


commit 687df8e18a907b28e69ea67e76e0ad2271ad5d37
Merge: 6219503 048b1f7
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jun 29 14:31:15 2018 +0500

    Merge branch 'develop' into feature/geodesic_direct

    Conflicts:
        include/boost/geometry/util/math.hpp
        test/formulas/direct.cpp

    The conflicting files have been updated.

commit 621950329ac5fe633b742403af1136d79c2c30a5
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 28 10:57:21 2018 +0500

    [util] Pass range into math::polyval() instead of std::vector

    This is done to avoid creating a separate container in each
    iteration.

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 3c03c46..3b67359 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -855,18 +855,19 @@ inline NT horner_evaluate(NT x,
 /*
 \brief Evaluate the polynomial.
 */
-template<typename CT>
-inline CT polyval(std::vector<CT> coeff,
+template<typename IteratorType, typename CT>
+inline CT polyval(IteratorType first,
+                  IteratorType last,
                   const CT eps)
 {
-    int N = boost::size(coeff) - 1;
+    int N = std::distance(first, last) - 1;
     int index = 0;

-    CT y = N < 0 ? 0 : coeff[index++];
+    CT y = N < 0 ? 0 : *(first + (index++));

     while (--N >= 0)
     {
-        y = y * eps + coeff[index++];
+        y = y * eps + *(first + (index++));
     }

     return y;
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 4ee6624..d0b5e36 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -642,8 +642,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             int m = Coeffs1::static_size - l - 1;
             mult *= eps;

-            std::vector<CT> coeffs2_slice(coeffs2.begin(), coeffs2.begin() + offset);
-            coeffs1[l] = mult * math::polyval(coeffs2_slice, eps);
+            coeffs1[l] = mult * math::polyval(coeffs2.begin(), coeffs2.begin() + offset, eps);

             offset += m + 1;
         }

commit 1fe3b3bd75d01ec6795f53dcde8eb7cdba2955a4
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 28 10:56:11 2018 +0500

    [util] Pass SeriesOrder as template parameter in evaluate_coeffs_C3x() function

    The coefficient container structs are moved to the
    bottom of the file.

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 17546db..4ee6624 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -30,66 +30,6 @@
 namespace boost { namespace geometry { namespace series_expansion {

     /*
-     The coefficient containers for the series expansions.
-     These structs allow the caller to only know the series order.
-    */
-    template <size_t SeriesOrder, typename CT>
-    struct coeffs_C1 : boost::array<CT, SeriesOrder + 1>
-    {
-        coeffs_C1(CT const& epsilon)
-        {
-            evaluate_coeffs_C1(*this, epsilon);
-        }
-    };
-
-    template <size_t SeriesOrder, typename CT>
-    struct coeffs_C1p : boost::array<CT, SeriesOrder + 1>
-    {
-        coeffs_C1p(CT const& epsilon)
-        {
-            evaluate_coeffs_C1p(*this, epsilon);
-        }
-    };
-
-    template <size_t SeriesOrder, typename CT>
-    struct coeffs_C2 : boost::array<CT, SeriesOrder + 1>
-    {
-        coeffs_C2(CT const& epsilon)
-        {
-            evaluate_coeffs_C2(*this, epsilon);
-        }
-    };
-
-    template <size_t SeriesOrder, typename CT>
-    struct coeffs_C3x : boost::array<CT, (SeriesOrder * (SeriesOrder - 1)) / 2>
-    {
-        coeffs_C3x(CT const& n)
-        {
-            evaluate_coeffs_C3x(*this, SeriesOrder, n);
-        }
-    };
-
-    template <size_t SeriesOrder, typename CT>
-    struct coeffs_C3 : boost::array<CT, SeriesOrder>
-    {
-        coeffs_C3(CT const& n, CT const& epsilon)
-        {
-            coeffs_C3x<SeriesOrder, CT> coeffs_C3x(n);
-
-            evaluate_coeffs_C3(*this, coeffs_C3x, epsilon);
-        }
-    };
-
-    template <size_t SeriesOrder, typename CT>
-    struct coeffs_A3 : boost::array<CT, SeriesOrder>
-    {
-        coeffs_A3(CT const& n)
-        {
-            evaluate_coeffs_A3(*this, n);
-        }
-    };
-
-    /*
      Generate and evaluate the series expansion of the following integral

      I1 = integrate( sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma )
@@ -570,10 +510,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename Coeffs, typename CT>
-    inline void evaluate_coeffs_C3x(Coeffs &c, size_t const& SeriesOrder, CT const& n) {
+    template <size_t SeriesOrder, typename Coeffs, typename CT>
+    inline void evaluate_coeffs_C3x(Coeffs &c, CT const& n) {
         size_t const coeff_size = Coeffs::static_size;
-        BOOST_GEOMETRY_ASSERT(coeff_size == (SeriesOrder * (SeriesOrder - 1)) / 2);
+        size_t const expected_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
+        BOOST_GEOMETRY_ASSERT((coeff_size == expected_size));

         const CT n2 = math::sqr(n);
         switch (SeriesOrder) {
@@ -741,6 +682,66 @@ namespace boost { namespace geometry { namespace series_expansion {
         return 2 * sinx * cosx * k0;
     }

+    /*
+     The coefficient containers for the series expansions.
+     These structs allow the caller to only know the series order.
+    */
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_C1 : boost::array<CT, SeriesOrder + 1>
+    {
+        coeffs_C1(CT const& epsilon)
+        {
+            evaluate_coeffs_C1(*this, epsilon);
+        }
+    };
+
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_C1p : boost::array<CT, SeriesOrder + 1>
+    {
+        coeffs_C1p(CT const& epsilon)
+        {
+            evaluate_coeffs_C1p(*this, epsilon);
+        }
+    };
+
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_C2 : boost::array<CT, SeriesOrder + 1>
+    {
+        coeffs_C2(CT const& epsilon)
+        {
+            evaluate_coeffs_C2(*this, epsilon);
+        }
+    };
+
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_C3x : boost::array<CT, (SeriesOrder * (SeriesOrder - 1)) / 2>
+    {
+        coeffs_C3x(CT const& n)
+        {
+            evaluate_coeffs_C3x<SeriesOrder>(*this, n);
+        }
+    };
+
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_C3 : boost::array<CT, SeriesOrder>
+    {
+        coeffs_C3(CT const& n, CT const& epsilon)
+        {
+            coeffs_C3x<SeriesOrder, CT> coeffs_C3x(n);
+
+            evaluate_coeffs_C3(*this, coeffs_C3x, epsilon);
+        }
+    };
+
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_A3 : boost::array<CT, SeriesOrder>
+    {
+        coeffs_A3(CT const& n)
+        {
+            evaluate_coeffs_A3(*this, n);
+        }
+    };
+
 }}} // namespace boost::geometry::series_expansion

 #endif // BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

commit b86a93bc5a81c066a9f93a986943874bca055cf2
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 28 09:51:25 2018 +0500

    [util] Rename math::normalize_values to math::normalize_unit_vector

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 95e4040..1e6add7 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -112,7 +112,7 @@ public:
         math::sin_cos_degrees<CT>(math::round_angle<CT>(lat1), sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

-        math::normalize_values<CT>(sin_beta1, cos_beta1);
+        math::normalize_unit_vector<CT>(sin_beta1, cos_beta1);

         cos_beta1 = (std::max)(c0, cos_beta1);

@@ -142,7 +142,7 @@ public:

         CT cos_sigma1, cos_omega1;
         cos_sigma1 = cos_omega1 = sin_beta1 != c0 || cos_alpha1 != c0 ? cos_beta1 * cos_alpha1 : c1;
-        math::normalize_values<CT>(sin_sigma1, cos_sigma1);
+        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);
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 866509d..ac1e447 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -387,7 +387,7 @@ TODO: adl1995 - Merge this function with
 formulas/vertex_longitude.hpp
 */
 template<typename ValueType>
-inline void normalize_values(ValueType& x, ValueType& y)
+inline void normalize_unit_vector(ValueType& x, ValueType& y)
 {
     ValueType h = boost::math::hypot(x, y);


commit 9ff4fbe94a9195411005d2a3a6c803b8736fb74b
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 27 10:46:27 2018 +0500

    [util] Use functions from math namespace instead of std

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 74afb49..3c03c46 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -788,14 +788,14 @@ inline void sin_cos_degrees(T const& x,
     // the argument to the range [-45, 45] before converting it to radians.
     T remainder; int quotient;

-    remainder = std::fmod(x, T(360));
-    quotient = int(std::floor(remainder / 90 + T(0.5)));
+    remainder = math::mod(x, T(360));
+    quotient = floor(remainder / 90 + T(0.5));
     remainder -= 90 * quotient;

     // Convert to radians.
     remainder *= d2r<T>();

-    T s = std::sin(remainder), c = std::cos(remainder);
+    T s = sin(remainder), c = cos(remainder);

     switch (unsigned(quotient) & 3U)
     {
@@ -824,7 +824,7 @@ inline T round_angle(T x) {
         return 0;
     }

-    T y = std::abs(x);
+    T y = math::abs(x);

     // z - (z - y) must not be simplified to y.
     y = y < z ? z - (z - y) : y;

commit 9699b4909891d2bbba7a6dd84bda2bf2ec8ef511
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 27 10:34:18 2018 +0500

    [util][formulas] Rename normalize_angle function to normalize_azimuth

    For normalizing longitudes, the normalize_longitude function is
    used instead.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 6de8a26..95e4040 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -80,7 +80,7 @@ public:
         CT const lat1 = la1;

         Azi azi12 = azimuth12;
-        math::normalize_angle<degree, Azi>(azi12);
+        math::normalize_azimuth<degree, Azi>(azi12);

         Dist const dist_c0 = 0;

@@ -114,7 +114,7 @@ public:

         math::normalize_values<CT>(sin_beta1, cos_beta1);

-        cos_beta1 = std::max(math::sqrt(c0), cos_beta1);
+        cos_beta1 = (std::max)(c0, cos_beta1);

         // Obtain alpha 0 by solving the spherical triangle.
         CT const sin_alpha0 = sin_alpha1 * cos_beta1;
@@ -216,8 +216,8 @@ public:

             // Add the longitude at first point to the longitudinal
             // difference and normalize the result.
-            math::normalize_angle<degree, CT>(lon1);
-            math::normalize_angle<degree, CT>(lon12);
+            math::normalize_longitude<degree, CT>(lon1);
+            math::normalize_longitude<degree, CT>(lon12);

             result.lon2 = lon1 + lon12;
         }
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 516bdb3..866509d 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -365,15 +365,15 @@ inline void normalize_longitude(CoordinateType& longitude)
 }

 /*!
-\brief Short utility to normalize an angle on a spheroid
-       normalized in range (-180, 180].
+\brief Short utility to normalize the azimuth on a spheroid
+       in the range (-180, 180].
 \tparam Units The units of the coordindate system in the spheroid
 \tparam CoordinateType The type of the coordinates
 \param angle Angle
 \ingroup utility
 */
 template <typename Units, typename CoordinateType>
-inline void normalize_angle(CoordinateType& angle)
+inline void normalize_azimuth(CoordinateType& angle)
 {
     normalize_longitude<Units, CoordinateType>(angle);
 }

commit c26483b9fcaed93a38811031f207b0d647dd704c
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 26 17:11:35 2018 +0500

    [util] Change static inline to inline in series_expansion.hpp file

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index a679ede..17546db 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -115,7 +115,7 @@ namespace boost { namespace geometry { namespace series_expansion {
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
     */
     template <size_t SeriesOrder, typename CT>
-    static inline CT evaluate_A1(CT eps)
+    inline CT evaluate_A1(CT eps)
     {
         CT eps2 = math::sqr(eps);
         CT t;
@@ -205,7 +205,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename Coeffs, typename CT>
-    static inline void evaluate_coeffs_A3(Coeffs &c, CT const& n)
+    inline void evaluate_coeffs_A3(Coeffs &c, CT const& n)
     {
         switch (int(Coeffs::static_size)) {
         case 0:
@@ -274,7 +274,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename Coeffs, typename CT>
-    static inline void evaluate_coeffs_C1(Coeffs &c, CT const& eps)
+    inline void evaluate_coeffs_C1(Coeffs &c, CT const& eps)
     {
         CT eps2 = math::sqr(eps);
         CT d = eps;
@@ -373,7 +373,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename Coeffs, typename CT>
-    static inline void evaluate_coeffs_C1p(Coeffs& c, CT const& eps)
+    inline void evaluate_coeffs_C1p(Coeffs& c, CT const& eps)
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;
@@ -472,7 +472,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename Coeffs, typename CT>
-    static inline void evaluate_coeffs_C2(Coeffs& c, CT const& eps)
+    inline void evaluate_coeffs_C2(Coeffs& c, CT const& eps)
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;
@@ -571,7 +571,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename Coeffs, typename CT>
-    static inline void evaluate_coeffs_C3x(Coeffs &c, size_t const& SeriesOrder, CT const& n) {
+    inline void evaluate_coeffs_C3x(Coeffs &c, size_t const& SeriesOrder, CT const& n) {
         size_t const coeff_size = Coeffs::static_size;
         BOOST_GEOMETRY_ASSERT(coeff_size == (SeriesOrder * (SeriesOrder - 1)) / 2);

@@ -689,7 +689,7 @@ namespace boost { namespace geometry { namespace series_expansion {
       Elements coeffs1[1] through coeffs1[SeriesOrder - 1] are set.
     */
     template <typename Coeffs1, typename Coeffs2, typename CT>
-    static inline void evaluate_coeffs_C3(Coeffs1 &coeffs1, Coeffs2 &coeffs2, CT const& eps)
+    inline void evaluate_coeffs_C3(Coeffs1 &coeffs1, Coeffs2 &coeffs2, CT const& eps)
     {
         CT mult = 1;
         int offset = 1;
@@ -717,7 +717,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      using Clenshaw summation.
     */
     template <typename CT, typename Coeffs>
-    static inline CT sin_cos_series(CT const& sinx, CT const& cosx, Coeffs const& coeffs)
+    inline CT sin_cos_series(CT const& sinx, CT const& cosx, Coeffs const& coeffs)
     {
         size_t n = Coeffs::static_size - 1;
         size_t index = 0;

commit 4d39eae2b688cadb0ec9581d667568d0fe2bb0e4
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 26 16:53:46 2018 +0500

    [util] Add BOOST_GEOMETRY_ASSERT in series expansion and normalization function

    Modified functions are:
    - evaluate_coeffs_C3x
    - normalize_values

diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 4c432a8..516bdb3 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -391,6 +391,8 @@ inline void normalize_values(ValueType& x, ValueType& y)
 {
     ValueType h = boost::math::hypot(x, y);

+    BOOST_GEOMETRY_ASSERT(h > 0);
+
     x /= h; y /= h;
 }

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 8fb69e7..a679ede 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -24,6 +24,7 @@
 #ifndef BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP
 #define BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

+#include <boost/geometry/core/assert.hpp>
 #include <boost/geometry/util/math.hpp>

 namespace boost { namespace geometry { namespace series_expansion {
@@ -571,6 +572,9 @@ namespace boost { namespace geometry { namespace series_expansion {
     */
     template <typename Coeffs, typename CT>
     static inline void evaluate_coeffs_C3x(Coeffs &c, size_t const& SeriesOrder, CT const& n) {
+        size_t const coeff_size = Coeffs::static_size;
+        BOOST_GEOMETRY_ASSERT(coeff_size == (SeriesOrder * (SeriesOrder - 1)) / 2);
+
         const CT n2 = math::sqr(n);
         switch (SeriesOrder) {
         case 0:

commit 9c96bec2bf8521e720a97674b3b93c626769e702
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 26 13:20:12 2018 +0500

    [util] Avoid passing array size using std::vector

    Previously, the array size was passed in as a
    separate parameter.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 891def0..6de8a26 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -114,7 +114,7 @@ public:

         math::normalize_values<CT>(sin_beta1, cos_beta1);

-        cos_beta1 = std::max(sqrt(std::numeric_limits<CT>::min()), cos_beta1);
+        cos_beta1 = std::max(math::sqrt(c0), cos_beta1);

         // Obtain alpha 0 by solving the spherical triangle.
         CT const sin_alpha0 = sin_alpha1 * cos_beta1;
@@ -122,7 +122,7 @@ public:

         CT const k2 = math::sqr(cos_alpha0) * ep2;

-        CT const epsilon = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);
+        CT const epsilon = k2 / (c2 * (c1 + math::sqrt(c1 + k2)) + k2);

         // Find the coefficients for A1 by computing the
         // series expansion using Horner scehme.
diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 6559910..74afb49 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -856,15 +856,17 @@ inline NT horner_evaluate(NT x,
 \brief Evaluate the polynomial.
 */
 template<typename CT>
-inline CT polyval(int N,
-                  const CT coeff[],
+inline CT polyval(std::vector<CT> coeff,
                   const CT eps)
 {
-    CT y = N < 0 ? 0 : *coeff++;
+    int N = boost::size(coeff) - 1;
+    int index = 0;
+
+    CT y = N < 0 ? 0 : coeff[index++];

     while (--N >= 0)
     {
-        y = y * eps + *coeff++;
+        y = y * eps + coeff[index++];
     }

     return y;
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 31decf6..8fb69e7 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -688,7 +688,7 @@ namespace boost { namespace geometry { namespace series_expansion {
     static inline void evaluate_coeffs_C3(Coeffs1 &coeffs1, Coeffs2 &coeffs2, CT const& eps)
     {
         CT mult = 1;
-        int offset = 0;
+        int offset = 1;

         // l is the index of C3[l].
         for (size_t l = 1; l < Coeffs1::static_size; ++l)
@@ -696,7 +696,10 @@ namespace boost { namespace geometry { namespace series_expansion {
             // Order of polynomial in eps.
             int m = Coeffs1::static_size - l - 1;
             mult *= eps;
-            coeffs1[l] = mult * math::polyval(m, coeffs2.begin() + offset, eps);
+
+            std::vector<CT> coeffs2_slice(coeffs2.begin(), coeffs2.begin() + offset);
+            coeffs1[l] = mult * math::polyval(coeffs2_slice, eps);
+
             offset += m + 1;
         }
         // Post condition: offset == coeffs_C3_size
@@ -719,15 +722,16 @@ namespace boost { namespace geometry { namespace series_expansion {
         index += (n + 1);
         CT ar = 2 * (cosx - sinx) * (cosx + sinx);

+        // If n is odd, get the last element.
         CT k0 = n & 1 ? coeffs[--index] : 0;
         CT k1 = 0;

         // Make n even.
         n /= 2;
         while (n--) {
-          // Unroll loop x 2, so accumulators return to their original role.
-          k1 = ar * k0 - k1 + coeffs[--index];
-          k0 = ar * k1 - k0 + coeffs[--index];
+            // Unroll loop x 2, so accumulators return to their original role.
+            k1 = ar * k0 - k1 + coeffs[--index];
+            k0 = ar * k1 - k0 + coeffs[--index];
         }

         return 2 * sinx * cosx * k0;

commit 06eb057fa99c99587b549e0d507e6f9765e169a9
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 25 18:44:37 2018 +0500

    [formulas] Use assignment operator on the same line for consistency

    Other changes include the update of series expansion function
    calls, as the template arguments are reversed.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 7a4f623..891def0 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -117,10 +117,8 @@ public:
         cos_beta1 = std::max(sqrt(std::numeric_limits<CT>::min()), cos_beta1);

         // Obtain alpha 0 by solving the spherical triangle.
-        CT const sin_alpha0
-            = sin_alpha1 * cos_beta1;
-        CT const cos_alpha0
-            = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_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;

@@ -128,11 +126,10 @@ public:

         // Find the coefficients for A1 by computing the
         // series expansion using Horner scehme.
-        CT const expansion_A1
-            = se::evaluate_series_A1<CT, SeriesOrder>(epsilon);
+        CT const expansion_A1 = se::evaluate_A1<SeriesOrder>(epsilon);

         // Index zero element of coeffs_C1 is unused.
-        se::coeffs_C1<CT, SeriesOrder> const coeffs_C1(epsilon);
+        se::coeffs_C1<SeriesOrder, CT> const coeffs_C1(epsilon);

         // Tau is an integration variable.
         CT const tau12 = distance / (b * (c1 + expansion_A1));
@@ -147,33 +144,27 @@ public:
         cos_sigma1 = cos_omega1 = sin_beta1 != c0 || cos_alpha1 != c0 ? cos_beta1 * cos_alpha1 : c1;
         math::normalize_values<CT>(sin_sigma1, cos_sigma1);

-        CT const B11 =
-            se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
+        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;
+        CT const sin_tau1 = sin_sigma1 * cos_B11 + cos_sigma1 * sin_B11;
+        CT const cos_tau1 = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;

         // Index zero element of coeffs_C1p is unused.
-        se::coeffs_C1p<CT, SeriesOrder> const coeffs_C1p(epsilon);
+        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 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;
+        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_CONDITION(CalcRevAzimuth))
         {
@@ -183,21 +174,19 @@ public:
             result.reverse_azimuth = atan2(sin_alpha2, cos_alpha2);

             // Convert the angle to radians.
-            result.reverse_azimuth /= math::d2r<T>();
+            result.reverse_azimuth /= math::d2r<CT>();
         }

         if (BOOST_GEOMETRY_CONDITION(CalcCoordinates))
         {
             // Find the latitude at the second point.
-            CT const sin_beta2
-                = cos_alpha0 * sin_sigma2;
-            CT const cos_beta2
-                = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);
+            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);

             // Convert the coordinate to radians.
-            result.lat2 /= math::d2r<T>();
+            result.lat2 /= math::d2r<CT>();

             // Find the longitude at the second point.
             CT const sin_omega2 = sin_alpha0 * sin_sigma2;
@@ -206,29 +195,27 @@ public:
             CT const omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
                                      cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);

-            se::coeffs_A3<CT, SeriesOrder> coeffs_A3(n);
+            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<CT, SeriesOrder> coeffs_C3(n, epsilon);
+            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 B31 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);

             CT const lam12 = omega12 + A3c *
                              (sigma12 + (se::sin_cos_series
-                                                           (sin_sigma2,
-                                                            cos_sigma2,
-                                                            coeffs_C3) - B31));
+                                             (sin_sigma2,
+                                              cos_sigma2,
+                                              coeffs_C3) - B31));

             // Convert to radians to get the
             // longitudinal difference.
-            CT lon12 = lam12 / math::d2r<T>();
+            CT lon12 = lam12 / math::d2r<CT>();

             // Add the longitude at first point to the longitudinal
             // difference and normalize the result.
-
             math::normalize_angle<degree, CT>(lon1);
             math::normalize_angle<degree, CT>(lon12);

@@ -239,17 +226,14 @@ public:
         {
             // Evaluate the coefficients for C2.
             // Index zero element of coeffs_C2 is unused.
-            se::coeffs_C2<CT, SeriesOrder> coeffs_C2(epsilon);
+            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 B21 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
+            CT const B22 = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);

             // Find the coefficients for A2 by computing the
             // series expansion using Horner scehme.
-            CT const expansion_A2
-                = se::evaluate_series_A2<CT, SeriesOrder>(epsilon);
+            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);

commit 19f06fa04ec36a3388ab9ae8e5ccffb86d4776a6
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 25 18:39:43 2018 +0500

    [util] Reverse template argument order for series expansion functions

    In some cases, this allows the caller to ignore the CT template
    argument, as it is deduced from the argument list.

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index f9a063c..31decf6 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -32,7 +32,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      The coefficient containers for the series expansions.
      These structs allow the caller to only know the series order.
     */
-    template <typename CT, size_t SeriesOrder>
+    template <size_t SeriesOrder, typename CT>
     struct coeffs_C1 : boost::array<CT, SeriesOrder + 1>
     {
         coeffs_C1(CT const& epsilon)
@@ -41,7 +41,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     };

-    template <typename CT, size_t SeriesOrder>
+    template <size_t SeriesOrder, typename CT>
     struct coeffs_C1p : boost::array<CT, SeriesOrder + 1>
     {
         coeffs_C1p(CT const& epsilon)
@@ -50,7 +50,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     };

-    template <typename CT, size_t SeriesOrder>
+    template <size_t SeriesOrder, typename CT>
     struct coeffs_C2 : boost::array<CT, SeriesOrder + 1>
     {
         coeffs_C2(CT const& epsilon)
@@ -59,7 +59,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     };

-    template <typename CT, size_t SeriesOrder>
+    template <size_t SeriesOrder, typename CT>
     struct coeffs_C3x : boost::array<CT, (SeriesOrder * (SeriesOrder - 1)) / 2>
     {
         coeffs_C3x(CT const& n)
@@ -68,18 +68,18 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     };

-    template <typename T, size_t SeriesOrder>
-    struct coeffs_C3 : boost::array<T, SeriesOrder>
+    template <size_t SeriesOrder, typename CT>
+    struct coeffs_C3 : boost::array<CT, SeriesOrder>
     {
-        coeffs_C3(T const& n, T const& epsilon)
+        coeffs_C3(CT const& n, CT const& epsilon)
         {
-            coeffs_C3x<T, SeriesOrder> coeffs_C3x(n);
+            coeffs_C3x<SeriesOrder, CT> coeffs_C3x(n);

             evaluate_coeffs_C3(*this, coeffs_C3x, epsilon);
         }
     };

-    template <typename CT, size_t SeriesOrder>
+    template <size_t SeriesOrder, typename CT>
     struct coeffs_A3 : boost::array<CT, SeriesOrder>
     {
         coeffs_A3(CT const& n)
@@ -104,7 +104,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      The scale factor A1-1 = mean value of (d/dsigma)I1 - 1

      The expansion above is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_A1 below) is
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac

@@ -113,8 +113,8 @@ namespace boost { namespace geometry { namespace series_expansion {
        sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
     */
-    template <typename CT, size_t SeriesOrder>
-    static inline CT evaluate_series_A1(CT eps)
+    template <size_t SeriesOrder, typename CT>
+    static inline CT evaluate_A1(CT eps)
     {
         CT eps2 = math::sqr(eps);
         CT t;
@@ -154,12 +154,12 @@ namespace boost { namespace geometry { namespace series_expansion {
      The scale factor A2-1 = mean value of (d/dsigma)2 - 1

      The expansion above is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A2 below) is
+     The C++ code (that yields the function evaluate_A2 below) is
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, size_t SeriesOrder>
-    CT evaluate_series_A2(CT const& eps)
+    template <size_t SeriesOrder, typename CT>
+    inline CT evaluate_A2(CT const& eps)
     {
         CT const eps2 = math::sqr(eps);
         CT t;
@@ -363,7 +363,6 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     }

-
     /*
      The coefficients C1p[l] in the Fourier expansion of B1p.


commit cc7e9e05c15410035dafc4d8daabc4efe3e25f5c
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 25 17:59:32 2018 +0500

    [formulas] Use namespace alias se for series_expansion

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index df9aaab..7a4f623 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -41,6 +41,7 @@
 namespace boost { namespace geometry { namespace formula
 {

+namespace se = series_expansion;

 /*!
 \brief The solution of the direct problem of geodesics on latlong coordinates,
@@ -128,10 +129,10 @@ public:
         // Find the coefficients for A1 by computing the
         // series expansion using Horner scehme.
         CT const expansion_A1
-            = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);
+            = se::evaluate_series_A1<CT, SeriesOrder>(epsilon);

         // Index zero element of coeffs_C1 is unused.
-        series_expansion::coeffs_C1<CT, SeriesOrder> const coeffs_C1(epsilon);
+        se::coeffs_C1<CT, SeriesOrder> const coeffs_C1(epsilon);

         // Tau is an integration variable.
         CT const tau12 = distance / (b * (c1 + expansion_A1));
@@ -147,7 +148,7 @@ public:
         math::normalize_values<CT>(sin_sigma1, cos_sigma1);

         CT const B11 =
-            series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
+            se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
         CT const sin_B11 = sin(B11);
         CT const cos_B11 = cos(B11);

@@ -157,10 +158,10 @@ public:
             = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;

         // Index zero element of coeffs_C1p is unused.
-        series_expansion::coeffs_C1p<CT, SeriesOrder> const coeffs_C1p(epsilon);
+        se::coeffs_C1p<CT, SeriesOrder> const coeffs_C1p(epsilon);

         CT const B12 =
-            - series_expansion::sin_cos_series
+            - se::sin_cos_series
                                 (sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
                                  cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
                                  coeffs_C1p);
@@ -205,18 +206,18 @@ public:
             CT const omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
                                      cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);

-            series_expansion::coeffs_A3<CT, SeriesOrder> coeffs_A3(n);
+            se::coeffs_A3<CT, SeriesOrder> coeffs_A3(n);

             CT const A3 = math::horner_evaluate(epsilon, coeffs_A3.begin(), coeffs_A3.end());
             CT const A3c = -f * sin_alpha0 * A3;

-            series_expansion::coeffs_C3<CT, SeriesOrder> coeffs_C3(n, epsilon);
+            se::coeffs_C3<CT, SeriesOrder> coeffs_C3(n, epsilon);

             CT const B31 =
-                series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
+                se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);

             CT const lam12 = omega12 + A3c *
-                             (sigma12 + (series_expansion::sin_cos_series
+                             (sigma12 + (se::sin_cos_series
                                                            (sin_sigma2,
                                                             cos_sigma2,
                                                             coeffs_C3) - B31));
@@ -238,17 +239,17 @@ public:
         {
             // Evaluate the coefficients for C2.
             // Index zero element of coeffs_C2 is unused.
-            series_expansion::coeffs_C2<CT, SeriesOrder> coeffs_C2(epsilon);
+            se::coeffs_C2<CT, SeriesOrder> coeffs_C2(epsilon);

             CT const B21 =
-                series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
+                se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
             CT const B22 =
-                series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);
+                se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);

             // Find the coefficients for A2 by computing the
             // series expansion using Horner scehme.
             CT const expansion_A2
-                = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);
+                = se::evaluate_series_A2<CT, SeriesOrder>(epsilon);

             CT const AB1 = (c1 + expansion_A1) * (B12 - B11);
             CT const AB2 = (c1 + expansion_A2) * (B22 - B21);

commit dedccdbdaeaddc2fb0d27568bbe2dc00b74da316
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 25 17:19:44 2018 +0500

    [formaulas][util] Define coefficient containers for computing series expansions

    The coefficient containers are defined as structs in
    series_expansion.hpp file. They allow the caller to
    compute expansions without specifying the size
    for the output array.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index c844f97..df9aaab 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -131,8 +131,7 @@ public:
             = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);

         // Index zero element of coeffs_C1 is unused.
-        boost::array<CT, SeriesOrder + 1> coeffs_C1;
-        series_expansion::evaluate_coeffs_C1(epsilon, coeffs_C1);
+        series_expansion::coeffs_C1<CT, SeriesOrder> const coeffs_C1(epsilon);

         // Tau is an integration variable.
         CT const tau12 = distance / (b * (c1 + expansion_A1));
@@ -148,7 +147,7 @@ public:
         math::normalize_values<CT>(sin_sigma1, cos_sigma1);

         CT const B11 =
-            series_expansion::sin_cos_series<CT, SeriesOrder + 1>(sin_sigma1, cos_sigma1, coeffs_C1);
+            series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
         CT const sin_B11 = sin(B11);
         CT const cos_B11 = cos(B11);

@@ -158,11 +157,10 @@ public:
             = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;

         // Index zero element of coeffs_C1p is unused.
-        boost::array<CT, SeriesOrder + 1> coeffs_C1p;
-        series_expansion::evaluate_coeffs_C1p(epsilon, coeffs_C1p);
+        series_expansion::coeffs_C1p<CT, SeriesOrder> const coeffs_C1p(epsilon);

         CT const B12 =
-            - series_expansion::sin_cos_series<CT, SeriesOrder + 1>
+            - series_expansion::sin_cos_series
                                 (sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
                                  cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
                                  coeffs_C1p);
@@ -207,26 +205,18 @@ public:
             CT const omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
                                      cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);

-            CT coeffs_A3[SeriesOrder];
-            series_expansion::evaluate_coeffs_A3<CT, SeriesOrder>(n, coeffs_A3);
+            series_expansion::coeffs_A3<CT, SeriesOrder> coeffs_A3(n);

-            CT const A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
+            CT const A3 = math::horner_evaluate(epsilon, coeffs_A3.begin(), coeffs_A3.end());
             CT const A3c = -f * sin_alpha0 * A3;

-            // Compute the size of coefficient array.
-            size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
-            CT coeffs_C3x[coeffs_C3_size];
-            series_expansion::evaluate_coeffs_C3x<CT, SeriesOrder>(n, coeffs_C3x);
-
-            // Evaluate C3 coefficients.
-            CT coeffs_C3[SeriesOrder];
-            series_expansion::evaluate_coeffs_C3<CT, SeriesOrder>(epsilon, coeffs_C3, coeffs_C3x);
+            series_expansion::coeffs_C3<CT, SeriesOrder> coeffs_C3(n, epsilon);

             CT const B31 =
-                series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C3);
+                series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);

             CT const lam12 = omega12 + A3c *
-                             (sigma12 + (series_expansion::sin_cos_series<CT, SeriesOrder>
+                             (sigma12 + (series_expansion::sin_cos_series
                                                            (sin_sigma2,
                                                             cos_sigma2,
                                                             coeffs_C3) - B31));
@@ -248,13 +238,12 @@ public:
         {
             // Evaluate the coefficients for C2.
             // Index zero element of coeffs_C2 is unused.
-            boost::array<CT, SeriesOrder + 1> coeffs_C2;
-            series_expansion::evaluate_coeffs_C2(epsilon, coeffs_C2);
+            series_expansion::coeffs_C2<CT, SeriesOrder> coeffs_C2(epsilon);

             CT const B21 =
-                series_expansion::sin_cos_series<CT, SeriesOrder + 1>(sin_sigma1, cos_sigma1, coeffs_C2);
+                series_expansion::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
             CT const B22 =
-                series_expansion::sin_cos_series<CT, SeriesOrder + 1>(sin_sigma2, cos_sigma2, coeffs_C2);
+                series_expansion::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);

             // Find the coefficients for A2 by computing the
             // series expansion using Horner scehme.
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 492393e..f9a063c 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -29,6 +29,66 @@
 namespace boost { namespace geometry { namespace series_expansion {

     /*
+     The coefficient containers for the series expansions.
+     These structs allow the caller to only know the series order.
+    */
+    template <typename CT, size_t SeriesOrder>
+    struct coeffs_C1 : boost::array<CT, SeriesOrder + 1>
+    {
+        coeffs_C1(CT const& epsilon)
+        {
+            evaluate_coeffs_C1(*this, epsilon);
+        }
+    };
+
+    template <typename CT, size_t SeriesOrder>
+    struct coeffs_C1p : boost::array<CT, SeriesOrder + 1>
+    {
+        coeffs_C1p(CT const& epsilon)
+        {
+            evaluate_coeffs_C1p(*this, epsilon);
+        }
+    };
+
+    template <typename CT, size_t SeriesOrder>
+    struct coeffs_C2 : boost::array<CT, SeriesOrder + 1>
+    {
+        coeffs_C2(CT const& epsilon)
+        {
+            evaluate_coeffs_C2(*this, epsilon);
+        }
+    };
+
+    template <typename CT, size_t SeriesOrder>
+    struct coeffs_C3x : boost::array<CT, (SeriesOrder * (SeriesOrder - 1)) / 2>
+    {
+        coeffs_C3x(CT const& n)
+        {
+            evaluate_coeffs_C3x(*this, SeriesOrder, n);
+        }
+    };
+
+    template <typename T, size_t SeriesOrder>
+    struct coeffs_C3 : boost::array<T, SeriesOrder>
+    {
+        coeffs_C3(T const& n, T const& epsilon)
+        {
+            coeffs_C3x<T, SeriesOrder> coeffs_C3x(n);
+
+            evaluate_coeffs_C3(*this, coeffs_C3x, epsilon);
+        }
+    };
+
+    template <typename CT, size_t SeriesOrder>
+    struct coeffs_A3 : boost::array<CT, SeriesOrder>
+    {
+        coeffs_A3(CT const& n)
+        {
+            evaluate_coeffs_A3(*this, n);
+        }
+    };
+
+    /*
      Generate and evaluate the series expansion of the following integral

      I1 = integrate( sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma )
@@ -53,7 +113,7 @@ namespace boost { namespace geometry { namespace series_expansion {
        sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
     */
-    template <typename CT, std::size_t SeriesOrder>
+    template <typename CT, size_t SeriesOrder>
     static inline CT evaluate_series_A1(CT eps)
     {
         CT eps2 = math::sqr(eps);
@@ -98,7 +158,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, std::size_t SeriesOrder>
+    template <typename CT, size_t SeriesOrder>
     CT evaluate_series_A2(CT const& eps)
     {
         CT const eps2 = math::sqr(eps);
@@ -116,7 +176,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         case 3:
             t = eps2*((-CT(11)*eps2-CT(28))*eps2-CT(192))/CT(256);
             break;
-        case 4:
+        default:
             t = eps2*(eps2*((-CT(375)*eps2-CT(704))*eps2-CT(1792))-CT(12288))/CT(16384);
             break;
         }
@@ -143,11 +203,10 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    // TODO: this produces different results that geographiclib
-    template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_A3(CT const& n, CT c[])
+    template <typename Coeffs, typename CT>
+    static inline void evaluate_coeffs_A3(Coeffs &c, CT const& n)
     {
-        switch (SeriesOrder) {
+        switch (int(Coeffs::static_size)) {
         case 0:
             break;
         case 1:
@@ -192,7 +251,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             c[5] = (-CT(5)*n-CT(3))/CT(128);
             c[6] = -CT(5)/CT(256);
             break;
-        case 8:
+        default:
             c[0] = CT(1);
             c[1] = (n-CT(1))/CT(2);
             c[2] = (n*(CT(3)*n-CT(1))-CT(2))/CT(8);
@@ -213,12 +272,12 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C1(CT eps, boost::array<CT, SeriesOrder>& c)
+    template <typename Coeffs, typename CT>
+    static inline void evaluate_coeffs_C1(Coeffs &c, CT const& eps)
     {
         CT eps2 = math::sqr(eps);
         CT d = eps;
-        switch (c.size() - 1) {
+        switch (int(Coeffs::static_size) - 1) {
         case 0:
             break;
         case 1:
@@ -284,7 +343,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             d *= eps;
             c[7] = -CT(33)*d/CT(14336);
             break;
-        case 8:
+        default:
             c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
             d *= eps;
             c[2] = d*(eps2*(eps2*(CT(7)*eps2-CT(18))+CT(128))-CT(256))/CT(4096);
@@ -304,6 +363,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     }

+
     /*
      The coefficients C1p[l] in the Fourier expansion of B1p.

@@ -312,12 +372,12 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C1p(CT eps, boost::array<CT, SeriesOrder>& c)
+    template <typename Coeffs, typename CT>
+    static inline void evaluate_coeffs_C1p(Coeffs& c, CT const& eps)
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;
-        switch (c.size() - 1) {
+        switch (int(Coeffs::static_size) - 1) {
         case 0:
             break;
         case 1:
@@ -383,7 +443,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             d *= eps;
             c[7] = CT(459485)*d/CT(516096);
             break;
-        case 8:
+        default:
             c[1] = d*(eps2*((CT(9840)-CT(4879)*eps2)*eps2-CT(20736))+CT(36864))/CT(73728);
             d *= eps;
             c[2] = d*(eps2*((CT(120150)-CT(86171)*eps2)*eps2-CT(142080))+CT(115200))/CT(368640);
@@ -411,12 +471,12 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C2(CT const& eps, boost::array<CT, SeriesOrder>& c)
+    template <typename Coeffs, typename CT>
+    static inline void evaluate_coeffs_C2(Coeffs& c, CT const& eps)
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;
-        switch (c.size() - 1) {
+        switch (int(Coeffs::static_size) - 1) {
         case 0:
             break;
         case 1:
@@ -482,7 +542,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             d *= eps;
             c[7] = CT(429)*d/CT(14336);
             break;
-        case 8:
+        default:
             c[1] = d*(eps2*(eps2*(CT(41)*eps2+CT(64))+CT(128))+CT(1024))/CT(2048);
             d *= eps;
             c[2] = d*(eps2*(eps2*(CT(47)*eps2+CT(70))+CT(128))+CT(768))/CT(4096);
@@ -510,8 +570,8 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, size_t SeriesOrder>
-    static inline void evaluate_coeffs_C3x(CT const& n, CT c[]) {
+    template <typename Coeffs, typename CT>
+    static inline void evaluate_coeffs_C3x(Coeffs &c, size_t const& SeriesOrder, CT const& n) {
         const CT n2 = math::sqr(n);
         switch (SeriesOrder) {
         case 0:
@@ -586,7 +646,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             c[19] = (CT(9)-CT(15)*n)/CT(1024);
             c[20] = (CT(44)-CT(99)*n)/CT(8192);
             break;
-        case 8:
+        default:
             c[0] = (CT(1)-n)/CT(4);
             c[1] = (CT(1)-n2)/CT(8);
             c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
@@ -625,19 +685,19 @@ namespace boost { namespace geometry { namespace series_expansion {

       Elements coeffs1[1] through coeffs1[SeriesOrder - 1] are set.
     */
-    template <typename CT, size_t SeriesOrder>
-    static inline void evaluate_coeffs_C3(CT eps, CT coeffs1[], CT coeffs2[])
+    template <typename Coeffs1, typename Coeffs2, typename CT>
+    static inline void evaluate_coeffs_C3(Coeffs1 &coeffs1, Coeffs2 &coeffs2, CT const& eps)
     {
         CT mult = 1;
         int offset = 0;

         // l is the index of C3[l].
-        for (size_t l = 1; l < SeriesOrder; ++l)
+        for (size_t l = 1; l < Coeffs1::static_size; ++l)
         {
             // Order of polynomial in eps.
-            int m = SeriesOrder - l - 1;
+            int m = Coeffs1::static_size - l - 1;
             mult *= eps;
-            coeffs1[l] = mult * math::polyval(m, coeffs2 + offset, eps);
+            coeffs1[l] = mult * math::polyval(m, coeffs2.begin() + offset, eps);
             offset += m + 1;
         }
         // Post condition: offset == coeffs_C3_size
@@ -650,33 +710,10 @@ namespace boost { namespace geometry { namespace series_expansion {

      using Clenshaw summation.
     */
-    template <typename CT, size_t SeriesOrder>
-    static inline CT sin_cos_series(CT sinx, CT cosx, const CT coeffs[])
+    template <typename CT, typename Coeffs>
+    static inline CT sin_cos_series(CT const& sinx, CT const& cosx, Coeffs const& coeffs)
     {
-        size_t n = SeriesOrder;
-
-        // Point to one beyond last element.
-        coeffs += (n + 1);
-        CT ar = 2 * (cosx - sinx) * (cosx + sinx);
-
-        CT k0 = n & 1 ? *--coeffs : 0;
-        CT k1 = 0;
-
-        // Make n even.
-        n /= 2;
-        while (n--) {
-          // Unroll loop x 2, so accumulators return to their original role.
-          k1 = ar * k0 - k1 + *--coeffs;
-          k0 = ar * k1 - k0 + *--coeffs;
-        }
-
-        return 2 * sinx * cosx * k0;
-    }
-
-    template <typename CT, size_t SeriesOrder>
-    static inline CT sin_cos_series(CT sinx, CT cosx, const boost::array<CT, SeriesOrder> coeffs)
-    {
-        size_t n = SeriesOrder - 1;
+        size_t n = Coeffs::static_size - 1;
         size_t index = 0;

         // Point to one beyond last element.
@@ -697,7 +734,6 @@ namespace boost { namespace geometry { namespace series_expansion {
         return 2 * sinx * cosx * k0;
     }

-
 }}} // namespace boost::geometry::series_expansion

 #endif // BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

commit 1972bcda3e5c204f2a0d0bda66239725828f1306
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jun 22 19:26:27 2018 +0500

    [formula][util] Pass boost::array to series expansion functions

    Using boost::array we don't have to explicitly provide
    the template parameters.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 327d9e1..c844f97 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -25,6 +25,8 @@
 #define BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP


+#include <boost/array.hpp>
+
 #include <boost/math/constants/constants.hpp>
 #include <boost/math/special_functions/hypot.hpp>

@@ -129,8 +131,8 @@ public:
             = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);

         // Index zero element of coeffs_C1 is unused.
-        CT coeffs_C1[SeriesOrder + 1];
-        series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);
+        boost::array<CT, SeriesOrder + 1> coeffs_C1;
+        series_expansion::evaluate_coeffs_C1(epsilon, coeffs_C1);

         // Tau is an integration variable.
         CT const tau12 = distance / (b * (c1 + expansion_A1));
@@ -146,7 +148,7 @@ public:
         math::normalize_values<CT>(sin_sigma1, cos_sigma1);

         CT const B11 =
-            series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C1);
+            series_expansion::sin_cos_series<CT, SeriesOrder + 1>(sin_sigma1, cos_sigma1, coeffs_C1);
         CT const sin_B11 = sin(B11);
         CT const cos_B11 = cos(B11);

@@ -156,11 +158,11 @@ public:
             = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;

         // Index zero element of coeffs_C1p is unused.
-        CT coeffs_C1p[SeriesOrder + 1];
-        series_expansion::evaluate_coeffs_C1p<CT, SeriesOrder>(epsilon, coeffs_C1p);
+        boost::array<CT, SeriesOrder + 1> coeffs_C1p;
+        series_expansion::evaluate_coeffs_C1p(epsilon, coeffs_C1p);

         CT const B12 =
-            - series_expansion::sin_cos_series<CT, SeriesOrder>
+            - series_expansion::sin_cos_series<CT, SeriesOrder + 1>
                                 (sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
                                  cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
                                  coeffs_C1p);
@@ -246,13 +248,13 @@ public:
         {
             // Evaluate the coefficients for C2.
             // Index zero element of coeffs_C2 is unused.
-            CT coeffs_C2[SeriesOrder + 1];
-            series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);
+            boost::array<CT, SeriesOrder + 1> coeffs_C2;
+            series_expansion::evaluate_coeffs_C2(epsilon, coeffs_C2);

             CT const B21 =
-                series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C2);
+                series_expansion::sin_cos_series<CT, SeriesOrder + 1>(sin_sigma1, cos_sigma1, coeffs_C2);
             CT const B22 =
-                series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma2, cos_sigma2, coeffs_C2);
+                series_expansion::sin_cos_series<CT, SeriesOrder + 1>(sin_sigma2, cos_sigma2, coeffs_C2);

             // Find the coefficients for A2 by computing the
             // series expansion using Horner scehme.
@@ -263,8 +265,8 @@ public:
             CT const AB2 = (c1 + expansion_A2) * (B22 - B21);
             CT const J12 = (expansion_A1 - expansion_A2) * sigma12 + (AB1 - AB2);

-            CT const dn1 = sqrt(c1 + ep2 * math::sqr(sin_beta1));
-            CT const dn2 = sqrt(c1 + k2 * math::sqr(sin_sigma2));
+            CT const dn1 = math::sqrt(c1 + ep2 * math::sqr(sin_beta1));
+            CT const dn2 = math::sqrt(c1 + k2 * math::sqr(sin_sigma2));

             // Find the reduced length.
             result.reduced_length = b * ((dn2 * (cos_sigma1 * sin_sigma2) -
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index c3e28f1..492393e 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -214,11 +214,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C1(CT eps, CT c[])
+    static inline void evaluate_coeffs_C1(CT eps, boost::array<CT, SeriesOrder>& c)
     {
         CT eps2 = math::sqr(eps);
         CT d = eps;
-        switch (SeriesOrder) {
+        switch (c.size() - 1) {
         case 0:
             break;
         case 1:
@@ -313,11 +313,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C1p(CT eps, CT c[])
+    static inline void evaluate_coeffs_C1p(CT eps, boost::array<CT, SeriesOrder>& c)
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;
-        switch (SeriesOrder) {
+        switch (c.size() - 1) {
         case 0:
             break;
         case 1:
@@ -412,11 +412,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
+    static inline void evaluate_coeffs_C2(CT const& eps, boost::array<CT, SeriesOrder>& c)
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;
-        switch (SeriesOrder) {
+        switch (c.size() - 1) {
         case 0:
             break;
         case 1:
@@ -510,7 +510,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      generated by the following Maxima script:
      geometry/doc/other/maxima/geod.mac
     */
-    template <typename CT, int SeriesOrder>
+    template <typename CT, size_t SeriesOrder>
     static inline void evaluate_coeffs_C3x(CT const& n, CT c[]) {
         const CT n2 = math::sqr(n);
         switch (SeriesOrder) {
@@ -673,6 +673,30 @@ namespace boost { namespace geometry { namespace series_expansion {
         return 2 * sinx * cosx * k0;
     }

+    template <typename CT, size_t SeriesOrder>
+    static inline CT sin_cos_series(CT sinx, CT cosx, const boost::array<CT, SeriesOrder> coeffs)
+    {
+        size_t n = SeriesOrder - 1;
+        size_t index = 0;
+
+        // Point to one beyond last element.
+        index += (n + 1);
+        CT ar = 2 * (cosx - sinx) * (cosx + sinx);
+
+        CT k0 = n & 1 ? coeffs[--index] : 0;
+        CT k1 = 0;
+
+        // Make n even.
+        n /= 2;
+        while (n--) {
+          // Unroll loop x 2, so accumulators return to their original role.
+          k1 = ar * k0 - k1 + coeffs[--index];
+          k0 = ar * k1 - k0 + coeffs[--index];
+        }
+
+        return 2 * sinx * cosx * k0;
+    }
+

 }}} // namespace boost::geometry::series_expansion


commit 6d0720b5ae1419469577229dbb0d7efb763e9b96
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 20 21:32:41 2018 +0500

    [formulas] Ensure reduced length and geodesic scale are computed in canonical form

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 4573641..5b6de69 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -394,6 +394,25 @@ public:
                              std::abs(sin_alpha1 - sin_alpha1b) + (cos_alpha1 - cos_alpha1b) < tol_bisection);

                 }
+                // Store values in temporary vairables.
+                // bool enable_reduced_length = EnableReducedLength;
+                // bool enable_geodesic_scale = EnableGeodesicScale;
+
+                // EnableReducedLength = false;
+                // EnableGeodesicScale = false;
+
+                CT dummy;
+                // Ensure that the reduced length and geodesic scale are computed in
+                // a "canonical" way, with the I2 integral.
+                meridian_length(n, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
+                                                 sin_sigma2, cos_sigma2, dn2,
+                                                 cos_beta1, cos_beta2, s12x,
+                                                 m12x, dummy, result.geodesic_scale,
+                                                 M21, coeffs_C1);
+
+                // Restore values to their previous state.
+                // EnableReducedLength = enable_reduced_length;
+                // EnableGeodesicScale = enable_geodesic_scale;
             }
         }
     }

commit 02577bda556df3cd3e596cc8eb1304ecac032b20
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 20 21:31:18 2018 +0500

    [formulas] Use midpoint of bracket when value lies outside of range

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index f8e5478..4573641 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -93,6 +93,10 @@ public:
         CT const tol0 = std::numeric_limits<CT>::epsilon();
         CT const tol1 = c200 * tol0;
         CT const tol2 = sqrt(tol0);
+
+        // Check on bisection interval.
+        CT const tol_bisection = tol0 * tol2;
+
         CT const etol2 = c0_1 * tol2 /
             sqrt(std::max(c0_001, std::abs(f)) * std::min(c1, c1 - f / c2) / c2);

@@ -373,6 +377,22 @@ public:
                             continue;
                         }
                     }
+
+                    // Either dv was not positive or updated value was outside legal
+                    // range. Use the midpoint of the bracket as the next estimate.
+                    // This mechanism is not needed for the WGS84 ellipsoid, but it does
+                    // catch problems with more eeccentric ellipsoids. Its efficacy is
+                    // such for the WGS84 test set with the starting guess set to alp1 =
+                    // 90deg:
+                    // the WGS84 test set: mean = 5.21, sd = 3.93, max = 24
+                    // WGS84 and random input: mean = 4.74, sd = 0.99
+                    sin_alpha1 = (sin_alpha1a + sin_alpha1b) / c2;
+                    cos_alpha1 = (cos_alpha1a + cos_alpha1b) / c2;
+                    math::normalize_values<CT>(sin_alpha1, cos_alpha1);
+                    tripn = false;
+                    tripb = (std::abs(sin_alpha1a - sin_alpha1) + (cos_alpha1a - cos_alpha1) < tol_bisection ||
+                             std::abs(sin_alpha1 - sin_alpha1b) + (cos_alpha1 - cos_alpha1b) < tol_bisection);
+
                 }
             }
         }

commit ead0b188f915bd987eb2c44770e3dcf29e94473c
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 19 20:21:05 2018 +0500

    [formulas] Update bracketing values in Newton's method

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 6d459ab..f8e5478 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -60,7 +60,9 @@ public:
     static CT constexpr c3 = 3;
     static CT constexpr c4 = 4;
     static CT constexpr c6 = 6;
+    static CT constexpr c8 = 8;
     static CT constexpr c10 = 10;
+    static CT constexpr c16 = 16;
     static CT constexpr c20 = 20;
     static CT constexpr c90 = 90;
     static CT constexpr c180 = 180;
@@ -331,6 +333,46 @@ public:
                                     iteration < max_iterations,
                                     dv, f, n, ep2, tiny, coeffs_C1);

+                    // Reversed test to allow escape with NaNs.
+                    if (tripb || !(std::abs(v) >= (tripn ? c8 : c1) * tol0))
+                        break;
+
+                    // Update bracketing values.
+                    if (v > c0 && (iteration > max_iterations ||
+                        cos_alpha1 / sin_alpha1 > cos_alpha1b / sin_alpha1b))
+                    {
+                        sin_alpha1b = sin_alpha1;
+                        cos_alpha1b = cos_alpha1;   
+                    }
+                    else if (v < c0 && (iteration > max_iterations ||
+                             cos_alpha1 / sin_alpha1 < cos_alpha1a / sin_alpha1a))
+                    {
+                        sin_alpha1a = sin_alpha1;
+                        cos_alpha1a = cos_alpha1;
+                    }
+                    if (iteration < max_iterations && dv > c0)
+                    {
+                        CT diff_alpha1 = -v / dv;
+
+                        CT sin_diff_alpha1 = sin(diff_alpha1);
+                        CT cos_diff_alpha1 = cos(diff_alpha1);
+
+                        CT nsin_alpa1 = sin_alpha1 * cos_diff_alpha1 +
+                                        cos_alpha1 * sin_diff_alpha1;
+
+                        if (nsin_alpa1 > c0 && std::abs(diff_alpha1) < math::pi<CT>())
+                        {
+                            cos_alpha1 = cos_alpha1 * cos_diff_alpha1 - sin_alpha1 * sin_diff_alpha1;
+                            sin_alpha1 = nsin_alpa1;
+                            math::normalize_values<CT>(sin_alpha1, cos_alpha1);
+
+                            // In some regimes we don't get quadratic convergence because
+                            // slope -> 0. So use convergence conditions based on epsilon
+                            // instead of sqrt(epsilon).
+                            tripn = std::abs(v) <= c16 * tol0;
+                            continue;
+                        }
+                    }
                 }
             }
         }

commit 2ddad45616ec884589235b07fe81d4043a785f3a
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 19 18:08:23 2018 +0500

    [util] Move difference_angle function to normalize_spheroidal_coordinates.hpp

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index e4ebb65..6d459ab 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -15,6 +15,7 @@

 #include <boost/geometry/util/math.hpp>
 #include <boost/geometry/util/series_expansion.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>

 #include <boost/geometry/formulas/flattening.hpp>
 #include <boost/geometry/formulas/result_inverse.hpp>
@@ -155,14 +156,14 @@ public:
         math::sin_cos_degrees(lat1, sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

-        math::normalize(sin_beta1, cos_beta1);
+        math::normalize_values<CT>(sin_beta1, cos_beta1);
         cos_beta1 = std::max(tiny, cos_beta1);

         CT sin_beta2, cos_beta2;
         math::sin_cos_degrees(lat2, sin_beta2, cos_beta2);
         sin_beta2 *= one_minus_f;

-        math::normalize(sin_beta2, cos_beta2);
+        math::normalize_values<CT>(sin_beta2, cos_beta2);
         cos_beta2 = std::max(tiny, cos_beta2);

         // If cos_beta1 < -sin_beta1, then cos_beta2 - cos_beta1 is a
@@ -329,6 +330,7 @@ public:
                                     eps, diff_omega12,
                                     iteration < max_iterations,
                                     dv, f, n, ep2, tiny, coeffs_C1);
+
                 }
             }
         }
@@ -588,7 +590,7 @@ public:
         // Apply sanity check on starting guess. Backwards check allows NaN through.
         if (!(sin_alpha1 <= c0))
         {
-          math::normalize<CT>(sin_alpha1, cos_alpha1);
+          math::normalize_values<CT>(sin_alpha1, cos_alpha1);
         }
         else
         {
@@ -707,7 +709,7 @@ public:
         cos_sigma1 = cos_omega1 =
             cos_alpha1 * cos_beta1;

-        math::normalize(sin_sigma1, cos_sigma1);
+        math::normalize_values<CT>(sin_sigma1, cos_sigma1);

         // Enforce symmetries in the case abs(beta2) = -beta1.
         // Otherwise, this can yield singularities in the Newton iteration.
@@ -729,7 +731,7 @@ public:
         cos_sigma2 = cos_omega2 =
             cos_alpha2 * cos_beta2;

-        math::normalize(sin_sigma2, cos_sigma2);
+        math::normalize_values<CT>(sin_sigma2, cos_sigma2);

         // sig12 = sig2 - sig1, limit to [0, pi].
         sigma12 = atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 42d910f..110fbd7 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -867,24 +867,6 @@ inline T sum_error(T u, T v, T& t)
 }

 /*!
-\brief The exact difference of two angles reduced to
-       (&minus;180&deg;, 180&deg;].
-*/
-template<typename T>
-inline T difference_angle(T x, T y, T& e)
-{
-    T t, d = normalize_angle(sum_error(std::remainder(-x, T(360)),
-                                       std::remainder(y, T(360)), t));
-
-    // Here y - x = d + t (mod 360), exactly, where d is in (-180,180] and
-    // abs(t) <= eps (eps = 2^-45 for doubles).  The only case where the
-    // addition of t takes the result outside the range (-180,180] is d = 180
-    // and t > 0.  The case, d = -180 + eps, t = -eps, can't happen, since
-    // sum_error would have returned the exact result in such a case (i.e., given t = 0).
-    return sum_error(d == 180 && t > 0 ? -180 : d, t, e);
-}
-
-/*!
 \brief Evaluate the polynomial in x using Horner's method.
 */
 // TODO: adl1995 - Merge these functions with formulas/area_formulas.hpp
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 71215b3..77c8b19 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -385,8 +385,9 @@ inline void normalize_angle(CoordinateType& angle)
 template<typename T>
 inline T difference_angle(T x, T y, T& e)
 {
-    T t, d = normalize_angle(math::sum_error(std::remainder(-x, T(360)),
-                                             std::remainder(y, T(360)), t));
+    T t, d = math::sum_error(std::remainder(-x, T(360)), std::remainder(y, T(360)), t);
+
+    normalize_angle<degree, T>(d);

     // Here y - x = d + t (mod 360), exactly, where d is in (-180,180] and
     // abs(t) <= eps (eps = 2^-45 for doubles).  The only case where the

commit 490b4df9434d45afb49ed081e3bf3eb251e55e07
Merge: 06fc06d 78411f6
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 19 10:05:16 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

    Conflicts (resolved):
        include/boost/geometry/util/math.hpp

commit 78411f63c8d552189c34bb3c5589696c9c4f6c8a
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jun 15 21:42:56 2018 +0500

    [doc][util][formulas][test] Add copyright information in updated files

diff --git a/doc/other/maxima/geod.mac b/doc/other/maxima/geod.mac
index 229e949..b0b052b 100644
--- a/doc/other/maxima/geod.mac
+++ b/doc/other/maxima/geod.mac
@@ -1,10 +1,27 @@
 /*
-Compute the series expansions for the ellipsoidal geodesic problem.
+Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.
+
+Use, modification and distribution is subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt)
+
+This file is converted from GeographicLib, https://geographiclib.sourceforge.io
+GeographicLib is originally written by Charles Karney.
+
+Author: Charles Karney (2008-2017)
+
+Last updated version of GeographicLib: 1.49
+
+Original copyright notice:

 Copyright (c) Charles Karney (2009-2015) <charles@karney.com> and
-licensed under the MIT/X11 License.  For more information, see
+licensed under the MIT/X11 License. For more information, see
 https://geographiclib.sourceforge.io

+Compute the series expansions for the ellipsoidal geodesic problem.
+
 References:

    Charles F. F. Karney,
diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 5e0f2f5..327d9e1 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -1,11 +1,26 @@
 // Boost.Geometry

-// Contributed and/or modified by Adeel Ahmad.
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt)

+// This file is converted from GeographicLib, https://geographiclib.sourceforge.io
+// GeographicLib is originally written by Charles Karney.
+
+// Author: Charles Karney (2008-2017)
+
+// Last updated version of GeographicLib: 1.49
+
+// Original copyright notice:
+
+// Copyright (c) Charles Karney (2008-2017) <charles@karney.com> and licensed
+// under the MIT/X11 License. For more information, see
+// https://geographiclib.sourceforge.io
+
 #ifndef BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
 #define BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 2ae2793..6559910 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -9,6 +9,7 @@

 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program

 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 04de04d..4c432a8 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -6,6 +6,7 @@

 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program

 // Licensed under the Boost Software License version 1.0.
 // http://www.boost.org/users/license.html
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 4bd09a1..c3e28f1 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -1,11 +1,26 @@
 // Boost.Geometry

-// Contributed and/or modified by Adeel Ahmad.
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt)

+// This file is converted from GeographicLib, https://geographiclib.sourceforge.io
+// GeographicLib is originally written by Charles Karney.
+
+// Author: Charles Karney (2008-2017)
+
+// Last updated version of GeographicLib: 1.49
+
+// Original copyright notice:
+
+// Copyright (c) Charles Karney (2008-2017) <charles@karney.com> and licensed
+// under the MIT/X11 License. For more information, see
+// https://geographiclib.sourceforge.io
+
 #ifndef BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP
 #define BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

diff --git a/test/formulas/direct.cpp b/test/formulas/direct.cpp
index 9cd4bdf..5a7e5d9 100644
--- a/test/formulas/direct.cpp
+++ b/test/formulas/direct.cpp
@@ -5,6 +5,7 @@
 // Copyright (c) 2016 Oracle and/or its affiliates.

 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
diff --git a/test/formulas/direct_cases_antipodal.hpp b/test/formulas/direct_cases_antipodal.hpp
index ad5db5d..c6ba852 100644
--- a/test/formulas/direct_cases_antipodal.hpp
+++ b/test/formulas/direct_cases_antipodal.hpp
@@ -1,7 +1,9 @@
 // Boost.Geometry
 // Unit Test

-// Contributed and/or modified by Adeel Ahmad.
+// Copyright (c) 2018 Adeel Ahmad, Islamabad, Pakistan.
+
+// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program.

 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at

commit 2c7a29e7dcfe71ec5a5a04f2d442477860e798d1
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jun 15 18:52:30 2018 +0500

    [formulas][util] Improve code formatting to conform with guidelines

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 5e382f0..5e0f2f5 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -64,7 +64,7 @@ public:
         Azi azi12 = azimuth12;
         math::normalize_angle<degree, Azi>(azi12);

-        CT const dist_c0 = 0;
+        Dist const dist_c0 = 0;

         if (math::equals(distance, dist_c0) || distance < dist_c0)
         {
@@ -73,6 +73,7 @@ public:
             return result;
         }

+        CT const c0 = 0;
         CT const c1 = 1;
         CT const c2 = 2;

@@ -126,7 +127,7 @@ public:
         CT sin_omega1 = sin_alpha0 * sin_beta1;

         CT cos_sigma1, cos_omega1;
-        cos_sigma1 = cos_omega1 = sin_beta1 != 0 || cos_alpha1 != 0 ? cos_beta1 * cos_alpha1 : 1;
+        cos_sigma1 = cos_omega1 = sin_beta1 != c0 || cos_alpha1 != c0 ? cos_beta1 * cos_alpha1 : c1;
         math::normalize_values<CT>(sin_sigma1, cos_sigma1);

         CT const B11 =
diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 6ba51b2..2ae2793 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -779,7 +779,9 @@ inline Result rounding_cast(T const& v)
       &minus;0 is returned.
 */
 template<typename T>
-inline void sin_cos_degrees(T const& x, T & sinx, T & cosx)
+inline void sin_cos_degrees(T const& x,
+                            T & sinx,
+                            T & cosx)
 {
     // In order to minimize round-off errors, this function exactly reduces
     // the argument to the range [-45, 45] before converting it to radians.
@@ -836,8 +838,8 @@ inline T round_angle(T x) {
 // i.e. place them in one file.
 template <typename NT, typename IteratorType>
 inline NT horner_evaluate(NT x,
-                                 IteratorType begin,
-                                 IteratorType end)
+                          IteratorType begin,
+                          IteratorType end)
 {
     NT result(0);
     IteratorType it = end;
@@ -854,8 +856,8 @@ inline NT horner_evaluate(NT x,
 */
 template<typename CT>
 inline CT polyval(int N,
-                         const CT coeff[],
-                         const CT eps)
+                  const CT coeff[],
+                  const CT eps)
 {
     CT y = N < 0 ? 0 : *coeff++;

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index e3dc826..4bd09a1 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -636,9 +636,7 @@ namespace boost { namespace geometry { namespace series_expansion {
      using Clenshaw summation.
     */
     template <typename CT, size_t SeriesOrder>
-    static inline CT sin_cos_series(CT sinx,
-                                    CT cosx,
-                                    const CT coeffs[])
+    static inline CT sin_cos_series(CT sinx, CT cosx, const CT coeffs[])
     {
         size_t n = SeriesOrder;


commit 318a61dce0a1fc9256275ff97254d6264fba10c1
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jun 15 18:15:03 2018 +0500

    [formulas] Use updated functions for normalization

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index e64e1da..5e382f0 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -15,6 +15,7 @@

 #include <boost/geometry/util/math.hpp>
 #include <boost/geometry/util/series_expansion.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>

 #include <boost/geometry/formulas/flattening.hpp>
 #include <boost/geometry/formulas/result_direct.hpp>
@@ -57,9 +58,11 @@ public:
     {
         result_type result;

-        CT const lon1 = lo1;
+        CT lon1 = lo1;
         CT const lat1 = la1;
-        Azi const azi12 = math::normalize_angle<CT>(azimuth12);
+
+        Azi azi12 = azimuth12;
+        math::normalize_angle<degree, Azi>(azi12);

         CT const dist_c0 = 0;

@@ -90,7 +93,8 @@ public:
         math::sin_cos_degrees<CT>(math::round_angle<CT>(lat1), sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

-        math::normalize<CT>(sin_beta1, cos_beta1);
+        math::normalize_values<CT>(sin_beta1, cos_beta1);
+
         cos_beta1 = std::max(sqrt(std::numeric_limits<CT>::min()), cos_beta1);

         // Obtain alpha 0 by solving the spherical triangle.
@@ -123,7 +127,7 @@ public:

         CT cos_sigma1, cos_omega1;
         cos_sigma1 = cos_omega1 = sin_beta1 != 0 || cos_alpha1 != 0 ? cos_beta1 * cos_alpha1 : 1;
-        math::normalize<CT>(sin_sigma1, cos_sigma1);
+        math::normalize_values<CT>(sin_sigma1, cos_sigma1);

         CT const B11 =
             series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C1);
@@ -211,12 +215,15 @@ public:

             // Convert to radians to get the
             // longitudinal difference.
-            CT const lon12 = lam12 / math::d2r<T>();
+            CT lon12 = lam12 / math::d2r<T>();

             // Add the longitude at first point to the longitudinal
             // difference and normalize the result.
-            result.lon2 = math::normalize_angle(math::normalize_angle(lon1) +
-                                                math::normalize_angle(lon12));
+
+            math::normalize_angle<degree, CT>(lon1);
+            math::normalize_angle<degree, CT>(lon12);
+
+            result.lon2 = lon1 + lon12;
         }

         if (BOOST_GEOMETRY_CONDITION(CalcQuantities))
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 7a0e8e4..04de04d 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -383,7 +383,7 @@ inline void normalize_angle(CoordinateType& angle)
 \param x Value x
 \param y Value y
 TODO: adl1995 - Merge this function with
-formulas/vertex_latitude.hpp
+formulas/vertex_longitude.hpp
 */
 template<typename ValueType>
 inline void normalize_values(ValueType& x, ValueType& y)

commit d591d7a7bb7aa5d921f53e14e1198fb698cd2558
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Fri Jun 15 18:08:39 2018 +0500

    [util] Use existing normalize_spheroidal_coordinates class for normalizing an angle

    - This should normalize the given angle in range (-180, 180].
    - The function normalize is also moved from math.hpp to
    normalize_spheroidal_coordinates.hpp where it is renamed
    to normalize_values

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index e0ab1c8..6ba51b2 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -829,29 +829,6 @@ inline T round_angle(T x) {
     return x < 0 ? -y : y;
 }

-/*!
-\brief Normalize the given values.
-*/
-template<typename T>
-inline void normalize(T& x, T& y)
-{
-    T h = boost::math::hypot(x, y);
-
-    x /= h; y /= h;
-}
-
-
-/*!
-\brief Normalize a given angle.
-*/
-template<typename T>
-    inline T normalize_angle(T x)
-{
-    T y = std::fmod(x, T(360));
-
-    return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360);
-}
-
 /*
 \brief Evaluate the polynomial in x using Horner's method.
 */
diff --git a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 785e52a..7a0e8e4 100644
--- a/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/include/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -363,6 +363,35 @@ inline void normalize_longitude(CoordinateType& longitude)
         >::apply(longitude);
 }

+/*!
+\brief Short utility to normalize an angle on a spheroid
+       normalized in range (-180, 180].
+\tparam Units The units of the coordindate system in the spheroid
+\tparam CoordinateType The type of the coordinates
+\param angle Angle
+\ingroup utility
+*/
+template <typename Units, typename CoordinateType>
+inline void normalize_angle(CoordinateType& angle)
+{
+    normalize_longitude<Units, CoordinateType>(angle);
+}
+
+/*!
+\brief Normalize the given values.
+\tparam ValueType The type of the values
+\param x Value x
+\param y Value y
+TODO: adl1995 - Merge this function with
+formulas/vertex_latitude.hpp
+*/
+template<typename ValueType>
+inline void normalize_values(ValueType& x, ValueType& y)
+{
+    ValueType h = boost::math::hypot(x, y);
+
+    x /= h; y /= h;
+}

 /*!
 \brief Short utility to calculate difference between two longitudes

commit 06fc06dc7faeb9008721a8b6b5120c47e0eaf312
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 14 13:42:44 2018 +0500

    [formulas] Add function lambda12 to regulate bracketing range in Karney inverse

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 4e988b3..e4ebb65 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -59,6 +59,8 @@ public:
     static CT constexpr c3 = 3;
     static CT constexpr c4 = 4;
     static CT constexpr c6 = 6;
+    static CT constexpr c10 = 10;
+    static CT constexpr c20 = 20;
     static CT constexpr c90 = 90;
     static CT constexpr c180 = 180;
     static CT constexpr c200 = 200;
@@ -274,13 +276,61 @@ public:
             // Find the starting point for Newton's method.
             CT dnm;
             sigma12 = newton_start(sin_beta1, cos_beta1, dn1,
-                                 sin_beta2, cos_beta2, dn2,
-                                 lam12, sin_lam12, cos_lam12,
-                                 sin_alpha1, cos_alpha1,
-                                 sin_alpha2, cos_alpha2,
-                                 dnm, coeffs_C1, ep2,
-                                 tol1, tol2, etol2,
-                                 n, f);
+                                   sin_beta2, cos_beta2, dn2,
+                                   lam12, sin_lam12, cos_lam12,
+                                   sin_alpha1, cos_alpha1,
+                                   sin_alpha2, cos_alpha2,
+                                   dnm, coeffs_C1, ep2,
+                                   tol1, tol2, etol2,
+                                   n, f);
+
+            if (sigma12 >= c0)
+            {
+                // Short lines case (newton_start sets salp2, calp2, dnm)
+                s12x = sigma12 * b * dnm;
+                m12x = math::sqr(dnm) * b * sin(sigma12 / dnm);
+                if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+                {
+                    result.geodesic_scale = cos(sigma12 / dnm);
+                }
+
+                // Convert to radians.
+                a12 = sigma12 / math::d2r<CT>();
+                omega12 = lam12 / (one_minus_f * dnm);
+            }
+            else
+            {
+                // Apply the Newton's method.
+                CT sin_sigma1 = c0, cos_sigma1 = c0;
+                CT sin_sigma2 = c0, cos_sigma2 = c0;
+                CT eps = c0, diff_omega12 = c0;
+
+                // Bracketing range.
+                CT sin_alpha1a = tiny, cos_alpha1a = c1;
+                CT sin_alpha1b = tiny, cos_alpha1b = -c1;
+
+                size_t iteration = 0;
+                size_t max_iterations = 20 + std::numeric_limits<size_t>::digits + 10;
+
+                for (bool tripn = false, tripb = false;
+                     iteration < max_iterations;
+                     ++iteration)
+                {
+                    CT dv;
+
+                    CT v = lambda12(sin_beta1, cos_beta1, dn1,
+                                    sin_beta2, cos_beta2, dn2,
+                                    sin_alpha1, cos_alpha1,
+                                    sin_lam12, cos_lam12,
+                                    sin_alpha2, cos_alpha2,
+                                    sigma12,
+                                    sin_sigma1, cos_sigma1,
+                                    sin_sigma2, cos_sigma2,
+                                    eps, diff_omega12,
+                                    iteration < max_iterations,
+                                    dv, f, n, ep2, tiny, coeffs_C1);
+                }
+            }
         }
     }

@@ -550,7 +600,7 @@ public:
     }

     /*
-     Solve the astroid problem using this equation:
+     Solve the astroid problem using the equation:
      κ4 + 2κ3 + (1 − x2 − y 2 )κ2 − 2y 2 κ − y 2 = 0.

      For details, please refer to Eq. (65) in,
@@ -615,11 +665,132 @@ public:
         else // q == 0 && r <= 0
         {
             // y = 0 with |x| <= 1. Handle this case directly.
-            // For y small, positive root is k = abs(y)/sqrt(1-x^2)
+            // For y small, positive root is k = abs(y)/sqrt(1-x^2).
             k = c0;
         }
         return k;
     }
+
+    static inline CT lambda12(CT sin_beta1, CT cos_beta1, CT dn1,
+                              CT sin_beta2, CT cos_beta2, CT dn2,
+                              CT sin_alpha1, CT cos_alpha1,
+                              CT sin_lam120, CT cos_lam120,
+                              CT& sin_alpha2, CT& cos_alpha2,
+                              CT& sigma12,
+                              CT& sin_sigma1, CT& cos_sigma1,
+                              CT& sin_sigma2, CT& cos_sigma2,
+                              CT& eps, CT& diff_omega12,
+                              bool diffp, CT& diff_lam12,
+                              CT f, CT n, CT ep2, CT tiny,
+                              CT coeffs_C1[])
+    {
+        CT const one_minus_f = c1 - f;
+
+        if (sin_beta1 == c0 && cos_alpha1 == c0)
+        {
+            // Break degeneracy of equatorial line.
+            cos_alpha1 = -tiny;
+        }
+
+        CT sin_alpha0 = sin_alpha1 * cos_beta1;
+        CT cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);
+
+        CT sin_omega1, cos_omega1;
+        CT sin_omega2, cos_omega2;
+        CT sin_omega12, cos_omega12;
+
+        CT lam12;
+
+        sin_sigma1 = sin_beta1;
+        sin_omega1 = sin_alpha0 * sin_beta1;
+
+        cos_sigma1 = cos_omega1 =
+            cos_alpha1 * cos_beta1;
+
+        math::normalize(sin_sigma1, cos_sigma1);
+
+        // Enforce symmetries in the case abs(beta2) = -beta1.
+        // Otherwise, this can yield singularities in the Newton iteration.
+
+        // sin(alpha2) * cos(beta2) = sin(alpha0).
+        sin_alpha2 = cos_beta2 != cos_beta1 ?
+            sin_alpha0 / cos_beta2 : sin_alpha1;
+
+        cos_alpha2 = cos_beta2 != cos_beta1 || std::abs(sin_beta2) != -sin_beta1 ?
+            sqrt(math::sqr(cos_alpha1 * cos_beta1) +
+                (cos_beta1 < -sin_beta1 ?
+                    (cos_beta2 - cos_beta1) * (cos_beta1 + cos_beta2) :
+                    (sin_beta1 - sin_beta2) * (sin_beta1 + sin_beta2))) / cos_beta2 :
+            std::abs(cos_alpha1);
+
+        sin_sigma2 = sin_beta2;
+        sin_omega2 = sin_alpha0 * sin_beta2;
+
+        cos_sigma2 = cos_omega2 =
+            cos_alpha2 * cos_beta2;
+
+        math::normalize(sin_sigma2, cos_sigma2);
+
+        // sig12 = sig2 - sig1, limit to [0, pi].
+        sigma12 = atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
+                                cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);
+
+        // omg12 = omg2 - omg1, limit to [0, pi].
+        sin_omega12 = std::max(c0, cos_omega1 * sin_omega2 - sin_omega1 * cos_omega2);
+        cos_omega12 = cos_omega1 * cos_omega2 + sin_omega1 * sin_omega2;
+
+        // eta = omg12 - lam120.
+        CT eta = atan2(sin_omega12 * cos_lam120 - cos_omega12 * sin_lam120,
+                       cos_omega12 * cos_lam120 + sin_omega12 * sin_lam120);
+
+        CT B312;
+        CT k2 = math::sqr(cos_alpha0) * ep2;
+
+        eps = k2 / (c2 * (c1 + std::sqrt(c1 + k2)) + k2);
+
+        // Compute the size of coefficient array.
+        size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
+        CT coeffs_C3x[coeffs_C3_size];
+        series_expansion::evaluate_coeffs_C3x<CT, SeriesOrder>(n, coeffs_C3x);
+
+        // Evaluate C3 coefficients.
+        CT coeffs_C3[SeriesOrder];
+        series_expansion::evaluate_coeffs_C3<CT, SeriesOrder>(eps, coeffs_C3, coeffs_C3x);
+
+        B312 = series_expansion::sin_cos_series<CT, SeriesOrder>
+                   (sin_sigma2, cos_sigma2, coeffs_C3) -
+               series_expansion::sin_cos_series<CT, SeriesOrder>
+                   (sin_sigma1, cos_sigma1, coeffs_C3);
+
+        CT coeffs_A3[SeriesOrder];
+        series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
+
+        CT const A3 = math::horner_evaluate(eps, coeffs_A3, coeffs_A3 + SeriesOrder);
+
+        diff_omega12 = -f * A3 * sin_alpha0 * (sigma12 + B312);
+        lam12 = eta + diff_omega12;
+
+        if (diffp)
+        {
+            if (cos_alpha2 == c0)
+            {
+                diff_lam12 = - c2 * one_minus_f * dn1 / sin_beta1;
+            }
+            else
+            {
+                CT dummy;
+                meridian_length(n, eps, sigma12, sin_sigma1, cos_sigma1, dn1,
+                                                 sin_sigma2, cos_sigma2, dn2,
+                                                 cos_beta1, cos_beta2, dummy,
+                                                 diff_lam12, dummy, dummy,
+                                                 dummy, coeffs_C1);
+
+                diff_lam12 *= one_minus_f / (cos_alpha2 * cos_beta2);
+            }
+        }
+        return lam12;
+    }
+
 };

 }}} // namespace boost::geometry::formula

commit 642a84c551d78eb9973070d23fb7109694093741
Merge: 2aac402 943672b
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 14 13:34:29 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

commit 943672bd3a7b2f6422cfa995ac94a04c73027c0e
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 14 13:27:33 2018 +0500

    [formulas] Use template argument CT instead of double

    This change is made in Karney's direct method.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index de101e9..e64e1da 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -186,7 +186,7 @@ public:
                                      cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);

             CT coeffs_A3[SeriesOrder];
-            series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
+            series_expansion::evaluate_coeffs_A3<CT, SeriesOrder>(n, coeffs_A3);

             CT const A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
             CT const A3c = -f * sin_alpha0 * A3;
@@ -194,11 +194,11 @@ public:
             // Compute the size of coefficient array.
             size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
             CT coeffs_C3x[coeffs_C3_size];
-            series_expansion::evaluate_coeffs_C3x<double, SeriesOrder>(n, coeffs_C3x);
+            series_expansion::evaluate_coeffs_C3x<CT, SeriesOrder>(n, coeffs_C3x);

             // Evaluate C3 coefficients.
             CT coeffs_C3[SeriesOrder];
-            series_expansion::evaluate_coeffs_C3<double, SeriesOrder>(epsilon, coeffs_C3, coeffs_C3x);
+            series_expansion::evaluate_coeffs_C3<CT, SeriesOrder>(epsilon, coeffs_C3, coeffs_C3x);

             CT const B31 =
                 series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C3);

commit 2aac4027aa514f3f9ea5ad4c883c12404d85d351
Merge: 15d5cd6 d11b716
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 14 11:54:09 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

commit d11b7160b2460f78830844c6892af2a94f6771a6
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 13 12:26:56 2018 +0500

    [formulas] Fix calculation of t for finding the geodesic scale (M12)

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 6f63cb1..de101e9 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -250,7 +250,7 @@ public:

             // Find the geodesic scale.
             CT const t = k2 * (sin_sigma2 - sin_sigma1) *
-                              (sin_sigma2 * sin_sigma1) / (dn1 + dn2);
+                              (sin_sigma2 + sin_sigma1) / (dn1 + dn2);

             result.geodesic_scale = cos_sigma12 +
                                     (t * sin_sigma2 - cos_sigma2 * J12) *

commit 15d5cd628100ef4f605b5b9ae5ee7aa484f33af8
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 12 18:32:26 2018 +0500

    [formulas] Perform normalization on starting guess if it passes the sanity check

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 2ad4505..4e988b3 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -534,6 +534,19 @@ public:
                     math::sqr(sin_omega12) / (c1 - cos_omega12);
             }
         }
+
+        // Apply sanity check on starting guess. Backwards check allows NaN through.
+        if (!(sin_alpha1 <= c0))
+        {
+          math::normalize<CT>(sin_alpha1, cos_alpha1);
+        }
+        else
+        {
+          sin_alpha1 = c1;
+          cos_alpha1 = c0;
+        }
+
+        return sig12;
     }

     /*

commit 2bde1c119a3dc04ce3c24261712e894824ff3d05
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 12 18:27:29 2018 +0500

    [formulas] Solve the astroid equation for inverse problem

    For details, please refer to Eq. (65) in,
    Geodesics on an ellipsoid of revolution, Charles F.F Karney,
    https://arxiv.org/abs/1102.1215

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 253198a..2ad4505 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -57,10 +57,12 @@ public:
     static CT constexpr c1 = 1;
     static CT constexpr c2 = 2;
     static CT constexpr c3 = 3;
+    static CT constexpr c4 = 4;
     static CT constexpr c6 = 6;
     static CT constexpr c90 = 90;
     static CT constexpr c180 = 180;
     static CT constexpr c200 = 200;
+    static CT constexpr c1000 = 1000;

     template <typename T1, typename T2, typename Spheroid>
     static inline result_type apply(T1 const& lo1,
@@ -276,7 +278,9 @@ public:
                                  lam12, sin_lam12, cos_lam12,
                                  sin_alpha1, cos_alpha1,
                                  sin_alpha2, cos_alpha2,
-                                 dnm, coeffs_C1, ep2, etol2, n, f);
+                                 dnm, coeffs_C1, ep2,
+                                 tol1, tol2, etol2,
+                                 n, f);
         }
     }

@@ -395,9 +399,10 @@ public:
                                   CT& sin_alpha1, CT& cos_alpha1,
                                   CT& sin_alpha2, CT& cos_alpha2,
                                   CT& dnm, CT coeffs_C1[], CT ep2,
-                                  CT etol2, CT n, CT f)
+                                  CT tol1, CT tol2, CT etol2, CT n, CT f)
     {
         CT const one_minus_f = c1 - f;
+        CT const x_thresh = c1000 * tol2;
         CT sig12 = -c1;

         CT sin_beta12 = sin_beta2 * cos_beta1 - cos_beta2 * sin_beta1;
@@ -497,7 +502,110 @@ public:

                 y = lam12x / lambda_scale;
             }
+
+            if (y > -tol1 && x > -c1 - x_thresh)
+            {
+                // Strip near cut.
+                if (f >= c0)
+                {
+                    sin_alpha1 = std::min(c1, -CT(x));
+                    cos_alpha1 = - std::sqrt(c1 - math::sqr(sin_alpha1));
+                }
+                else
+                {
+                    cos_alpha1 = std::max(x > -tol1 ? c0 : -c1, CT(x));
+                    sin_alpha1 = std::sqrt(c1 - math::sqr(cos_alpha1));
+                }
+            }
+            else
+            {
+                // Solve the astroid problem.
+                CT k = astroid(x, y);
+
+                CT omega12a = lambda_scale * (f >= c0 ? -x * k /
+                    (c1 + k) : -y * (c1 + k) / k);
+
+                CT sin_omega12 = sin(omega12a);
+                CT cos_omega12 = -cos(omega12a);
+
+                // Update spherical estimate of alpha1 using omgega12 instead of lam12.
+                sin_alpha1 = cos_beta2 * sin_omega12;
+                cos_alpha1 = sin_beta12a - cos_beta2 * sin_beta1 *
+                    math::sqr(sin_omega12) / (c1 - cos_omega12);
+            }
+        }
+    }
+
+    /*
+     Solve the astroid problem using this equation:
+     κ4 + 2κ3 + (1 − x2 − y 2 )κ2 − 2y 2 κ − y 2 = 0.
+
+     For details, please refer to Eq. (65) in,
+     Geodesics on an ellipsoid of revolution, Charles F.F Karney,
+     https://arxiv.org/abs/1102.1215
+    */
+    static inline CT astroid(CT x, CT y)
+    {
+        CT k;
+
+        CT p = math::sqr(x);
+        CT q = math::sqr(y);
+        CT r = (p + q - c1) / c6;
+
+        if (!(q == c0 && r <= c0))
+        {
+            // Avoid possible division by zero when r = 0 by multiplying
+            // equations for s and t by r^3 and r, respectively.
+            CT S = p * q / c4;
+            CT r2 = math::sqr(r);
+            CT r3 = r * r2;
+
+            // The discriminant of the quadratic equation for T3. This is
+            // zero on the evolute curve p^(1/3)+q^(1/3) = 1.
+            CT discriminant = S * (S + c2 * r3);
+
+            CT u = r;
+
+            if (discriminant >= c0)
+            {
+                CT T3 = S + r3;
+
+                // Pick the sign on the sqrt to maximize abs(T3). This minimizes
+                // loss of precision due to cancellation. The result is unchanged
+                // because of the way the T is used in definition of u.
+                T3 += T3 < c0 ? -std::sqrt(discriminant) : std::sqrt(discriminant);
+
+                CT T = std::cbrt(T3);
+
+                // T can be zero; but then r2 / T -> 0.
+                u += T + (T != c0 ? r2 / T : c0);
+            }
+            else
+            {
+                CT ang = std::atan2(std::sqrt(-discriminant), -(S + r3));
+
+                // There are three possible cube roots. We choose the root which avoids
+                // cancellation. Note that discriminant < 0 implies that r < 0.
+                u += c2 * r * cos(ang / c3);
+            }
+
+            CT v = std::sqrt(math::sqr(u) + q);
+
+            // Avoid loss of accuracy when u < 0.
+            CT uv = u < c0 ? q / (v - u) : u + v;
+            CT w = (uv - q) / (c2 * v);
+
+            // Rearrange expression for k to avoid loss of accuracy due to
+            // subtraction. Division by 0 not possible because uv > 0, w >= 0.
+            k = uv / (std::sqrt(uv + math::sqr(w)) + w);
+        }
+        else // q == 0 && r <= 0
+        {
+            // y = 0 with |x| <= 1. Handle this case directly.
+            // For y small, positive root is k = abs(y)/sqrt(1-x^2)
+            k = c0;
         }
+        return k;
     }
 };


commit 5bb581c932295f0243386cb9504c8b7409bbab2b
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 12 15:44:07 2018 +0500

    [formulas] Flip sign of cos_lam12

    This fixes the inaccuracy caused during the
    calculation of Newton's starting point.

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 0f3c686..253198a 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -91,6 +91,7 @@ public:

         CT tiny = std::sqrt(std::numeric_limits<CT>::min());

+
         CT const n = f / two_minus_f;
         CT const e2 = f * two_minus_f;
         CT const ep2 = e2 / math::sqr(one_minus_f);
@@ -110,8 +111,15 @@ public:
         CT sin_lam12;
         CT cos_lam12;

-        lon12 > c90 ? math::sin_cos_degrees(lon12_error, sin_lam12, cos_lam12)
-                    : math::sin_cos_degrees(lon12, sin_lam12, cos_lam12);
+        if (lon12 > c90)
+        {
+            math::sin_cos_degrees(lon12_error, sin_lam12, cos_lam12);
+            cos_lam12 *= -c1;
+        }
+        else
+        {
+            math::sin_cos_degrees(lon12, sin_lam12, cos_lam12);
+        }

         // Make points close to the equator to lie on it.
         lat1 = std::abs(lat1) > 90 ? math::NaN<CT>() : lat1;
@@ -421,8 +429,6 @@ public:
         }

         sin_alpha1 = cos_beta2 * sin_omega12;
-        // TODO: adl1995 - Resolve inaccuracy with
-        // cos_alpha1 calculation.
         cos_alpha1 = cos_omega12 >= c0 ?
             sin_beta12 + cos_beta2 * sin_beta1 * math::sqr(sin_omega12) / (c1 + cos_omega12) :
             sin_beta12a - cos_beta2 * sin_beta1 * math::sqr(sin_omega12) / (c1 - cos_omega12);

commit 71fbc86f44ec2d8ebf261808f233ec10cabf3260
Merge: 485a2f9 2cba2fa
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 12 15:42:41 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

commit 2cba2fa83fe62c52efd5fc2d7fcb1401264701cf
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 12 12:00:52 2018 +0500

    [test] Calculate geodesic scale (M12) using high precision arithmetic

    Instructions for building GeographicLib are given here:
    https://geographiclib.sourceforge.io/html/highprec.html

    It requires the use of libquadmath package, which is present
    in g++-7 by default. The cmake command used is:
    cmake -DCMAKE_CXX_COMPILER=g++-7 -DGEOGRAPHICLIB_PRECISION=4 ..

    Internally, GeographicLib makes use of float128 as part of Boost
    Multiprecision library. To output full precision values, use:
    std::setprecision(std::numeric_limits<float128>::max_digits10)

diff --git a/test/formulas/direct_cases_antipodal.hpp b/test/formulas/direct_cases_antipodal.hpp
index fdbbc6e..ad5db5d 100644
--- a/test/formulas/direct_cases_antipodal.hpp
+++ b/test/formulas/direct_cases_antipodal.hpp
@@ -35,304 +35,304 @@ expected_results_antipodal expected_antipodal[] =
 {
     {
         { 0, 31.394417440639 }, 19980218.4055399, 34.266322930672,
-        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209, -0.9961164510125257909767434 }
+        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209, -0.996116451012525883079717914370121434 }
     },{
         { 0, 29.788792273749 }, 19887224.5407334, 74.302205994192,
-        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058, -0.9986240311478448829847661 }
+        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058, -0.998624031147844926081802441331092268 }
     },{
         { 0, 46.471843094141 }, 19944337.8863917, 63.693680310665,
-        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365, -0.9975973096455918888284843 }
+        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365, -0.997597309645591900917338534782174975 }
     },{
         { 0, 63.016506345929 }, 20000925.7533636, 153.393656073038,
-        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772, -1.003813177921433850612286 }
+        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772, -1.00381317792143387457315384381217882 }
     },{
         { 0, 19.796231412719 }, 19956338.1330537, 28.272934411318,
-        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931, -0.9970154090276648134395961 }
+        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931, -0.997015409027664833985227232915349305 }
     },{
         { 0, 6.373459459035 }, 19946581.6983394, 56.859050230583,
-        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939, -0.9993490490811010928734123 }
+        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939, -0.999349049081101004077254401636309922 }
     },{
         { 0, 66.380766469414 }, 19986277.7696849, 38.646950203356,
-        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214, -0.996949176054954412282659 }
+        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214, -0.996949176054954366854587988200364634 }
     },{
         { 0, 16.483421185231 }, 19962737.9842573, 163.431254767325,
-        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431, -1.002722102329797498345386 }
+        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431, -1.00272210232979741562076014815829694 }
     },{
         { 0, 4.215702155486 }, 19932517.393764, 65.543168480886,
-        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317, -0.9996558584250565483090949 }
+        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317, -0.999655858425056553784315838129259646 }
     },{
         { 0, 40.71372085907 }, 19951133.3595356, 143.672151631634,
-        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621, -1.004141695740772786027591 }
+        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621, -1.00414169574077272173440178448799998 }
     },{
         { 0, 15.465481491654 }, 19877383.8879911, 36.289185640976,
-        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957, -0.9976390743971695870329942 }
+        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957, -0.997639074397169589580869342171354219 }
     },{
         { 0, 17.586197343531 }, 19982280.4639115, 157.929615091529,
-        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557, -1.00280451698301228773396 }
+        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557, -1.00280451698301242835498214844847098 }
     },{
         { 0, 5.7442768247 }, 19902873.7431814, 116.146983678305,
-        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673, -1.000393328930967508458988 }
+        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673, -1.00039332893096744037109147029696032 }
     },{
         { 0, 32.002904282111 }, 19967670.3104795, 163.052160078191,
-        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582, -1.004499034453024313763049 }
+        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582, -1.00449903445302446414189034840092063 }
     },{
         { 0, 55.902716926362 }, 19970525.337607, 98.927641063414,
-        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067, -1.0007278877908344522649 }
+        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067, -1.00072788779083454713259015989024192 }
     },{
         { 0, 22.69939784398 }, 19959286.1903172, 74.253870776761,
-        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679, -0.9989721814190034790826959 }
+        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679, -0.998972181419003457669703038845909759 }
     },{
         { 0, 41.312328471121 }, 19962690.5721867, 11.277616109847,
-        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201, -0.9948251514715273688795397 }
+        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201, -0.994825151471527391322524636052548885 }
     },{
         { 0, 27.927415327453 }, 19961296.8828333, 23.166421459647,
-        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101, -0.9959596927676567156505726 }
+        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101, -0.995959692767656723511038308060960844 }
     },{
         { 0, 41.567228741451 }, 19944253.4454809, 176.66609526064,
-        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197, -1.005136071404876275492239 }
+        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197, -1.00513607140487626345759508694754913 }
     },{
         { 0, 37.384208978567 }, 19928705.5911445, 39.072534864532,
-        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402, -0.9959555168591592858788435 }
+        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402, -0.995955516859159284415170532156480476 }
     },{
         { 0, 59.011868682852 }, 19970442.3788306, 44.970301291063,
-        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857, -0.9966589428927073192592684 }
+        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857, -0.996658942892707400140750451100757346 }
     },{
         { 0, 35.515406087737 }, 19948918.9139751, 28.528972431952,
-        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751, -0.9955628617991693771129176 }
+        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751, -0.995562861799169418475230486365035176 }
     },{
         { 0, 58.170252463184 }, 19961407.0813807, 128.021116291844,
-        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309, -1.002852737132807475024451 }
+        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309, -1.00285273713280753682397516968194395 }
     },{
         { 0, 34.012183807959 }, 19970955.843065, 168.944519134772,
-        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151, -1.004765235455867102248688 }
+        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151, -1.0047652354558671561335359001532197 }
     },{
         { 0, 45.510762948553 }, 19940248.3450143, 99.886784003837,
-        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972, -1.000838077509063557589755 }
+        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972, -1.00083807750906350619857221317943186 }
     },{
         { 0, 4.19841765451 }, 19970496.5132933, 89.561550657928,
-        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109, -0.9999941048102859313703554 }
+        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109, -0.999994104810285944218151144013972953 }
     },{
         { 0, 40.890119148103 }, 19926563.5817492, 165.437641169967,
-        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923, -1.004922949334065759787078 }
+        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923, -1.00492294933406567380984597548376769 }
     },{
         { 0, 28.096672787686 }, 19883901.8482359, 115.174366374632,
-        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363, -1.001708030733315814243475 }
+        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363, -1.00170803073331593502359737613005564 }
     },{
         { 0, 6.50572154271 }, 19917276.4101551, 79.069492719523,
-        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707, -0.9997366669338085325645891 }
+        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707, -0.999736666933808471036115861352300271 }
     },{
         { 0, .468835109567 }, 19849380.7342734, 80.234636214474,
-        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908, -0.9998014372091407881673782 }
+        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908, -0.999801437209140719808431185811059549 }
     },{
         { 0, 1.682746325049 }, 19890026.0274781, 10.076182752451,
-        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981, -0.9995380556912621520019267 }
+        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981, -0.999538055691262194990542866435134783 }
     },{
         { 0, 10.711305126218 }, 19962987.2134077, 7.528253696796,
-        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456, -0.9980718537552389151793625 }
+        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456, -0.998071853755238880268052525934763253 }
     },{
         { 0, 53.374321544652 }, 19980478.1457438, 23.324715976877,
-        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053, -0.9953335962777076279710611 }
+        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053, -0.995333596277707566279957518418086693 }
     },{
         { 0, 39.680221664519 }, 19956191.7841809, 7.075406493429,
-        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148, -0.9948010879096678981434003 }
+        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148, -0.994801087909667924868983845954062417 }
     },{
         { 0, 1.377666714083 }, 19925401.4931301, 95.29199069739,
-        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059, -0.9999980317051245028462866 }
+        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059, -0.99999803170512457928253979844157584 }
     },{
         { 0, 48.751426624188 }, 19988599.1160495, 40.252328570137,
-        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568, -0.9959992457241298392713741 }
+        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568, -0.995999245724129789181233718409202993 }
     },{
         { 0, 59.443039048494 }, 19969935.9534732, 93.052184108221,
-        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534, -1.000207278488970808263958 }
+        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534, -1.00020727848897084122370415570912883 }
     },{
         { 0, 4.122408476235 }, 19938291.6332293, 167.73479753304,
-        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497, -1.000686009028376572587218 }
+        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497, -1.00068600902837667732114823593292385 }
     },{
         { 0, 46.422470082432 }, 19931980.7029341, 86.67365350297,
-        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064, -0.9996070961163002954936486 }
+        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064, -0.999607096116300386512421027873642743 }
     },{
         { 0, 32.614423729024 }, 19926887.3785175, 24.943814520557,
-        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104, -0.9955621506768719286041558 }
+        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104, -0.995562150676871926435751447570510209 }
     },{
         { 0, 3.242895277973 }, 19964490.4789049, 30.247458779683,
-        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044, -0.9994741842703449041015323 }
+        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044, -0.999474184270344845337774586369050667 }
     },{
         { 0, 6.29069210113 }, 19877160.8505733, 94.34299459284,
-        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083, -0.9999763973509048521344338 }
+        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083, -0.999976397350904933070125935046235099 }
     },{
         { 0, 18.232086569498 }, 19927978.7462175, 164.41905055334,
-        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559, -1.002934604390638743953712 }
+        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559, -1.00293460439063886191490837518358603 }
     },{
         { 0, 12.049849333181 }, 19908004.4552909, 9.418096768309,
-        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343, -0.9977614744975109587398973 }
+        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343, -0.997761474497510958414636661473196 }
     },{
         { 0, 40.289465276136 }, 19985674.936106, 143.092606818963,
-        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593, -1.004149658760912620643173 }
+        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593, -1.00414965876091266672176516294712201 }
     },{
         { 0, 2.197784650379 }, 19910509.7517973, 1.542117609437,
-        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996, -0.999488724639301117833555 }
+        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996, -0.999488724639301051588802238256903365 }
     },{
         { 0, 1.966575272177 }, 19875595.6267266, 170.112968791865,
-        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908, -1.000154635898045583290543 }
+        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908, -1.00015463589804554089823795948177576 }
     },{
         { 0, 25.078832492684 }, 19887997.7953866, 77.264585323781,
-        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839, -0.9989811898386008840464503 }
+        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839, -0.998981189838600847075156252685701475 }
     },{
         { 0, 31.740361941314 }, 19972325.3556069, 143.930820896999,
-        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145, -1.003794616281159395249425 }
+        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145, -1.00379461628115951299378139083273709 }
     },{
         { 0, .05479250563 }, 19858049.4780499, 41.349430623518,
-        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714, -0.9997793696948588326408637 }
+        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714, -0.9997793696948588104689292777038645 }
     },{
         { 0, 36.685139871608 }, 19968965.6773632, 89.167975517493,
-        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918, -0.9999165379463486296850866 }
+        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918, -0.999916537946348604748436628142371774 }
     },{
         { 0, 3.451199399671 }, 19938203.3838544, 91.541212417048,
-        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781, -1.000003974843958109899184 }
+        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781, -1.00000397484395819880376166111091152 }
     },{
         { 0, 27.692898794247 }, 19883493.6699045, 88.406440883665,
-        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836, -0.9997364583229516115064732 }
+        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836, -0.999736458322951659916100197733612731 }
     },{
         { 0, 17.363238291869 }, 19980749.7638027, 39.697196316589,
-        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379, -0.9976876919817150126995782 }
+        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379, -0.997687691981715030209443284547887743 }
     },{
         { 0, 37.006775102539 }, 19949309.9180043, 116.455543532607,
-        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701, -1.002219628589184219390543 }
+        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701, -1.00221962858918423044940482213860378 }
     },{
         { 0, 45.572883540957 }, 19940027.8586414, 137.627256708444,
-        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496, -1.003808877864471522261582 }
+        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496, -1.00380887786447159371050474874209613 }
     },{
         { 0, 43.63393981955 }, 19931045.2914508, 91.203625101465,
-        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764, -1.000029741531505212250378 }
+        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764, -1.00002974153150514524668324156664312 }
     },{
         { 0, 38.4995307019 }, 19918391.2222193, 141.232864609445,
-        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077, -1.003881641157329480734325 }
+        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077, -1.00388164115732947401227193040540442 }
     },{
         { 0, 27.55015339382 }, 19986004.7358853, 137.025135713548,
-        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654, -1.003160443902811658199205 }
+        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654, -1.00316044390281167153489150223322213 }
     },{
         { 0, 1.54507498314 }, 19978593.3191777, 36.816106412092,
-        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168, -0.9997704994624671810221454 }
+        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168, -0.999770499462467210349814195069484413 }
     },{
         { 0, 45.217063644222 }, 19987042.0782465, 18.114645812265,
-        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936, -0.9949741794148549555321798 }
+        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936, -0.994974179414854997816064496873877943 }
     },{
         { 0, 13.473522450751 }, 19987364.078382, 156.839609002403,
-        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472, -1.002190931895065541886065 }
+        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472, -1.00219093189506569530067281448282301 }
     },{
         { 0, 6.287741997374 }, 19912159.8245954, 132.954797451112,
-        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375, -1.00071252411103014544249 }
+        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375, -1.00071252411103017720961361192166805 }
     },{
         { 0, 7.639709001531 }, 19976374.3699535, 29.731916588299,
-        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539, -0.9987897920867413009931961 }
+        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539, -0.998789792086741234911073661351110786 }
     },{
         { 0, 5.893688050348 }, 19886907.2520668, 14.653438882877,
-        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022, -0.9987946470311208020708207 }
+        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022, -0.998794647031120752522781458537792787 }
     },{
         { 0, 61.997076235476 }, 19976288.2901729, 149.562797049254,
-        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176, -1.003730714324371446686916 }
+        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176, -1.00373071432437144245852778112748638 }
     },{
         { 0, 50.507637741656 }, 19979542.5263293, 171.564028344478,
-        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697, -1.005088816322817598953449 }
+        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697, -1.00508881632281776852266830246662721 }
     },{
         { 0, 7.484475238477 }, 19867425.2906303, 57.020570370985,
-        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633, -0.9990970426773380551267907 }
+        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633, -0.999097042677338120775232255255104974 }
     },{
         { 0, 56.851165323215 }, 19988235.9960515, 112.345749045605,
-        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518, -1.001828592498714131384455 }
+        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518, -1.00182859249871403228837607457535341 }
     },{
         { 0, 10.692273150738 }, 19893210.3050033, 102.824601316946,
-        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111, -1.000343455845084243900113 }
+        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111, -1.00034345584508432835946223349310458 }
     },{
         { 0, 46.694739303788 }, 19975447.9283188, 174.663684259477,
-        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645, -1.005204848752017347248908 }
+        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645, -1.00520484875201732144489596976200119 }
     },{
         { 0, 15.804386137005 }, 19855850.8800526, 74.932089158884,
-        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628, -0.9990915785464752706503469 }
+        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628, -0.999091578546475345135036150168161839 }
     },{
         { 0, 4.371450175299 }, 19979071.1035552, 164.163592252794,
-        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728, -1.00076323969894748092211 }
+        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728, -1.00076323969894742660358133434783667 }
     },{
         { 0, 30.894388279688 }, 19968681.8321577, 77.35154610481,
-        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058, -0.9989751763364228440383701 }
+        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058, -0.998975176336422854284080585784977302 }
     },{
         { 0, 9.541166838639 }, 19848553.7844137, 118.441353539081,
-        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614, -1.000605486201104942726309 }
+        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614, -1.00060548620110489892454097571317106 }
     },{
         { 0, 8.489292700054 }, 19995477.1669578, 171.963952699866,
-        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974, -1.001520684863064588341133 }
+        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974, -1.00152068486306466965629624610301107 }
     },{
         { 0, 19.562401114224 }, 19893208.1788508, 126.362762598128,
-        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615, -1.001852026688027773315692 }
+        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615, -1.00185202668802775249901060306001455 }
     },{
         { 0, 42.260350252749 }, 19942715.0054774, 170.703419847646,
-        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769, -1.005086424064435460636394 }
+        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769, -1.00508642406443549077721399953588843 }
     },{
         { 0, 24.511403144656 }, 19924809.5184876, 102.913211410163,
-        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318, -1.00084083091888388877648 }
+        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318, -1.0008408309188838725134473861544393 }
     },{
         { 0, 20.844284170708 }, 19909084.6340808, 44.172784008084,
-        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608, -0.997389183621779017239594 }
+        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608, -0.997389183621778974142557672166731209 }
     },{
         { 0, 2.426010809098 }, 19840940.6924189, 94.315194952561,
-        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638, -0.9998252498449916409405634 }
+        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638, -0.999825249844991659209370027383556589 }
     },{
         { 0, 6.600682554664 }, 19878412.28273, 168.167678684515,
-        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692, -1.000982848560649784010017 }
+        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692, -1.00098284856064978498579876031726599 }
     },{
         { 0, 23.372339802326 }, 19899498.4582543, 161.197647943542,
-        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091, -1.003476668684313999812749 }
+        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091, -1.00347666868431395492677893344080076 }
     },{
         { 0, 16.194668264095 }, 19874825.6683239, 148.942349959054,
-        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622, -1.002220322222336505702499 }
+        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622, -1.00222032222233647935638600756647065 }
     },{
         { 0, 1.528726471528 }, 19897803.9939987, 69.212891442493,
-        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133, -0.9998271442281568740497941 }
+        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133, -0.999827144228156883265512533398577943 }
     },{
         { 0, 6.297249676078 }, 19864042.0495193, 56.274639904925,
-        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258, -0.9991904501783995893996783 }
+        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258, -0.999190450178399580671850799262756482 }
     },{
         { 0, 17.393540327984 }, 19962624.6302607, 107.855062015266,
-        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839, -1.000918417796891303852592 }
+        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839, -1.00091841779689127989172447996679693 }
     },{
         { 0, 46.284685151236 }, 19990422.3478916, 14.758013867151,
-        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104, -0.9948945922618399753472283 }
+        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104, -0.994894592261839960656288894824683666 }
     },{
         { 0, 14.924320176299 }, 19891861.8615337, 31.446544793174,
-        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804, -0.9976201425853329563713315 }
+        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804, -0.997620142585332936313591289945179597 }
     },{
         { 0, 23.668824656069 }, 19938736.4442268, 148.091483667618,
-        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819, -1.003232628720005910772511 }
+        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819, -1.00323262872000595891108787327539176 }
     },{
         { 0, 46.986276695896 }, 19968596.0414782, 174.796708941456,
-        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769, -1.005190954526080850226118 }
+        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769, -1.00519095452608087093437916337279603 }
     },{
         { 0, 65.946144289524 }, 19993734.5109736, 25.375428509648,
-        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769, -0.9964369359146106126432461 }
+        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769, -0.996436935914610577569305860379245132 }
     },{
         { 0, 10.950298933293 }, 19975919.5586889, 28.779018914489,
-        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581, -0.9982720718341152112444356 }
+        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581, -0.998272071834115148902810688014142215 }
     },{
         { 0, 13.609869340778 }, 19913213.8514358, 129.616021271129,
-        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776, -1.00146664642314031927646 }
+        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776, -1.00146664642314031645753402699483559 }
     },{
         { 0, 48.701427557433 }, 19972955.2699173, 102.875149183407,
-        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697, -1.001146768554290695098057 }
+        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697, -1.00114676855429074464609584538266063 }
     },{
         { 0, 31.519172055785 }, 19952318.3772514, 26.247105619999,
-        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002, -0.9957399483998249749283627 }
+        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002, -0.995739948399825047786748655198607594 }
     },{
         { 0, 31.863784754278 }, 19993324.8682601, 29.572313410211,
-        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234, -0.9958880090011472640794746 }
+        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234, -0.995888009001147267440501309465616941 }
     },{
         { 0, 76.434608546092 }, 19997750.023578, 167.428385412814,
-        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108, -1.002339638930915896456245 }
+        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108, -1.00233963893091582164629471662919968 }
     },{
         { 0, 73.114273316483 }, 19992866.6147806, 78.154765899661,
-        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946, -0.9993841433084754598747609 }
+        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946, -0.999384143308475469957841141876997426 }
     },{
         { 0, 1.125639056292 }, 19852573.5442848, 67.184842289382,
-        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937, -0.9997329579628334908763393 }
+        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937, -0.999732957962833457266071945923613384 }
     }
 };


commit 485a2f9a0f6d245ae3b2fb3762e664ced7754ea9
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 11 18:44:27 2018 +0500

    [formulas] Find starting point for inverse problem (short lines)

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 59b3cbd..0f3c686 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -50,11 +50,17 @@ class karney_inverse
 public:
     typedef result_inverse<CT> result_type;
     static CT constexpr c0 = 0;
+    static CT constexpr c0_001 = 0.001;
+    static CT constexpr c0_01 = 0.01;
+    static CT constexpr c0_1 = 0.1;
+    static CT constexpr c0_5 = 0.5;
     static CT constexpr c1 = 1;
     static CT constexpr c2 = 2;
     static CT constexpr c3 = 3;
-    static CT constexpr c180 = 180;
+    static CT constexpr c6 = 6;
     static CT constexpr c90 = 90;
+    static CT constexpr c180 = 180;
+    static CT constexpr c200 = 200;

     template <typename T1, typename T2, typename Spheroid>
     static inline result_type apply(T1 const& lo1,
@@ -71,14 +77,20 @@ public:
         CT lon1 = lo1;
         CT lon2 = lo2;

-        CT tiny = std::sqrt(std::numeric_limits<CT>::min());
-
         CT const a = CT(get_radius<0>(spheroid));
         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 tol0 = std::numeric_limits<CT>::epsilon();
+        CT const tol1 = c200 * tol0;
+        CT const tol2 = sqrt(tol0);
+        CT const etol2 = c0_1 * tol2 /
+            sqrt(std::max(c0_001, std::abs(f)) * std::min(c1, c1 - f / c2) / c2);
+
+        CT tiny = std::sqrt(std::numeric_limits<CT>::min());
+
         CT const n = f / two_minus_f;
         CT const e2 = f * two_minus_f;
         CT const ep2 = e2 / math::sqr(one_minus_f);
@@ -198,10 +210,12 @@ public:
             CT sigma12 = std::atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
                                              cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);

+            CT dummy;
             meridian_length(n, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
                                              sin_sigma2, cos_sigma2, dn2,
                                              cos_beta1, cos_beta2, s12x,
-                                             m12x, result.geodesic_scale, M21);
+                                             m12x, dummy, result.geodesic_scale,
+                                             M21, coeffs_C1);


             if (sigma12 < c1 || m12x >= c0)
@@ -227,7 +241,6 @@ public:
         if (!meridian && sin_beta1 == 0 &&
             (f <= 0 || lon12_error >= f * c180))
         {
-            std::cout << "Points lie on the equator." << std::endl;
             // Points lie on the equator.
             cos_alpha1 = cos_alpha2 = c0;
             sin_alpha1 = sin_alpha2 = c1;
@@ -239,24 +252,37 @@ public:
             if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
             {
                 result.geodesic_scale = cos(sigma12);
-                M21 = cos(sigma12);
             }
             a12 = lon12 / one_minus_f;
         }
+
+        else if (!meridian)
+        {
+            // If point1 and point2 belong within a hemisphere bounded by a
+            // meridian and geodesic is neither meridional nor equatorial.
+
+            // Find the starting point for Newton's method.
+            CT dnm;
+            sigma12 = newton_start(sin_beta1, cos_beta1, dn1,
+                                 sin_beta2, cos_beta2, dn2,
+                                 lam12, sin_lam12, cos_lam12,
+                                 sin_alpha1, cos_alpha1,
+                                 sin_alpha2, cos_alpha2,
+                                 dnm, coeffs_C1, ep2, etol2, n, f);
+        }
     }

     static inline void meridian_length(CT epsilon, CT ep2, CT sigma12,
                                        CT sin_sigma1, CT cos_sigma1, CT dn1,
                                        CT sin_sigma2, CT cos_sigma2, CT dn2,
                                        CT cos_beta1, CT cos_beta2,
-                                       CT& s12x, CT& m12x,
-                                       CT& M12, CT& M21)
+                                       CT& s12x, CT& m12x, CT& m0,
+                                       CT& M12, CT& M21, CT coeffs_C1[])
     {
         CT A12x = 0, J12 = 0;
         CT expansion_A1, expansion_A2;

-        // Index zero element of coeffs_C1 and coeffs_C2 is unused.
-        CT coeffs_C1[SeriesOrder + 1];
+        // Index zero element of coeffs_C2 is unused.
         CT coeffs_C2[SeriesOrder + 1];

         if (BOOST_GEOMETRY_CONDITION(EnableDistance) ||
@@ -331,6 +357,8 @@ public:

         if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
         {
+            m0 = A12x;
+
             m12x = dn2 * (cos_sigma1 * sin_sigma2) -
                    dn1 * (sin_sigma1 * cos_sigma2) -
                    cos_sigma1 * cos_sigma2 * J12;
@@ -347,6 +375,124 @@ public:
         }
     }

+    /*
+     Return a starting point for Newton's method in sin_alpha1 and
+     cos_alpha1 (function value is -1). If Newton's method
+     doesn't need to be used, return also sin_alpha2 and
+     cos_alpha2 and function value is sig12.
+    */
+    static inline CT newton_start(CT sin_beta1, CT cos_beta1, CT dn1,
+                                  CT sin_beta2, CT cos_beta2, CT dn2,
+                                  CT lam12, CT sin_lam12, CT cos_lam12,
+                                  CT& sin_alpha1, CT& cos_alpha1,
+                                  CT& sin_alpha2, CT& cos_alpha2,
+                                  CT& dnm, CT coeffs_C1[], CT ep2,
+                                  CT etol2, CT n, CT f)
+    {
+        CT const one_minus_f = c1 - f;
+        CT sig12 = -c1;
+
+        CT sin_beta12 = sin_beta2 * cos_beta1 - cos_beta2 * sin_beta1;
+        CT cos_beta12 = cos_beta2 * cos_beta1 + sin_beta2 * sin_beta1;
+
+        CT sin_beta12a = sin_beta2 * cos_beta1 + cos_beta2 * sin_beta1;
+
+        bool shortline = cos_beta12 >= c0 && sin_beta12 < c0_5 &&
+                         cos_beta2 * lam12 < c0_5;
+
+        CT sin_omega12, cos_omega12;
+
+        if (shortline)
+        {
+            CT sin_beta_m2 = math::sqr(sin_beta1 + sin_beta2);
+
+            sin_beta_m2 /= sin_beta_m2 + math::sqr(cos_beta1 + cos_beta2);
+            dnm = math::sqrt(c1 + ep2 * sin_beta_m2);
+
+            CT omega12 = lam12 / (one_minus_f * dnm);
+
+            sin_omega12 = sin(omega12);
+            cos_omega12 = cos(omega12);
+        }
+        else
+        {
+            sin_omega12 = sin_lam12;
+            cos_omega12 = cos_lam12;
+        }
+
+        sin_alpha1 = cos_beta2 * sin_omega12;
+        // TODO: adl1995 - Resolve inaccuracy with
+        // cos_alpha1 calculation.
+        cos_alpha1 = cos_omega12 >= c0 ?
+            sin_beta12 + cos_beta2 * sin_beta1 * math::sqr(sin_omega12) / (c1 + cos_omega12) :
+            sin_beta12a - cos_beta2 * sin_beta1 * math::sqr(sin_omega12) / (c1 - cos_omega12);
+
+        CT sin_sigma12 = boost::math::hypot(sin_alpha1, cos_alpha1);
+        CT cos_sigma12 = sin_beta1 * sin_beta2 + cos_beta1 * cos_beta2 * cos_omega12;
+
+        if (shortline && sin_sigma12 < etol2)
+        {
+            sin_alpha2 = cos_beta1 * sin_omega12;
+            cos_alpha2 = sin_beta12 - cos_beta1 * sin_beta2 *
+                (cos_omega12 >= c0 ? math::sqr(sin_omega12) /
+                (c1 + cos_omega12) : c1 - cos_omega12);
+        }
+        // Skip astroid calculation if too eccentric.
+        else if (std::abs(n) > c0_1 ||
+                 cos_sigma12 >= c0 ||
+                 sin_sigma12 >= c6 * std::abs(n) * math::pi<CT>() *
+                 math::sqr(cos_beta1))
+        {
+            // Nothing to do (?).
+        }
+        else
+        {
+            // Scale lam12 and beta2 to x, y coordinate system where antipodal
+            // point is at origin and singular point is at y = 0, x = -1.
+            CT lambda_scale, beta_scale;
+
+            CT y;
+            volatile CT x;
+
+            CT lam12x = atan2(-sin_lam12, -cos_lam12);
+            if (f >= 0)
+            {
+                CT k2 = math::sqr(sin_beta1) * ep2;
+                CT epsilon = k2 / (c2 * (c1 * sqrt(c1 + k2)) + k2);
+
+                CT coeffs_A3[SeriesOrder];
+                series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
+
+                CT const A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
+
+                lambda_scale = f * cos_beta1 * A3 * math::pi<CT>();
+
+                beta_scale = lambda_scale * cos_beta1;
+
+                x = lam12x / lambda_scale;
+                y = sin_beta12a / beta_scale;
+            }
+            else
+            {
+                CT cos_beta12a = cos_beta2 * cos_beta1 - sin_beta2 * sin_beta1;
+                CT beta12a = atan2(sin_beta12a, cos_beta12a);
+
+                CT m12b, m0, dummy;
+                meridian_length(n, ep2, math::pi<CT>() + beta12a,
+                                sin_beta1, -cos_beta1, dn1,
+                                sin_beta2, cos_beta2, dn2,
+                                cos_beta1, cos_beta2, dummy,
+                                m12b, m0, dummy, dummy, coeffs_C1);
+
+                x = -c1 + m12b / (cos_beta1 * cos_beta2 * m0 * math::pi<CT>());
+                beta_scale = x < -c0_01 ? sin_beta12a / x :
+                    -f * math::sqr(cos_beta1) * math::pi<CT>();
+                lambda_scale = beta_scale / cos_beta1;
+
+                y = lam12x / lambda_scale;
+            }
+        }
+    }
 };

 }}} // namespace boost::geometry::formula

commit 0344ba5c1a3e596a4558eeb677324bcf7c7d2c30
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 11 11:06:18 2018 +0500

    [formulas] Handle case for equatorial points in inverse problem

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 9297034..59b3cbd 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -73,6 +73,7 @@ public:

         CT tiny = std::sqrt(std::numeric_limits<CT>::min());

+        CT const a = CT(get_radius<0>(spheroid));
         CT const b = CT(get_radius<2>(spheroid));
         CT const f = formula::flattening<CT>(spheroid);
         CT const one_minus_f = c1 - f;
@@ -108,7 +109,7 @@ public:
         lat2 = math::round_angle(lat2);

         // Arrange points in a canonical form, as explained in
-        // paper Algorithms for geodesics, Eq. (44):
+        // paper, Algorithms for geodesics, Eq. (44):
         //
         //     0 <= lon12 <= 180
         //     -90 <= lat1 <= 0
@@ -141,7 +142,7 @@ public:
         cos_beta2 = std::max(tiny, cos_beta2);

         // If cos_beta1 < -sin_beta1, then cos_beta2 - cos_beta1 is a
-        // sensitive measure of the |beta1| - |beta2|.  Alternatively,
+        // sensitive measure of the |beta1| - |beta2|. Alternatively,
         // (cos_beta1 >= -sin_beta1), abs(sin_beta2) + sin_beta1 is
         // a better measure.
         // Sometimes these quantities vanish and in that case we
@@ -173,17 +174,20 @@ public:

         bool meridian = lat1 == -90 || sin_lam12 == 0;

+        CT cos_alpha1, sin_alpha1;
+        CT cos_alpha2, sin_alpha2;
+
         if (meridian)
         {
             // Endpoints lie on a single full meridian.

             // Point to the target latitude.
-            CT cos_alpha1 = cos_lam12;
-            CT sin_alpha1 = sin_lam12;
+            cos_alpha1 = cos_lam12;
+            sin_alpha1 = sin_lam12;

             // Heading north at the target.
-            CT cos_alpha2 = 1;
-            CT sin_alpha2 = 0;
+            cos_alpha2 = 1;
+            sin_alpha2 = 0;

             CT sin_sigma1 = sin_beta1;
             CT cos_sigma1 = cos_alpha1 * cos_beta1;
@@ -217,6 +221,28 @@ public:
                 meridian = false;
             }
         }
+
+        CT omega12, sin_omega12, cos_omega12;
+
+        if (!meridian && sin_beta1 == 0 &&
+            (f <= 0 || lon12_error >= f * c180))
+        {
+            std::cout << "Points lie on the equator." << std::endl;
+            // Points lie on the equator.
+            cos_alpha1 = cos_alpha2 = c0;
+            sin_alpha1 = sin_alpha2 = c1;
+
+            s12x = a * lam12;
+            sigma12 = omega12 = lam12 / one_minus_f;
+            m12x = b * sin(sigma12);
+
+            if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+            {
+                result.geodesic_scale = cos(sigma12);
+                M21 = cos(sigma12);
+            }
+            a12 = lon12 / one_minus_f;
+        }
     }

     static inline void meridian_length(CT epsilon, CT ep2, CT sigma12,

commit fe1b9ff8ba3b4f7ed799ae4e5a9c5c69bd795f5f
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat Jun 9 16:17:42 2018 +0500

    [test] Update geodesic scale (M12) in GeographicLib dataset

    M12 is calculated manually using GeographicLib. Previously,
    GEOGRAPHICLIB_PRECISION was set to 2 (default) with series
    order set to 6. The updated values are generated with
    GEOGRAPHICLIB_PRECISION set to 3 and series order set to 7.

    Build instructions are provided here:
    https://geographiclib.sourceforge.io/html/install.html

diff --git a/test/formulas/direct_cases_antipodal.hpp b/test/formulas/direct_cases_antipodal.hpp
index 37214fe..fdbbc6e 100644
--- a/test/formulas/direct_cases_antipodal.hpp
+++ b/test/formulas/direct_cases_antipodal.hpp
@@ -35,304 +35,304 @@ expected_results_antipodal expected_antipodal[] =
 {
     {
         { 0, 31.394417440639 }, 19980218.4055399, 34.266322930672,
-        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209, -0.99598340069666346785 }
+        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209, -0.9961164510125257909767434 }
     },{
         { 0, 29.788792273749 }, 19887224.5407334, 74.302205994192,
-        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058, -0.99585265538534928353 }
+        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058, -0.9986240311478448829847661 }
     },{
         { 0, 46.471843094141 }, 19944337.8863917, 63.693680310665,
-        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365, -0.99628290151178156009 }
+        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365, -0.9975973096455918888284843 }
     },{
         { 0, 63.016506345929 }, 20000925.7533636, 153.393656073038,
-        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772, -0.99806730524837738994 }
+        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772, -1.003813177921433850612286 }
     },{
         { 0, 19.796231412719 }, 19956338.1330537, 28.272934411318,
-        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931, -0.99680355285706290225 }
+        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931, -0.9970154090276648134395961 }
     },{
         { 0, 6.373459459035 }, 19946581.6983394, 56.859050230583,
-        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939, -0.99880439595523196061 }
+        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939, -0.9993490490811010928734123 }
     },{
         { 0, 66.380766469414 }, 19986277.7696849, 38.646950203356,
-        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214, -0.9984201835509521894 }
+        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214, -0.996949176054954412282659 }
     },{
         { 0, 16.483421185231 }, 19962737.9842573, 163.431254767325,
-        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431, -0.99723427960580335316 }
+        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431, -1.002722102329797498345386 }
     },{
         { 0, 4.215702155486 }, 19932517.393764, 65.543168480886,
-        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317, -0.99916694551569362748 }
+        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317, -0.9996558584250565483090949 }
     },{
         { 0, 40.71372085907 }, 19951133.3595356, 143.672151631634,
-        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621, -0.99601226064330683485 }
+        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621, -1.004141695740772786027591 }
     },{
         { 0, 15.465481491654 }, 19877383.8879911, 36.289185640976,
-        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957, -0.99717590257108590368 }
+        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957, -0.9976390743971695870329942 }
     },{
         { 0, 17.586197343531 }, 19982280.4639115, 157.929615091529,
-        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557, -0.99710409371925123878 }
+        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557, -1.00280451698301228773396 }
     },{
         { 0, 5.7442768247 }, 19902873.7431814, 116.146983678305,
-        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673, -0.99883071172416715289 }
+        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673, -1.000393328930967508458988 }
     },{
         { 0, 32.002904282111 }, 19967670.3104795, 163.052160078191,
-        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582, -0.99597193334487110761 }
+        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582, -1.004499034453024313763049 }
     },{
         { 0, 55.902716926362 }, 19970525.337607, 98.927641063414,
-        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067, -0.99721760041260698593 }
+        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067, -1.0007278877908344522649 }
     },{
         { 0, 22.69939784398 }, 19959286.1903172, 74.253870776761,
-        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679, -0.99650952667426662135 }
+        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679, -0.9989721814190034790826959 }
     },{
         { 0, 41.312328471121 }, 19962690.5721867, 11.277616109847,
-        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201, -0.99601334953687414853 }
+        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201, -0.9948251514715273688795397 }
     },{
         { 0, 27.927415327453 }, 19961296.8828333, 23.166421459647,
-        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101, -0.99610609795569049485 }
+        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101, -0.9959596927676567156505726 }
     },{
         { 0, 41.567228741451 }, 19944253.4454809, 176.66609526064,
-        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197, -0.99604624873858405021 }
+        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197, -1.005136071404876275492239 }
     },{
         { 0, 37.384208978567 }, 19928705.5911445, 39.072534864532,
-        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402, -0.99583616315460821156 }
+        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402, -0.9959555168591592858788435 }
     },{
         { 0, 59.011868682852 }, 19970442.3788306, 44.970301291063,
-        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857, -0.99754686309848117354 }
+        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857, -0.9966589428927073192592684 }
     },{
         { 0, 35.515406087737 }, 19948918.9139751, 28.528972431952,
-        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751, -0.9958683164291525225 }
+        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751, -0.9955628617991693771129176 }
     },{
         { 0, 58.170252463184 }, 19961407.0813807, 128.021116291844,
-        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309, -0.99746161015888423762 }
+        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309, -1.002852737132807475024451 }
     },{
         { 0, 34.012183807959 }, 19970955.843065, 168.944519134772,
-        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151, -0.99594085068133375582 }
+        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151, -1.004765235455867102248688 }
     },{
         { 0, 45.510762948553 }, 19940248.3450143, 99.886784003837,
-        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972, -0.99622530350349169925 }
+        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972, -1.000838077509063557589755 }
     },{
         { 0, 4.19841765451 }, 19970496.5132933, 89.561550657928,
-        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109, -0.99921964515553229891 }
+        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109, -0.9999941048102859313703554 }
     },{
         { 0, 40.890119148103 }, 19926563.5817492, 165.437641169967,
-        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923, -0.99598758014963484353 }
+        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923, -1.004922949334065759787078 }
     },{
         { 0, 28.096672787686 }, 19883901.8482359, 115.174366374632,
-        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363, -0.99595011741363181912 }
+        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363, -1.001708030733315814243475 }
     },{
         { 0, 6.50572154271 }, 19917276.4101551, 79.069492719523,
-        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707, -0.99872883639262399758 }
+        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707, -0.9997366669338085325645891 }
     },{
         { 0, .468835109567 }, 19849380.7342734, 80.234636214474,
-        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908, -0.99961835625163353303 }
+        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908, -0.9998014372091407881673782 }
     },{
         { 0, 1.682746325049 }, 19890026.0274781, 10.076182752451,
-        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981, -0.9995304688134802884 }
+        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981, -0.9995380556912621520019267 }
     },{
         { 0, 10.711305126218 }, 19962987.2134077, 7.528253696796,
-        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456, -0.99808700197799249398 }
+        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456, -0.9980718537552389151793625 }
     },{
         { 0, 53.374321544652 }, 19980478.1457438, 23.324715976877,
-        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053, -0.99695322723379165009 }
+        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053, -0.9953335962777076279710611 }
     },{
         { 0, 39.680221664519 }, 19956191.7841809, 7.075406493429,
-        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148, -0.99594142266924268192 }
+        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148, -0.9948010879096678981434003 }
     },{
         { 0, 1.377666714083 }, 19925401.4931301, 95.29199069739,
-        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059, -0.99967079575227224542 }
+        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059, -0.9999980317051245028462866 }
     },{
         { 0, 48.751426624188 }, 19988599.1160495, 40.252328570137,
-        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568, -0.99654000795747821329 }
+        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568, -0.9959992457241298392713741 }
     },{
         { 0, 59.443039048494 }, 19969935.9534732, 93.052184108221,
-        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534, -0.99760844716107632824 }
+        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534, -1.000207278488970808263958 }
     },{
         { 0, 4.122408476235 }, 19938291.6332293, 167.73479753304,
-        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497, -0.99919442400871316678 }
+        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497, -1.000686009028376572587218 }
     },{
         { 0, 46.422470082432 }, 19931980.7029341, 86.67365350297,
-        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064, -0.99626178341627869006 }
+        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064, -0.9996070961163002954936486 }
     },{
         { 0, 32.614423729024 }, 19926887.3785175, 24.943814520557,
-        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104, -0.99584842355298219818 }
+        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104, -0.9955621506768719286041558 }
     },{
         { 0, 3.242895277973 }, 19964490.4789049, 30.247458779683,
-        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044, -0.99938705290848561802 }
+        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044, -0.9994741842703449041015323 }
     },{
         { 0, 6.29069210113 }, 19877160.8505733, 94.34299459284,
-        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083, -0.99866089792332934927 }
+        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083, -0.9999763973509048521344338 }
     },{
         { 0, 18.232086569498 }, 19927978.7462175, 164.41905055334,
-        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559, -0.99696204469368099321 }
+        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559, -1.002934604390638743953712 }
     },{
         { 0, 12.049849333181 }, 19908004.4552909, 9.418096768309,
-        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343, -0.99777424243303902696 }
+        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343, -0.9977614744975109587398973 }
     },{
         { 0, 40.289465276136 }, 19985674.936106, 143.092606818963,
-        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593, -0.99602880093986934096 }
+        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593, -1.004149658760912620643173 }
     },{
         { 0, 2.197784650379 }, 19910509.7517973, 1.542117609437,
-        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996, -0.99948867836200405712 }
+        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996, -0.999488724639301117833555 }
     },{
         { 0, 1.966575272177 }, 19875595.6267266, 170.112968791865,
-        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908, -0.99943592820130777721 }
+        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908, -1.000154635898045583290543 }
     },{
         { 0, 25.078832492684 }, 19887997.7953866, 77.264585323781,
-        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839, -0.99614702274067257193 }
+        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839, -0.9989811898386008840464503 }
     },{
         { 0, 31.740361941314 }, 19972325.3556069, 143.930820896999,
-        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145, -0.99597837783719567195 }
+        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145, -1.003794616281159395249425 }
     },{
         { 0, .05479250563 }, 19858049.4780499, 41.349430623518,
-        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714, -0.9997266451533399767 }
+        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714, -0.9997793696948588326408637 }
     },{
         { 0, 36.685139871608 }, 19968965.6773632, 89.167975517493,
-        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918, -0.99592417628692353482 }
+        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918, -0.9999165379463486296850866 }
     },{
         { 0, 3.451199399671 }, 19938203.3838544, 91.541212417048,
-        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781, -0.9993151254968675179 }
+        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781, -1.000003974843958109899184 }
     },{
         { 0, 27.692898794247 }, 19883493.6699045, 88.406440883665,
-        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836, -0.99595722110800843918 }
+        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836, -0.9997364583229516115064732 }
     },{
         { 0, 17.363238291869 }, 19980749.7638027, 39.697196316589,
-        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379, -0.9971281847750985694 }
+        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379, -0.9976876919817150126995782 }
     },{
         { 0, 37.006775102539 }, 19949309.9180043, 116.455543532607,
-        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701, -0.99590619058035212419 }
+        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701, -1.002219628589184219390543 }
     },{
         { 0, 45.572883540957 }, 19940027.8586414, 137.627256708444,
-        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496, -0.99624902751220101305 }
+        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496, -1.003808877864471522261582 }
     },{
         { 0, 43.63393981955 }, 19931045.2914508, 91.203625101465,
-        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764, -0.99608620009401716011 }
+        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764, -1.000029741531505212250378 }
     },{
         { 0, 38.4995307019 }, 19918391.2222193, 141.232864609445,
-        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077, -0.99588724635854519729 }
+        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077, -1.003881641157329480734325 }
     },{
         { 0, 27.55015339382 }, 19986004.7358853, 137.025135713548,
-        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654, -0.99616434874063342075 }
+        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654, -1.003160443902811658199205 }
     },{
         { 0, 1.54507498314 }, 19978593.3191777, 36.816106412092,
-        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168, -0.99970846248568390191 }
+        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168, -0.9997704994624671810221454 }
     },{
         { 0, 45.217063644222 }, 19987042.0782465, 18.114645812265,
-        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936, -0.99626823185730628563 }
+        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936, -0.9949741794148549555321798 }
     },{
         { 0, 13.473522450751 }, 19987364.078382, 156.839609002403,
-        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472, -0.99767717345868900392 }
+        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472, -1.002190931895065541886065 }
     },{
         { 0, 6.287741997374 }, 19912159.8245954, 132.954797451112,
-        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375, -0.99875728461227553101 }
+        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375, -1.00071252411103014544249 }
     },{
         { 0, 7.639709001531 }, 19976374.3699535, 29.731916588299,
-        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539, -0.99861517221927087462 }
+        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539, -0.9987897920867413009931961 }
     },{
         { 0, 5.893688050348 }, 19886907.2520668, 14.653438882877,
-        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022, -0.99875831501903877818 }
+        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022, -0.9987946470311208020708207 }
     },{
         { 0, 61.997076235476 }, 19976288.2901729, 149.562797049254,
-        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176, -0.99792483695855294101 }
+        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176, -1.003730714324371446686916 }
     },{
         { 0, 50.507637741656 }, 19979542.5263293, 171.564028344478,
-        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697, -0.99670226818003293534 }
+        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697, -1.005088816322817598953449 }
     },{
         { 0, 7.484475238477 }, 19867425.2906303, 57.020570370985,
-        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633, -0.99841820367274103365 }
+        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633, -0.9990970426773380551267907 }
     },{
         { 0, 56.851165323215 }, 19988235.9960515, 112.345749045605,
-        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518, -0.99734849887992094164 }
+        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518, -1.001828592498714131384455 }
     },{
         { 0, 10.692273150738 }, 19893210.3050033, 102.824601316946,
-        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111, -0.99796077650539405379 }
+        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111, -1.000343455845084243900113 }
     },{
         { 0, 46.694739303788 }, 19975447.9283188, 174.663684259477,
-        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645, -0.9963829846069084395 }
+        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645, -1.005204848752017347248908 }
     },{
         { 0, 15.804386137005 }, 19855850.8800526, 74.932089158884,
-        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628, -0.99706137589256171871 }
+        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628, -0.9990915785464752706503469 }
     },{
         { 0, 4.371450175299 }, 19979071.1035552, 164.163592252794,
-        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728, -0.99919490909391039946 }
+        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728, -1.00076323969894748092211 }
     },{
         { 0, 30.894388279688 }, 19968681.8321577, 77.35154610481,
-        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058, -0.99599179229723178164 }
+        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058, -0.9989751763364228440383701 }
     },{
         { 0, 9.541166838639 }, 19848553.7844137, 118.441353539081,
-        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614, -0.99800476808793336936 }
+        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614, -1.000605486201104942726309 }
     },{
         { 0, 8.489292700054 }, 19995477.1669578, 171.963952699866,
-        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974, -0.9984792781676200546 }
+        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974, -1.001520684863064588341133 }
     },{
         { 0, 19.562401114224 }, 19893208.1788508, 126.362762598128,
-        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615, -0.99671734436245396083 }
+        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615, -1.001852026688027773315692 }
     },{
         { 0, 42.260350252749 }, 19942715.0054774, 170.703419847646,
-        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769, -0.99607495753304098329 }
+        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769, -1.005086424064435460636394 }
     },{
         { 0, 24.511403144656 }, 19924809.5184876, 102.913211410163,
-        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318, -0.99629589741710011808 }
+        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318, -1.00084083091888388877648 }
     },{
         { 0, 20.844284170708 }, 19909084.6340808, 44.172784008084,
-        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608, -0.99659406562612795621 }
+        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608, -0.997389183621779017239594 }
     },{
         { 0, 2.426010809098 }, 19840940.6924189, 94.315194952561,
-        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638, -0.99922656404178245015 }
+        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638, -0.9998252498449916409405634 }
     },{
         { 0, 6.600682554664 }, 19878412.28273, 168.167678684515,
-        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692, -0.99861342289130949901 }
+        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692, -1.000982848560649784010017 }
     },{
         { 0, 23.372339802326 }, 19899498.4582543, 161.197647943542,
-        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091, -0.99635421423038206257 }
+        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091, -1.003476668684313999812749 }
     },{
         { 0, 16.194668264095 }, 19874825.6683239, 148.942349959054,
-        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622, -0.99709176416695455281 }
+        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622, -1.002220322222336505702499 }
     },{
         { 0, 1.528726471528 }, 19897803.9939987, 69.212891442493,
-        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133, -0.99957999688525089876 }
+        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133, -0.9998271442281568740497941 }
     },{
         { 0, 6.297249676078 }, 19864042.0495193, 56.274639904925,
-        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258, -0.99861474729636867664 }
+        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258, -0.9991904501783995893996783 }
     },{
         { 0, 17.393540327984 }, 19962624.6302607, 107.855062015266,
-        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839, -0.99711019484200580365 }
+        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839, -1.000918417796891303852592 }
     },{
         { 0, 46.284685151236 }, 19990422.3478916, 14.758013867151,
-        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104, -0.99634649632519134421 }
+        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104, -0.9948945922618399753472283 }
     },{
         { 0, 14.924320176299 }, 19891861.8615337, 31.446544793174,
-        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804, -0.99729741460688270394 }
+        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804, -0.9976201425853329563713315 }
     },{
         { 0, 23.668824656069 }, 19938736.4442268, 148.091483667618,
-        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819, -0.99640366072092678706 }
+        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819, -1.003232628720005910772511 }
     },{
         { 0, 46.986276695896 }, 19968596.0414782, 174.796708941456,
-        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769, -0.99639889458222818952 }
+        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769, -1.005190954526080850226118 }
     },{
         { 0, 65.946144289524 }, 19993734.5109736, 25.375428509648,
-        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769, -0.99838571720931879039 }
+        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769, -0.9964369359146106126432461 }
     },{
         { 0, 10.950298933293 }, 19975919.5586889, 28.779018914489,
-        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581, -0.99806099887646559932 }
+        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581, -0.9982720718341152112444356 }
     },{
         { 0, 13.609869340778 }, 19913213.8514358, 129.616021271129,
-        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776, -0.99755852834357494618 }
+        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776, -1.00146664642314031927646 }
     },{
         { 0, 48.701427557433 }, 19972955.2699173, 102.875149183407,
-        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697, -0.99652223116852467477 }
+        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697, -1.001146768554290695098057 }
     },{
         { 0, 31.519172055785 }, 19952318.3772514, 26.247105619999,
-        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002, -0.99593468381798511135 }
+        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002, -0.9957399483998249749283627 }
     },{
         { 0, 31.863784754278 }, 19993324.8682601, 29.572313410211,
-        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234, -0.9959831508497293262 }
+        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234, -0.9958880090011472640794746 }
     },{
         { 0, 76.434608546092 }, 19997750.023578, 167.428385412814,
-        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108, -0.99943031992965880583 }
+        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108, -1.002339638930915896456245 }
     },{
         { 0, 73.114273316483 }, 19992866.6147806, 78.154765899661,
-        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946, -0.99913315932148838439 }
+        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946, -0.9993841433084754598747609 }
     },{
         { 0, 1.125639056292 }, 19852573.5442848, 67.184842289382,
-        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937, -0.99950982898040086067 }
+        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937, -0.9997329579628334908763393 }
     }
 };


commit 96074e2ab2e9f3bddd81f56c5d23438574c0c040
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat Jun 9 16:15:55 2018 +0500

    [test] Use series order 2 for Karney's direct method

    Boost Geometry dataset is created with series order 2. Therefore,
    the tests fail at all other values.

diff --git a/test/formulas/direct.cpp b/test/formulas/direct.cpp
index bcfcec3..9cd4bdf 100644
--- a/test/formulas/direct.cpp
+++ b/test/formulas/direct.cpp
@@ -64,7 +64,7 @@ void test_all(expected_results const& results)
     result.reverse_azimuth *= r2d;
     check_direct(result, results.thomas, results.karney, 0.0000001);

-    typedef bg::formula::karney_direct<double, true, true, true, true, 8> ka_t;
+    typedef bg::formula::karney_direct<double, true, true, true, true, 2> ka_t;
     result = ka_t::apply(lon1d, lat1d, distance, azi12d, spheroid);
     check_direct(result, results.thomas, results.karney, 0.0000001);
 }

commit 043f401fbe22a2fbf8c3cb3e852a16c00e6fd942
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat Jun 9 16:11:46 2018 +0500

    [util] Use Maxima generated function for computing C3x coefficients

    The script used is geod.mac:
    https://sourceforge.net/p/geographiclib/code/ci/release/tree/maxima/geod.mac

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 02f1074..e3dc826 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -496,230 +496,112 @@ namespace boost { namespace geometry { namespace series_expansion {
      geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, int SeriesOrder>
-    void evaluate_coeffs_C3x(CT const& n, CT c[], const CT coeff[])
-    {
-        int offset = 0, k = 0;
-        // l is index of C3[l].
-        for (int l = 1; l < SeriesOrder; ++l)
-        {
-            for (int j = SeriesOrder - 1; j >= l; --j)
-            {
-                // Order of polynomial in n.
-                int m = std::min(SeriesOrder - j - 1, j);
-                c[k++] = math::polyval(m, coeff + offset, n) /
-                coeff[offset + m + 1];
-                offset += m + 2;
-            }
-        }
-    }
-
-    template <typename CT, int SeriesOrder>
-    void evaluate_coeffs_C3x(CT const& n, CT c[]) {
-        if (SeriesOrder == 3) {
-            static const CT coeff[] = {
-            // C3[1], coeff of eps^2, polynomial in n of order 0
-            1, 8,
-            // C3[1], coeff of eps^1, polynomial in n of order 1
-            -1, 1, 4,
-            // C3[2], coeff of eps^2, polynomial in n of order 0
-            1, 16,
-            };
-
-            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
-        }
-        else if (SeriesOrder == 4) {
-            static const CT coeff[] = {
-            // C3[1], coeff of eps^3, polynomial in n of order 0
-            3, 64,
-            // C3[1], coeff of eps^2, polynomial in n of order 1
-            // This is a case where a leading 0 term has been inserted to maintain the
-            // pattern in the orders of the polynomials.
-            0, 1, 8,
-            // C3[1], coeff of eps^1, polynomial in n of order 1
-            -1, 1, 4,
-            // C3[2], coeff of eps^3, polynomial in n of order 0
-            3, 64,
-            // C3[2], coeff of eps^2, polynomial in n of order 1
-            -3, 2, 32,
-            // C3[3], coeff of eps^3, polynomial in n of order 0
-            5, 192,
-            };
-
-            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
-        }
-        else if (SeriesOrder == 5) {
-            static const CT coeff[] = {
-            // C3[1], coeff of eps^4, polynomial in n of order 0
-            5, 128,
-            // C3[1], coeff of eps^3, polynomial in n of order 1
-            3, 3, 64,
-            // C3[1], coeff of eps^2, polynomial in n of order 2
-            -1, 0, 1, 8,
-            // C3[1], coeff of eps^1, polynomial in n of order 1
-            -1, 1, 4,
-            // C3[2], coeff of eps^4, polynomial in n of order 0
-            3, 128,
-            // C3[2], coeff of eps^3, polynomial in n of order 1
-            -2, 3, 64,
-            // C3[2], coeff of eps^2, polynomial in n of order 2
-            1, -3, 2, 32,
-            // C3[3], coeff of eps^4, polynomial in n of order 0
-            3, 128,
-            // C3[3], coeff of eps^3, polynomial in n of order 1
-            -9, 5, 192,
-            // C3[4], coeff of eps^4, polynomial in n of order 0
-            7, 512,
-            };
-
-            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
-        }
-        else if (SeriesOrder == 6) {
-            static const CT coeff[] = {
-            // C3[1], coeff of eps^5, polynomial in n of order 0
-            3, 128,
-            // C3[1], coeff of eps^4, polynomial in n of order 1
-            2, 5, 128,
-            // C3[1], coeff of eps^3, polynomial in n of order 2
-            -1, 3, 3, 64,
-            // C3[1], coeff of eps^2, polynomial in n of order 2
-            -1, 0, 1, 8,
-            // C3[1], coeff of eps^1, polynomial in n of order 1
-            -1, 1, 4,
-            // C3[2], coeff of eps^5, polynomial in n of order 0
-            5, 256,
-            // C3[2], coeff of eps^4, polynomial in n of order 1
-            1, 3, 128,
-            // C3[2], coeff of eps^3, polynomial in n of order 2
-            -3, -2, 3, 64,
-            // C3[2], coeff of eps^2, polynomial in n of order 2
-            1, -3, 2, 32,
-            // C3[3], coeff of eps^5, polynomial in n of order 0
-            7, 512,
-            // C3[3], coeff of eps^4, polynomial in n of order 1
-            -10, 9, 384,
-            // C3[3], coeff of eps^3, polynomial in n of order 2
-            5, -9, 5, 192,
-            // C3[4], coeff of eps^5, polynomial in n of order 0
-            7, 512,
-            // C3[4], coeff of eps^4, polynomial in n of order 1
-            -14, 7, 512,
-            // C3[5], coeff of eps^5, polynomial in n of order 0
-            21, 2560,
-            };
-
-            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
-        }
-        else if (SeriesOrder == 7) {
-            static const CT coeff[] = {
-            // C3[1], coeff of eps^6, polynomial in n of order 0
-            21, 1024,
-            // C3[1], coeff of eps^5, polynomial in n of order 1
-            11, 12, 512,
-            // C3[1], coeff of eps^4, polynomial in n of order 2
-            2, 2, 5, 128,
-            // C3[1], coeff of eps^3, polynomial in n of order 3
-            -5, -1, 3, 3, 64,
-            // C3[1], coeff of eps^2, polynomial in n of order 2
-            -1, 0, 1, 8,
-            // C3[1], coeff of eps^1, polynomial in n of order 1
-            -1, 1, 4,
-            // C3[2], coeff of eps^6, polynomial in n of order 0
-            27, 2048,
-            // C3[2], coeff of eps^5, polynomial in n of order 1
-            1, 5, 256,
-            // C3[2], coeff of eps^4, polynomial in n of order 2
-            -9, 2, 6, 256,
-            // C3[2], coeff of eps^3, polynomial in n of order 3
-            2, -3, -2, 3, 64,
-            // C3[2], coeff of eps^2, polynomial in n of order 2
-            1, -3, 2, 32,
-            // C3[3], coeff of eps^6, polynomial in n of order 0
-            3, 256,
-            // C3[3], coeff of eps^5, polynomial in n of order 1
-            -4, 21, 1536,
-            // C3[3], coeff of eps^4, polynomial in n of order 2
-            -6, -10, 9, 384,
-            // C3[3], coeff of eps^3, polynomial in n of order 3
-            -1, 5, -9, 5, 192,
-            // C3[4], coeff of eps^6, polynomial in n of order 0
-            9, 1024,
-            // C3[4], coeff of eps^5, polynomial in n of order 1
-            -10, 7, 512,
-            // C3[4], coeff of eps^4, polynomial in n of order 2
-            10, -14, 7, 512,
-            // C3[5], coeff of eps^6, polynomial in n of order 0
-            9, 1024,
-            // C3[5], coeff of eps^5, polynomial in n of order 1
-            -45, 21, 2560,
-            // C3[6], coeff of eps^6, polynomial in n of order 0
-            11, 2048,
-            };
-
-            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
-        }
-        else if (SeriesOrder == 8) {
-            static const CT coeff[] = {
-            // C3[1], coeff of eps^7, polynomial in n of order 0
-            243, 16384,
-            // C3[1], coeff of eps^6, polynomial in n of order 1
-            10, 21, 1024,
-            // C3[1], coeff of eps^5, polynomial in n of order 2
-            3, 11, 12, 512,
-            // C3[1], coeff of eps^4, polynomial in n of order 3
-            -2, 2, 2, 5, 128,
-            // C3[1], coeff of eps^3, polynomial in n of order 3
-            -5, -1, 3, 3, 64,
-            // C3[1], coeff of eps^2, polynomial in n of order 2
-            -1, 0, 1, 8,
-            // C3[1], coeff of eps^1, polynomial in n of order 1
-            -1, 1, 4,
-            // C3[2], coeff of eps^7, polynomial in n of order 0
-            187, 16384,
-            // C3[2], coeff of eps^6, polynomial in n of order 1
-            69, 108, 8192,
-            // C3[2], coeff of eps^5, polynomial in n of order 2
-            -2, 1, 5, 256,
-            // C3[2], coeff of eps^4, polynomial in n of order 3
-            -6, -9, 2, 6, 256,
-            // C3[2], coeff of eps^3, polynomial in n of order 3
-            2, -3, -2, 3, 64,
-            // C3[2], coeff of eps^2, polynomial in n of order 2
-            1, -3, 2, 32,
-            // C3[3], coeff of eps^7, polynomial in n of order 0
-            139, 16384,
-            // C3[3], coeff of eps^6, polynomial in n of order 1
-            -1, 12, 1024,
-            // C3[3], coeff of eps^5, polynomial in n of order 2
-            -77, -8, 42, 3072,
-            // C3[3], coeff of eps^4, polynomial in n of order 3
-            10, -6, -10, 9, 384,
-            // C3[3], coeff of eps^3, polynomial in n of order 3
-            -1, 5, -9, 5, 192,
-            // C3[4], coeff of eps^7, polynomial in n of order 0
-            127, 16384,
-            // C3[4], coeff of eps^6, polynomial in n of order 1
-            -43, 72, 8192,
-            // C3[4], coeff of eps^5, polynomial in n of order 2
-            -7, -40, 28, 2048,
-            // C3[4], coeff of eps^4, polynomial in n of order 3
-            -7, 20, -28, 14, 1024,
-            // C3[5], coeff of eps^7, polynomial in n of order 0
-            99, 16384,
-            // C3[5], coeff of eps^6, polynomial in n of order 1
-            -15, 9, 1024,
-            // C3[5], coeff of eps^5, polynomial in n of order 2
-            75, -90, 42, 5120,
-            // C3[6], coeff of eps^7, polynomial in n of order 0
-            99, 16384,
-            // C3[6], coeff of eps^6, polynomial in n of order 1
-            -99, 44, 8192,
-            // C3[7], coeff of eps^7, polynomial in n of order 0
-            429, 114688,
-            };
-
-            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
+    static inline void evaluate_coeffs_C3x(CT const& n, CT c[]) {
+        const CT n2 = math::sqr(n);
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            break;
+        case 2:
+            c[0] = (CT(1)-n)/CT(4);
+            break;
+        case 3:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = ((n-CT(3))*n+CT(2))/CT(32);
+            break;
+        case 4:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[4] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[5] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            break;
+        case 5:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[5] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[6] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[7] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[8] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[9] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            break;
+        case 6:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
+            c[5] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[6] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[7] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[8] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
+            c[9] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[10] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[11] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
+            c[12] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            c[13] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
+            c[14] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
+            break;
+        case 7:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
+            c[5] = (CT(10)*n+CT(21))/CT(1024);
+            c[6] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[7] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[8] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[9] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
+            c[10] = (CT(69)*n+CT(108))/CT(8192);
+            c[11] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[12] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[13] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
+            c[14] = (CT(12)-n)/CT(1024);
+            c[15] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            c[16] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
+            c[17] = (CT(72)-CT(43)*n)/CT(8192);
+            c[18] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
+            c[19] = (CT(9)-CT(15)*n)/CT(1024);
+            c[20] = (CT(44)-CT(99)*n)/CT(8192);
+            break;
+        case 8:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
+            c[5] = (CT(10)*n+CT(21))/CT(1024);
+            c[6] = CT(243)/CT(16384);
+            c[7] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[8] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[9] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[10] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
+            c[11] = (CT(69)*n+CT(108))/CT(8192);
+            c[12] = CT(187)/CT(16384);
+            c[13] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[14] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[15] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
+            c[16] = (CT(12)-n)/CT(1024);
+            c[17] = CT(139)/CT(16384);
+            c[18] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            c[19] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
+            c[20] = (CT(72)-CT(43)*n)/CT(8192);
+            c[21] = CT(127)/CT(16384);
+            c[22] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
+            c[23] = (CT(9)-CT(15)*n)/CT(1024);
+            c[24] = CT(99)/CT(16384);
+            c[25] = (CT(44)-CT(99)*n)/CT(8192);
+            c[26] = CT(99)/CT(16384);
+            c[27] = CT(429)/CT(114688);
+            break;
         }
-        // Post condition: offset == sizeof(coeff) / sizeof(CT) && k == coeffs_C3_size
     }

     /*

commit 276e8e6d7a673a5e9676c4135f23805697a80eee
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 7 18:28:22 2018 +0500

    [formulas] Add function for computing the length at the meridians

    This method is an integral part of Karney's solution to inverse
    geodesic problem. It is only invoked for points that lie on
    the meridian, or are close to it.

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
index 4929f9c..9297034 100644
--- a/include/boost/geometry/formulas/karney_inverse.hpp
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -49,6 +49,12 @@ class karney_inverse

 public:
     typedef result_inverse<CT> result_type;
+    static CT constexpr c0 = 0;
+    static CT constexpr c1 = 1;
+    static CT constexpr c2 = 2;
+    static CT constexpr c3 = 3;
+    static CT constexpr c180 = 180;
+    static CT constexpr c90 = 90;

     template <typename T1, typename T2, typename Spheroid>
     static inline result_type apply(T1 const& lo1,
@@ -65,10 +71,16 @@ public:
         CT lon1 = lo1;
         CT lon2 = lo2;

-        CT const c1 = 1;
-        CT const c2 = 2;
-        CT const c180 = 180;
-        CT const c90 = 90;
+        CT tiny = std::sqrt(std::numeric_limits<CT>::min());
+
+        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);

         // Compute the longitudinal difference.
         CT lon12_error;
@@ -80,6 +92,7 @@ public:
         lon12 = lon12_sign * math::round_angle(lon12);
         lon12_error = math::round_angle((c180 - lon12) - lon12_sign * lon12_error);

+        // Convert to radians.
         CT lam12 = lon12 * math::d2r<CT>();
         CT sin_lam12;
         CT cos_lam12;
@@ -112,7 +125,202 @@ public:
         int lat_sign = lat1 < 0 ? 1 : -1;
         lat1 *= lat_sign;
         lat2 *= lat_sign;
+
+        CT sin_beta1, cos_beta1;
+        math::sin_cos_degrees(lat1, sin_beta1, cos_beta1);
+        sin_beta1 *= one_minus_f;
+
+        math::normalize(sin_beta1, cos_beta1);
+        cos_beta1 = std::max(tiny, cos_beta1);
+
+        CT sin_beta2, cos_beta2;
+        math::sin_cos_degrees(lat2, sin_beta2, cos_beta2);
+        sin_beta2 *= one_minus_f;
+
+        math::normalize(sin_beta2, cos_beta2);
+        cos_beta2 = std::max(tiny, cos_beta2);
+
+        // If cos_beta1 < -sin_beta1, then cos_beta2 - cos_beta1 is a
+        // sensitive measure of the |beta1| - |beta2|.  Alternatively,
+        // (cos_beta1 >= -sin_beta1), abs(sin_beta2) + sin_beta1 is
+        // a better measure.
+        // Sometimes these quantities vanish and in that case we
+        // force beta2 = +/- bet1a exactly.
+        if (cos_beta1 < -sin_beta1)
+        {
+            if (cos_beta1 == cos_beta2)
+            {
+                sin_beta2 = sin_beta2 < 0 ? sin_beta1 :
+                                            -sin_beta1;
+            }
+        }
+        else
+        {
+            if (std::abs(sin_beta2) == -sin_beta1)
+            {
+                cos_beta2 = cos_beta1;
+            }
+        }
+
+        CT const dn1 = sqrt(c1 + ep2 * math::sqr(sin_beta1));
+        CT const dn2 = sqrt(c1 + ep2 * math::sqr(sin_beta2));
+
+        CT a12, sigma12;
+        CT m12x, s12x, M21;
+
+        // Index zero element of coeffs_C1 is unused.
+        CT coeffs_C1[SeriesOrder + 1];
+
+        bool meridian = lat1 == -90 || sin_lam12 == 0;
+
+        if (meridian)
+        {
+            // Endpoints lie on a single full meridian.
+
+            // Point to the target latitude.
+            CT cos_alpha1 = cos_lam12;
+            CT sin_alpha1 = sin_lam12;
+
+            // Heading north at the target.
+            CT cos_alpha2 = 1;
+            CT sin_alpha2 = 0;
+
+            CT sin_sigma1 = sin_beta1;
+            CT cos_sigma1 = cos_alpha1 * cos_beta1;
+
+            CT sin_sigma2 = sin_beta2;
+            CT cos_sigma2 = cos_alpha2 * cos_beta2;
+
+            CT sigma12 = std::atan2(std::max(c0, cos_sigma1 * sin_sigma2 - sin_sigma1 * cos_sigma2),
+                                             cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2);
+
+            meridian_length(n, ep2, sigma12, sin_sigma1, cos_sigma1, dn1,
+                                             sin_sigma2, cos_sigma2, dn2,
+                                             cos_beta1, cos_beta2, s12x,
+                                             m12x, result.geodesic_scale, M21);
+
+
+            if (sigma12 < c1 || m12x >= c0)
+            {
+                if (sigma12 < c3 * tiny)
+                {
+                    sigma12  = m12x = s12x = c0;
+                }
+
+                m12x *= b;
+                s12x *= b;
+                a12 = sigma12 / math::d2r<CT>();
+            }
+            else
+            {
+                // m12 < 0, i.e., prolate and too close to anti-podal.
+                meridian = false;
+            }
+        }
     }
+
+    static inline void meridian_length(CT epsilon, CT ep2, CT sigma12,
+                                       CT sin_sigma1, CT cos_sigma1, CT dn1,
+                                       CT sin_sigma2, CT cos_sigma2, CT dn2,
+                                       CT cos_beta1, CT cos_beta2,
+                                       CT& s12x, CT& m12x,
+                                       CT& M12, CT& M21)
+    {
+        CT A12x = 0, J12 = 0;
+        CT expansion_A1, expansion_A2;
+
+        // Index zero element of coeffs_C1 and coeffs_C2 is unused.
+        CT coeffs_C1[SeriesOrder + 1];
+        CT coeffs_C2[SeriesOrder + 1];
+
+        if (BOOST_GEOMETRY_CONDITION(EnableDistance) ||
+            BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
+            BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+        {
+            // Find the coefficients for A1 by computing the
+            // series expansion using Horner scehme.
+            expansion_A1
+                = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);
+
+            // Evaluate the coefficients for C1.
+            series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);
+
+            if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
+                BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+            {
+                // Find the coefficients for A2 by computing the
+                // series expansion using Horner scehme.
+                expansion_A2
+                    = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);
+
+                // Evaluate the coefficients for C2.
+                series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);
+
+                A12x = expansion_A1 - expansion_A2;
+                expansion_A2 += c1;
+            }
+            expansion_A1 += c1;
+        }
+
+        if (BOOST_GEOMETRY_CONDITION(EnableDistance))
+        {
+            CT B1 = series_expansion::sin_cos_series<CT, SeriesOrder>
+                                      (sin_sigma2, cos_sigma2, coeffs_C1)
+                  - series_expansion::sin_cos_series<CT, SeriesOrder>
+                                      (sin_sigma1, cos_sigma1, coeffs_C1);
+
+            m12x = expansion_A1 * (sigma12 + B1);
+
+            if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
+                BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+            {
+                CT B2 = series_expansion::sin_cos_series<CT, SeriesOrder>
+                                          (sin_sigma2, cos_sigma2, coeffs_C2)
+                      - series_expansion::sin_cos_series<CT, SeriesOrder>
+                                          (sin_sigma1, cos_sigma1, coeffs_C2);
+
+                J12 = A12x * sigma12 + (expansion_A1 * B1 -
+                                        expansion_A2 * B2);
+            }
+        }
+        else if (BOOST_GEOMETRY_CONDITION(EnableReducedLength) ||
+                 BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+        {
+            for (size_t i = 1; i <= SeriesOrder; ++i)
+            {
+                coeffs_C2[i] = expansion_A1 * coeffs_C1[i] -
+                               expansion_A2 * coeffs_C2[i];
+            }
+
+            J12 = A12x * sigma12 +
+                   (series_expansion::sin_cos_series<CT, SeriesOrder>
+                                      (sin_sigma2,
+                                       cos_sigma2,
+                                       coeffs_C2)
+                  - series_expansion::sin_cos_series<CT, SeriesOrder>
+                                      (sin_sigma1,
+                                       cos_sigma1,
+                                       coeffs_C2));
+        }
+
+        if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
+        {
+            m12x = dn2 * (cos_sigma1 * sin_sigma2) -
+                   dn1 * (sin_sigma1 * cos_sigma2) -
+                   cos_sigma1 * cos_sigma2 * J12;
+        }
+
+        if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
+        {
+            CT cos_sigma12 = cos_sigma1 * cos_sigma2 + sin_sigma1 * sin_sigma2;
+            CT t = ep2 * (cos_beta1 - cos_beta2) *
+                         (cos_beta1 + cos_beta2) / (dn1 + dn2);
+
+            M12 = cos_sigma12 + (t * sin_sigma2 - cos_sigma2 * J12) * sin_sigma1 / dn1;
+            M21 = cos_sigma12 - (t * sin_sigma1 - cos_sigma1 * J12) * sin_sigma2 / dn2;
+        }
+    }
+
 };

 }}} // namespace boost::geometry::formula

commit efd30c8ccc581a6669c836675f5d87ad0f26e733
Merge: 2e064c0 8a2dd63
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 7 11:00:37 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

commit 8a2dd63ccf85f80134d9d88e049ac6d272531f0f
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu Jun 7 10:58:13 2018 +0500

    [util] Move sin_cos_series function to series_expansion.hpp

    This function is extensively used for the direct and
    inverse geodesic problem, therefore, it is moved
    to a more accessible location.

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 934122b..6f63cb1 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -48,38 +48,6 @@ class karney_direct
 public:
     typedef result_direct<CT> result_type;

-    /*
-     Evaluate
-
-     y = sum(c[i] * sin(2*i * x), i, 1, n)
-
-     using Clenshaw summation.
-    */
-    static inline CT sin_cos_series(CT sinx,
-                                    CT cosx,
-                                    const CT coeffs[])
-    {
-        size_t n = SeriesOrder;
-
-        // Point to one beyond last element.
-        coeffs += (n + 1);
-        CT ar = 2 * (cosx - sinx) * (cosx + sinx);
-
-        CT k0 = n & 1 ? *--coeffs : 0;
-        CT k1 = 0;
-
-        // Make n even.
-        n /= 2;
-        while (n--) {
-          // Unroll loop x 2, so accumulators return to their original role.
-          k1 = ar * k0 - k1 + *--coeffs;
-          k0 = ar * k1 - k0 + *--coeffs;
-        }
-
-        return 2 * sinx * cosx * k0;
-    }
-
-
     template <typename T, typename Dist, typename Azi, typename Spheroid>
     static inline result_type apply(T const& lo1,
                                     T const& la1,
@@ -157,7 +125,8 @@ public:
         cos_sigma1 = cos_omega1 = sin_beta1 != 0 || cos_alpha1 != 0 ? cos_beta1 * cos_alpha1 : 1;
         math::normalize<CT>(sin_sigma1, cos_sigma1);

-        CT const B11 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
+        CT const B11 =
+            series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C1);
         CT const sin_B11 = sin(B11);
         CT const cos_B11 = cos(B11);

@@ -170,9 +139,11 @@ public:
         CT coeffs_C1p[SeriesOrder + 1];
         series_expansion::evaluate_coeffs_C1p<CT, SeriesOrder>(epsilon, coeffs_C1p);

-        CT const B12 = - sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
-                                      cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
-                                      coeffs_C1p);
+        CT const B12 =
+            - series_expansion::sin_cos_series<CT, SeriesOrder>
+                                (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);
@@ -229,12 +200,14 @@ public:
             CT coeffs_C3[SeriesOrder];
             series_expansion::evaluate_coeffs_C3<double, SeriesOrder>(epsilon, coeffs_C3, coeffs_C3x);

-            CT const B31 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
+            CT const B31 =
+                series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C3);

             CT const lam12 = omega12 + A3c *
-                             (sigma12 + (sin_cos_series(sin_sigma2,
-                                                        cos_sigma2,
-                                                        coeffs_C3) - B31));
+                             (sigma12 + (series_expansion::sin_cos_series<CT, SeriesOrder>
+                                                           (sin_sigma2,
+                                                            cos_sigma2,
+                                                            coeffs_C3) - B31));

             // Convert to radians to get the
             // longitudinal difference.
@@ -253,8 +226,10 @@ public:
             CT coeffs_C2[SeriesOrder + 1];
             series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);

-            CT const B21 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
-            CT const B22 = sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);
+            CT const B21 =
+                series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma1, cos_sigma1, coeffs_C2);
+            CT const B22 =
+                series_expansion::sin_cos_series<CT, SeriesOrder>(sin_sigma2, cos_sigma2, coeffs_C2);

             // Find the coefficients for A2 by computing the
             // series expansion using Horner scehme.
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index ba3c214..02f1074 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -746,6 +746,38 @@ namespace boost { namespace geometry { namespace series_expansion {
         // Post condition: offset == coeffs_C3_size
     }

+    /*
+    \brief Evaluate the following:
+
+     y = sum(c[i] * sin(2*i * x), i, 1, n)
+
+     using Clenshaw summation.
+    */
+    template <typename CT, size_t SeriesOrder>
+    static inline CT sin_cos_series(CT sinx,
+                                    CT cosx,
+                                    const CT coeffs[])
+    {
+        size_t n = SeriesOrder;
+
+        // Point to one beyond last element.
+        coeffs += (n + 1);
+        CT ar = 2 * (cosx - sinx) * (cosx + sinx);
+
+        CT k0 = n & 1 ? *--coeffs : 0;
+        CT k1 = 0;
+
+        // Make n even.
+        n /= 2;
+        while (n--) {
+          // Unroll loop x 2, so accumulators return to their original role.
+          k1 = ar * k0 - k1 + *--coeffs;
+          k0 = ar * k1 - k0 + *--coeffs;
+        }
+
+        return 2 * sinx * cosx * k0;
+    }
+

 }}} // namespace boost::geometry::series_expansion


commit 2e064c0f0d1cb0e9fde38643413a76257d11346e
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 6 09:42:09 2018 +0500

    [formulas] Arrange points in canonical form for inverse geodesic problem

diff --git a/include/boost/geometry/formulas/karney_inverse.hpp b/include/boost/geometry/formulas/karney_inverse.hpp
new file mode 100644
index 0000000..4929f9c
--- /dev/null
+++ b/include/boost/geometry/formulas/karney_inverse.hpp
@@ -0,0 +1,121 @@
+// Boost.Geometry
+
+// Contributed and/or modified by Adeel Ahmad.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_FORMULAS_KARNEY_INVERSE_HPP
+#define BOOST_GEOMETRY_FORMULAS_KARNEY_INVERSE_HPP
+
+
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/special_functions/hypot.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/series_expansion.hpp>
+
+#include <boost/geometry/formulas/flattening.hpp>
+#include <boost/geometry/formulas/result_inverse.hpp>
+
+
+namespace boost { namespace geometry { namespace formula
+{
+
+
+/*!
+\brief The solution of the inverse problem of geodesics on latlong coordinates,
+       after Karney (2011).
+\author See
+- Charles F.F Karney, Algorithms for geodesics, 2011
+https://arxiv.org/pdf/1109.4448.pdf
+*/
+template <
+    typename CT,
+    bool EnableDistance,
+    bool EnableAzimuth,
+    bool EnableReverseAzimuth = false,
+    bool EnableReducedLength = false,
+    bool EnableGeodesicScale = false,
+    size_t SeriesOrder = 8
+>
+class karney_inverse
+{
+    static const bool CalcQuantities = EnableReducedLength || EnableGeodesicScale;
+    static const bool CalcAzimuths = EnableAzimuth || EnableReverseAzimuth || CalcQuantities;
+    static const bool CalcFwdAzimuth = EnableAzimuth || CalcQuantities;
+    static const bool CalcRevAzimuth = EnableReverseAzimuth || CalcQuantities;
+
+public:
+    typedef result_inverse<CT> result_type;
+
+    template <typename T1, typename T2, typename Spheroid>
+    static inline result_type apply(T1 const& lo1,
+                                    T1 const& la1,
+                                    T2 const& lo2,
+                                    T2 const& la2,
+                                    Spheroid const& spheroid)
+    {
+        result_type result;
+
+        CT lat1 = la1;
+        CT lat2 = la2;
+
+        CT lon1 = lo1;
+        CT lon2 = lo2;
+
+        CT const c1 = 1;
+        CT const c2 = 2;
+        CT const c180 = 180;
+        CT const c90 = 90;
+
+        // Compute the longitudinal difference.
+        CT lon12_error;
+        CT lon12 = math::difference_angle(lon1, lon2, lon12_error);
+
+        int lon12_sign = lon12 >= 0 ? 1 : -1;
+
+        // Make points close to the meridian to lie on it.
+        lon12 = lon12_sign * math::round_angle(lon12);
+        lon12_error = math::round_angle((c180 - lon12) - lon12_sign * lon12_error);
+
+        CT lam12 = lon12 * math::d2r<CT>();
+        CT sin_lam12;
+        CT cos_lam12;
+
+        lon12 > c90 ? math::sin_cos_degrees(lon12_error, sin_lam12, cos_lam12)
+                    : math::sin_cos_degrees(lon12, sin_lam12, cos_lam12);
+
+        // Make points close to the equator to lie on it.
+        lat1 = std::abs(lat1) > 90 ? math::NaN<CT>() : lat1;
+        lat2 = std::abs(lat2) > 90 ? math::NaN<CT>() : lat2;
+
+        lat1 = math::round_angle(lat1);
+        lat2 = math::round_angle(lat2);
+
+        // Arrange points in a canonical form, as explained in
+        // paper Algorithms for geodesics, Eq. (44):
+        //
+        //     0 <= lon12 <= 180
+        //     -90 <= lat1 <= 0
+        //     lat1 <= lat2 <= -lat1
+        int swap_point = std::abs(lat1) < std::abs(lat2) ? -1 : 1;
+
+        if (swap_point < 0)
+        {
+            lon12_sign *= -1;
+            swap(lat1, lat2);
+        }
+
+        // Enforce lat1 to be <= 0.
+        int lat_sign = lat1 < 0 ? 1 : -1;
+        lat1 *= lat_sign;
+        lat2 *= lat_sign;
+    }
+};
+
+}}} // namespace boost::geometry::formula
+
+
+#endif // BOOST_GEOMETRY_FORMULAS_KARNEY_INVERSE_HPP

commit 7561d68c086d85ce990e32196dc95874f11ac4c4
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 6 09:39:31 2018 +0500

    [util] Add function for returning NaN (not a number)

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 652ca85..f8b3707 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -810,6 +810,23 @@ inline void sin_cos_degrees(T const& x, T & sinx, T & cosx)
 }

 /*!
+\brief The NaN (not a number)
+*/
+template<typename T>
+inline T NaN()
+{
+#if defined(_MSC_VER)
+    return std::numeric_limits<T>::has_quiet_NaN ?
+      std::numeric_limits<T>::quiet_NaN() :
+      (std::numeric_limits<T>::max)();
+#else
+    return std::numeric_limits<T>::has_quiet_NaN ?
+      std::numeric_limits<T>::quiet_NaN() :
+      std::numeric_limits<T>::max();
+#endif
+}
+
+/*!
 \brief Round off a given angle
 */
 template<typename T>
@@ -889,7 +906,7 @@ inline T difference_angle(T x, T y, T& e)
 }


-/*
+/*!
 \brief Evaluate the polynomial in x using Horner's method.
 */
 // TODO: adl1995 - Merge these functions with formulas/area_formulas.hpp
@@ -909,7 +926,7 @@ inline NT horner_evaluate(NT x,
     return result;
 }

-/*
+/*!
 \brief Evaluate the polynomial.
 */
 template<typename CT>

commit 49e0a4fdaee2a78b5691c3c0db616fbb9ecd4f28
Merge: b9b0f85 df0cafd
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed Jun 6 08:24:27 2018 +0500

    Merge branch 'feature/geodesic_direct' into feature/karney_inverse

commit df0cafdd190d1ce51e75dab32f9e302527acea49
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 5 17:26:30 2018 +0500

    [doc] Move Maxima scripts for geodesics to doc/other/maxima/geod.mac

diff --git a/doc/other/maxima/geod.mac b/doc/other/maxima/geod.mac
new file mode 100644
index 0000000..229e949
--- /dev/null
+++ b/doc/other/maxima/geod.mac
@@ -0,0 +1,232 @@
+/*
+Compute the series expansions for the ellipsoidal geodesic problem.
+
+Copyright (c) Charles Karney (2009-2015) <charles@karney.com> and
+licensed under the MIT/X11 License.  For more information, see
+https://geographiclib.sourceforge.io
+
+References:
+
+   Charles F. F. Karney,
+   Algorithms for geodesics, J. Geodesy 87, 43-55 (2013),
+   https://doi.org/10.1007/s00190-012-0578-z
+   Addenda: https://geographiclib.sourceforge.io/geod-addenda.html
+
+The code below contains minor modifications to conform with
+Boost Geometry style guidelines.
+
+To run the code, start Maxima and enter
+
+  load("geod.mac")$
+*/
+
+taylordepth:5$
+ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+computeI1(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+  sintegrand:sqrt(1+k2*sin(sigma)^2),
+  sintegrandexp:ataylor(
+      (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+      eps,maxpow),
+  s:trigreduce(integrate(sintegrandexp,sigma)),
+  s:s-subst(sigma=0,s),
+  A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+  tau1:ataylor(s/A1,eps,maxpow),
+  for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
+  if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+  then error("left over terms in B1"),
+  A1:A1/(1-eps),
+  'done)$
+
+codeA1(maxpow):=block([tab2:"    ",tab3:"        "],
+print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
+static inline CT evaluate_series_A1(CT eps) {
+    CT eps2 = math::sqr(eps);
+    CT t;
+    switch (SeriesOrder/2) {"),
+  for n:0 thru entier(maxpow/2) do block([
+    q:horner(ataylor(subst([eps=sqrt(eps2)],A1*(1-eps)-1),eps2,n)),
+    linel:1200],
+    print(concat(tab2,"case ",string(n),":")),
+    print(concat(tab3,"t = ",string(q),";")),
+    print(concat(tab3,"break;"))),
+  print("    }
+    return (t + eps) / (1 - eps);
+}"),
+'done)$
+
+computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+  sintegrand:1/sqrt(1+k2*sin(sigma)^2),
+  sintegrandexp:ataylor(
+      (1+eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+      eps,maxpow),
+  s:trigreduce(integrate(sintegrandexp,sigma)),
+  s:s-subst(sigma=0,s),
+  A2:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+  tau1:ataylor(s/A2,eps,maxpow),
+  for i:1 thru maxpow do C2[i]:coeff(tau1,sin(2*i*sigma)),
+  if expand(tau1-sigma-sum(C2[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+  then error("left over terms in B2"),
+  A2:A2/(1+eps),
+  'done)$
+
+codeA2(maxpow):=block([tab2:"    ",tab3:"        "],
+print("// The scale factor A2-1 = mean value of (d/dsigma)I2 - 1
+CT evaluate_series_A2(CT const& eps)
+{
+    CT const eps2 = math::sqr(eps);
+    CT t;
+    switch (SeriesOrder/2) {"),
+  for n:0 thru entier(maxpow/2) do block([
+    q:horner(ataylor(subst([eps=sqrt(eps2)],A2*(1+eps)-1),eps2,n)),
+    linel:1200],
+    print(concat(tab2,"case ",string(n),":")),
+    print(concat(tab3,"t = ",string(q),";")),
+    print(concat(tab3,"break;"))),
+  print("    }
+    return (t - eps) / (1 + eps);
+}"),
+'done)$
+
+computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n],
+  maxpow:maxpow-1,
+  int:subst([k2=4*eps/(1-eps)^2],
+    (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma)^2))),
+  int:subst([f=2*n/(1+n)],int),
+  intexp:jtaylor(int,n,eps,maxpow),
+  dlam:trigreduce(integrate(intexp,sigma)),
+  dlam:dlam-subst(sigma=0,dlam),
+  A3:expand(subst(sigma=2*%pi,dlam)/(2*%pi)),
+  eta:jtaylor(dlam/A3,n,eps,maxpow),
+  A3:jtaylor(A3,n,eps,maxpow),
+  for i:1 thru maxpow do C3[i]:coeff(eta,sin(2*i*sigma)),
+  if expand(eta-sigma-sum(C3[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+  then error("left over terms in B3"),
+  'done)$
+
+codeA3(maxpow):=block([tab2:"    ",tab3:"        "],
+print("// The scale factor A3 = mean value of (d/dsigma)I3
+static inline void evaluate_series_A3(CT const& n, CT c[])
+{
+    switch (SeriesOrder) {"),
+  for nn:0 thru maxpow do block(
+    [q:if nn=0 then 0 else
+    jtaylor(subst([n=n],A3),n,eps,nn-1),
+    linel:1200],
+    print(concat(tab2,"case ",string(nn),":")),
+    for i : 0 thru nn-1 do
+    print(concat(tab3,"c[",i,"] = ",
+        string(horner(coeff(q,eps,i))),";")),
+    print(concat(tab3,"break;"))),
+  print("    }
+}"),
+'done)$
+
+codeC1(maxpow):=block([tab2:"    ",tab3:"        "],
+  print("// The coefficients C1[l] in the Fourier expansion of B1
+static inline evaluate_coeffs_C1(CT eps, CT c[]) {
+    CT eps2 = math::sqr(eps);
+    CT d = eps;
+    switch (SeriesOrder) {"),
+  for n:0 thru maxpow do (
+    print(concat(tab2,"case ",string(n),":")),
+    for m:1 thru n do block([q:d*horner(
+        subst([eps=sqrt(eps2)],ataylor(C1[m],eps,n)/eps^m)),
+      linel:1200],
+      if m>1 then print(concat(tab3,"d *= eps;")),
+      print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+    print(concat(tab3,"break;"))),
+  print("    }
+}"),
+'done)$
+
+revertI1(maxpow):=block([tau,eps,tauacc:1,sigacc:0],
+  for n:1 thru maxpow do (
+    tauacc:trigreduce(ataylor(
+          -sum(C1[j]*sin(2*j*tau),j,1,maxpow-n+1)*tauacc/n,
+          eps,maxpow)),
+    sigacc:sigacc+expand(diff(tauacc,tau,n-1))),
+  for i:1 thru maxpow do C1p[i]:coeff(sigacc,sin(2*i*tau)),
+  if expand(sigacc-sum(C1p[i]*sin(2*i*tau),i,1,maxpow)) # 0
+  then error("left over terms in B1p"),
+  'done)$
+
+codeC1p(maxpow):=block([tab2:"    ",tab3:"        "],
+  print("// The coefficients C1p[l] in the Fourier expansion of B1p
+static inline evaluate_coeffs_C1p(CT eps, CT c[])
+{
+    CT const eps2 = math::sqr(eps);
+    CT d = eps;
+    switch (SeriesOrder) {"),
+  for n:0 thru maxpow do (
+    print(concat(tab2,"case ",string(n),":")),
+    for m:1 thru n do block([q:d*horner(
+        subst([eps=sqrt(eps2)],ataylor(C1p[m],eps,n)/eps^m)),
+      linel:1200],
+      if m>1 then print(concat(tab3,"d *= eps;")),
+      print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+    print(concat(tab3,"break;"))),
+  print("    }
+}"),
+'done)$
+
+codeC2(maxpow):=block([tab2:"    ",tab3:"        "],
+print("// The coefficients C2[l] in the Fourier expansion of B2
+static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
+{
+    CT const eps2 = math::sqr(eps);
+    CT d = eps;
+    switch (SeriesOrder) {"),
+  for n:0 thru maxpow do (
+    print(concat(tab2,"case ",string(n),":")),
+    for m:1 thru n do block([q:d*horner(
+        subst([eps=sqrt(eps2)],ataylor(C2[m],eps,n)/eps^m)),
+      linel:1200],
+      if m>1 then print(concat(tab3,"d *= eps;")),
+      print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+    print(concat(tab3,"break;"))),
+print("    }
+}"),
+'done)$
+
+codeC3(maxpow):=block([tab2:"    ",tab3:"        "],
+print("// The coefficients C3[l] in the Fourier expansion of B3
+static inline void evaluate_coeffs_C3(CT const& n, CT c[])
+{
+    const CT n2 = math::sqr(n);
+    switch (SeriesOrder) {"),
+  for nn:0 thru maxpow do block([c],
+    print(concat(tab2,"case ",string(nn),":")),
+    c:0,
+    for m:1 thru nn-1 do block(
+      [q:if nn = 0 then 0 else
+      jtaylor(subst([n=n],C3[m]),_n,eps,nn-1),
+      linel:1200],
+      for j:m thru nn-1 do (
+        print(concat(tab3,"c[",c,"] = ",
+            string(horner(coeff(q,eps,j))),";")),
+        c:c+1)
+    ),
+    print(concat(tab3,"break;"))),
+  print("    }
+}"),
+'done)$
+
+maxpow:8$
+
+computeI1(maxpow)$
+computeI2(maxpow)$
+computeI3(maxpow)$
+
+revertI1(maxpow)$
+codeA1(maxpow)$
+codeA2(maxpow)$
+codeA3(maxpow)$
+
+codeC1(maxpow)$
+codeC2(maxpow)$
+codeC3(maxpow)$
+
+codeC1p(maxpow)$
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index a61df68..ba3c214 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -30,51 +30,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion above is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_series_A1 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        computeI1(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
-          sintegrand:sqrt(1+k2*sin(sigma)^2),
-          sintegrandexp:ataylor(
-              (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
-              eps,maxpow),
-          s:trigreduce(integrate(sintegrandexp,sigma)),
-          s:s-subst(sigma=0,s),
-          A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
-          tau1:ataylor(s/A1,eps,maxpow),
-          for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
-          if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B1"),
-          A1:A1/(1-eps),
-          'done)$
-
-        codeA1(maxpow):=block([tab2:"    ",tab3:"        "],
-        print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
-        static inline CT evaluate_series_A1(CT eps) {
-            CT eps2 = math::sqr(eps);
-            CT t;
-            switch (SeriesOrder/2) {"),
-          for n:0 thru entier(maxpow/2) do block([
-            q:horner(ataylor(subst([eps=sqrt(eps2)],A1*(1-eps)-1),eps2,n)),
-            linel:1200],
-            print(concat(tab2,"case ",string(n),":")),
-            print(concat(tab3,"t = ",string(q),";")),
-            print(concat(tab3,"break;"))),
-          print("    }
-            return (t + eps) / (1 - eps);
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI1(maxpow)$
-        codeA1(maxpow)$
-        // Maxima script end
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac

      To replace each number x by CT(x) the following
      script can be used:
@@ -123,52 +80,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion above is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_series_A2 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
-          sintegrand:1/sqrt(1+k2*sin(sigma)^2),
-          sintegrandexp:ataylor(
-              (1+eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
-              eps,maxpow),
-          s:trigreduce(integrate(sintegrandexp,sigma)),
-          s:s-subst(sigma=0,s),
-          A2:expand(subst(sigma=2*%pi,s)/(2*%pi)),
-          tau1:ataylor(s/A2,eps,maxpow),
-          for i:1 thru maxpow do C2[i]:coeff(tau1,sin(2*i*sigma)),
-          if expand(tau1-sigma-sum(C2[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B2"),
-          A2:A2/(1+eps),
-          'done)$
-
-        codeA2(maxpow):=block([tab2:"    ",tab3:"        "],
-        print("// The scale factor A2-1 = mean value of (d/dsigma)I2 - 1
-        CT evaluate_series_A2(CT const& eps)
-        {
-            CT const eps2 = math::sqr(eps);
-            CT t;
-            switch (SeriesOrder/2) {"),
-          for n:0 thru entier(maxpow/2) do block([
-            q:horner(ataylor(subst([eps=sqrt(eps2)],A2*(1+eps)-1),eps2,n)),
-            linel:1200],
-            print(concat(tab2,"case ",string(n),":")),
-            print(concat(tab3,"t = ",string(q),";")),
-            print(concat(tab3,"break;"))),
-          print("    }
-            return (t - eps) / (1 + eps);
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI2(maxpow)$
-        codeA2(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     script can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
     CT evaluate_series_A2(CT const& eps)
@@ -212,53 +125,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion above is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_coeffs_A3 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n],
-          maxpow:maxpow-1,
-          int:subst([k2=4*eps/(1-eps)^2],
-            (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma)^2))),
-          int:subst([f=2*n/(1+n)],int),
-          intexp:jtaylor(int,n,eps,maxpow),
-          dlam:trigreduce(integrate(intexp,sigma)),
-          dlam:dlam-subst(sigma=0,dlam),
-          A3:expand(subst(sigma=2*%pi,dlam)/(2*%pi)),
-          eta:jtaylor(dlam/A3,n,eps,maxpow),
-          A3:jtaylor(A3,n,eps,maxpow),
-          for i:1 thru maxpow do C3[i]:coeff(eta,sin(2*i*sigma)),
-          if expand(eta-sigma-sum(C3[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B3"),
-          'done)$
-
-        codeA3(maxpow):=block([tab2:"    ",tab3:"        "],
-        print("// The scale factor A3 = mean value of (d/dsigma)I3
-        static inline void evaluate_series_A3(CT const& n, CT c[])
-        {
-            switch (SeriesOrder) {"),
-          for nn:0 thru maxpow do block(
-            [q:if nn=0 then 0 else
-            jtaylor(subst([n=n],A3),n,eps,nn-1),
-            linel:1200],
-            print(concat(tab2,"case ",string(nn),":")),
-            for i : 0 thru nn-1 do
-            print(concat(tab3,"c[",i,"] = ",
-                string(horner(coeff(q,eps,i))),";")),
-            print(concat(tab3,"break;"))),
-          print("    }
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI3(maxpow)$
-        codeA3(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     script can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g'
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac
     */
     // TODO: this produces different results that geographiclib
     template <typename CT, std::size_t SeriesOrder>
@@ -327,38 +195,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion below is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_coeffs_C1 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        codeC1(maxpow):=block([tab2:"    ",tab3:"        "],
-          print("// The coefficients C1[l] in the Fourier expansion of B1
-        static inline evaluate_coeffs_C1(CT eps, CT c[]) {
-            CT eps2 = math::sqr(eps);
-            CT d = eps;
-            switch (SeriesOrder) {"),
-          for n:0 thru maxpow do (
-            print(concat(tab2,"case ",string(n),":")),
-            for m:1 thru n do block([q:d*horner(
-                subst([eps=sqrt(eps2)],ataylor(C1[m],eps,n)/eps^m)),
-              linel:1200],
-              if m>1 then print(concat(tab3,"d *= eps;")),
-              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
-            print(concat(tab3,"break;"))),
-          print("    }
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI1(maxpow)$
-        codeC1(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     script can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
-               s/eps(CT(2))/eps2/g;'
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
     static inline void evaluate_coeffs_C1(CT eps, CT c[])
@@ -456,51 +294,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion below is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_coeffs_C1p below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        revertI1(maxpow):=block([tau,eps,tauacc:1,sigacc:0],
-          for n:1 thru maxpow do (
-            tauacc:trigreduce(ataylor(
-                  -sum(C1[j]*sin(2*j*tau),j,1,maxpow-n+1)*tauacc/n,
-                  eps,maxpow)),
-            sigacc:sigacc+expand(diff(tauacc,tau,n-1))),
-          for i:1 thru maxpow do C1p[i]:coeff(sigacc,sin(2*i*tau)),
-          if expand(sigacc-sum(C1p[i]*sin(2*i*tau),i,1,maxpow)) # 0
-          then error("left over terms in B1p"),
-          'done)$
-
-        codeC1p(maxpow):=block([tab2:"    ",tab3:"        "],
-          print("// The coefficients C1p[l] in the Fourier expansion of B1p
-        static inline evaluate_coeffs_C1p(CT eps, CT c[])
-        {
-            CT const eps2 = math::sqr(eps);
-            CT d = eps;
-            switch (SeriesOrder) {"),
-          for n:0 thru maxpow do (
-            print(concat(tab2,"case ",string(n),":")),
-            for m:1 thru n do block([q:d*horner(
-                subst([eps=sqrt(eps2)],ataylor(C1p[m],eps,n)/eps^m)),
-              linel:1200],
-              if m>1 then print(concat(tab3,"d *= eps;")),
-              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
-            print(concat(tab3,"break;"))),
-          print("    }
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI1(maxpow)$
-        revertI1(maxpow)$
-        codeC1p(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     script can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
-               s/eps(CT(2))/eps2/g;'
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
     static inline void evaluate_coeffs_C1p(CT eps, CT c[])
@@ -598,39 +393,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion below is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_coeffs_C2 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        codeC2(maxpow):=block([tab2:"    ",tab3:"        "],
-        print("// The coefficients C2[l] in the Fourier expansion of B2
-        static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
-        {
-            CT const eps2 = math::sqr(eps);
-            CT d = eps;
-            switch (SeriesOrder) {"),
-          for n:0 thru maxpow do (
-            print(concat(tab2,"case ",string(n),":")),
-            for m:1 thru n do block([q:d*horner(
-                subst([eps=sqrt(eps2)],ataylor(C2[m],eps,n)/eps^m)),
-              linel:1200],
-              if m>1 then print(concat(tab3,"d *= eps;")),
-              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
-            print(concat(tab3,"break;"))),
-        print("    }
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI2(maxpow)$
-        codeC2(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     script can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
-               s/eps(CT(2))/eps2/g;'
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, std::size_t SeriesOrder>
     static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
@@ -728,43 +492,8 @@ namespace boost { namespace geometry { namespace series_expansion {

      The expansion below is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_coeffs_C3 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        codeC3(maxpow):=block([tab2:"    ",tab3:"        "],
-        print("// The coefficients C3[l] in the Fourier expansion of B3
-        static inline void evaluate_coeffs_C3(CT const& n, CT c[])
-        {
-            const CT n2 = math::sqr(n);
-            switch (SeriesOrder) {"),
-          for nn:0 thru maxpow do block([c],
-            print(concat(tab2,"case ",string(nn),":")),
-            c:0,
-            for m:1 thru nn-1 do block(
-              [q:if nn = 0 then 0 else
-              jtaylor(subst([n=n],C3[m]),_n,eps,nn-1),
-              linel:1200],
-              for j:m thru nn-1 do (
-                print(concat(tab3,"c[",c,"] = ",
-                    string(horner(coeff(q,eps,j))),";")),
-                c:c+1)
-            ),
-            print(concat(tab3,"break;"))),
-          print("    }
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeI3(maxpow)$
-        codeC3(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     script can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
-               s/eps(CT(2))/eps2/g;'
+     generated by the following Maxima script:
+     geometry/doc/other/maxima/geod.mac
     */
     template <typename CT, int SeriesOrder>
     void evaluate_coeffs_C3x(CT const& n, CT c[], const CT coeff[])

commit b9b0f85560e719278e8d4e9fdc7da998dd5c7857
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 5 12:44:36 2018 +0500

    [util] Add functions to normalize / sum two given values (angles)

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index e0ab1c8..652ca85 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -845,13 +845,50 @@ inline void normalize(T& x, T& y)
 \brief Normalize a given angle.
 */
 template<typename T>
-    inline T normalize_angle(T x)
+inline T normalize_angle(T x)
 {
     T y = std::fmod(x, T(360));

     return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360);
 }

+/*!
+\brief The error-free sum of two numbers.
+*/
+template<typename T>
+inline T sum_error(T u, T v, T& t)
+{
+    volatile T s = u + v;
+    volatile T up = s - v;
+    volatile T vpp = s - up;
+
+    up -= u;
+    vpp -= v;
+    t = -(up + vpp);
+
+    return s;
+}
+
+
+/*!
+\brief The exact difference of two angles reduced to
+       (&minus;180&deg;, 180&deg;].
+*/
+template<typename T>
+inline T difference_angle(T x, T y, T& e)
+{
+    T t, d = normalize_angle(sum_error(std::remainder(-x, T(360)),
+                                       std::remainder(y, T(360)), t));
+
+    // Here y - x = d + t (mod 360), exactly, where d is in (-180,180] and
+    // abs(t) <= eps (eps = 2^-45 for doubles).  The only case where the
+    // addition of t takes the result outside the range (-180,180] is d = 180
+    // and t > 0.  The case, d = -180 + eps, t = -eps, can't happen, since
+    // sum_error would have returned the exact result in such a case (i.e., given t = 0).
+    return sum_error(d == 180 && t > 0 ? -180 : d, t, e);
+}
+
+
 /*
 \brief Evaluate the polynomial in x using Horner's method.
 */

commit a10815366a58d1dd058dd0447843fbac89327b37
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 5 10:21:49 2018 +0500

    [test] Add comment providing dataset source and how it is parsed

diff --git a/test/formulas/direct_cases_antipodal.hpp b/test/formulas/direct_cases_antipodal.hpp
index 541d3bf..37214fe 100644
--- a/test/formulas/direct_cases_antipodal.hpp
+++ b/test/formulas/direct_cases_antipodal.hpp
@@ -20,6 +20,17 @@ struct expected_results_antipodal
     expected_result karney;
 };

+/*
+ These values are collected from GeodTest which is associated with GeographicLib:
+     https://zenodo.org/record/32156
+
+ The conversion to C++ array format is done using this Python script:
+     https://github.com/adl1995/boost-geometry-extra/blob/master/geographicLib-dataset-parse.py
+
+ Geodesic scale (M12) is absent from the GeodTest dataset, so it is manually generated
+ using GeographicLib through this C++ script:
+     https://github.com/adl1995/boost-geometry-extra/blob/master/geographicLib-direct-antipodal.cpp
+*/
 expected_results_antipodal expected_antipodal[] =
 {
     {

commit cc19342b4eac30183fd6f40d4d4d0a8b36fed885
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue Jun 5 09:28:37 2018 +0500

    [util] Remove duplicated Maxima code from series_expansion.hpp

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 3566aca..a61df68 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -39,7 +39,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
         ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$

-        computeintegral(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+        computeI1(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
           sintegrand:sqrt(1+k2*sin(sigma)^2),
           sintegrandexp:ataylor(
               (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
@@ -54,7 +54,7 @@ namespace boost { namespace geometry { namespace series_expansion {
           A1:A1/(1-eps),
           'done)$

-        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
+        codeA1(maxpow):=block([tab2:"    ",tab3:"        "],
         print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
         static inline CT evaluate_series_A1(CT eps) {
             CT eps2 = math::sqr(eps);
@@ -72,8 +72,8 @@ namespace boost { namespace geometry { namespace series_expansion {
         'done)$

         maxpow:8$
-        computeintegral(maxpow)$
-        generatecode(maxpow)$
+        computeI1(maxpow)$
+        codeA1(maxpow)$
         // Maxima script end

      To replace each number x by CT(x) the following
@@ -122,16 +122,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      The scale factor A2-1 = mean value of (d/dsigma)2 - 1

      The expansion above is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_series_A2 below) is
      generated by the following Maxima script and is based on script:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
         computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
           sintegrand:1/sqrt(1+k2*sin(sigma)^2),
           sintegrandexp:ataylor(
@@ -216,16 +211,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      The scale factor A3 = mean value of (d/dsigma)I3

      The expansion above is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_coeffs_A3 below) is
      generated by the following Maxima script and is based on script:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
         computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n],
           maxpow:maxpow-1,
           int:subst([k2=4*eps/(1-eps)^2],
@@ -336,17 +326,12 @@ namespace boost { namespace geometry { namespace series_expansion {
      The coefficients C1[l] in the Fourier expansion of B1.

      The expansion below is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_coeffs_C1 below) is
      generated by the following Maxima script and is based on script:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
+        codeC1(maxpow):=block([tab2:"    ",tab3:"        "],
           print("// The coefficients C1[l] in the Fourier expansion of B1
         static inline evaluate_coeffs_C1(CT eps, CT c[]) {
             CT eps2 = math::sqr(eps);
@@ -365,8 +350,8 @@ namespace boost { namespace geometry { namespace series_expansion {
         'done)$

         maxpow:8$
-        computeintegral(maxpow)$
-        generatecode(maxpow)$
+        computeI1(maxpow)$
+        codeC1(maxpow)$
         // Maxima script end

      To replace each number x by CT(x) the following
@@ -470,31 +455,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      The coefficients C1p[l] in the Fourier expansion of B1p.

      The expansion below is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_coeffs_C1p below) is
      generated by the following Maxima script and is based on script:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        computeintegral(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
-          sintegrand:sqrt(1+k2*sin(sigma)^2),
-          sintegrandexp:ataylor(
-              (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
-              eps,maxpow),
-          s:trigreduce(integrate(sintegrandexp,sigma)),
-          s:s-subst(sigma=0,s),
-          A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
-          tau1:ataylor(s/A1,eps,maxpow),
-          for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
-          if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B1"),
-          A1:A1/(1-eps),
-          'done)$
-
         revertI1(maxpow):=block([tau,eps,tauacc:1,sigacc:0],
           for n:1 thru maxpow do (
             tauacc:trigreduce(ataylor(
@@ -506,7 +471,7 @@ namespace boost { namespace geometry { namespace series_expansion {
           then error("left over terms in B1p"),
           'done)$

-        generatecodeC1p(maxpow):=block([tab2:"    ",tab3:"        "],
+        codeC1p(maxpow):=block([tab2:"    ",tab3:"        "],
           print("// The coefficients C1p[l] in the Fourier expansion of B1p
         static inline evaluate_coeffs_C1p(CT eps, CT c[])
         {
@@ -526,9 +491,9 @@ namespace boost { namespace geometry { namespace series_expansion {
         'done)$

         maxpow:8$
-        computeintegral(maxpow)$
+        computeI1(maxpow)$
         revertI1(maxpow)$
-        generatecodeC1p(maxpow)$
+        codeC1p(maxpow)$
         // Maxima script end

      To replace each number x by CT(x) the following
@@ -632,31 +597,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      The coefficients C2[l] in the Fourier expansion of B2.

      The expansion below is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_coeffs_C2 below) is
      generated by the following Maxima script and is based on script:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
-          sintegrand:1/sqrt(1+k2*sin(sigma)^2),
-          sintegrandexp:ataylor(
-              (1+eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
-              eps,maxpow),
-          s:trigreduce(integrate(sintegrandexp,sigma)),
-          s:s-subst(sigma=0,s),
-          A2:expand(subst(sigma=2*%pi,s)/(2*%pi)),
-          tau1:ataylor(s/A2,eps,maxpow),
-          for i:1 thru maxpow do C2[i]:coeff(tau1,sin(2*i*sigma)),
-          if expand(tau1-sigma-sum(C2[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B2"),
-          A2:A2/(1+eps),
-          'done)$
-
         codeC2(maxpow):=block([tab2:"    ",tab3:"        "],
         print("// The coefficients C2[l] in the Fourier expansion of B2
         static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
@@ -782,32 +727,11 @@ namespace boost { namespace geometry { namespace series_expansion {
      The coefficients C3[l] in the Fourier expansion of B3.

      The expansion below is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
+     The C++ code (that yields the function evaluate_coeffs_C3 below) is
      generated by the following Maxima script and is based on script:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n],
-          maxpow:maxpow-1,
-          int:subst([k2=4*eps/(1-eps)^2],
-            (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma)^2))),
-          int:subst([f=2*n/(1+n)],int),
-          intexp:jtaylor(int,n,eps,maxpow),
-          dlam:trigreduce(integrate(intexp,sigma)),
-          dlam:dlam-subst(sigma=0,dlam),
-          A3:expand(subst(sigma=2*%pi,dlam)/(2*%pi)),
-          eta:jtaylor(dlam/A3,n,eps,maxpow),
-          A3:jtaylor(A3,n,eps,maxpow),
-          for i:1 thru maxpow do C3[i]:coeff(eta,sin(2*i*sigma)),
-          if expand(eta-sigma-sum(C3[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B3"),
-          'done)$
-
         codeC3(maxpow):=block([tab2:"    ",tab3:"        "],
         print("// The coefficients C3[l] in the Fourier expansion of B3
         static inline void evaluate_coeffs_C3(CT const& n, CT c[])

commit 831873752dd7875e485a87a70e6ce2e75803a672
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 4 19:12:50 2018 +0500

    [formulas] Use constant type variables for comparison

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index e24bd74..934122b 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -93,7 +93,9 @@ public:
         CT const lat1 = la1;
         Azi const azi12 = math::normalize_angle<CT>(azimuth12);

-        if (math::equals(distance, Dist(0)) || distance < Dist(0))
+        CT const dist_c0 = 0;
+
+        if (math::equals(distance, dist_c0) || distance < dist_c0)
         {
             result.lon2 = lon1;
             result.lat2 = lat1;
@@ -263,8 +265,8 @@ public:
             CT const AB2 = (c1 + expansion_A2) * (B22 - B21);
             CT const J12 = (expansion_A1 - expansion_A2) * sigma12 + (AB1 - AB2);

-            CT const dn1 = sqrt(1 + ep2 * math::sqr(sin_beta1));
-            CT const dn2 = sqrt(1 + k2 * math::sqr(sin_sigma2));
+            CT const dn1 = sqrt(c1 + ep2 * math::sqr(sin_beta1));
+            CT const dn2 = sqrt(c1 + k2 * math::sqr(sin_sigma2));

             // Find the reduced length.
             result.reduced_length = b * ((dn2 * (cos_sigma1 * sin_sigma2) -

commit 1ed5f103f48356f8c3b300905107117f3eca76f5
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon Jun 4 19:09:07 2018 +0500

    [formulas] Move SeriesOrder to the end of template parameter list

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index c0faa05..e24bd74 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -33,11 +33,11 @@ https://arxiv.org/pdf/1109.4448.pdf
 */
 template <
     typename CT,
-    size_t SeriesOrder = 8,
     bool EnableCoordinates = true,
     bool EnableReverseAzimuth = false,
     bool EnableReducedLength = false,
-    bool EnableGeodesicScale = false
+    bool EnableGeodesicScale = false,
+    size_t SeriesOrder = 8
 >
 class karney_direct
 {
diff --git a/test/formulas/direct.cpp b/test/formulas/direct.cpp
index 0fb500b..bcfcec3 100644
--- a/test/formulas/direct.cpp
+++ b/test/formulas/direct.cpp
@@ -64,7 +64,7 @@ void test_all(expected_results const& results)
     result.reverse_azimuth *= r2d;
     check_direct(result, results.thomas, results.karney, 0.0000001);

-    typedef bg::formula::karney_direct<double, 8, true, true, true, true> ka_t;
+    typedef bg::formula::karney_direct<double, true, true, true, true, 8> ka_t;
     result = ka_t::apply(lon1d, lat1d, distance, azi12d, spheroid);
     check_direct(result, results.thomas, results.karney, 0.0000001);
 }
@@ -81,7 +81,7 @@ void test_karney_antipodal(expected_results_antipodal const& results)

     bg::formula::result_direct<double> result;

-    typedef bg::formula::karney_direct<double, 8, true, true, true, true> ka_t;
+    typedef bg::formula::karney_direct<double, true, true, true, true, 8> ka_t;
     result = ka_t::apply(lon1d, lat1d, distance, azi12d, spheroid);
     check_direct(result, results.karney, results.karney, 0.0000001, true);
 }

commit 4fa4a8206a65ddd63c136989de026c0bb0d3e64f
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu May 31 17:40:53 2018 +0500

    [util] Update series expansion for C3x

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index 59511c2..3566aca 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -842,9 +842,24 @@ namespace boost { namespace geometry { namespace series_expansion {
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
                s/eps(CT(2))/eps2/g;'
     */
-    // TODO: adl1995
-    // Update docstring and function body.
-    // The coefficients C3[l] in the Fourier expansion of B3
+    template <typename CT, int SeriesOrder>
+    void evaluate_coeffs_C3x(CT const& n, CT c[], const CT coeff[])
+    {
+        int offset = 0, k = 0;
+        // l is index of C3[l].
+        for (int l = 1; l < SeriesOrder; ++l)
+        {
+            for (int j = SeriesOrder - 1; j >= l; --j)
+            {
+                // Order of polynomial in n.
+                int m = std::min(SeriesOrder - j - 1, j);
+                c[k++] = math::polyval(m, coeff + offset, n) /
+                coeff[offset + m + 1];
+                offset += m + 2;
+            }
+        }
+    }
+
     template <typename CT, int SeriesOrder>
     void evaluate_coeffs_C3x(CT const& n, CT c[]) {
         if (SeriesOrder == 3) {
@@ -856,6 +871,8 @@ namespace boost { namespace geometry { namespace series_expansion {
             // C3[2], coeff of eps^2, polynomial in n of order 0
             1, 16,
             };
+
+            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
         }
         else if (SeriesOrder == 4) {
             static const CT coeff[] = {
@@ -874,6 +891,8 @@ namespace boost { namespace geometry { namespace series_expansion {
             // C3[3], coeff of eps^3, polynomial in n of order 0
             5, 192,
             };
+
+            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
         }
         else if (SeriesOrder == 5) {
             static const CT coeff[] = {
@@ -898,6 +917,8 @@ namespace boost { namespace geometry { namespace series_expansion {
             // C3[4], coeff of eps^4, polynomial in n of order 0
             7, 512,
             };
+
+            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
         }
         else if (SeriesOrder == 6) {
             static const CT coeff[] = {
@@ -932,6 +953,8 @@ namespace boost { namespace geometry { namespace series_expansion {
             // C3[5], coeff of eps^5, polynomial in n of order 0
             21, 2560,
             };
+
+            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
         }
         else if (SeriesOrder == 7) {
             static const CT coeff[] = {
@@ -978,6 +1001,8 @@ namespace boost { namespace geometry { namespace series_expansion {
             // C3[6], coeff of eps^6, polynomial in n of order 0
             11, 2048,
             };
+
+            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
         }
         else if (SeriesOrder == 8) {
             static const CT coeff[] = {
@@ -1039,17 +1064,7 @@ namespace boost { namespace geometry { namespace series_expansion {
             429, 114688,
             };

-            int offset = 0, k = 0;
-            // l is index of C3[l].
-            for (int l = 1; l < SeriesOrder; ++l) {
-                for (int j = SeriesOrder - 1; j >= l; --j) {
-                    // Order of polynomial in n.
-                    int m = std::min(SeriesOrder - j - 1, j);
-                    c[k++] = math::polyval(m, coeff + offset, n) /
-                             coeff[offset + m + 1];
-                    offset += m + 2;
-                }
-            }
+            evaluate_coeffs_C3x<CT, SeriesOrder>(n, c, coeff);
         }
         // Post condition: offset == sizeof(coeff) / sizeof(CT) && k == coeffs_C3_size
     }

commit 6ff97a69910529d31f880d0674a4015723156864
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu May 31 16:36:16 2018 +0500

    [test] Test Karney's method on antipodal points dataset

diff --git a/test/formulas/direct.cpp b/test/formulas/direct.cpp
index 7cf076b..0fb500b 100644
--- a/test/formulas/direct.cpp
+++ b/test/formulas/direct.cpp
@@ -12,6 +12,7 @@

 #include "test_formula.hpp"
 #include "direct_cases.hpp"
+#include "direct_cases_antipodal.hpp"

 #include <boost/geometry/formulas/vincenty_direct.hpp>
 #include <boost/geometry/formulas/thomas_direct.hpp>
@@ -20,13 +21,14 @@
 #include <boost/geometry/srs/spheroid.hpp>

 template <typename Result>
-void check_direct(Result const& result, expected_result const& expected, expected_result const& reference, double reference_error)
+void check_direct(Result const& result, expected_result const& expected, expected_result const& reference,
+                  double reference_error, bool check_reference_only = false)
 {
-    check_one(result.lon2, expected.lon2, reference.lon2, reference_error);
-    check_one(result.lat2, expected.lat2, reference.lat2, reference_error);
-    check_one(result.reverse_azimuth, expected.reverse_azimuth, reference.reverse_azimuth, reference_error, true);
-    check_one(result.reduced_length, expected.reduced_length, reference.reduced_length, reference_error);
-    check_one(result.geodesic_scale, expected.geodesic_scale, reference.geodesic_scale, reference_error);
+    check_one(result.lon2, expected.lon2, reference.lon2, reference_error, false, check_reference_only);
+    check_one(result.lat2, expected.lat2, reference.lat2, reference_error, false, check_reference_only);
+    check_one(result.reverse_azimuth, expected.reverse_azimuth, reference.reverse_azimuth, reference_error, true, check_reference_only);
+    check_one(result.reduced_length, expected.reduced_length, reference.reduced_length, reference_error, false, check_reference_only);
+    check_one(result.geodesic_scale, expected.geodesic_scale, reference.geodesic_scale, reference_error, false, check_reference_only);
 }

 void test_all(expected_results const& results)
@@ -67,6 +69,23 @@ void test_all(expected_results const& results)
     check_direct(result, results.thomas, results.karney, 0.0000001);
 }

+void test_karney_antipodal(expected_results_antipodal const& results)
+{
+    double lon1d = results.p1.lon;
+    double lat1d = results.p1.lat;
+    double distance = results.distance;
+    double azi12d = results.azimuth12;
+
+    // WGS84
+    bg::srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);
+
+    bg::formula::result_direct<double> result;
+
+    typedef bg::formula::karney_direct<double, 8, true, true, true, true> ka_t;
+    result = ka_t::apply(lon1d, lat1d, distance, azi12d, spheroid);
+    check_direct(result, results.karney, results.karney, 0.0000001, true);
+}
+
 int test_main(int, char*[])
 {
     for (size_t i = 0; i < expected_size; ++i)
@@ -74,5 +93,10 @@ int test_main(int, char*[])
         test_all(expected[i]);
     }

+    for (size_t i = 0; i < expected_size_antipodal; ++i)
+    {
+        test_karney_antipodal(expected_antipodal[i]);
+    }
+
     return 0;
 }

commit 3c21b13c9161f0d7bd3169c44a23ebdd87846bbb
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu May 31 16:28:09 2018 +0500

    [test] Add geodesic length to antipodal points dataset

    The geodesic length is calculated manually using GeographicLib/Geodesic.hpp
    in C++. However, this value differs when calculated using the
    CLI tool GeodSolve.

diff --git a/test/formulas/direct_cases_antipodal.hpp b/test/formulas/direct_cases_antipodal.hpp
index 8e24847..541d3bf 100644
--- a/test/formulas/direct_cases_antipodal.hpp
+++ b/test/formulas/direct_cases_antipodal.hpp
@@ -10,8 +10,7 @@
 #ifndef BOOST_GEOMETRY_TEST_DIRECT_CASES_ANTIPODAL_HPP
 #define BOOST_GEOMETRY_TEST_DIRECT_CASES_ANTIPODAL_HPP

-// TODO: adl1995
-// Add geodesic scale to expected_antipodal[] array.
+#include "direct_cases.hpp"

 struct expected_results_antipodal
 {
@@ -25,304 +24,304 @@ expected_results_antipodal expected_antipodal[] =
 {
     {
         { 0, 31.394417440639 }, 19980218.4055399, 34.266322930672,
-        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209 }
+        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209, -0.99598340069666346785 }
     },{
         { 0, 29.788792273749 }, 19887224.5407334, 74.302205994192,
-        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058 }
+        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058, -0.99585265538534928353 }
     },{
         { 0, 46.471843094141 }, 19944337.8863917, 63.693680310665,
-        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365 }
+        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365, -0.99628290151178156009 }
     },{
         { 0, 63.016506345929 }, 20000925.7533636, 153.393656073038,
-        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772 }
+        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772, -0.99806730524837738994 }
     },{
         { 0, 19.796231412719 }, 19956338.1330537, 28.272934411318,
-        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931 }
+        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931, -0.99680355285706290225 }
     },{
         { 0, 6.373459459035 }, 19946581.6983394, 56.859050230583,
-        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939 }
+        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939, -0.99880439595523196061 }
     },{
         { 0, 66.380766469414 }, 19986277.7696849, 38.646950203356,
-        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214 }
+        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214, -0.9984201835509521894 }
     },{
         { 0, 16.483421185231 }, 19962737.9842573, 163.431254767325,
-        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431 }
+        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431, -0.99723427960580335316 }
     },{
         { 0, 4.215702155486 }, 19932517.393764, 65.543168480886,
-        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317 }
+        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317, -0.99916694551569362748 }
     },{
         { 0, 40.71372085907 }, 19951133.3595356, 143.672151631634,
-        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621 }
+        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621, -0.99601226064330683485 }
     },{
         { 0, 15.465481491654 }, 19877383.8879911, 36.289185640976,
-        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957 }
+        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957, -0.99717590257108590368 }
     },{
         { 0, 17.586197343531 }, 19982280.4639115, 157.929615091529,
-        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557 }
+        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557, -0.99710409371925123878 }
     },{
         { 0, 5.7442768247 }, 19902873.7431814, 116.146983678305,
-        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673 }
+        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673, -0.99883071172416715289 }
     },{
         { 0, 32.002904282111 }, 19967670.3104795, 163.052160078191,
-        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582 }
+        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582, -0.99597193334487110761 }
     },{
         { 0, 55.902716926362 }, 19970525.337607, 98.927641063414,
-        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067 }
+        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067, -0.99721760041260698593 }
     },{
         { 0, 22.69939784398 }, 19959286.1903172, 74.253870776761,
-        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679 }
+        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679, -0.99650952667426662135 }
     },{
         { 0, 41.312328471121 }, 19962690.5721867, 11.277616109847,
-        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201 }
+        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201, -0.99601334953687414853 }
     },{
         { 0, 27.927415327453 }, 19961296.8828333, 23.166421459647,
-        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101 }
+        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101, -0.99610609795569049485 }
     },{
         { 0, 41.567228741451 }, 19944253.4454809, 176.66609526064,
-        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197 }
+        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197, -0.99604624873858405021 }
     },{
         { 0, 37.384208978567 }, 19928705.5911445, 39.072534864532,
-        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402 }
+        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402, -0.99583616315460821156 }
     },{
         { 0, 59.011868682852 }, 19970442.3788306, 44.970301291063,
-        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857 }
+        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857, -0.99754686309848117354 }
     },{
         { 0, 35.515406087737 }, 19948918.9139751, 28.528972431952,
-        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751 }
+        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751, -0.9958683164291525225 }
     },{
         { 0, 58.170252463184 }, 19961407.0813807, 128.021116291844,
-        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309 }
+        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309, -0.99746161015888423762 }
     },{
         { 0, 34.012183807959 }, 19970955.843065, 168.944519134772,
-        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151 }
+        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151, -0.99594085068133375582 }
     },{
         { 0, 45.510762948553 }, 19940248.3450143, 99.886784003837,
-        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972 }
+        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972, -0.99622530350349169925 }
     },{
         { 0, 4.19841765451 }, 19970496.5132933, 89.561550657928,
-        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109 }
+        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109, -0.99921964515553229891 }
     },{
         { 0, 40.890119148103 }, 19926563.5817492, 165.437641169967,
-        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923 }
+        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923, -0.99598758014963484353 }
     },{
         { 0, 28.096672787686 }, 19883901.8482359, 115.174366374632,
-        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363 }
+        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363, -0.99595011741363181912 }
     },{
         { 0, 6.50572154271 }, 19917276.4101551, 79.069492719523,
-        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707 }
+        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707, -0.99872883639262399758 }
     },{
         { 0, .468835109567 }, 19849380.7342734, 80.234636214474,
-        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908 }
+        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908, -0.99961835625163353303 }
     },{
         { 0, 1.682746325049 }, 19890026.0274781, 10.076182752451,
-        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981 }
+        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981, -0.9995304688134802884 }
     },{
         { 0, 10.711305126218 }, 19962987.2134077, 7.528253696796,
-        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456 }
+        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456, -0.99808700197799249398 }
     },{
         { 0, 53.374321544652 }, 19980478.1457438, 23.324715976877,
-        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053 }
+        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053, -0.99695322723379165009 }
     },{
         { 0, 39.680221664519 }, 19956191.7841809, 7.075406493429,
-        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148 }
+        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148, -0.99594142266924268192 }
     },{
         { 0, 1.377666714083 }, 19925401.4931301, 95.29199069739,
-        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059 }
+        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059, -0.99967079575227224542 }
     },{
         { 0, 48.751426624188 }, 19988599.1160495, 40.252328570137,
-        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568 }
+        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568, -0.99654000795747821329 }
     },{
         { 0, 59.443039048494 }, 19969935.9534732, 93.052184108221,
-        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534 }
+        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534, -0.99760844716107632824 }
     },{
         { 0, 4.122408476235 }, 19938291.6332293, 167.73479753304,
-        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497 }
+        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497, -0.99919442400871316678 }
     },{
         { 0, 46.422470082432 }, 19931980.7029341, 86.67365350297,
-        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064 }
+        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064, -0.99626178341627869006 }
     },{
         { 0, 32.614423729024 }, 19926887.3785175, 24.943814520557,
-        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104 }
+        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104, -0.99584842355298219818 }
     },{
         { 0, 3.242895277973 }, 19964490.4789049, 30.247458779683,
-        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044 }
+        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044, -0.99938705290848561802 }
     },{
         { 0, 6.29069210113 }, 19877160.8505733, 94.34299459284,
-        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083 }
+        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083, -0.99866089792332934927 }
     },{
         { 0, 18.232086569498 }, 19927978.7462175, 164.41905055334,
-        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559 }
+        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559, -0.99696204469368099321 }
     },{
         { 0, 12.049849333181 }, 19908004.4552909, 9.418096768309,
-        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343 }
+        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343, -0.99777424243303902696 }
     },{
         { 0, 40.289465276136 }, 19985674.936106, 143.092606818963,
-        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593 }
+        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593, -0.99602880093986934096 }
     },{
         { 0, 2.197784650379 }, 19910509.7517973, 1.542117609437,
-        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996 }
+        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996, -0.99948867836200405712 }
     },{
         { 0, 1.966575272177 }, 19875595.6267266, 170.112968791865,
-        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908 }
+        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908, -0.99943592820130777721 }
     },{
         { 0, 25.078832492684 }, 19887997.7953866, 77.264585323781,
-        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839 }
+        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839, -0.99614702274067257193 }
     },{
         { 0, 31.740361941314 }, 19972325.3556069, 143.930820896999,
-        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145 }
+        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145, -0.99597837783719567195 }
     },{
         { 0, .05479250563 }, 19858049.4780499, 41.349430623518,
-        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714 }
+        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714, -0.9997266451533399767 }
     },{
         { 0, 36.685139871608 }, 19968965.6773632, 89.167975517493,
-        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918 }
+        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918, -0.99592417628692353482 }
     },{
         { 0, 3.451199399671 }, 19938203.3838544, 91.541212417048,
-        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781 }
+        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781, -0.9993151254968675179 }
     },{
         { 0, 27.692898794247 }, 19883493.6699045, 88.406440883665,
-        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836 }
+        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836, -0.99595722110800843918 }
     },{
         { 0, 17.363238291869 }, 19980749.7638027, 39.697196316589,
-        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379 }
+        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379, -0.9971281847750985694 }
     },{
         { 0, 37.006775102539 }, 19949309.9180043, 116.455543532607,
-        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701 }
+        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701, -0.99590619058035212419 }
     },{
         { 0, 45.572883540957 }, 19940027.8586414, 137.627256708444,
-        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496 }
+        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496, -0.99624902751220101305 }
     },{
         { 0, 43.63393981955 }, 19931045.2914508, 91.203625101465,
-        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764 }
+        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764, -0.99608620009401716011 }
     },{
         { 0, 38.4995307019 }, 19918391.2222193, 141.232864609445,
-        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077 }
+        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077, -0.99588724635854519729 }
     },{
         { 0, 27.55015339382 }, 19986004.7358853, 137.025135713548,
-        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654 }
+        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654, -0.99616434874063342075 }
     },{
         { 0, 1.54507498314 }, 19978593.3191777, 36.816106412092,
-        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168 }
+        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168, -0.99970846248568390191 }
     },{
         { 0, 45.217063644222 }, 19987042.0782465, 18.114645812265,
-        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936 }
+        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936, -0.99626823185730628563 }
     },{
         { 0, 13.473522450751 }, 19987364.078382, 156.839609002403,
-        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472 }
+        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472, -0.99767717345868900392 }
     },{
         { 0, 6.287741997374 }, 19912159.8245954, 132.954797451112,
-        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375 }
+        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375, -0.99875728461227553101 }
     },{
         { 0, 7.639709001531 }, 19976374.3699535, 29.731916588299,
-        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539 }
+        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539, -0.99861517221927087462 }
     },{
         { 0, 5.893688050348 }, 19886907.2520668, 14.653438882877,
-        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022 }
+        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022, -0.99875831501903877818 }
     },{
         { 0, 61.997076235476 }, 19976288.2901729, 149.562797049254,
-        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176 }
+        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176, -0.99792483695855294101 }
     },{
         { 0, 50.507637741656 }, 19979542.5263293, 171.564028344478,
-        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697 }
+        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697, -0.99670226818003293534 }
     },{
         { 0, 7.484475238477 }, 19867425.2906303, 57.020570370985,
-        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633 }
+        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633, -0.99841820367274103365 }
     },{
         { 0, 56.851165323215 }, 19988235.9960515, 112.345749045605,
-        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518 }
+        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518, -0.99734849887992094164 }
     },{
         { 0, 10.692273150738 }, 19893210.3050033, 102.824601316946,
-        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111 }
+        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111, -0.99796077650539405379 }
     },{
         { 0, 46.694739303788 }, 19975447.9283188, 174.663684259477,
-        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645 }
+        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645, -0.9963829846069084395 }
     },{
         { 0, 15.804386137005 }, 19855850.8800526, 74.932089158884,
-        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628 }
+        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628, -0.99706137589256171871 }
     },{
         { 0, 4.371450175299 }, 19979071.1035552, 164.163592252794,
-        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728 }
+        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728, -0.99919490909391039946 }
     },{
         { 0, 30.894388279688 }, 19968681.8321577, 77.35154610481,
-        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058 }
+        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058, -0.99599179229723178164 }
     },{
         { 0, 9.541166838639 }, 19848553.7844137, 118.441353539081,
-        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614 }
+        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614, -0.99800476808793336936 }
     },{
         { 0, 8.489292700054 }, 19995477.1669578, 171.963952699866,
-        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974 }
+        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974, -0.9984792781676200546 }
     },{
         { 0, 19.562401114224 }, 19893208.1788508, 126.362762598128,
-        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615 }
+        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615, -0.99671734436245396083 }
     },{
         { 0, 42.260350252749 }, 19942715.0054774, 170.703419847646,
-        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769 }
+        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769, -0.99607495753304098329 }
     },{
         { 0, 24.511403144656 }, 19924809.5184876, 102.913211410163,
-        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318 }
+        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318, -0.99629589741710011808 }
     },{
         { 0, 20.844284170708 }, 19909084.6340808, 44.172784008084,
-        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608 }
+        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608, -0.99659406562612795621 }
     },{
         { 0, 2.426010809098 }, 19840940.6924189, 94.315194952561,
-        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638 }
+        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638, -0.99922656404178245015 }
     },{
         { 0, 6.600682554664 }, 19878412.28273, 168.167678684515,
-        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692 }
+        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692, -0.99861342289130949901 }
     },{
         { 0, 23.372339802326 }, 19899498.4582543, 161.197647943542,
-        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091 }
+        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091, -0.99635421423038206257 }
     },{
         { 0, 16.194668264095 }, 19874825.6683239, 148.942349959054,
-        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622 }
+        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622, -0.99709176416695455281 }
     },{
         { 0, 1.528726471528 }, 19897803.9939987, 69.212891442493,
-        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133 }
+        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133, -0.99957999688525089876 }
     },{
         { 0, 6.297249676078 }, 19864042.0495193, 56.274639904925,
-        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258 }
+        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258, -0.99861474729636867664 }
     },{
         { 0, 17.393540327984 }, 19962624.6302607, 107.855062015266,
-        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839 }
+        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839, -0.99711019484200580365 }
     },{
         { 0, 46.284685151236 }, 19990422.3478916, 14.758013867151,
-        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104 }
+        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104, -0.99634649632519134421 }
     },{
         { 0, 14.924320176299 }, 19891861.8615337, 31.446544793174,
-        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804 }
+        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804, -0.99729741460688270394 }
     },{
         { 0, 23.668824656069 }, 19938736.4442268, 148.091483667618,
-        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819 }
+        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819, -0.99640366072092678706 }
     },{
         { 0, 46.986276695896 }, 19968596.0414782, 174.796708941456,
-        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769 }
+        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769, -0.99639889458222818952 }
     },{
         { 0, 65.946144289524 }, 19993734.5109736, 25.375428509648,
-        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769 }
+        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769, -0.99838571720931879039 }
     },{
         { 0, 10.950298933293 }, 19975919.5586889, 28.779018914489,
-        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581 }
+        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581, -0.99806099887646559932 }
     },{
         { 0, 13.609869340778 }, 19913213.8514358, 129.616021271129,
-        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776 }
+        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776, -0.99755852834357494618 }
     },{
         { 0, 48.701427557433 }, 19972955.2699173, 102.875149183407,
-        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697 }
+        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697, -0.99652223116852467477 }
     },{
         { 0, 31.519172055785 }, 19952318.3772514, 26.247105619999,
-        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002 }
+        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002, -0.99593468381798511135 }
     },{
         { 0, 31.863784754278 }, 19993324.8682601, 29.572313410211,
-        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234 }
+        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234, -0.9959831508497293262 }
     },{
         { 0, 76.434608546092 }, 19997750.023578, 167.428385412814,
-        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108 }
+        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108, -0.99943031992965880583 }
     },{
         { 0, 73.114273316483 }, 19992866.6147806, 78.154765899661,
-        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946 }
+        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946, -0.99913315932148838439 }
     },{
         { 0, 1.125639056292 }, 19852573.5442848, 67.184842289382,
-        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937 }
+        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937, -0.99950982898040086067 }
     }
 };


commit fdbb3886d3ddfac617f6df0efe83d31e360f1d77
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed May 30 12:14:33 2018 +0500

    [test] Add nearly antipodal points dataset for direct geodesic problem

    Dataset is collected from:
    https://zenodo.org/record/32156

    It is then parsed using a Python script.

diff --git a/test/formulas/direct_cases_antipodal.hpp b/test/formulas/direct_cases_antipodal.hpp
new file mode 100644
index 0000000..8e24847
--- /dev/null
+++ b/test/formulas/direct_cases_antipodal.hpp
@@ -0,0 +1,331 @@
+// Boost.Geometry
+// Unit Test
+
+// Contributed and/or modified by Adeel Ahmad.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_TEST_DIRECT_CASES_ANTIPODAL_HPP
+#define BOOST_GEOMETRY_TEST_DIRECT_CASES_ANTIPODAL_HPP
+
+// TODO: adl1995
+// Add geodesic scale to expected_antipodal[] array.
+
+struct expected_results_antipodal
+{
+    coordinates p1;
+    double distance;
+    double azimuth12;
+    expected_result karney;
+};
+
+expected_results_antipodal expected_antipodal[] =
+{
+    {
+        { 0, 31.394417440639 }, 19980218.4055399, 34.266322930672,
+        { 179.615601631202912322, -31.275540610835465807, 145.782701113414306756, 49490.8807994496209 }
+    },{
+        { 0, 29.788792273749 }, 19887224.5407334, 74.302205994192,
+        { 178.569451327813675741, -29.558013672069422725, 106.156240654579267308, 97043.7545600593058 }
+    },{
+        { 0, 46.471843094141 }, 19944337.8863917, 63.693680310665,
+        { 179.083144618009561276, -46.284166405924629853, 116.699978859005570535, 53139.140576552365 }
+    },{
+        { 0, 63.016506345929 }, 20000925.7533636, 153.393656073038,
+        { 179.862869954071637855, -63.02943882703369735, 26.619056019474552953, 12713.9284725111772 }
+    },{
+        { 0, 19.796231412719 }, 19956338.1330537, 28.272934411318,
+        { 179.546498474461283862, -19.470586923091672503, 151.789094611690988249, 87191.1749625132931 }
+    },{
+        { 0, 6.373459459035 }, 19946581.6983394, 56.859050230583,
+        { 179.240009269347556917, -6.204887833274217382, 123.169200847008284851, 53958.8698005263939 }
+    },{
+        { 0, 66.380766469414 }, 19986277.7696849, 38.646950203356,
+        { 179.632633596894388233, -66.27177494016956425, 141.550919825824399405, 22198.215635049214 }
+    },{
+        { 0, 16.483421185231 }, 19962737.9842573, 163.431254767325,
+        { 179.731567273052604726, -16.818424446748042212, 16.598399455529231288, 95318.4104529881431 }
+    },{
+        { 0, 4.215702155486 }, 19932517.393764, 65.543168480886,
+        { 179.093771177769992874, -4.051917290690976764, 114.482669479963380006, 55205.4553703842317 }
+    },{
+        { 0, 40.71372085907 }, 19951133.3595356, 143.672151631634,
+        { 179.404612926861498984, -41.047052242159400671, 36.54002600969304553, 70931.1530155553621 }
+    },{
+        { 0, 15.465481491654 }, 19877383.8879911, 36.289185640976,
+        { 179.020726605204181801, -14.622355549425900341, 143.875673907461159912, 156419.0806764376957 }
+    },{
+        { 0, 17.586197343531 }, 19982280.4639115, 157.929615091529,
+        { 179.722490735835379144, -17.731394230364437075, 22.089021105298661023, 69727.5357849255557 }
+    },{
+        { 0, 5.7442768247 }, 19902873.7431814, 116.146983678305,
+        { 178.85894724576868462, -6.039853564481335581, 63.91482549951374061, 87149.6188944111673 }
+    },{
+        { 0, 32.002904282111 }, 19967670.3104795, 163.052160078191,
+        { 179.744925422107715439, -32.297934520693132807, 17.004175883388454943, 78311.3164829640582 }
+    },{
+        { 0, 55.902716926362 }, 19970525.337607, 98.927641063414,
+        { 179.300685189522463007, -55.934320218634018206, 81.374264168520557301, 23554.0093185709067 }
+    },{
+        { 0, 22.69939784398 }, 19959286.1903172, 74.253870776761,
+        { 179.294173474584020749, -22.654875407651067149, 105.811588890213155275, 22369.7179951557679 }
+    },{
+        { 0, 41.312328471121 }, 19962690.5721867, 11.277616109847,
+        { 179.817186837717804928, -40.954523601529804886, 168.784288786443902199, 77252.6121237260201 }
+    },{
+        { 0, 27.927415327453 }, 19961296.8828333, 23.166421459647,
+        { 179.636508875679110143, -27.607314264234172721, 156.905194492817275222, 83096.5801709291101 }
+    },{
+        { 0, 41.567228741451 }, 19944253.4454809, 176.66609526064,
+        { 179.931812964300204608, -42.103039532074194347, 3.361859685835349219, 96859.08180779197 }
+    },{
+        { 0, 37.384208978567 }, 19928705.5911445, 39.072534864532,
+        { 179.225180174670992261, -36.916085670712060029, 141.212743814390850106, 92667.7834060578402 }
+    },{
+        { 0, 59.011868682852 }, 19970442.3788306, 44.970301291063,
+        { 179.424923485514312807, -58.82705468054708336, 135.333817989802309531, 38071.1136293083857 }
+    },{
+        { 0, 35.515406087737 }, 19948918.9139751, 28.528972431952,
+        { 179.50369572149476218, -35.119747127350258822, 151.622257906284404073, 84564.0387217601751 }
+    },{
+        { 0, 58.170252463184 }, 19961407.0813807, 128.021116291844,
+        { 179.254737571455023977, -58.372261836268550805, 52.399129705193347143, 43715.3070711393309 }
+    },{
+        { 0, 34.012183807959 }, 19970955.843065, 168.944519134772,
+        { 179.83713352180447672, -34.29640782899529639, 11.093048811826875835, 76493.5814538538151 }
+    },{
+        { 0, 45.510762948553 }, 19940248.3450143, 99.886784003837,
+        { 178.981682578823726535, -45.582753595227824235, 80.542330522982505877, 48555.1946627894972 }
+    },{
+        { 0, 4.19841765451 }, 19970496.5132933, 89.561550657928,
+        { 179.398024428225540172, -4.198416896099783242, 90.438456568689151881, 14.8790480103109 }
+    },{
+        { 0, 40.890119148103 }, 19926563.5817492, 165.437641169967,
+        { 179.6557148951668192, -41.553556264538302258, 14.713597527941311478, 111805.7305227545923 }
+    },{
+        { 0, 28.096672787686 }, 19883901.8482359, 115.174366374632,
+        { 178.606868012231657724, -28.472055035513955205, 65.257367020445564176, 107880.4353518862363 }
+    },{
+        { 0, 6.50572154271 }, 19917276.4101551, 79.069492719523,
+        { 178.926013840891647541, -6.411745140559297675, 100.985091481519557845, 57073.3242952680707 }
+    },{
+        { 0, .468835109567 }, 19849380.7342734, 80.234636214474,
+        { 178.325942223692180692, -.281751687044281805, 99.77243368342786593, 123845.4568822078908 }
+    },{
+        { 0, 1.682746325049 }, 19890026.0274781, 10.076182752451,
+        { 179.717131561406935483, -.677647430701204515, 169.927471515299313238, 177917.2104306563981 }
+    },{
+        { 0, 10.711305126218 }, 19962987.2134077, 7.528253696796,
+        { 179.874050163405229937, -10.349315378531556046, 172.480576051850009046, 104175.1095378254456 }
+    },{
+        { 0, 53.374321544652 }, 19980478.1457438, 23.324715976877,
+        { 179.729445806011012057, -53.196257519024042184, 156.777734080146664812, 41907.8869272231053 }
+    },{
+        { 0, 39.680221664519 }, 19956191.7841809, 7.075406493429,
+        { 179.87506206720154785, -39.256187213040660911, 172.967624741991546131, 86943.8110669895148 }
+    },{
+        { 0, 1.377666714083 }, 19925401.4931301, 95.29199069739,
+        { 178.994542525209058878, -1.415358715570225495, 84.7178724483824156, 45800.9140624827059 }
+    },{
+        { 0, 48.751426624188 }, 19988599.1160495, 40.252328570137,
+        { 179.661697715070846977, -48.688146707479475147, 139.808452951157199824, 26322.3790862461568 }
+    },{
+        { 0, 59.443039048494 }, 19969935.9534732, 93.052184108221,
+        { 179.247605418616998285, -59.454371825393424121, 87.331416513795326158, 25342.4691896499534 }
+    },{
+        { 0, 4.122408476235 }, 19938291.6332293, 167.73479753304,
+        { 179.749430572914989772, -4.689124208743755363, 12.274635577599782826, 127855.6475863583497 }
+    },{
+        { 0, 46.422470082432 }, 19931980.7029341, 86.67365350297,
+        { 178.857408435141563774, -46.390934261324541952, 93.852683224054943377, 56114.680046867064 }
+    },{
+        { 0, 32.614423729024 }, 19926887.3785175, 24.943814520557,
+        { 179.460593512880455451, -32.01874745886238612, 155.229917137448282531, 112355.3319340873104 }
+    },{
+        { 0, 3.242895277973 }, 19964490.4789049, 30.247458779683,
+        { 179.556428318080663113, -3.001106476068264917, 149.760178923092147784, 80929.0418317066044 }
+    },{
+        { 0, 6.29069210113 }, 19877160.8505733, 94.34299459284,
+        { 178.556859259685624933, -6.354208910915346725, 85.750059038253282986, 94127.1566760840083 }
+    },{
+        { 0, 18.232086569498 }, 19927978.7462175, 164.41905055334,
+        { 179.658073278238477245, -18.87394850776853555, 15.640779355822506503, 129771.1882449660559 }
+    },{
+        { 0, 12.049849333181 }, 19908004.4552909, 9.418096768309,
+        { 179.761046682699610657, -11.201990279782499264, 170.610608272305604585, 157761.5040571466343 }
+    },{
+        { 0, 40.289465276136 }, 19985674.936106, 143.092606818963,
+        { 179.644208494155329095, -40.370034926441385999, 36.958610382613096419, 36200.8933724688593 }
+    },{
+        { 0, 2.197784650379 }, 19910509.7517973, 1.542117609437,
+        { 179.961199531084784854, -1.353440827124394777, 178.458582198505846426, 160403.6285079348996 }
+    },{
+        { 0, 1.966575272177 }, 19875595.6267266, 170.112968791865,
+        { 179.699817324905962184, -3.101125282483752618, 9.89572776349855838, 192355.7206665719908 }
+    },{
+        { 0, 25.078832492684 }, 19887997.7953866, 77.264585323781,
+        { 178.600804840925824646, -24.897833702325682511, 103.101167809583406892, 92442.9124509225839 }
+    },{
+        { 0, 31.740361941314 }, 19972325.3556069, 143.930820896999,
+        { 179.553485210731879874, -31.909206787477701871, 36.145242998351638503, 54883.4113710054145 }
+    },{
+        { 0, .05479250563 }, 19858049.4780499, 41.349430623518,
+        { 178.822647462220726609, .836079031223269324, 138.645259065012502544, 169078.442370111714 }
+    },{
+        { 0, 36.685139871608 }, 19968965.6773632, 89.167975517493,
+        { 179.366667224014334712, -36.6833040833258687, 90.921025521408327068, 13327.2156799476918 }
+    },{
+        { 0, 3.451199399671 }, 19938203.3838544, 91.541212417048,
+        { 179.107509334399258305, -3.459003521120242021, 88.476282464773035164, 32316.1747698810781 }
+    },{
+        { 0, 27.692898794247 }, 19883493.6699045, 88.406440883665,
+        { 178.512356615673144314, -27.666009301228316555, 92.036345087713397961, 94128.7880896190836 }
+    },{
+        { 0, 17.363238291869 }, 19980749.7638027, 39.697196316589,
+        { 179.567921315455829491, -17.288872648596950413, 140.321938237586060826, 46975.9359427664379 }
+    },{
+        { 0, 37.006775102539 }, 19949309.9180043, 116.455543532607,
+        { 179.191103068859169842, -37.156365616364686838, 63.771817992036617793, 45856.1961421018701 }
+    },{
+        { 0, 45.572883540957 }, 19940027.8586414, 137.627256708444,
+        { 179.224707765088686272, -45.94675931323086696, 42.723991162977357301, 74208.4359612889496 }
+    },{
+        { 0, 43.63393981955 }, 19931045.2914508, 91.203625101465,
+        { 178.878236417027994157, -43.642335115130514773, 89.268780774643462256, 55253.5406349861764 }
+    },{
+        { 0, 38.4995307019 }, 19918391.2222193, 141.232864609445,
+        { 179.143856004445269342, -39.042223438550921467, 39.117947060740562295, 102217.2563106863077 }
+    },{
+        { 0, 27.55015339382 }, 19986004.7358853, 137.025135713548,
+        { 179.596220103573824099, -27.587412128122249651, 42.992898351962011956, 33938.7346646670654 }
+    },{
+        { 0, 1.54507498314 }, 19978593.3191777, 36.816106412092,
+        { 179.567115633151308577, -1.448861185025252004, 143.185763012309022403, 56320.5800276739168 }
+    },{
+        { 0, 45.217063644222 }, 19987042.0782465, 18.114645812265,
+        { 179.807382581661125, -45.086424050571516283, 161.928120141429818658, 45544.2915061261936 }
+    },{
+        { 0, 13.473522450751 }, 19987364.078382, 156.839609002403,
+        { 179.726941062277208626, -13.570372758027936877, 23.170293747820406391, 65329.9068132034472 }
+    },{
+        { 0, 6.287741997374 }, 19912159.8245954, 132.954797451112,
+        { 179.071252372259552052, -6.743450924917895817, 47.100789519677419746, 104772.4027498097375 }
+    },{
+        { 0, 7.639709001531 }, 19976374.3699535, 29.731916588299,
+        { 179.616156296978583335, -7.48702643786017917, 150.279582966919438164, 69224.6591757209539 }
+    },{
+        { 0, 5.893688050348 }, 19886907.2520668, 14.653438882877,
+        { 179.586212000450856399, -4.888408917114795625, 165.371181401863458848, 177183.5330818593022 }
+    },{
+        { 0, 61.997076235476 }, 19976288.2901729, 149.562797049254,
+        { 179.605779116829636081, -62.19593758437129915, 30.65850204223272625, 36696.2853801462176 }
+    },{
+        { 0, 50.507637741656 }, 19979542.5263293, 171.564028344478,
+        { 179.893569206021038536, -50.721890799900161112, 8.4746613464253591, 50644.5234828162697 }
+    },{
+        { 0, 7.484475238477 }, 19867425.2906303, 57.020570370985,
+        { 178.638400003000590878, -6.926155588124333461, 123.087267812322270238, 132929.2775641349633 }
+    },{
+        { 0, 56.851165323215 }, 19988235.9960515, 112.345749045605,
+        { 179.587046628550073045, -56.875248360744638525, 67.744017057185404441, 9971.0934553515518 }
+    },{
+        { 0, 10.692273150738 }, 19893210.3050033, 102.824601316946,
+        { 178.709520715733071393, -10.851727623036704339, 77.308514969817191459, 83032.7122948051111 }
+    },{
+        { 0, 46.694739303788 }, 19975447.9283188, 174.663684259477,
+        { 179.926838145841924189, -46.948618153686522669, 5.361568174833475454, 59614.5876209460645 }
+    },{
+        { 0, 15.804386137005 }, 19855850.8800526, 74.932089158884,
+        { 178.367587635209819128, -15.522042847777054984, 105.357235560913450667, 123350.4326645237628 }
+    },{
+        { 0, 4.371450175299 }, 19979071.1035552, 164.163592252794,
+        { 179.780887420199549421, -4.566109732313098407, 15.840695025950408814, 84137.2115482558728 }
+    },{
+        { 0, 30.894388279688 }, 19968681.8321577, 77.35154610481,
+        { 179.375426183521944524, -30.871308884744172663, 102.709506078439532936, 14048.0277985734058 }
+    },{
+        { 0, 9.541166838639 }, 19848553.7844137, 118.441353539081,
+        { 178.432934555386452839, -10.09982228112793472, 61.736686215549403663, 144831.1911566651614 }
+    },{
+        { 0, 8.489292700054 }, 19995477.1669578, 171.963952699866,
+        { 179.906698338023119097, -8.559237750032113623, 8.037517851139094467, 72192.60793572974 }
+    },{
+        { 0, 19.562401114224 }, 19893208.1788508, 126.362762598128,
+        { 178.838724116996037606, -20.05038360490599475, 53.875560227496658204, 112181.7524188837615 }
+    },{
+        { 0, 42.260350252749 }, 19942715.0054774, 170.703419847646,
+        { 179.807860448877064601, -42.79985897702184353, 9.377654670896439828, 96336.3477142010769 }
+    },{
+        { 0, 24.511403144656 }, 19924809.5184876, 102.913211410163,
+        { 178.957598444862223515, -24.616808725039883945, 77.297538210434837096, 55403.453072179318 }
+    },{
+        { 0, 20.844284170708 }, 19909084.6340808, 44.172784008084,
+        { 179.069258863637226633, -20.321320573298341477, 136.01627115731728436, 111009.0987238994608 }
+    },{
+        { 0, 2.426010809098 }, 19840940.6924189, 94.315194952561,
+        { 178.236397468862000784, -2.513715200833756776, 85.734896842737189557, 130002.6104886615638 }
+    },{
+        { 0, 6.600682554664 }, 19878412.28273, 168.167678684515,
+        { 179.646475458013797028, -7.699164822656561787, 11.861035812918738552, 187426.3958525886692 }
+    },{
+        { 0, 23.372339802326 }, 19899498.4582543, 161.197647943542,
+        { 179.499422665106094027, -24.239465200482591299, 18.932355367478826536, 151863.2545535951091 }
+    },{
+        { 0, 16.194668264095 }, 19874825.6683239, 148.942349959054,
+        { 179.115193814080201851, -17.129419031459576897, 31.225656401221968078, 166033.3161394594622 }
+    },{
+        { 0, 1.528726471528 }, 19897803.9939987, 69.212891442493,
+        { 178.791047180477802091, -1.282203000582034597, 110.802928803578167132, 85252.8333849204133 }
+    },{
+        { 0, 6.297249676078 }, 19864042.0495193, 56.274639904925,
+        { 178.623258703845895437, -5.709470001196540278, 123.817184177744186806, 137475.1283083659258 }
+    },{
+        { 0, 17.393540327984 }, 19962624.6302607, 107.855062015266,
+        { 179.330156510680163326, -17.431100690958209424, 72.181322855288535245, 19320.5501845044839 }
+    },{
+        { 0, 46.284685151236 }, 19990422.3478916, 14.758013867151,
+        { 179.852534804091121255, -46.176234945675219984, 165.271681964991897184, 42614.1796365710104 }
+    },{
+        { 0, 14.924320176299 }, 19891861.8615337, 31.446544793174,
+        { 179.195663739713760883, -14.125476432252858442, 148.678916887199611191, 149419.6596309045804 }
+    },{
+        { 0, 23.668824656069 }, 19938736.4442268, 148.091483667618,
+        { 179.409875478773990359, -24.107855233601412399, 32.02919257641173958, 97771.7687385830819 }
+    },{
+        { 0, 46.986276695896 }, 19968596.0414782, 174.796708941456,
+        { 179.92040916864362177, -47.301644191214905832, 5.234240076649939638, 66113.7417494369769 }
+    },{
+        { 0, 65.946144289524 }, 19993734.5109736, 25.375428509648,
+        { 179.808282612725835525, -65.871840130833632868, 154.703163938350061652, 18355.2254271672769 }
+    },{
+        { 0, 10.950298933293 }, 19975919.5586889, 28.779018914489,
+        { 179.624609619829763098, -10.787771536605316781, 151.238005588662201946, 70291.1998404303581 }
+    },{
+        { 0, 13.609869340778 }, 19913213.8514358, 129.616021271129,
+        { 179.035623147420893383, -14.023624108675206222, 50.506400999466711623, 97596.7664002074776 }
+    },{
+        { 0, 48.701427557433 }, 19972955.2699173, 102.875149183407,
+        { 179.385565054218238481, -48.735316652259656533, 77.294384444682547869, 18461.7742226227697 }
+    },{
+        { 0, 31.519172055785 }, 19952318.3772514, 26.247105619999,
+        { 179.555251675378549409, -31.140142027808697534, 153.865822276646938125, 86354.7117605101002 }
+    },{
+        { 0, 31.863784754278 }, 19993324.8682601, 29.572313410211,
+        { 179.722489476483407524, -31.826935359797657785, 150.440607907359037187, 41427.6181613499234 }
+    },{
+        { 0, 76.434608546092 }, 19997750.023578, 167.428385412814,
+        { 179.918287057674124459, -76.48787937532808951, 12.621032110142724567, 9619.5267710862108 }
+    },{
+        { 0, 73.114273316483 }, 19992866.6147806, 78.154765899661,
+        { 179.576736605988553624, -73.098788070892914568, 102.085693546950923465, 8580.6475692800946 }
+    },{
+        { 0, 1.125639056292 }, 19852573.5442848, 67.184842289382,
+        { 178.426819580880619395, -.694775021853292564, 112.831314850896246589, 132932.8743502563937 }
+    }
+};
+
+size_t const expected_size_antipodal = sizeof(expected_antipodal) / sizeof(expected_results_antipodal);
+
+#endif // BOOST_GEOMETRY_TEST_DIRECT_CASES_ANTIPODAL_HPP

commit b8a225e1cfa057b15aded81a9822219fee3323db
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue May 29 21:11:53 2018 +0500

    [formulas] Fix direct geodesic method by performing normalization

    - Add minus sign for B12 evaluation

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 8e81cf4..c0faa05 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -103,7 +103,6 @@ public:
         CT const c1 = 1;
         CT const c2 = 2;

-        CT const a = CT(get_radius<0>(spheroid));
         CT const b = CT(get_radius<2>(spheroid));
         CT const f = formula::flattening<CT>(spheroid);
         CT const one_minus_f = c1 - f;
@@ -121,6 +120,9 @@ public:
         math::sin_cos_degrees<CT>(math::round_angle<CT>(lat1), sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

+        math::normalize<CT>(sin_beta1, cos_beta1);
+        cos_beta1 = std::max(sqrt(std::numeric_limits<CT>::min()), cos_beta1);
+
         // Obtain alpha 0 by solving the spherical triangle.
         CT const sin_alpha0
             = sin_alpha1 * cos_beta1;
@@ -146,8 +148,12 @@ public:
         CT const sin_tau12 = sin(tau12);
         CT const cos_tau12 = cos(tau12);

-        CT const sin_sigma1 = sin_beta1;
-        CT const cos_sigma1 = cos_beta1 * cos_alpha1;
+        CT sin_sigma1 = sin_beta1;
+        CT sin_omega1 = sin_alpha0 * sin_beta1;
+
+        CT cos_sigma1, cos_omega1;
+        cos_sigma1 = cos_omega1 = sin_beta1 != 0 || cos_alpha1 != 0 ? cos_beta1 * cos_alpha1 : 1;
+        math::normalize<CT>(sin_sigma1, cos_sigma1);

         CT const B11 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
         CT const sin_B11 = sin(B11);
@@ -162,9 +168,9 @@ public:
         CT coeffs_C1p[SeriesOrder + 1];
         series_expansion::evaluate_coeffs_C1p<CT, SeriesOrder>(epsilon, coeffs_C1p);

-        CT const B12 = sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
+        CT const B12 = - sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
                                       cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
-                                      coeffs_C1p); // < 0?
+                                      coeffs_C1p);

         CT const sigma12 = tau12 - (B12 - B11);
         CT const sin_sigma12 = sin(sigma12);
@@ -200,9 +206,6 @@ public:
             result.lat2 /= math::d2r<T>();

             // Find the longitude at the second point.
-            CT const sin_omega1 = sin_beta1 * sin_alpha0;
-            CT const cos_omega1 = cos_beta1 * cos_alpha1;
-
             CT const sin_omega2 = sin_alpha0 * sin_sigma2;
             CT const cos_omega2 = cos_sigma2;

@@ -218,11 +221,11 @@ public:
             // Compute the size of coefficient array.
             size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
             CT coeffs_C3x[coeffs_C3_size];
-            series_expansion::evaluate_coeffs_C3<double, SeriesOrder>(n, coeffs_C3x);
+            series_expansion::evaluate_coeffs_C3x<double, SeriesOrder>(n, coeffs_C3x);

             // Evaluate C3 coefficients.
             CT coeffs_C3[SeriesOrder];
-            math::evaluate_coeffs_var2<double, SeriesOrder>(epsilon, coeffs_C3x, coeffs_C3);
+            series_expansion::evaluate_coeffs_C3<double, SeriesOrder>(epsilon, coeffs_C3, coeffs_C3x);

             CT const B31 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);


commit 3dd6bce7202e3050a8f5d1c26b7111d0689a591a
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue May 29 21:08:06 2018 +0500

    [util] Add functions for normalizing and evaluating polynomial

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 60d3646..e0ab1c8 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -830,10 +830,23 @@ inline T round_angle(T x) {
 }

 /*!
+\brief Normalize the given values.
+*/
+template<typename T>
+inline void normalize(T& x, T& y)
+{
+    T h = boost::math::hypot(x, y);
+
+    x /= h; y /= h;
+}
+
+
+/*!
 \brief Normalize a given angle.
 */
 template<typename T>
-    inline T normalize_angle(T x) {
+    inline T normalize_angle(T x)
+{
     T y = std::fmod(x, T(360));

     return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360);
@@ -845,7 +858,7 @@ template<typename T>
 // TODO: adl1995 - Merge these functions with formulas/area_formulas.hpp
 // i.e. place them in one file.
 template <typename NT, typename IteratorType>
-static inline NT horner_evaluate(NT x,
+inline NT horner_evaluate(NT x,
                                  IteratorType begin,
                                  IteratorType end)
 {
@@ -860,20 +873,21 @@ static inline NT horner_evaluate(NT x,
 }

 /*
-\brief Given the set of coefficients coeffs1[] evaluate on
-    var2 and return the set of coefficients coeffs2[].
+\brief Evaluate the polynomial.
 */
-template <typename CT, std::size_t SeriesOrder>
-static inline void evaluate_coeffs_var2(CT var2,
-                                        CT coeffs1[],
-                                        CT coeffs2[]){
-    std::size_t begin(0), end(0);
-    for(std::size_t i = 0; i <= SeriesOrder; i++){
-        end = begin + SeriesOrder + 1 - i;
-        coeffs2[i] = ((i==0) ? CT(1) : pow(var2,int(i)))
-                    * horner_evaluate(var2, coeffs1 + begin, coeffs1 + end);
-        begin = end;
+template<typename CT>
+inline CT polyval(int N,
+                         const CT coeff[],
+                         const CT eps)
+{
+    CT y = N < 0 ? 0 : *coeff++;
+
+    while (--N >= 0)
+    {
+        y = y * eps + *coeff++;
     }
+
+    return y;
 }

 } // namespace math

commit 1e31876e9446d359d4b389d916e6d61486ccc057
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue May 29 21:06:19 2018 +0500

    [util] Modify function for evaluting C3x coefficient

    - Add separate function for evaluating C3 from C3x coefficient

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index f7e4595..59511c2 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -842,116 +842,243 @@ namespace boost { namespace geometry { namespace series_expansion {
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
                s/eps(CT(2))/eps2/g;'
     */
-    template <typename CT, std::size_t SeriesOrder>
-    static inline void evaluate_coeffs_C3(CT const& n, CT c[])
+    // TODO: adl1995
+    // Update docstring and function body.
+    // The coefficients C3[l] in the Fourier expansion of B3
+    template <typename CT, int SeriesOrder>
+    void evaluate_coeffs_C3x(CT const& n, CT c[]) {
+        if (SeriesOrder == 3) {
+            static const CT coeff[] = {
+            // C3[1], coeff of eps^2, polynomial in n of order 0
+            1, 8,
+            // C3[1], coeff of eps^1, polynomial in n of order 1
+            -1, 1, 4,
+            // C3[2], coeff of eps^2, polynomial in n of order 0
+            1, 16,
+            };
+        }
+        else if (SeriesOrder == 4) {
+            static const CT coeff[] = {
+            // C3[1], coeff of eps^3, polynomial in n of order 0
+            3, 64,
+            // C3[1], coeff of eps^2, polynomial in n of order 1
+            // This is a case where a leading 0 term has been inserted to maintain the
+            // pattern in the orders of the polynomials.
+            0, 1, 8,
+            // C3[1], coeff of eps^1, polynomial in n of order 1
+            -1, 1, 4,
+            // C3[2], coeff of eps^3, polynomial in n of order 0
+            3, 64,
+            // C3[2], coeff of eps^2, polynomial in n of order 1
+            -3, 2, 32,
+            // C3[3], coeff of eps^3, polynomial in n of order 0
+            5, 192,
+            };
+        }
+        else if (SeriesOrder == 5) {
+            static const CT coeff[] = {
+            // C3[1], coeff of eps^4, polynomial in n of order 0
+            5, 128,
+            // C3[1], coeff of eps^3, polynomial in n of order 1
+            3, 3, 64,
+            // C3[1], coeff of eps^2, polynomial in n of order 2
+            -1, 0, 1, 8,
+            // C3[1], coeff of eps^1, polynomial in n of order 1
+            -1, 1, 4,
+            // C3[2], coeff of eps^4, polynomial in n of order 0
+            3, 128,
+            // C3[2], coeff of eps^3, polynomial in n of order 1
+            -2, 3, 64,
+            // C3[2], coeff of eps^2, polynomial in n of order 2
+            1, -3, 2, 32,
+            // C3[3], coeff of eps^4, polynomial in n of order 0
+            3, 128,
+            // C3[3], coeff of eps^3, polynomial in n of order 1
+            -9, 5, 192,
+            // C3[4], coeff of eps^4, polynomial in n of order 0
+            7, 512,
+            };
+        }
+        else if (SeriesOrder == 6) {
+            static const CT coeff[] = {
+            // C3[1], coeff of eps^5, polynomial in n of order 0
+            3, 128,
+            // C3[1], coeff of eps^4, polynomial in n of order 1
+            2, 5, 128,
+            // C3[1], coeff of eps^3, polynomial in n of order 2
+            -1, 3, 3, 64,
+            // C3[1], coeff of eps^2, polynomial in n of order 2
+            -1, 0, 1, 8,
+            // C3[1], coeff of eps^1, polynomial in n of order 1
+            -1, 1, 4,
+            // C3[2], coeff of eps^5, polynomial in n of order 0
+            5, 256,
+            // C3[2], coeff of eps^4, polynomial in n of order 1
+            1, 3, 128,
+            // C3[2], coeff of eps^3, polynomial in n of order 2
+            -3, -2, 3, 64,
+            // C3[2], coeff of eps^2, polynomial in n of order 2
+            1, -3, 2, 32,
+            // C3[3], coeff of eps^5, polynomial in n of order 0
+            7, 512,
+            // C3[3], coeff of eps^4, polynomial in n of order 1
+            -10, 9, 384,
+            // C3[3], coeff of eps^3, polynomial in n of order 2
+            5, -9, 5, 192,
+            // C3[4], coeff of eps^5, polynomial in n of order 0
+            7, 512,
+            // C3[4], coeff of eps^4, polynomial in n of order 1
+            -14, 7, 512,
+            // C3[5], coeff of eps^5, polynomial in n of order 0
+            21, 2560,
+            };
+        }
+        else if (SeriesOrder == 7) {
+            static const CT coeff[] = {
+            // C3[1], coeff of eps^6, polynomial in n of order 0
+            21, 1024,
+            // C3[1], coeff of eps^5, polynomial in n of order 1
+            11, 12, 512,
+            // C3[1], coeff of eps^4, polynomial in n of order 2
+            2, 2, 5, 128,
+            // C3[1], coeff of eps^3, polynomial in n of order 3
+            -5, -1, 3, 3, 64,
+            // C3[1], coeff of eps^2, polynomial in n of order 2
+            -1, 0, 1, 8,
+            // C3[1], coeff of eps^1, polynomial in n of order 1
+            -1, 1, 4,
+            // C3[2], coeff of eps^6, polynomial in n of order 0
+            27, 2048,
+            // C3[2], coeff of eps^5, polynomial in n of order 1
+            1, 5, 256,
+            // C3[2], coeff of eps^4, polynomial in n of order 2
+            -9, 2, 6, 256,
+            // C3[2], coeff of eps^3, polynomial in n of order 3
+            2, -3, -2, 3, 64,
+            // C3[2], coeff of eps^2, polynomial in n of order 2
+            1, -3, 2, 32,
+            // C3[3], coeff of eps^6, polynomial in n of order 0
+            3, 256,
+            // C3[3], coeff of eps^5, polynomial in n of order 1
+            -4, 21, 1536,
+            // C3[3], coeff of eps^4, polynomial in n of order 2
+            -6, -10, 9, 384,
+            // C3[3], coeff of eps^3, polynomial in n of order 3
+            -1, 5, -9, 5, 192,
+            // C3[4], coeff of eps^6, polynomial in n of order 0
+            9, 1024,
+            // C3[4], coeff of eps^5, polynomial in n of order 1
+            -10, 7, 512,
+            // C3[4], coeff of eps^4, polynomial in n of order 2
+            10, -14, 7, 512,
+            // C3[5], coeff of eps^6, polynomial in n of order 0
+            9, 1024,
+            // C3[5], coeff of eps^5, polynomial in n of order 1
+            -45, 21, 2560,
+            // C3[6], coeff of eps^6, polynomial in n of order 0
+            11, 2048,
+            };
+        }
+        else if (SeriesOrder == 8) {
+            static const CT coeff[] = {
+            // C3[1], coeff of eps^7, polynomial in n of order 0
+            243, 16384,
+            // C3[1], coeff of eps^6, polynomial in n of order 1
+            10, 21, 1024,
+            // C3[1], coeff of eps^5, polynomial in n of order 2
+            3, 11, 12, 512,
+            // C3[1], coeff of eps^4, polynomial in n of order 3
+            -2, 2, 2, 5, 128,
+            // C3[1], coeff of eps^3, polynomial in n of order 3
+            -5, -1, 3, 3, 64,
+            // C3[1], coeff of eps^2, polynomial in n of order 2
+            -1, 0, 1, 8,
+            // C3[1], coeff of eps^1, polynomial in n of order 1
+            -1, 1, 4,
+            // C3[2], coeff of eps^7, polynomial in n of order 0
+            187, 16384,
+            // C3[2], coeff of eps^6, polynomial in n of order 1
+            69, 108, 8192,
+            // C3[2], coeff of eps^5, polynomial in n of order 2
+            -2, 1, 5, 256,
+            // C3[2], coeff of eps^4, polynomial in n of order 3
+            -6, -9, 2, 6, 256,
+            // C3[2], coeff of eps^3, polynomial in n of order 3
+            2, -3, -2, 3, 64,
+            // C3[2], coeff of eps^2, polynomial in n of order 2
+            1, -3, 2, 32,
+            // C3[3], coeff of eps^7, polynomial in n of order 0
+            139, 16384,
+            // C3[3], coeff of eps^6, polynomial in n of order 1
+            -1, 12, 1024,
+            // C3[3], coeff of eps^5, polynomial in n of order 2
+            -77, -8, 42, 3072,
+            // C3[3], coeff of eps^4, polynomial in n of order 3
+            10, -6, -10, 9, 384,
+            // C3[3], coeff of eps^3, polynomial in n of order 3
+            -1, 5, -9, 5, 192,
+            // C3[4], coeff of eps^7, polynomial in n of order 0
+            127, 16384,
+            // C3[4], coeff of eps^6, polynomial in n of order 1
+            -43, 72, 8192,
+            // C3[4], coeff of eps^5, polynomial in n of order 2
+            -7, -40, 28, 2048,
+            // C3[4], coeff of eps^4, polynomial in n of order 3
+            -7, 20, -28, 14, 1024,
+            // C3[5], coeff of eps^7, polynomial in n of order 0
+            99, 16384,
+            // C3[5], coeff of eps^6, polynomial in n of order 1
+            -15, 9, 1024,
+            // C3[5], coeff of eps^5, polynomial in n of order 2
+            75, -90, 42, 5120,
+            // C3[6], coeff of eps^7, polynomial in n of order 0
+            99, 16384,
+            // C3[6], coeff of eps^6, polynomial in n of order 1
+            -99, 44, 8192,
+            // C3[7], coeff of eps^7, polynomial in n of order 0
+            429, 114688,
+            };
+
+            int offset = 0, k = 0;
+            // l is index of C3[l].
+            for (int l = 1; l < SeriesOrder; ++l) {
+                for (int j = SeriesOrder - 1; j >= l; --j) {
+                    // Order of polynomial in n.
+                    int m = std::min(SeriesOrder - j - 1, j);
+                    c[k++] = math::polyval(m, coeff + offset, n) /
+                             coeff[offset + m + 1];
+                    offset += m + 2;
+                }
+            }
+        }
+        // Post condition: offset == sizeof(coeff) / sizeof(CT) && k == coeffs_C3_size
+    }
+
+    /*
+    \brief Given the set of coefficients coeffs2[] evaluate on
+      C3 and return the set of coefficients coeffs1[].
+
+      Elements coeffs1[1] through coeffs1[SeriesOrder - 1] are set.
+    */
+    template <typename CT, size_t SeriesOrder>
+    static inline void evaluate_coeffs_C3(CT eps, CT coeffs1[], CT coeffs2[])
     {
-        const CT n2 = math::sqr(n);
-        switch (SeriesOrder) {
-        case 0:
-            break;
-        case 1:
-            break;
-        case 2:
-            c[0] = (CT(1)-n)/CT(4);
-            break;
-        case 3:
-            c[0] = (CT(1)-n)/CT(4);
-            c[1] = (CT(1)-n2)/CT(8);
-            c[2] = ((n-CT(3))*n+CT(2))/CT(32);
-            break;
-        case 4:
-            c[0] = (CT(1)-n)/CT(4);
-            c[1] = (CT(1)-n2)/CT(8);
-            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
-            c[3] = ((n-CT(3))*n+CT(2))/CT(32);
-            c[4] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
-            c[5] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
-            break;
-        case 5:
-            c[0] = (CT(1)-n)/CT(4);
-            c[1] = (CT(1)-n2)/CT(8);
-            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
-            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
-            c[4] = ((n-CT(3))*n+CT(2))/CT(32);
-            c[5] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
-            c[6] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
-            c[7] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
-            c[8] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
-            c[9] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
-            break;
-        case 6:
-            c[0] = (CT(1)-n)/CT(4);
-            c[1] = (CT(1)-n2)/CT(8);
-            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
-            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
-            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
-            c[5] = ((n-CT(3))*n+CT(2))/CT(32);
-            c[6] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
-            c[7] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
-            c[8] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
-            c[9] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
-            c[10] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
-            c[11] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
-            c[12] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
-            c[13] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
-            c[14] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
-            break;
-        case 7:
-            c[0] = (CT(1)-n)/CT(4);
-            c[1] = (CT(1)-n2)/CT(8);
-            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
-            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
-            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
-            c[5] = (CT(10)*n+CT(21))/CT(1024);
-            c[6] = ((n-CT(3))*n+CT(2))/CT(32);
-            c[7] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
-            c[8] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
-            c[9] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
-            c[10] = (CT(69)*n+CT(108))/CT(8192);
-            c[11] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
-            c[12] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
-            c[13] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
-            c[14] = (CT(12)-n)/CT(1024);
-            c[15] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
-            c[16] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
-            c[17] = (CT(72)-CT(43)*n)/CT(8192);
-            c[18] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
-            c[19] = (CT(9)-CT(15)*n)/CT(1024);
-            c[20] = (CT(44)-CT(99)*n)/CT(8192);
-            break;
-        case 8:
-            c[0] = (CT(1)-n)/CT(4);
-            c[1] = (CT(1)-n2)/CT(8);
-            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
-            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
-            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
-            c[5] = (CT(10)*n+CT(21))/CT(1024);
-            c[6] = CT(243)/CT(16384);
-            c[7] = ((n-CT(3))*n+CT(2))/CT(32);
-            c[8] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
-            c[9] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
-            c[10] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
-            c[11] = (CT(69)*n+CT(108))/CT(8192);
-            c[12] = CT(187)/CT(16384);
-            c[13] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
-            c[14] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
-            c[15] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
-            c[16] = (CT(12)-n)/CT(1024);
-            c[17] = CT(139)/CT(16384);
-            c[18] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
-            c[19] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
-            c[20] = (CT(72)-CT(43)*n)/CT(8192);
-            c[21] = CT(127)/CT(16384);
-            c[22] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
-            c[23] = (CT(9)-CT(15)*n)/CT(1024);
-            c[24] = CT(99)/CT(16384);
-            c[25] = (CT(44)-CT(99)*n)/CT(8192);
-            c[26] = CT(99)/CT(16384);
-            c[27] = CT(429)/CT(114688);
-            break;
+        CT mult = 1;
+        int offset = 0;
+
+        // l is the index of C3[l].
+        for (size_t l = 1; l < SeriesOrder; ++l)
+        {
+            // Order of polynomial in eps.
+            int m = SeriesOrder - l - 1;
+            mult *= eps;
+            coeffs1[l] = mult * math::polyval(m, coeffs2 + offset, eps);
+            offset += m + 1;
         }
+        // Post condition: offset == coeffs_C3_size
     }

+
 }}} // namespace boost::geometry::series_expansion

 #endif // BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

commit afe7bc679c7e90852e6e4441259f12dda4db7962
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon May 28 16:46:20 2018 +0500

    [test] Add direct Karney's method to direct.cpp test cases

diff --git a/test/formulas/direct.cpp b/test/formulas/direct.cpp
index 72778ab..7cf076b 100644
--- a/test/formulas/direct.cpp
+++ b/test/formulas/direct.cpp
@@ -1,3 +1,4 @@
+
 // Boost.Geometry
 // Unit Test

@@ -14,6 +15,7 @@

 #include <boost/geometry/formulas/vincenty_direct.hpp>
 #include <boost/geometry/formulas/thomas_direct.hpp>
+#include <boost/geometry/formulas/karney_direct.hpp>

 #include <boost/geometry/srs/spheroid.hpp>

@@ -37,6 +39,10 @@ void test_all(expected_results const& results)
     double distance = results.distance;
     double azi12r = results.azimuth12 * d2r;

+    double lon1d = results.p1.lon;
+    double lat1d = results.p1.lat;
+    double azi12d = results.azimuth12;
+
     // WGS84
     bg::srs::spheroid<double> spheroid(6378137.0, 6356752.3142451793);

@@ -55,6 +61,10 @@ void test_all(expected_results const& results)
     result.lat2 *= r2d;
     result.reverse_azimuth *= r2d;
     check_direct(result, results.thomas, results.karney, 0.0000001);
+
+    typedef bg::formula::karney_direct<double, 8, true, true, true, true> ka_t;
+    result = ka_t::apply(lon1d, lat1d, distance, azi12d, spheroid);
+    check_direct(result, results.thomas, results.karney, 0.0000001);
 }

 int test_main(int, char*[])

commit 6a2897db25844d1bbcc8dc59bf88328e342cb5a9
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon May 28 12:28:14 2018 +0500

    [formulas][util] Add missing import and function return type

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 38460fb..8e81cf4 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -11,6 +11,7 @@


 #include <boost/math/constants/constants.hpp>
+#include <boost/math/special_functions/hypot.hpp>

 #include <boost/geometry/util/math.hpp>
 #include <boost/geometry/util/series_expansion.hpp>
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index cca4328..f7e4595 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -538,7 +538,7 @@ namespace boost { namespace geometry { namespace series_expansion {
                s/eps(CT(2))/eps2/g;'
     */
     template <typename CT, std::size_t SeriesOrder>
-    static inline evaluate_coeffs_C1p(CT eps, CT c[])
+    static inline void evaluate_coeffs_C1p(CT eps, CT c[])
     {
         CT const eps2 = math::sqr(eps);
         CT d = eps;

commit 0c2b8cdbab3fd6e5b525617641b260cba26ee3b9
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu May 24 11:37:28 2018 +0500

    [formulas] Make variable declarations constant

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 798a862..38460fb 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -90,7 +90,7 @@ public:

         CT const lon1 = lo1;
         CT const lat1 = la1;
-        Azi azi12 = azimuth12;
+        Azi const azi12 = math::normalize_angle<CT>(azimuth12);

         if (math::equals(distance, Dist(0)) || distance < Dist(0))
         {
@@ -112,7 +112,6 @@ public:
         CT const e2 = f * two_minus_f;
         CT const ep2 = e2 / math::sqr(one_minus_f);

-        azi12 = math::normalize_angle<CT>(azi12);
         CT sin_alpha1, cos_alpha1;
         math::sin_cos_degrees<CT>(math::round_angle<CT>(azi12), sin_alpha1, cos_alpha1);

@@ -122,56 +121,63 @@ public:
         sin_beta1 *= one_minus_f;

         // Obtain alpha 0 by solving the spherical triangle.
-        CT sin_alpha0 = sin_alpha1 * cos_beta1;
-        CT cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);
+        CT const sin_alpha0
+            = sin_alpha1 * cos_beta1;
+        CT const cos_alpha0
+            = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);

-        CT k2 = math::sqr(cos_alpha0) * ep2;
+        CT const k2 = math::sqr(cos_alpha0) * ep2;

-        CT epsilon = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);
+        CT const epsilon = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);

         // Find the coefficients for A1 by computing the
         // series expansion using Horner scehme.
-        CT expansion_A1 = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);
+        CT const expansion_A1
+            = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);

         // Index zero element of coeffs_C1 is unused.
         CT coeffs_C1[SeriesOrder + 1];
         series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);

         // Tau is an integration variable.
-        CT tau12 = distance / (b * (c1 + expansion_A1));
+        CT const tau12 = distance / (b * (c1 + expansion_A1));

-        CT sin_tau12 = sin(tau12);
-        CT cos_tau12 = cos(tau12);
+        CT const sin_tau12 = sin(tau12);
+        CT const cos_tau12 = cos(tau12);

-        CT sin_sigma1 = sin_beta1;
-        CT cos_sigma1 = cos_beta1 * cos_alpha1;
+        CT const sin_sigma1 = sin_beta1;
+        CT const cos_sigma1 = cos_beta1 * cos_alpha1;

-        CT B11 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
-        CT sin_B11 = sin(B11);
-        CT cos_B11 = cos(B11);
+        CT const B11 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
+        CT const sin_B11 = sin(B11);
+        CT const cos_B11 = cos(B11);

-        CT sin_tau1 = sin_sigma1 * cos_B11 + cos_sigma1 * sin_B11;
-        CT cos_tau1 = cos_sigma1 * cos_B11 - sin_sigma1 * sin_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;

         // Index zero element of coeffs_C1p is unused.
         CT coeffs_C1p[SeriesOrder + 1];
         series_expansion::evaluate_coeffs_C1p<CT, SeriesOrder>(epsilon, coeffs_C1p);

-        CT B12 = sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
-                                cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
-                                coeffs_C1p); // < 0?
+        CT const B12 = sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
+                                      cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
+                                      coeffs_C1p); // < 0?

-        CT sigma12 = tau12 - (B12 - B11);
-        CT sin_sigma12 = sin(sigma12);
-        CT cos_sigma12 = cos(sigma12);
+        CT const sigma12 = tau12 - (B12 - B11);
+        CT const sin_sigma12 = sin(sigma12);
+        CT const cos_sigma12 = cos(sigma12);

-        CT sin_sigma2 = sin_sigma1 * cos_sigma12 + cos_sigma1 * sin_sigma12;
-        CT cos_sigma2 = cos_sigma1 * cos_sigma12 - sin_sigma1 * sin_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_CONDITION(CalcRevAzimuth))
         {
-            CT sin_alpha2 = sin_alpha0;
-            CT cos_alpha2 = cos_alpha0 * cos_sigma2;
+            CT const sin_alpha2 = sin_alpha0;
+            CT const cos_alpha2 = cos_alpha0 * cos_sigma2;

             result.reverse_azimuth = atan2(sin_alpha2, cos_alpha2);

@@ -182,8 +188,10 @@ public:
         if (BOOST_GEOMETRY_CONDITION(CalcCoordinates))
         {
             // Find the latitude at the second point.
-            CT sin_beta2 = cos_alpha0 * sin_sigma2;
-            CT cos_beta2 = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);
+            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);

@@ -191,20 +199,20 @@ public:
             result.lat2 /= math::d2r<T>();

             // Find the longitude at the second point.
-            CT sin_omega1 = sin_beta1 * sin_alpha0;
-            CT cos_omega1 = cos_beta1 * cos_alpha1;
+            CT const sin_omega1 = sin_beta1 * sin_alpha0;
+            CT const cos_omega1 = cos_beta1 * cos_alpha1;

-            CT sin_omega2 = sin_alpha0 * sin_sigma2;
-            CT cos_omega2 = cos_sigma2;
+            CT const sin_omega2 = sin_alpha0 * sin_sigma2;
+            CT const cos_omega2 = cos_sigma2;

-            CT omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
-                               cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);
+            CT const omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
+                                     cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);

             CT coeffs_A3[SeriesOrder];
             series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);

-            CT A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
-            CT A3c = -f * sin_alpha0 * A3;
+            CT const A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
+            CT const A3c = -f * sin_alpha0 * A3;

             // Compute the size of coefficient array.
             size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
@@ -215,16 +223,16 @@ public:
             CT coeffs_C3[SeriesOrder];
             math::evaluate_coeffs_var2<double, SeriesOrder>(epsilon, coeffs_C3x, coeffs_C3);

-            CT B31 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
+            CT const B31 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);

-            CT lam12 = omega12 + A3c *
-                       (sigma12 + (sin_cos_series(sin_sigma2,
-                                                  cos_sigma2,
-                                                  coeffs_C3) - B31));
+            CT const lam12 = omega12 + A3c *
+                             (sigma12 + (sin_cos_series(sin_sigma2,
+                                                        cos_sigma2,
+                                                        coeffs_C3) - B31));

-            // Convert to radians to get the longitudinal
-            // difference.
-            CT lon12 = lam12 / math::d2r<T>();
+            // Convert to radians to get the
+            // longitudinal difference.
+            CT const lon12 = lam12 / math::d2r<T>();

             // Add the longitude at first point to the longitudinal
             // difference and normalize the result.
@@ -239,16 +247,17 @@ public:
             CT coeffs_C2[SeriesOrder + 1];
             series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);

-            CT B21 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
-            CT B22 = sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);
+            CT const B21 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
+            CT const B22 = sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);

             // Find the coefficients for A2 by computing the
             // series expansion using Horner scehme.
-            CT expansion_A2 = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);
+            CT const expansion_A2
+                = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);

-            CT AB1 = (c1 + expansion_A1) * (B12 - B11);
-            CT AB2 = (c1 + expansion_A2) * (B22 - B21);
-            CT J12 = (expansion_A1 - expansion_A2) * sigma12 + (AB1 - AB2);
+            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 = sqrt(1 + ep2 * math::sqr(sin_beta1));
             CT const dn2 = sqrt(1 + k2 * math::sqr(sin_sigma2));
@@ -259,8 +268,8 @@ public:
                                           cos_sigma1 * cos_sigma2 * J12);

             // Find the geodesic scale.
-            CT t = k2 * (sin_sigma2 - sin_sigma1) *
-                        (sin_sigma2 * sin_sigma1) / (dn1 + dn2);
+            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) *

commit ac4e483c9271507aa84b30aadaba32a221efab5f
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu May 24 11:26:56 2018 +0500

    [formulas] Compute the reduced length and geodesic scale using Karney's direct method

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 58ed326..798a862 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -1,5 +1,7 @@
 // Boost.Geometry

+// Contributed and/or modified by Adeel Ahmad.
+
 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt)
@@ -30,7 +32,7 @@ https://arxiv.org/pdf/1109.4448.pdf
 */
 template <
     typename CT,
-    std::size_t SeriesOrder = 8,
+    size_t SeriesOrder = 8,
     bool EnableCoordinates = true,
     bool EnableReverseAzimuth = false,
     bool EnableReducedLength = false,
@@ -56,7 +58,7 @@ public:
                                     CT cosx,
                                     const CT coeffs[])
     {
-        std::size_t n = SeriesOrder;
+        size_t n = SeriesOrder;

         // Point to one beyond last element.
         coeffs += (n + 1);
@@ -125,9 +127,9 @@ public:

         CT k2 = math::sqr(cos_alpha0) * ep2;

-        CT epsilon = k2 / (c2 * (c1 + std::sqrt(c1 + k2)) + k2);
+        CT epsilon = k2 / (c2 * (c1 + sqrt(c1 + k2)) + k2);

-        // Find the coefficients for Aj by computing the
+        // Find the coefficients for A1 by computing the
         // series expansion using Horner scehme.
         CT expansion_A1 = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);

@@ -171,7 +173,7 @@ public:
             CT sin_alpha2 = sin_alpha0;
             CT cos_alpha2 = cos_alpha0 * cos_sigma2;

-            result.reverse_azimuth = std::atan2(sin_alpha2, cos_alpha2);
+            result.reverse_azimuth = atan2(sin_alpha2, cos_alpha2);

             // Convert the angle to radians.
             result.reverse_azimuth /= math::d2r<T>();
@@ -183,7 +185,7 @@ public:
             CT sin_beta2 = cos_alpha0 * sin_sigma2;
             CT cos_beta2 = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);

-            result.lat2 = std::atan2(sin_beta2, one_minus_f * cos_beta2);
+            result.lat2 = atan2(sin_beta2, one_minus_f * cos_beta2);

             // Convert the coordinate to radians.
             result.lat2 /= math::d2r<T>();
@@ -195,8 +197,8 @@ public:
             CT sin_omega2 = sin_alpha0 * sin_sigma2;
             CT cos_omega2 = cos_sigma2;

-            CT omega12 = std::atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
-                                    cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);
+            CT omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
+                               cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);

             CT coeffs_A3[SeriesOrder];
             series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
@@ -205,7 +207,7 @@ public:
             CT A3c = -f * sin_alpha0 * A3;

             // Compute the size of coefficient array.
-            const std::size_t coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
+            size_t const coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
             CT coeffs_C3x[coeffs_C3_size];
             series_expansion::evaluate_coeffs_C3<double, SeriesOrder>(n, coeffs_C3x);

@@ -229,6 +231,43 @@ public:
             result.lon2 = math::normalize_angle(math::normalize_angle(lon1) +
                                                 math::normalize_angle(lon12));
         }
+
+        if (BOOST_GEOMETRY_CONDITION(CalcQuantities))
+        {
+            // Evaluate the coefficients for C2.
+            // Index zero element of coeffs_C2 is unused.
+            CT coeffs_C2[SeriesOrder + 1];
+            series_expansion::evaluate_coeffs_C2<CT, SeriesOrder>(epsilon, coeffs_C2);
+
+            CT B21 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
+            CT B22 = sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);
+
+            // Find the coefficients for A2 by computing the
+            // series expansion using Horner scehme.
+            CT expansion_A2 = series_expansion::evaluate_series_A2<CT, SeriesOrder>(epsilon);
+
+            CT AB1 = (c1 + expansion_A1) * (B12 - B11);
+            CT AB2 = (c1 + expansion_A2) * (B22 - B21);
+            CT J12 = (expansion_A1 - expansion_A2) * sigma12 + (AB1 - AB2);
+
+            CT const dn1 = sqrt(1 + ep2 * math::sqr(sin_beta1));
+            CT const dn2 = sqrt(1 + k2 * math::sqr(sin_sigma2));
+
+            // Find the reduced length.
+            result.reduced_length = b * ((dn2 * (cos_sigma1 * sin_sigma2) -
+                                          dn1 * (sin_sigma1 * cos_sigma2)) -
+                                          cos_sigma1 * cos_sigma2 * J12);
+
+            // Find the geodesic scale.
+            CT 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;
     }
 };

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index df7507e..60d3646 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -830,7 +830,7 @@ inline T round_angle(T x) {
 }

 /*!
-\brief Normalize a given angle
+\brief Normalize a given angle.
 */
 template<typename T>
     inline T normalize_angle(T x) {
@@ -839,6 +839,43 @@ template<typename T>
     return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360);
 }

+/*
+\brief Evaluate the polynomial in x using Horner's method.
+*/
+// TODO: adl1995 - Merge these functions with formulas/area_formulas.hpp
+// i.e. place them in one file.
+template <typename NT, typename IteratorType>
+static inline NT horner_evaluate(NT x,
+                                 IteratorType begin,
+                                 IteratorType end)
+{
+    NT result(0);
+    IteratorType it = end;
+    do
+    {
+        result = result * x + *--it;
+    }
+    while (it != begin);
+    return result;
+}
+
+/*
+\brief Given the set of coefficients coeffs1[] evaluate on
+    var2 and return the set of coefficients coeffs2[].
+*/
+template <typename CT, std::size_t SeriesOrder>
+static inline void evaluate_coeffs_var2(CT var2,
+                                        CT coeffs1[],
+                                        CT coeffs2[]){
+    std::size_t begin(0), end(0);
+    for(std::size_t i = 0; i <= SeriesOrder; i++){
+        end = begin + SeriesOrder + 1 - i;
+        coeffs2[i] = ((i==0) ? CT(1) : pow(var2,int(i)))
+                    * horner_evaluate(var2, coeffs1 + begin, coeffs1 + end);
+        begin = end;
+    }
+}
+
 } // namespace math



commit a0a55f361f6d3f4931369ec2d60ae28722a2d718
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Thu May 24 11:18:26 2018 +0500

    [util] Evaluate series and coefficients for A2 and C2 using series expansion

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index c637563..cca4328 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -1,5 +1,7 @@
 // Boost.Geometry

+// Contributed and/or modified by Adeel Ahmad.
+
 // Use, modification and distribution is subject to the Boost Software License,
 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt)
@@ -105,6 +107,100 @@ namespace boost { namespace geometry { namespace series_expansion {
     }

     /*
+     Generate and evaluate the series expansion of the following integral
+
+     I2 = integrate( 1/sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma )
+
+     which is valid for k2 small. We substitute k2 = 4 * eps / (1 - eps)^2
+     and expand (1 - eps) * I2 retaining terms up to order eps^maxpow
+     in A2 and C2[l].
+
+     The resulting series is of the form
+
+     A2 * ( sigma + sum(C2[l] * sin(2*l*sigma), l, 1, maxpow) )
+
+     The scale factor A2-1 = mean value of (d/dsigma)2 - 1
+
+     The expansion above is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+          sintegrand:1/sqrt(1+k2*sin(sigma)^2),
+          sintegrandexp:ataylor(
+              (1+eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+              eps,maxpow),
+          s:trigreduce(integrate(sintegrandexp,sigma)),
+          s:s-subst(sigma=0,s),
+          A2:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+          tau1:ataylor(s/A2,eps,maxpow),
+          for i:1 thru maxpow do C2[i]:coeff(tau1,sin(2*i*sigma)),
+          if expand(tau1-sigma-sum(C2[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B2"),
+          A2:A2/(1+eps),
+          'done)$
+
+        codeA2(maxpow):=block([tab2:"    ",tab3:"        "],
+        print("// The scale factor A2-1 = mean value of (d/dsigma)I2 - 1
+        CT evaluate_series_A2(CT const& eps)
+        {
+            CT const eps2 = math::sqr(eps);
+            CT t;
+            switch (SeriesOrder/2) {"),
+          for n:0 thru entier(maxpow/2) do block([
+            q:horner(ataylor(subst([eps=sqrt(eps2)],A2*(1+eps)-1),eps2,n)),
+            linel:1200],
+            print(concat(tab2,"case ",string(n),":")),
+            print(concat(tab3,"t = ",string(q),";")),
+            print(concat(tab3,"break;"))),
+          print("    }
+            return (t - eps) / (1 + eps);
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeI2(maxpow)$
+        codeA2(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     script can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
+    */
+    template <typename CT, std::size_t SeriesOrder>
+    CT evaluate_series_A2(CT const& eps)
+    {
+        CT const eps2 = math::sqr(eps);
+        CT t;
+        switch (SeriesOrder/2) {
+        case 0:
+            t = CT(0);
+            break;
+        case 1:
+            t = -CT(3)*eps2/CT(4);
+            break;
+        case 2:
+            t = (-CT(7)*eps2-CT(48))*eps2/CT(64);
+            break;
+        case 3:
+            t = eps2*((-CT(11)*eps2-CT(28))*eps2-CT(192))/CT(256);
+            break;
+        case 4:
+            t = eps2*(eps2*((-CT(375)*eps2-CT(704))*eps2-CT(1792))-CT(12288))/CT(16384);
+            break;
+        }
+        return (t - eps) / (CT(1) + eps);
+    }
+
+    /*
      Express

         I3 = integrate( (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma1)^2)), sigma1, 0, sigma )
@@ -533,6 +629,156 @@ namespace boost { namespace geometry { namespace series_expansion {
     }

     /*
+     The coefficients C2[l] in the Fourier expansion of B2.
+
+     The expansion below is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeI2(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+          sintegrand:1/sqrt(1+k2*sin(sigma)^2),
+          sintegrandexp:ataylor(
+              (1+eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+              eps,maxpow),
+          s:trigreduce(integrate(sintegrandexp,sigma)),
+          s:s-subst(sigma=0,s),
+          A2:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+          tau1:ataylor(s/A2,eps,maxpow),
+          for i:1 thru maxpow do C2[i]:coeff(tau1,sin(2*i*sigma)),
+          if expand(tau1-sigma-sum(C2[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B2"),
+          A2:A2/(1+eps),
+          'done)$
+
+        codeC2(maxpow):=block([tab2:"    ",tab3:"        "],
+        print("// The coefficients C2[l] in the Fourier expansion of B2
+        static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
+        {
+            CT const eps2 = math::sqr(eps);
+            CT d = eps;
+            switch (SeriesOrder) {"),
+          for n:0 thru maxpow do (
+            print(concat(tab2,"case ",string(n),":")),
+            for m:1 thru n do block([q:d*horner(
+                subst([eps=sqrt(eps2)],ataylor(C2[m],eps,n)/eps^m)),
+              linel:1200],
+              if m>1 then print(concat(tab3,"d *= eps;")),
+              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+            print(concat(tab3,"break;"))),
+        print("    }
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeI2(maxpow)$
+        codeC2(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     script can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
+               s/eps(CT(2))/eps2/g;'
+    */
+    template <typename CT, std::size_t SeriesOrder>
+    static inline void evaluate_coeffs_C2(CT const& eps, CT c[])
+    {
+        CT const eps2 = math::sqr(eps);
+        CT d = eps;
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            c[1] = d/CT(2);
+            break;
+        case 2:
+            c[1] = d/CT(2);
+            d *= eps;
+            c[2] = CT(3)*d/CT(16);
+            break;
+        case 3:
+            c[1] = d*(eps2+CT(8))/CT(16);
+            d *= eps;
+            c[2] = CT(3)*d/CT(16);
+            d *= eps;
+            c[3] = CT(5)*d/CT(48);
+            break;
+        case 4:
+            c[1] = d*(eps2+CT(8))/CT(16);
+            d *= eps;
+            c[2] = d*(eps2+CT(6))/CT(32);
+            d *= eps;
+            c[3] = CT(5)*d/CT(48);
+            d *= eps;
+            c[4] = CT(35)*d/CT(512);
+            break;
+        case 5:
+            c[1] = d*(eps2*(eps2+CT(2))+CT(16))/CT(32);
+            d *= eps;
+            c[2] = d*(eps2+CT(6))/CT(32);
+            d *= eps;
+            c[3] = d*(CT(15)*eps2+CT(80))/CT(768);
+            d *= eps;
+            c[4] = CT(35)*d/CT(512);
+            d *= eps;
+            c[5] = CT(63)*d/CT(1280);
+            break;
+        case 6:
+            c[1] = d*(eps2*(eps2+CT(2))+CT(16))/CT(32);
+            d *= eps;
+            c[2] = d*(eps2*(CT(35)*eps2+CT(64))+CT(384))/CT(2048);
+            d *= eps;
+            c[3] = d*(CT(15)*eps2+CT(80))/CT(768);
+            d *= eps;
+            c[4] = d*(CT(7)*eps2+CT(35))/CT(512);
+            d *= eps;
+            c[5] = CT(63)*d/CT(1280);
+            d *= eps;
+            c[6] = CT(77)*d/CT(2048);
+            break;
+        case 7:
+            c[1] = d*(eps2*(eps2*(CT(41)*eps2+CT(64))+CT(128))+CT(1024))/CT(2048);
+            d *= eps;
+            c[2] = d*(eps2*(CT(35)*eps2+CT(64))+CT(384))/CT(2048);
+            d *= eps;
+            c[3] = d*(eps2*(CT(69)*eps2+CT(120))+CT(640))/CT(6144);
+            d *= eps;
+            c[4] = d*(CT(7)*eps2+CT(35))/CT(512);
+            d *= eps;
+            c[5] = d*(CT(105)*eps2+CT(504))/CT(10240);
+            d *= eps;
+            c[6] = CT(77)*d/CT(2048);
+            d *= eps;
+            c[7] = CT(429)*d/CT(14336);
+            break;
+        case 8:
+            c[1] = d*(eps2*(eps2*(CT(41)*eps2+CT(64))+CT(128))+CT(1024))/CT(2048);
+            d *= eps;
+            c[2] = d*(eps2*(eps2*(CT(47)*eps2+CT(70))+CT(128))+CT(768))/CT(4096);
+            d *= eps;
+            c[3] = d*(eps2*(CT(69)*eps2+CT(120))+CT(640))/CT(6144);
+            d *= eps;
+            c[4] = d*(eps2*(CT(133)*eps2+CT(224))+CT(1120))/CT(16384);
+            d *= eps;
+            c[5] = d*(CT(105)*eps2+CT(504))/CT(10240);
+            d *= eps;
+            c[6] = d*(CT(33)*eps2+CT(154))/CT(4096);
+            d *= eps;
+            c[7] = CT(429)*d/CT(14336);
+            d *= eps;
+            c[8] = CT(6435)*d/CT(262144);
+            break;
+        }
+    }
+
+    /*
      The coefficients C3[l] in the Fourier expansion of B3.

      The expansion below is performed in Maxima, a Computer Algebra System.

commit 9e2c74afc8523374cc9801817b48e40bcc6f78c3
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed May 23 14:22:40 2018 +0500

    [formulas] Compute the longitude for second point using the longitudinal difference

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 058febc..58ed326 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -106,6 +106,7 @@ public:
         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);

@@ -165,15 +166,68 @@ public:
         CT sin_sigma2 = sin_sigma1 * cos_sigma12 + cos_sigma1 * sin_sigma12;
         CT cos_sigma2 = cos_sigma1 * cos_sigma12 - sin_sigma1 * sin_sigma12;

+        if (BOOST_GEOMETRY_CONDITION(CalcRevAzimuth))
+        {
+            CT sin_alpha2 = sin_alpha0;
+            CT cos_alpha2 = cos_alpha0 * cos_sigma2;
+
+            result.reverse_azimuth = std::atan2(sin_alpha2, cos_alpha2);
+
+            // Convert the angle to radians.
+            result.reverse_azimuth /= math::d2r<T>();
+        }
+
         if (BOOST_GEOMETRY_CONDITION(CalcCoordinates))
         {
+            // Find the latitude at the second point.
             CT sin_beta2 = cos_alpha0 * sin_sigma2;
             CT cos_beta2 = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);

             result.lat2 = std::atan2(sin_beta2, one_minus_f * cos_beta2);

-            // Convert the angle to radians.
+            // Convert the coordinate to radians.
             result.lat2 /= math::d2r<T>();
+
+            // Find the longitude at the second point.
+            CT sin_omega1 = sin_beta1 * sin_alpha0;
+            CT cos_omega1 = cos_beta1 * cos_alpha1;
+
+            CT sin_omega2 = sin_alpha0 * sin_sigma2;
+            CT cos_omega2 = cos_sigma2;
+
+            CT omega12 = std::atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
+                                    cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);
+
+            CT coeffs_A3[SeriesOrder];
+            series_expansion::evaluate_coeffs_A3<double, SeriesOrder>(n, coeffs_A3);
+
+            CT A3 = math::horner_evaluate(epsilon, coeffs_A3, coeffs_A3 + SeriesOrder);
+            CT A3c = -f * sin_alpha0 * A3;
+
+            // Compute the size of coefficient array.
+            const std::size_t coeffs_C3_size = (SeriesOrder * (SeriesOrder - 1)) / 2;
+            CT coeffs_C3x[coeffs_C3_size];
+            series_expansion::evaluate_coeffs_C3<double, SeriesOrder>(n, coeffs_C3x);
+
+            // Evaluate C3 coefficients.
+            CT coeffs_C3[SeriesOrder];
+            math::evaluate_coeffs_var2<double, SeriesOrder>(epsilon, coeffs_C3x, coeffs_C3);
+
+            CT B31 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
+
+            CT lam12 = omega12 + A3c *
+                       (sigma12 + (sin_cos_series(sin_sigma2,
+                                                  cos_sigma2,
+                                                  coeffs_C3) - B31));
+
+            // Convert to radians to get the longitudinal
+            // difference.
+            CT lon12 = lam12 / math::d2r<T>();
+
+            // Add the longitude at first point to the longitudinal
+            // difference and normalize the result.
+            result.lon2 = math::normalize_angle(math::normalize_angle(lon1) +
+                                                math::normalize_angle(lon12));
         }
     }
 };

commit 915219198602320924af1c88f6db02b669233beb
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Wed May 23 12:32:21 2018 +0500

    [util] Add functions to evaluate coefficients for A3 and C3 using series expansion

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index f15b2d1..c637563 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -75,7 +75,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         // Maxima script end

      To replace each number x by CT(x) the following
-     scirpt can be used:
+     script can be used:
        sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
     */
@@ -105,6 +105,138 @@ namespace boost { namespace geometry { namespace series_expansion {
     }

     /*
+     Express
+
+        I3 = integrate( (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma1)^2)), sigma1, 0, sigma )
+
+     as a series
+
+        A3 * ( sigma + sum(C3[l] * sin(2*l*sigma), l, 1, maxpow-1) )
+
+     valid for f and k2 small.  It is convenient to write k2 = 4 * eps / (1 -
+     eps)^2 and f = 2*n/(1+n) and expand in eps and n.  This procedure leads
+     to a series where the coefficients of eps^j are terminating series in n.
+
+     The scale factor A3 = mean value of (d/dsigma)I3
+
+     The expansion above is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n],
+          maxpow:maxpow-1,
+          int:subst([k2=4*eps/(1-eps)^2],
+            (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma)^2))),
+          int:subst([f=2*n/(1+n)],int),
+          intexp:jtaylor(int,n,eps,maxpow),
+          dlam:trigreduce(integrate(intexp,sigma)),
+          dlam:dlam-subst(sigma=0,dlam),
+          A3:expand(subst(sigma=2*%pi,dlam)/(2*%pi)),
+          eta:jtaylor(dlam/A3,n,eps,maxpow),
+          A3:jtaylor(A3,n,eps,maxpow),
+          for i:1 thru maxpow do C3[i]:coeff(eta,sin(2*i*sigma)),
+          if expand(eta-sigma-sum(C3[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B3"),
+          'done)$
+
+        codeA3(maxpow):=block([tab2:"    ",tab3:"        "],
+        print("// The scale factor A3 = mean value of (d/dsigma)I3
+        static inline void evaluate_series_A3(CT const& n, CT c[])
+        {
+            switch (SeriesOrder) {"),
+          for nn:0 thru maxpow do block(
+            [q:if nn=0 then 0 else
+            jtaylor(subst([n=n],A3),n,eps,nn-1),
+            linel:1200],
+            print(concat(tab2,"case ",string(nn),":")),
+            for i : 0 thru nn-1 do
+            print(concat(tab3,"c[",i,"] = ",
+                string(horner(coeff(q,eps,i))),";")),
+            print(concat(tab3,"break;"))),
+          print("    }
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeI3(maxpow)$
+        codeA3(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     script can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g'
+    */
+    // TODO: this produces different results that geographiclib
+    template <typename CT, std::size_t SeriesOrder>
+    static inline void evaluate_coeffs_A3(CT const& n, CT c[])
+    {
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            c[0] = CT(1);
+            break;
+        case 2:
+            c[0] = CT(1);
+            c[1] = -CT(1)/CT(2);
+            break;
+        case 3:
+            c[0] = CT(1);
+            c[1] = (n-CT(1))/CT(2);
+            c[2] = -CT(1)/CT(4);
+            break;
+        case 4:
+            c[0] = CT(1);
+            c[1] = (n-CT(1))/CT(2);
+            c[2] = (-n-CT(2))/CT(8);
+            c[3] = -CT(1)/CT(16);
+            break;
+        case 5:
+            c[0] = CT(1);
+            c[1] = (n-CT(1))/CT(2);
+            c[2] = (n*(CT(3)*n-CT(1))-CT(2))/CT(8);
+            c[3] = (-CT(3)*n-CT(1))/CT(16);
+            c[4] = -CT(3)/CT(64);
+            break;
+        case 6:
+            c[0] = CT(1);
+            c[1] = (n-CT(1))/CT(2);
+            c[2] = (n*(CT(3)*n-CT(1))-CT(2))/CT(8);
+            c[3] = ((-n-CT(3))*n-CT(1))/CT(16);
+            c[4] = (-CT(2)*n-CT(3))/CT(64);
+            c[5] = -CT(3)/CT(128);
+            break;
+        case 7:
+            c[0] = CT(1);
+            c[1] = (n-CT(1))/CT(2);
+            c[2] = (n*(CT(3)*n-CT(1))-CT(2))/CT(8);
+            c[3] = (n*(n*(CT(5)*n-CT(1))-CT(3))-CT(1))/CT(16);
+            c[4] = ((-CT(10)*n-CT(2))*n-CT(3))/CT(64);
+            c[5] = (-CT(5)*n-CT(3))/CT(128);
+            c[6] = -CT(5)/CT(256);
+            break;
+        case 8:
+            c[0] = CT(1);
+            c[1] = (n-CT(1))/CT(2);
+            c[2] = (n*(CT(3)*n-CT(1))-CT(2))/CT(8);
+            c[3] = (n*(n*(CT(5)*n-CT(1))-CT(3))-CT(1))/CT(16);
+            c[4] = (n*((-CT(5)*n-CT(20))*n-CT(4))-CT(6))/CT(128);
+            c[5] = ((-CT(5)*n-CT(10))*n-CT(6))/CT(256);
+            c[6] = (-CT(15)*n-CT(20))/CT(1024);
+            c[7] = -CT(25)/CT(2048);
+            break;
+        }
+    }
+
+    /*
      The coefficients C1[l] in the Fourier expansion of B1.

      The expansion below is performed in Maxima, a Computer Algebra System.
@@ -142,7 +274,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         // Maxima script end

      To replace each number x by CT(x) the following
-     scirpt can be used:
+     script can be used:
        sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
                s/eps(CT(2))/eps2/g;'
@@ -304,7 +436,7 @@ namespace boost { namespace geometry { namespace series_expansion {
         // Maxima script end

      To replace each number x by CT(x) the following
-     scirpt can be used:
+     script can be used:
        sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
                s/eps(CT(2))/eps2/g;'
@@ -400,6 +532,180 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     }

+    /*
+     The coefficients C3[l] in the Fourier expansion of B3.
+
+     The expansion below is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeI3(maxpow):=block([int,intexp,dlam,eta,del,eps,nu,f,z,n],
+          maxpow:maxpow-1,
+          int:subst([k2=4*eps/(1-eps)^2],
+            (2-f)/(1+(1-f)*sqrt(1+k2*sin(sigma)^2))),
+          int:subst([f=2*n/(1+n)],int),
+          intexp:jtaylor(int,n,eps,maxpow),
+          dlam:trigreduce(integrate(intexp,sigma)),
+          dlam:dlam-subst(sigma=0,dlam),
+          A3:expand(subst(sigma=2*%pi,dlam)/(2*%pi)),
+          eta:jtaylor(dlam/A3,n,eps,maxpow),
+          A3:jtaylor(A3,n,eps,maxpow),
+          for i:1 thru maxpow do C3[i]:coeff(eta,sin(2*i*sigma)),
+          if expand(eta-sigma-sum(C3[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B3"),
+          'done)$
+
+        codeC3(maxpow):=block([tab2:"    ",tab3:"        "],
+        print("// The coefficients C3[l] in the Fourier expansion of B3
+        static inline void evaluate_coeffs_C3(CT const& n, CT c[])
+        {
+            const CT n2 = math::sqr(n);
+            switch (SeriesOrder) {"),
+          for nn:0 thru maxpow do block([c],
+            print(concat(tab2,"case ",string(nn),":")),
+            c:0,
+            for m:1 thru nn-1 do block(
+              [q:if nn = 0 then 0 else
+              jtaylor(subst([n=n],C3[m]),_n,eps,nn-1),
+              linel:1200],
+              for j:m thru nn-1 do (
+                print(concat(tab3,"c[",c,"] = ",
+                    string(horner(coeff(q,eps,j))),";")),
+                c:c+1)
+            ),
+            print(concat(tab3,"break;"))),
+          print("    }
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeI3(maxpow)$
+        codeC3(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     script can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
+               s/eps(CT(2))/eps2/g;'
+    */
+    template <typename CT, std::size_t SeriesOrder>
+    static inline void evaluate_coeffs_C3(CT const& n, CT c[])
+    {
+        const CT n2 = math::sqr(n);
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            break;
+        case 2:
+            c[0] = (CT(1)-n)/CT(4);
+            break;
+        case 3:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = ((n-CT(3))*n+CT(2))/CT(32);
+            break;
+        case 4:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[4] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[5] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            break;
+        case 5:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[5] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[6] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[7] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[8] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[9] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            break;
+        case 6:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
+            c[5] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[6] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[7] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[8] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
+            c[9] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[10] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[11] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
+            c[12] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            c[13] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
+            c[14] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
+            break;
+        case 7:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
+            c[5] = (CT(10)*n+CT(21))/CT(1024);
+            c[6] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[7] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[8] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[9] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
+            c[10] = (CT(69)*n+CT(108))/CT(8192);
+            c[11] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[12] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[13] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
+            c[14] = (CT(12)-n)/CT(1024);
+            c[15] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            c[16] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
+            c[17] = (CT(72)-CT(43)*n)/CT(8192);
+            c[18] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
+            c[19] = (CT(9)-CT(15)*n)/CT(1024);
+            c[20] = (CT(44)-CT(99)*n)/CT(8192);
+            break;
+        case 8:
+            c[0] = (CT(1)-n)/CT(4);
+            c[1] = (CT(1)-n2)/CT(8);
+            c[2] = (n*((-CT(5)*n-CT(1))*n+CT(3))+CT(3))/CT(64);
+            c[3] = (n*((CT(2)-CT(2)*n)*n+CT(2))+CT(5))/CT(128);
+            c[4] = (n*(CT(3)*n+CT(11))+CT(12))/CT(512);
+            c[5] = (CT(10)*n+CT(21))/CT(1024);
+            c[6] = CT(243)/CT(16384);
+            c[7] = ((n-CT(3))*n+CT(2))/CT(32);
+            c[8] = (n*(n*(CT(2)*n-CT(3))-CT(2))+CT(3))/CT(64);
+            c[9] = (n*((-CT(6)*n-CT(9))*n+CT(2))+CT(6))/CT(256);
+            c[10] = ((CT(1)-CT(2)*n)*n+CT(5))/CT(256);
+            c[11] = (CT(69)*n+CT(108))/CT(8192);
+            c[12] = CT(187)/CT(16384);
+            c[13] = (n*((CT(5)-n)*n-CT(9))+CT(5))/CT(192);
+            c[14] = (n*(n*(CT(10)*n-CT(6))-CT(10))+CT(9))/CT(384);
+            c[15] = ((-CT(77)*n-CT(8))*n+CT(42))/CT(3072);
+            c[16] = (CT(12)-n)/CT(1024);
+            c[17] = CT(139)/CT(16384);
+            c[18] = (n*((CT(20)-CT(7)*n)*n-CT(28))+CT(14))/CT(1024);
+            c[19] = ((-CT(7)*n-CT(40))*n+CT(28))/CT(2048);
+            c[20] = (CT(72)-CT(43)*n)/CT(8192);
+            c[21] = CT(127)/CT(16384);
+            c[22] = (n*(CT(75)*n-CT(90))+CT(42))/CT(5120);
+            c[23] = (CT(9)-CT(15)*n)/CT(1024);
+            c[24] = CT(99)/CT(16384);
+            c[25] = (CT(44)-CT(99)*n)/CT(8192);
+            c[26] = CT(99)/CT(16384);
+            c[27] = CT(429)/CT(114688);
+            break;
+        }
+    }
+
 }}} // namespace boost::geometry::series_expansion

 #endif // BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

commit 881c73c90b131525deb03a59a4350868be8ffbe2
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue May 22 17:18:37 2018 +0500

    [formulas] Compute the latitude for second point following Karney's method

    - Link to paper: https://arxiv.org/pdf/1109.4448.pdf

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index c6fb03c..058febc 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -119,6 +119,7 @@ public:
         sin_beta1 *= one_minus_f;

         // Obtain alpha 0 by solving the spherical triangle.
+        CT sin_alpha0 = sin_alpha1 * cos_beta1;
         CT cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);

         CT k2 = math::sqr(cos_alpha0) * ep2;
@@ -134,11 +135,47 @@ public:
         series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);

         // Tau is an integration variable.
-        CT tau12 = distance / (b + (c1 + expansion_A1));
+        CT tau12 = distance / (b * (c1 + expansion_A1));
+
         CT sin_tau12 = sin(tau12);
         CT cos_tau12 = cos(tau12);
-    }

+        CT sin_sigma1 = sin_beta1;
+        CT cos_sigma1 = cos_beta1 * cos_alpha1;
+
+        CT B11 = sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
+        CT sin_B11 = sin(B11);
+        CT cos_B11 = cos(B11);
+
+        CT sin_tau1 = sin_sigma1 * cos_B11 + cos_sigma1 * sin_B11;
+        CT cos_tau1 = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;
+
+        // Index zero element of coeffs_C1p is unused.
+        CT coeffs_C1p[SeriesOrder + 1];
+        series_expansion::evaluate_coeffs_C1p<CT, SeriesOrder>(epsilon, coeffs_C1p);
+
+        CT B12 = sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
+                                cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
+                                coeffs_C1p); // < 0?
+
+        CT sigma12 = tau12 - (B12 - B11);
+        CT sin_sigma12 = sin(sigma12);
+        CT cos_sigma12 = cos(sigma12);
+
+        CT sin_sigma2 = sin_sigma1 * cos_sigma12 + cos_sigma1 * sin_sigma12;
+        CT cos_sigma2 = cos_sigma1 * cos_sigma12 - sin_sigma1 * sin_sigma12;
+
+        if (BOOST_GEOMETRY_CONDITION(CalcCoordinates))
+        {
+            CT sin_beta2 = cos_alpha0 * sin_sigma2;
+            CT cos_beta2 = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);
+
+            result.lat2 = std::atan2(sin_beta2, one_minus_f * cos_beta2);
+
+            // Convert the angle to radians.
+            result.lat2 /= math::d2r<T>();
+        }
+    }
 };

 }}} // namespace boost::geometry::formula

commit 6ce1b099cb33e94d5577a089460af4310962a964
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Mon May 21 16:32:28 2018 +0500

    [util] Evaluate coefficients for C1p using series expansion

    - Fix conversion from degree to radian in sin_cos_degrees function

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 4d927b3..df7507e 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -790,7 +790,7 @@ inline void sin_cos_degrees(T const& x, T & sinx, T & cosx)
     remainder -= 90 * quotient;

     // Convert to radians.
-    remainder = as_radian<T>(remainder);
+    remainder *= d2r<T>();

     T s = std::sin(remainder), c = std::cos(remainder);

diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
index b2e2277..f15b2d1 100644
--- a/include/boost/geometry/util/series_expansion.hpp
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -105,7 +105,7 @@ namespace boost { namespace geometry { namespace series_expansion {
     }

     /*
-     The coefficients C1[l] in the Fourier expansion of B1
+     The coefficients C1[l] in the Fourier expansion of B1.

      The expansion below is performed in Maxima, a Computer Algebra System.
      The C++ code (that yields the function evaluate_series_A1 below) is
@@ -238,6 +238,168 @@ namespace boost { namespace geometry { namespace series_expansion {
         }
     }

-}}} // namespace boost::geometry::formula
+    /*
+     The coefficients C1p[l] in the Fourier expansion of B1p.
+
+     The expansion below is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeintegral(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+          sintegrand:sqrt(1+k2*sin(sigma)^2),
+          sintegrandexp:ataylor(
+              (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+              eps,maxpow),
+          s:trigreduce(integrate(sintegrandexp,sigma)),
+          s:s-subst(sigma=0,s),
+          A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+          tau1:ataylor(s/A1,eps,maxpow),
+          for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
+          if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B1"),
+          A1:A1/(1-eps),
+          'done)$
+
+        revertI1(maxpow):=block([tau,eps,tauacc:1,sigacc:0],
+          for n:1 thru maxpow do (
+            tauacc:trigreduce(ataylor(
+                  -sum(C1[j]*sin(2*j*tau),j,1,maxpow-n+1)*tauacc/n,
+                  eps,maxpow)),
+            sigacc:sigacc+expand(diff(tauacc,tau,n-1))),
+          for i:1 thru maxpow do C1p[i]:coeff(sigacc,sin(2*i*tau)),
+          if expand(sigacc-sum(C1p[i]*sin(2*i*tau),i,1,maxpow)) # 0
+          then error("left over terms in B1p"),
+          'done)$
+
+        generatecodeC1p(maxpow):=block([tab2:"    ",tab3:"        "],
+          print("// The coefficients C1p[l] in the Fourier expansion of B1p
+        static inline evaluate_coeffs_C1p(CT eps, CT c[])
+        {
+            CT const eps2 = math::sqr(eps);
+            CT d = eps;
+            switch (SeriesOrder) {"),
+          for n:0 thru maxpow do (
+            print(concat(tab2,"case ",string(n),":")),
+            for m:1 thru n do block([q:d*horner(
+                subst([eps=sqrt(eps2)],ataylor(C1p[m],eps,n)/eps^m)),
+              linel:1200],
+              if m>1 then print(concat(tab3,"d *= eps;")),
+              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+            print(concat(tab3,"break;"))),
+          print("    }
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeintegral(maxpow)$
+        revertI1(maxpow)$
+        generatecodeC1p(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     scirpt can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
+               s/eps(CT(2))/eps2/g;'
+    */
+    template <typename CT, std::size_t SeriesOrder>
+    static inline evaluate_coeffs_C1p(CT eps, CT c[])
+    {
+        CT const eps2 = math::sqr(eps);
+        CT d = eps;
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            c[1] = d/CT(2);
+            break;
+        case 2:
+            c[1] = d/CT(2);
+            d *= eps;
+            c[2] = CT(5)*d/CT(16);
+            break;
+        case 3:
+            c[1] = d*(CT(16)-CT(9)*eps2)/CT(32);
+            d *= eps;
+            c[2] = CT(5)*d/CT(16);
+            d *= eps;
+            c[3] = CT(29)*d/CT(96);
+            break;
+        case 4:
+            c[1] = d*(CT(16)-CT(9)*eps2)/CT(32);
+            d *= eps;
+            c[2] = d*(CT(30)-CT(37)*eps2)/CT(96);
+            d *= eps;
+            c[3] = CT(29)*d/CT(96);
+            d *= eps;
+            c[4] = CT(539)*d/CT(1536);
+            break;
+        case 5:
+            c[1] = d*(eps2*(CT(205)*eps2-CT(432))+CT(768))/CT(1536);
+            d *= eps;
+            c[2] = d*(CT(30)-CT(37)*eps2)/CT(96);
+            d *= eps;
+            c[3] = d*(CT(116)-CT(225)*eps2)/CT(384);
+            d *= eps;
+            c[4] = CT(539)*d/CT(1536);
+            d *= eps;
+            c[5] = CT(3467)*d/CT(7680);
+            break;
+        case 6:
+            c[1] = d*(eps2*(CT(205)*eps2-CT(432))+CT(768))/CT(1536);
+            d *= eps;
+            c[2] = d*(eps2*(CT(4005)*eps2-CT(4736))+CT(3840))/CT(12288);
+            d *= eps;
+            c[3] = d*(CT(116)-CT(225)*eps2)/CT(384);
+            d *= eps;
+            c[4] = d*(CT(2695)-CT(7173)*eps2)/CT(7680);
+            d *= eps;
+            c[5] = CT(3467)*d/CT(7680);
+            d *= eps;
+            c[6] = CT(38081)*d/CT(61440);
+            break;
+        case 7:
+            c[1] = d*(eps2*((CT(9840)-CT(4879)*eps2)*eps2-CT(20736))+CT(36864))/CT(73728);
+            d *= eps;
+            c[2] = d*(eps2*(CT(4005)*eps2-CT(4736))+CT(3840))/CT(12288);
+            d *= eps;
+            c[3] = d*(eps2*(CT(8703)*eps2-CT(7200))+CT(3712))/CT(12288);
+            d *= eps;
+            c[4] = d*(CT(2695)-CT(7173)*eps2)/CT(7680);
+            d *= eps;
+            c[5] = d*(CT(41604)-CT(141115)*eps2)/CT(92160);
+            d *= eps;
+            c[6] = CT(38081)*d/CT(61440);
+            d *= eps;
+            c[7] = CT(459485)*d/CT(516096);
+            break;
+        case 8:
+            c[1] = d*(eps2*((CT(9840)-CT(4879)*eps2)*eps2-CT(20736))+CT(36864))/CT(73728);
+            d *= eps;
+            c[2] = d*(eps2*((CT(120150)-CT(86171)*eps2)*eps2-CT(142080))+CT(115200))/CT(368640);
+            d *= eps;
+            c[3] = d*(eps2*(CT(8703)*eps2-CT(7200))+CT(3712))/CT(12288);
+            d *= eps;
+            c[4] = d*(eps2*(CT(1082857)*eps2-CT(688608))+CT(258720))/CT(737280);
+            d *= eps;
+            c[5] = d*(CT(41604)-CT(141115)*eps2)/CT(92160);
+            d *= eps;
+            c[6] = d*(CT(533134)-CT(2200311)*eps2)/CT(860160);
+            d *= eps;
+            c[7] = CT(459485)*d/CT(516096);
+            d *= eps;
+            c[8] = CT(109167851)*d/CT(82575360);
+            break;
+        }
+    }
+
+}}} // namespace boost::geometry::series_expansion

 #endif // BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

commit 3700b4fafa16959d3b64233ff4a3611988eabccb
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat May 19 21:49:24 2018 +0500

    [util] Move series expansion functions to util/series_expansion.hpp

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 32ee804..c6fb03c 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -11,6 +11,7 @@
 #include <boost/math/constants/constants.hpp>

 #include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/series_expansion.hpp>

 #include <boost/geometry/formulas/flattening.hpp>
 #include <boost/geometry/formulas/result_direct.hpp>
@@ -45,231 +46,6 @@ public:
     typedef result_direct<CT> result_type;

     /*
-     Generate and evaluate the series expansion of the following integral
-
-     I1 = integrate( sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma )
-
-     which is valid for k2 small. We substitute k2 = 4 * eps / (1 - eps)^2
-     and expand (1 - eps) * I1 retaining terms up to order eps^maxpow
-     in A1 and C1[l].
-
-     The resulting series is of the form
-
-     A1 * ( sigma + sum(C1[l] * sin(2*l*sigma), l, 1, maxpow) ).
-
-     The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
-
-     The expansion above is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        computeintegral(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
-          sintegrand:sqrt(1+k2*sin(sigma)^2),
-          sintegrandexp:ataylor(
-              (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
-              eps,maxpow),
-          s:trigreduce(integrate(sintegrandexp,sigma)),
-          s:s-subst(sigma=0,s),
-          A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
-          tau1:ataylor(s/A1,eps,maxpow),
-          for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
-          if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
-          then error("left over terms in B1"),
-          A1:A1/(1-eps),
-          'done)$
-
-        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
-        print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
-        static inline CT evaluate_series_A1(CT eps) {
-            CT eps2 = math::sqr(eps);
-            CT t;
-            switch (SeriesOrder/2) {"),
-          for n:0 thru entier(maxpow/2) do block([
-            q:horner(ataylor(subst([eps=sqrt(eps2)],A1*(1-eps)-1),eps2,n)),
-            linel:1200],
-            print(concat(tab2,"case ",string(n),":")),
-            print(concat(tab3,"t = ",string(q),";")),
-            print(concat(tab3,"break;"))),
-          print("    }
-            return (t + eps) / (1 - eps);
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeintegral(maxpow)$
-        generatecode(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     scirpt can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
-    */
-    static inline CT evaluate_series_A1(CT eps)
-    {
-        CT eps2 = math::sqr(eps);
-        CT t;
-        switch (SeriesOrder/2) {
-        case 0:
-            t = CT(0);
-            break;
-        case 1:
-            t = eps2/CT(4);
-            break;
-        case 2:
-            t = eps2*(eps2+CT(16))/CT(64);
-            break;
-        case 3:
-            t = eps2*(eps2*(eps2+CT(4))+CT(64))/CT(256);
-            break;
-        case 4:
-            t = eps2*(eps2*(eps2*(CT(25)*eps2+CT(64))+CT(256))+CT(4096))/CT(16384);
-            break;
-        }
-        return (t + eps) / (CT(1) - eps);
-    }
-
-    /*
-     The coefficients C1[l] in the Fourier expansion of B1
-
-     The expansion below is performed in Maxima, a Computer Algebra System.
-     The C++ code (that yields the function evaluate_series_A1 below) is
-     generated by the following Maxima script and is based on script:
-     http://geographiclib.sourceforge.net/html/geod.mac
-
-        // Maxima script begin
-        taylordepth:5$
-        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
-        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
-        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
-
-        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
-          print("// The coefficients C1[l] in the Fourier expansion of B1
-        static inline evaluate_coeffs_C1(CT eps, CT c[]) {
-            CT eps2 = math::sqr(eps);
-            CT d = eps;
-            switch (SeriesOrder) {"),
-          for n:0 thru maxpow do (
-            print(concat(tab2,"case ",string(n),":")),
-            for m:1 thru n do block([q:d*horner(
-                subst([eps=sqrt(eps2)],ataylor(C1[m],eps,n)/eps^m)),
-              linel:1200],
-              if m>1 then print(concat(tab3,"d *= eps;")),
-              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
-            print(concat(tab3,"break;"))),
-          print("    }
-        }"),
-        'done)$
-
-        maxpow:8$
-        computeintegral(maxpow)$
-        generatecode(maxpow)$
-        // Maxima script end
-
-     To replace each number x by CT(x) the following
-     scirpt can be used:
-       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
-               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
-               s/eps(CT(2))/eps2/g;'
-    */
-    static inline void evaluate_coeffs_C1(CT eps, CT c[])
-    {
-        CT eps2 = math::sqr(eps);
-        CT d = eps;
-        switch (SeriesOrder) {
-        case 0:
-            break;
-        case 1:
-            c[1] = -d/CT(2);
-            break;
-        case 2:
-            c[1] = -d/CT(2);
-            d *= eps;
-            c[2] = -d/CT(16);
-            break;
-        case 3:
-            c[1] = d*(CT(3)*eps2-CT(8))/CT(16);
-            d *= eps;
-            c[2] = -d/CT(16);
-            d *= eps;
-            c[3] = -d/CT(48);
-            break;
-        case 4:
-            c[1] = d*(CT(3)*eps2-CT(8))/CT(16);
-            d *= eps;
-            c[2] = d*(eps2-CT(2))/CT(32);
-            d *= eps;
-            c[3] = -d/CT(48);
-            d *= eps;
-            c[4] = -CT(5)*d/CT(512);
-            break;
-        case 5:
-            c[1] = d*((CT(6)-eps2)*eps2-CT(16))/CT(32);
-            d *= eps;
-            c[2] = d*(eps2-CT(2))/CT(32);
-            d *= eps;
-            c[3] = d*(CT(9)*eps2-CT(16))/CT(768);
-            d *= eps;
-            c[4] = -CT(5)*d/CT(512);
-            d *= eps;
-            c[5] = -CT(7)*d/CT(1280);
-            break;
-        case 6:
-            c[1] = d*((CT(6)-eps2)*eps2-CT(16))/CT(32);
-            d *= eps;
-            c[2] = d*((CT(64)-CT(9)*eps2)*eps2-CT(128))/CT(2048);
-            d *= eps;
-            c[3] = d*(CT(9)*eps2-CT(16))/CT(768);
-            d *= eps;
-            c[4] = d*(CT(3)*eps2-CT(5))/CT(512);
-            d *= eps;
-            c[5] = -CT(7)*d/CT(1280);
-            d *= eps;
-            c[6] = -CT(7)*d/CT(2048);
-            break;
-        case 7:
-            c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
-            d *= eps;
-            c[2] = d*((CT(64)-CT(9)*eps2)*eps2-CT(128))/CT(2048);
-            d *= eps;
-            c[3] = d*((CT(72)-CT(9)*eps2)*eps2-CT(128))/CT(6144);
-            d *= eps;
-            c[4] = d*(CT(3)*eps2-CT(5))/CT(512);
-            d *= eps;
-            c[5] = d*(CT(35)*eps2-CT(56))/CT(10240);
-            d *= eps;
-            c[6] = -CT(7)*d/CT(2048);
-            d *= eps;
-            c[7] = -CT(33)*d/CT(14336);
-            break;
-        case 8:
-            c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
-            d *= eps;
-            c[2] = d*(eps2*(eps2*(CT(7)*eps2-CT(18))+CT(128))-CT(256))/CT(4096);
-            d *= eps;
-            c[3] = d*((CT(72)-CT(9)*eps2)*eps2-CT(128))/CT(6144);
-            d *= eps;
-            c[4] = d*((CT(96)-CT(11)*eps2)*eps2-CT(160))/CT(16384);
-            d *= eps;
-            c[5] = d*(CT(35)*eps2-CT(56))/CT(10240);
-            d *= eps;
-            c[6] = d*(CT(9)*eps2-CT(14))/CT(4096);
-            d *= eps;
-            c[7] = -CT(33)*d/CT(14336);
-            d *= eps;
-            c[8] = -CT(429)*d/CT(262144);
-            break;
-        }
-    }
-
-    /*
      Evaluate

      y = sum(c[i] * sin(2*i * x), i, 1, n)
@@ -351,11 +127,11 @@ public:

         // Find the coefficients for Aj by computing the
         // series expansion using Horner scehme.
-        CT expansion_A1 = evaluate_series_A1(epsilon);
+        CT expansion_A1 = series_expansion::evaluate_series_A1<CT, SeriesOrder>(epsilon);

         // Index zero element of coeffs_C1 is unused.
         CT coeffs_C1[SeriesOrder + 1];
-        evaluate_coeffs_C1(epsilon, coeffs_C1);
+        series_expansion::evaluate_coeffs_C1<CT, SeriesOrder>(epsilon, coeffs_C1);

         // Tau is an integration variable.
         CT tau12 = distance / (b + (c1 + expansion_A1));
diff --git a/include/boost/geometry/util/series_expansion.hpp b/include/boost/geometry/util/series_expansion.hpp
new file mode 100644
index 0000000..b2e2277
--- /dev/null
+++ b/include/boost/geometry/util/series_expansion.hpp
@@ -0,0 +1,243 @@
+// Boost.Geometry
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP
+#define BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP
+
+#include <boost/geometry/util/math.hpp>
+
+namespace boost { namespace geometry { namespace series_expansion {
+
+    /*
+     Generate and evaluate the series expansion of the following integral
+
+     I1 = integrate( sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma )
+
+     which is valid for k2 small. We substitute k2 = 4 * eps / (1 - eps)^2
+     and expand (1 - eps) * I1 retaining terms up to order eps^maxpow
+     in A1 and C1[l].
+
+     The resulting series is of the form
+
+     A1 * ( sigma + sum(C1[l] * sin(2*l*sigma), l, 1, maxpow) ).
+
+     The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
+
+     The expansion above is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeintegral(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+          sintegrand:sqrt(1+k2*sin(sigma)^2),
+          sintegrandexp:ataylor(
+              (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+              eps,maxpow),
+          s:trigreduce(integrate(sintegrandexp,sigma)),
+          s:s-subst(sigma=0,s),
+          A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+          tau1:ataylor(s/A1,eps,maxpow),
+          for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
+          if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B1"),
+          A1:A1/(1-eps),
+          'done)$
+
+        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
+        print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
+        static inline CT evaluate_series_A1(CT eps) {
+            CT eps2 = math::sqr(eps);
+            CT t;
+            switch (SeriesOrder/2) {"),
+          for n:0 thru entier(maxpow/2) do block([
+            q:horner(ataylor(subst([eps=sqrt(eps2)],A1*(1-eps)-1),eps2,n)),
+            linel:1200],
+            print(concat(tab2,"case ",string(n),":")),
+            print(concat(tab3,"t = ",string(q),";")),
+            print(concat(tab3,"break;"))),
+          print("    }
+            return (t + eps) / (1 - eps);
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeintegral(maxpow)$
+        generatecode(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     scirpt can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
+    */
+    template <typename CT, std::size_t SeriesOrder>
+    static inline CT evaluate_series_A1(CT eps)
+    {
+        CT eps2 = math::sqr(eps);
+        CT t;
+        switch (SeriesOrder/2) {
+        case 0:
+            t = CT(0);
+            break;
+        case 1:
+            t = eps2/CT(4);
+            break;
+        case 2:
+            t = eps2*(eps2+CT(16))/CT(64);
+            break;
+        case 3:
+            t = eps2*(eps2*(eps2+CT(4))+CT(64))/CT(256);
+            break;
+        case 4:
+            t = eps2*(eps2*(eps2*(CT(25)*eps2+CT(64))+CT(256))+CT(4096))/CT(16384);
+            break;
+        }
+        return (t + eps) / (CT(1) - eps);
+    }
+
+    /*
+     The coefficients C1[l] in the Fourier expansion of B1
+
+     The expansion below is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
+          print("// The coefficients C1[l] in the Fourier expansion of B1
+        static inline evaluate_coeffs_C1(CT eps, CT c[]) {
+            CT eps2 = math::sqr(eps);
+            CT d = eps;
+            switch (SeriesOrder) {"),
+          for n:0 thru maxpow do (
+            print(concat(tab2,"case ",string(n),":")),
+            for m:1 thru n do block([q:d*horner(
+                subst([eps=sqrt(eps2)],ataylor(C1[m],eps,n)/eps^m)),
+              linel:1200],
+              if m>1 then print(concat(tab3,"d *= eps;")),
+              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+            print(concat(tab3,"break;"))),
+          print("    }
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeintegral(maxpow)$
+        generatecode(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     scirpt can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
+               s/eps(CT(2))/eps2/g;'
+    */
+    template <typename CT, std::size_t SeriesOrder>
+    static inline void evaluate_coeffs_C1(CT eps, CT c[])
+    {
+        CT eps2 = math::sqr(eps);
+        CT d = eps;
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            c[1] = -d/CT(2);
+            break;
+        case 2:
+            c[1] = -d/CT(2);
+            d *= eps;
+            c[2] = -d/CT(16);
+            break;
+        case 3:
+            c[1] = d*(CT(3)*eps2-CT(8))/CT(16);
+            d *= eps;
+            c[2] = -d/CT(16);
+            d *= eps;
+            c[3] = -d/CT(48);
+            break;
+        case 4:
+            c[1] = d*(CT(3)*eps2-CT(8))/CT(16);
+            d *= eps;
+            c[2] = d*(eps2-CT(2))/CT(32);
+            d *= eps;
+            c[3] = -d/CT(48);
+            d *= eps;
+            c[4] = -CT(5)*d/CT(512);
+            break;
+        case 5:
+            c[1] = d*((CT(6)-eps2)*eps2-CT(16))/CT(32);
+            d *= eps;
+            c[2] = d*(eps2-CT(2))/CT(32);
+            d *= eps;
+            c[3] = d*(CT(9)*eps2-CT(16))/CT(768);
+            d *= eps;
+            c[4] = -CT(5)*d/CT(512);
+            d *= eps;
+            c[5] = -CT(7)*d/CT(1280);
+            break;
+        case 6:
+            c[1] = d*((CT(6)-eps2)*eps2-CT(16))/CT(32);
+            d *= eps;
+            c[2] = d*((CT(64)-CT(9)*eps2)*eps2-CT(128))/CT(2048);
+            d *= eps;
+            c[3] = d*(CT(9)*eps2-CT(16))/CT(768);
+            d *= eps;
+            c[4] = d*(CT(3)*eps2-CT(5))/CT(512);
+            d *= eps;
+            c[5] = -CT(7)*d/CT(1280);
+            d *= eps;
+            c[6] = -CT(7)*d/CT(2048);
+            break;
+        case 7:
+            c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
+            d *= eps;
+            c[2] = d*((CT(64)-CT(9)*eps2)*eps2-CT(128))/CT(2048);
+            d *= eps;
+            c[3] = d*((CT(72)-CT(9)*eps2)*eps2-CT(128))/CT(6144);
+            d *= eps;
+            c[4] = d*(CT(3)*eps2-CT(5))/CT(512);
+            d *= eps;
+            c[5] = d*(CT(35)*eps2-CT(56))/CT(10240);
+            d *= eps;
+            c[6] = -CT(7)*d/CT(2048);
+            d *= eps;
+            c[7] = -CT(33)*d/CT(14336);
+            break;
+        case 8:
+            c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
+            d *= eps;
+            c[2] = d*(eps2*(eps2*(CT(7)*eps2-CT(18))+CT(128))-CT(256))/CT(4096);
+            d *= eps;
+            c[3] = d*((CT(72)-CT(9)*eps2)*eps2-CT(128))/CT(6144);
+            d *= eps;
+            c[4] = d*((CT(96)-CT(11)*eps2)*eps2-CT(160))/CT(16384);
+            d *= eps;
+            c[5] = d*(CT(35)*eps2-CT(56))/CT(10240);
+            d *= eps;
+            c[6] = d*(CT(9)*eps2-CT(14))/CT(4096);
+            d *= eps;
+            c[7] = -CT(33)*d/CT(14336);
+            d *= eps;
+            c[8] = -CT(429)*d/CT(262144);
+            break;
+        }
+    }
+
+}}} // namespace boost::geometry::formula
+
+#endif // BOOST_GEOMETRY_UTIL_SERIES_EXPANSION_HPP

commit b6fcee8f303d37016449f7014c31cfcf00b926ae
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat May 19 21:33:01 2018 +0500

    [formulas] Compute sin cos series using Clenshaw summation

    - Update function headers

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 3057715..32ee804 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -112,7 +112,8 @@ public:
        sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
     */
-    static inline CT evaluate_series_A1(CT eps) {
+    static inline CT evaluate_series_A1(CT eps)
+    {
         CT eps2 = math::sqr(eps);
         CT t;
         switch (SeriesOrder/2) {
@@ -178,7 +179,8 @@ public:
                s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
                s/eps(CT(2))/eps2/g;'
     */
-    static inline evaluate_coeffs_C1(CT eps, CT c[]) {
+    static inline void evaluate_coeffs_C1(CT eps, CT c[])
+    {
         CT eps2 = math::sqr(eps);
         CT d = eps;
         switch (SeriesOrder) {
@@ -267,6 +269,38 @@ public:
         }
     }

+    /*
+     Evaluate
+
+     y = sum(c[i] * sin(2*i * x), i, 1, n)
+
+     using Clenshaw summation.
+    */
+    static inline CT sin_cos_series(CT sinx,
+                                    CT cosx,
+                                    const CT coeffs[])
+    {
+        std::size_t n = SeriesOrder;
+
+        // Point to one beyond last element.
+        coeffs += (n + 1);
+        CT ar = 2 * (cosx - sinx) * (cosx + sinx);
+
+        CT k0 = n & 1 ? *--coeffs : 0;
+        CT k1 = 0;
+
+        // Make n even.
+        n /= 2;
+        while (n--) {
+          // Unroll loop x 2, so accumulators return to their original role.
+          k1 = ar * k0 - k1 + *--coeffs;
+          k0 = ar * k1 - k0 + *--coeffs;
+        }
+
+        return 2 * sinx * cosx * k0;
+    }
+
+
     template <typename T, typename Dist, typename Azi, typename Spheroid>
     static inline result_type apply(T const& lo1,
                                     T const& la1,
@@ -278,6 +312,7 @@ public:

         CT const lon1 = lo1;
         CT const lat1 = la1;
+        Azi azi12 = azimuth12;

         if (math::equals(distance, Dist(0)) || distance < Dist(0))
         {
@@ -298,13 +333,13 @@ public:
         CT const e2 = f * two_minus_f;
         CT const ep2 = e2 / math::sqr(one_minus_f);

-        azi12 = math::AngNormalize<CT>(azi12);
+        azi12 = math::normalize_angle<CT>(azi12);
         CT sin_alpha1, cos_alpha1;
-        math::sin_cos_degrees<CT>(azimuth12, sin_alpha1, cos_alpha1);
+        math::sin_cos_degrees<CT>(math::round_angle<CT>(azi12), sin_alpha1, cos_alpha1);

         // Find the reduced latitude.
         CT sin_beta1, cos_beta1;
-        math::sin_cos_degrees<CT>(lat1, sin_beta1, cos_beta1);
+        math::sin_cos_degrees<CT>(math::round_angle<CT>(lat1), sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

         // Obtain alpha 0 by solving the spherical triangle.
@@ -318,8 +353,14 @@ public:
         // series expansion using Horner scehme.
         CT expansion_A1 = evaluate_series_A1(epsilon);

+        // Index zero element of coeffs_C1 is unused.
+        CT coeffs_C1[SeriesOrder + 1];
+        evaluate_coeffs_C1(epsilon, coeffs_C1);
+
         // Tau is an integration variable.
         CT tau12 = distance / (b + (c1 + expansion_A1));
+        CT sin_tau12 = sin(tau12);
+        CT cos_tau12 = cos(tau12);
     }

 };

commit 320891caefdfbb920b9e81259c14d19889faf70c
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat May 19 21:32:09 2018 +0500

    [utils] Add function for normalizing and rounding off an angle

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index 9d9fa10..4d927b3 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -809,6 +809,36 @@ inline void sin_cos_degrees(T const& x, T & sinx, T & cosx)
     }
 }

+/*!
+\brief Round off a given angle
+*/
+template<typename T>
+inline T round_angle(T x) {
+    static const T z = 1/T(16);
+
+    if (x == 0)
+    {
+        return 0;
+    }
+
+    T y = std::abs(x);
+
+    // z - (z - y) must not be simplified to y.
+    y = y < z ? z - (z - y) : y;
+
+    return x < 0 ? -y : y;
+}
+
+/*!
+\brief Normalize a given angle
+*/
+template<typename T>
+    inline T normalize_angle(T x) {
+    T y = std::fmod(x, T(360));
+
+    return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360);
+}
+
 } // namespace math



commit c73ea927c4f88bd3da590757ffa3fec77ba4aa72
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Tue May 15 23:43:52 2018 +0500

    [formulas] Add function for evaluating coefficients for C1

    - Add SED script for converting x to CT(x)
    - Improve code documentation

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
index 900a4da..3057715 100644
--- a/include/boost/geometry/formulas/karney_direct.hpp
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -65,7 +65,27 @@ public:
      http://geographiclib.sourceforge.net/html/geod.mac

         // Maxima script begin
-        codeA1(maxpow):=block([tab2:"    ",tab3:"        "],
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        computeintegral(maxpow):=block([sintegrand,sintegrandexp,s,sigma,tau1,k2,eps],
+          sintegrand:sqrt(1+k2*sin(sigma)^2),
+          sintegrandexp:ataylor(
+              (1-eps)*subst([k2=4*eps/(1-eps)^2],sintegrand),
+              eps,maxpow),
+          s:trigreduce(integrate(sintegrandexp,sigma)),
+          s:s-subst(sigma=0,s),
+          A1:expand(subst(sigma=2*%pi,s)/(2*%pi)),
+          tau1:ataylor(s/A1,eps,maxpow),
+          for i:1 thru maxpow do C1[i]:coeff(tau1,sin(2*i*sigma)),
+          if expand(tau1-sigma-sum(C1[i]*sin(2*i*sigma),i,1,maxpow)) # 0
+          then error("left over terms in B1"),
+          A1:A1/(1-eps),
+          'done)$
+
+        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
         print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
         static inline CT evaluate_series_A1(CT eps) {
             CT eps2 = math::sqr(eps);
@@ -81,9 +101,17 @@ public:
             return (t + eps) / (1 - eps);
         }"),
         'done)$
-        codeA1(8)$        
+
+        maxpow:8$
+        computeintegral(maxpow)$
+        generatecode(maxpow)$
         // Maxima script end
-     */
+
+     To replace each number x by CT(x) the following
+     scirpt can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;'
+    */
     static inline CT evaluate_series_A1(CT eps) {
         CT eps2 = math::sqr(eps);
         CT t;
@@ -107,6 +135,138 @@ public:
         return (t + eps) / (CT(1) - eps);
     }

+    /*
+     The coefficients C1[l] in the Fourier expansion of B1
+
+     The expansion below is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        taylordepth:5$
+        ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$
+        jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1],
+        ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$
+
+        generatecode(maxpow):=block([tab2:"    ",tab3:"        "],
+          print("// The coefficients C1[l] in the Fourier expansion of B1
+        static inline evaluate_coeffs_C1(CT eps, CT c[]) {
+            CT eps2 = math::sqr(eps);
+            CT d = eps;
+            switch (SeriesOrder) {"),
+          for n:0 thru maxpow do (
+            print(concat(tab2,"case ",string(n),":")),
+            for m:1 thru n do block([q:d*horner(
+                subst([eps=sqrt(eps2)],ataylor(C1[m],eps,n)/eps^m)),
+              linel:1200],
+              if m>1 then print(concat(tab3,"d *= eps;")),
+              print(concat(tab3,"c[",string(m),"] = ",string(q),";"))),
+            print(concat(tab3,"break;"))),
+          print("    }
+        }"),
+        'done)$
+
+        maxpow:8$
+        computeintegral(maxpow)$
+        generatecode(maxpow)$
+        // Maxima script end
+
+     To replace each number x by CT(x) the following
+     scirpt can be used:
+       sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g;
+               s/case\sCT(/case /g; s/):/:/g; s/epsCT(2)/eps2/g;
+               s/eps(CT(2))/eps2/g;'
+    */
+    static inline evaluate_coeffs_C1(CT eps, CT c[]) {
+        CT eps2 = math::sqr(eps);
+        CT d = eps;
+        switch (SeriesOrder) {
+        case 0:
+            break;
+        case 1:
+            c[1] = -d/CT(2);
+            break;
+        case 2:
+            c[1] = -d/CT(2);
+            d *= eps;
+            c[2] = -d/CT(16);
+            break;
+        case 3:
+            c[1] = d*(CT(3)*eps2-CT(8))/CT(16);
+            d *= eps;
+            c[2] = -d/CT(16);
+            d *= eps;
+            c[3] = -d/CT(48);
+            break;
+        case 4:
+            c[1] = d*(CT(3)*eps2-CT(8))/CT(16);
+            d *= eps;
+            c[2] = d*(eps2-CT(2))/CT(32);
+            d *= eps;
+            c[3] = -d/CT(48);
+            d *= eps;
+            c[4] = -CT(5)*d/CT(512);
+            break;
+        case 5:
+            c[1] = d*((CT(6)-eps2)*eps2-CT(16))/CT(32);
+            d *= eps;
+            c[2] = d*(eps2-CT(2))/CT(32);
+            d *= eps;
+            c[3] = d*(CT(9)*eps2-CT(16))/CT(768);
+            d *= eps;
+            c[4] = -CT(5)*d/CT(512);
+            d *= eps;
+            c[5] = -CT(7)*d/CT(1280);
+            break;
+        case 6:
+            c[1] = d*((CT(6)-eps2)*eps2-CT(16))/CT(32);
+            d *= eps;
+            c[2] = d*((CT(64)-CT(9)*eps2)*eps2-CT(128))/CT(2048);
+            d *= eps;
+            c[3] = d*(CT(9)*eps2-CT(16))/CT(768);
+            d *= eps;
+            c[4] = d*(CT(3)*eps2-CT(5))/CT(512);
+            d *= eps;
+            c[5] = -CT(7)*d/CT(1280);
+            d *= eps;
+            c[6] = -CT(7)*d/CT(2048);
+            break;
+        case 7:
+            c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
+            d *= eps;
+            c[2] = d*((CT(64)-CT(9)*eps2)*eps2-CT(128))/CT(2048);
+            d *= eps;
+            c[3] = d*((CT(72)-CT(9)*eps2)*eps2-CT(128))/CT(6144);
+            d *= eps;
+            c[4] = d*(CT(3)*eps2-CT(5))/CT(512);
+            d *= eps;
+            c[5] = d*(CT(35)*eps2-CT(56))/CT(10240);
+            d *= eps;
+            c[6] = -CT(7)*d/CT(2048);
+            d *= eps;
+            c[7] = -CT(33)*d/CT(14336);
+            break;
+        case 8:
+            c[1] = d*(eps2*(eps2*(CT(19)*eps2-CT(64))+CT(384))-CT(1024))/CT(2048);
+            d *= eps;
+            c[2] = d*(eps2*(eps2*(CT(7)*eps2-CT(18))+CT(128))-CT(256))/CT(4096);
+            d *= eps;
+            c[3] = d*((CT(72)-CT(9)*eps2)*eps2-CT(128))/CT(6144);
+            d *= eps;
+            c[4] = d*((CT(96)-CT(11)*eps2)*eps2-CT(160))/CT(16384);
+            d *= eps;
+            c[5] = d*(CT(35)*eps2-CT(56))/CT(10240);
+            d *= eps;
+            c[6] = d*(CT(9)*eps2-CT(14))/CT(4096);
+            d *= eps;
+            c[7] = -CT(33)*d/CT(14336);
+            d *= eps;
+            c[8] = -CT(429)*d/CT(262144);
+            break;
+        }
+    }
+
     template <typename T, typename Dist, typename Azi, typename Spheroid>
     static inline result_type apply(T const& lo1,
                                     T const& la1,
@@ -138,21 +298,27 @@ public:
         CT const e2 = f * two_minus_f;
         CT const ep2 = e2 / math::sqr(one_minus_f);

+        azi12 = math::AngNormalize<CT>(azi12);
         CT sin_alpha1, cos_alpha1;
         math::sin_cos_degrees<CT>(azimuth12, sin_alpha1, cos_alpha1);

-        // The reduced latitude.
+        // Find the reduced latitude.
         CT sin_beta1, cos_beta1;
         math::sin_cos_degrees<CT>(lat1, sin_beta1, cos_beta1);
         sin_beta1 *= one_minus_f;

+        // Obtain alpha 0 by solving the spherical triangle.
         CT cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);

         CT k2 = math::sqr(cos_alpha0) * ep2;

         CT epsilon = k2 / (c2 * (c1 + std::sqrt(c1 + k2)) + k2);

+        // Find the coefficients for Aj by computing the
+        // series expansion using Horner scehme.
         CT expansion_A1 = evaluate_series_A1(epsilon);
+
+        // Tau is an integration variable.
         CT tau12 = distance / (b + (c1 + expansion_A1));
     }


commit 8d5d3bc8a96b819830a25d96bd1200d8389f68da
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat May 12 22:09:26 2018 +0500

    [formulas] Add draft of direct geodesic problem from Karney (2011)

    The paper can be found at: https://arxiv.org/pdf/1109.4448.pdf
    This commit also introduces the evaluate_series_A1 function
    for evaluating the series expantion, which was generated
    using Maxima: http://maxima.sourceforge.net

diff --git a/include/boost/geometry/formulas/karney_direct.hpp b/include/boost/geometry/formulas/karney_direct.hpp
new file mode 100644
index 0000000..900a4da
--- /dev/null
+++ b/include/boost/geometry/formulas/karney_direct.hpp
@@ -0,0 +1,164 @@
+// Boost.Geometry
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
+#define BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
+
+
+#include <boost/math/constants/constants.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/formulas/flattening.hpp>
+#include <boost/geometry/formulas/result_direct.hpp>
+
+
+namespace boost { namespace geometry { namespace formula
+{
+
+
+/*!
+\brief The solution of the direct problem of geodesics on latlong coordinates,
+       after Karney (2011).
+\author See
+- Charles F.F Karney, Algorithms for geodesics, 2011
+https://arxiv.org/pdf/1109.4448.pdf
+*/
+template <
+    typename CT,
+    std::size_t SeriesOrder = 8,
+    bool EnableCoordinates = true,
+    bool EnableReverseAzimuth = false,
+    bool EnableReducedLength = false,
+    bool EnableGeodesicScale = false
+>
+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;
+
+    /*
+     Generate and evaluate the series expansion of the following integral
+
+     I1 = integrate( sqrt(1+k2*sin(sigma1)^2), sigma1, 0, sigma )
+
+     which is valid for k2 small. We substitute k2 = 4 * eps / (1 - eps)^2
+     and expand (1 - eps) * I1 retaining terms up to order eps^maxpow
+     in A1 and C1[l].
+
+     The resulting series is of the form
+
+     A1 * ( sigma + sum(C1[l] * sin(2*l*sigma), l, 1, maxpow) ).
+
+     The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
+
+     The expansion above is performed in Maxima, a Computer Algebra System.
+     The C++ code (that yields the function evaluate_series_A1 below) is
+     generated by the following Maxima script and is based on script:
+     http://geographiclib.sourceforge.net/html/geod.mac
+
+        // Maxima script begin
+        codeA1(maxpow):=block([tab2:"    ",tab3:"        "],
+        print("// The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
+        static inline CT evaluate_series_A1(CT eps) {
+            CT eps2 = math::sqr(eps);
+            CT t;
+            switch (SeriesOrder/2) {"),
+          for n:0 thru entier(maxpow/2) do block([
+            q:horner(ataylor(subst([eps=sqrt(eps2)],A1*(1-eps)-1),eps2,n)),
+            linel:1200],
+            print(concat(tab2,"case ",string(n),":")),
+            print(concat(tab3,"t = ",string(q),";")),
+            print(concat(tab3,"break;"))),
+          print("    }
+            return (t + eps) / (1 - eps);
+        }"),
+        'done)$
+        codeA1(8)$        
+        // Maxima script end
+     */
+    static inline CT evaluate_series_A1(CT eps) {
+        CT eps2 = math::sqr(eps);
+        CT t;
+        switch (SeriesOrder/2) {
+        case 0:
+            t = CT(0);
+            break;
+        case 1:
+            t = eps2/CT(4);
+            break;
+        case 2:
+            t = eps2*(eps2+CT(16))/CT(64);
+            break;
+        case 3:
+            t = eps2*(eps2*(eps2+CT(4))+CT(64))/CT(256);
+            break;
+        case 4:
+            t = eps2*(eps2*(eps2*(CT(25)*eps2+CT(64))+CT(256))+CT(4096))/CT(16384);
+            break;
+        }
+        return (t + eps) / (CT(1) - eps);
+    }
+
+    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 const lon1 = lo1;
+        CT const lat1 = la1;
+
+        if (math::equals(distance, Dist(0)) || distance < Dist(0))
+        {
+            result.lon2 = lon1;
+            result.lat2 = lat1;
+            return result;
+        }
+
+        CT const c1 = 1;
+        CT const c2 = 2;
+
+        CT const a = CT(get_radius<0>(spheroid));
+        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 e2 = f * two_minus_f;
+        CT const ep2 = e2 / math::sqr(one_minus_f);
+
+        CT sin_alpha1, cos_alpha1;
+        math::sin_cos_degrees<CT>(azimuth12, sin_alpha1, cos_alpha1);
+
+        // The reduced latitude.
+        CT sin_beta1, cos_beta1;
+        math::sin_cos_degrees<CT>(lat1, sin_beta1, cos_beta1);
+        sin_beta1 *= one_minus_f;
+
+        CT cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);
+
+        CT k2 = math::sqr(cos_alpha0) * ep2;
+
+        CT epsilon = k2 / (c2 * (c1 + std::sqrt(c1 + k2)) + k2);
+
+        CT expansion_A1 = evaluate_series_A1(epsilon);
+        CT tau12 = distance / (b + (c1 + expansion_A1));
+    }
+
+};
+
+}}} // namespace boost::geometry::formula
+
+
+#endif // BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP

commit 302e24066776301b5fdae795d43e3497a137678e
Author: Adeel Ahmad <adeelahmad14@hotmail.com>
Date:   Sat May 12 22:08:25 2018 +0500

    [utils] Add function sin_cos_degrees for evaluating sine and cosine function

diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp
index b1c3648..9d9fa10 100644
--- a/include/boost/geometry/util/math.hpp
+++ b/include/boost/geometry/util/math.hpp
@@ -771,6 +771,44 @@ inline Result rounding_cast(T const& v)
     return detail::rounding_cast<Result, T>::apply(v);
 }

+/*!
+\brief Evaluate the sine and cosine function with the argument in degrees
+\note The results obey exactly the elementary properties of the trigonometric
+      functions, e.g., sin 9&deg; = cos 81&deg; = &minus; sin 123456789&deg;.
+      If x = &minus;0, then \e sinx = &minus;0; this is the only case where
+      &minus;0 is returned.
+*/
+template<typename T>
+inline void sin_cos_degrees(T const& x, T & sinx, T & cosx)
+{
+    // In order to minimize round-off errors, this function exactly reduces
+    // the argument to the range [-45, 45] before converting it to radians.
+    T remainder; int quotient;
+
+    remainder = std::fmod(x, T(360));
+    quotient = int(std::floor(remainder / 90 + T(0.5)));
+    remainder -= 90 * quotient;
+
+    // Convert to radians.
+    remainder = as_radian<T>(remainder);
+
+    T s = std::sin(remainder), c = std::cos(remainder);
+
+    switch (unsigned(quotient) & 3U)
+    {
+        case 0U: sinx =  s; cosx =  c; break;
+        case 1U: sinx =  c; cosx = -s; break;
+        case 2U: sinx = -s; cosx = -c; break;
+        default: sinx = -c; cosx =  s; break; // case 3U
+    }
+
+    // Set sign of 0 results. -0 only produced for sin(-0).
+    if (x != 0)
+    {
+        sinx += T(0); cosx += T(0);
+    }
+}
+
 } // namespace math