Approximate inverse Gudermannian function by a Padé approximant

This commit is contained in:
Michael Krasnyk 2016-05-04 00:37:53 +02:00
parent 7e80dae59b
commit 24a75d37fb
No known key found for this signature in database
GPG Key ID: A277FCFBE39A658D

View File

@ -35,7 +35,7 @@ inline FloatLatitude yToLat(const double y)
const double normalized_lat =
detail::RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * detail::DEGREE_TO_RAD));
return FloatLatitude(normalized_lat - 90.);
return FloatLatitude(std::round(normalized_lat * COORDINATE_PRECISION) / COORDINATE_PRECISION - 90.);
}
inline double latToY(const FloatLatitude latitude)
@ -47,6 +47,31 @@ inline double latToY(const FloatLatitude latitude)
return clamped_y;
}
template<typename T>
constexpr double horner(double, T an) { return an; }
template<typename T, typename... U>
constexpr double horner(double x, T an, U ...a) { return horner(x, a...) * x + an; }
inline double latToYapprox(const FloatLatitude latitude)
{
if (latitude < FloatLatitude(-70.) || latitude > FloatLatitude(70.))
return latToY(latitude);
// Approximate the inverse Gudermannian function with the Padé approximant [11/11]: deg → deg
// Coefficients are computed for the argument range [-70°,70°] by Remez algorithm |err|_∞=3.387e-12
const auto x = static_cast<double>(latitude);
return
horner(x, 0.00000000000000000000000000e+00, 1.00000000000089108431373566e+00, 2.34439410386997223035693483e-06,
-3.21291701673364717170998957e-04, -6.62778508496089940141103135e-10, 3.68188055470304769936079078e-08,
6.31192702320492485752941578e-14, -1.77274453235716299127325443e-12, -2.24563810831776747318521450e-18,
3.13524754818073129982475171e-17, 2.09014225025314211415458228e-23, -9.82938075991732185095509716e-23) /
horner(x, 1.00000000000000000000000000e+00, 2.34439410398970701719081061e-06, -3.72061271627251952928813333e-04,
-7.81802389685429267252612620e-10, 5.18418724186576447072888605e-08, 9.37468561198098681003717477e-14,
-3.30833288607921773936702558e-12, -4.78446279888774903983338274e-18, 9.32999229169156878168234191e-17,
9.17695141954265959600965170e-23, -8.72130728982012387640166055e-22, -3.23083224835967391884404730e-28);
}
inline FloatLatitude clamp(const FloatLatitude lat)
{
return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
@ -87,7 +112,7 @@ inline double degreeToPixel(FloatLatitude lat, unsigned zoom)
inline FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
{
return {wgs84_coordinate.lon, FloatLatitude{latToY(wgs84_coordinate.lat)}};
return {wgs84_coordinate.lon, FloatLatitude{latToYapprox(wgs84_coordinate.lat)}};
}
inline FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)