inline FloatLatitude yToLat(const double y)
{
    const auto clamped_y = std::max(-180., std::min(180., y));
    const double normalized_lat =
        detail::RAD_TO_DEGREE * 2. * std::atan(std::exp(clamped_y * detail::DEGREE_TO_RAD));

    return FloatLatitude(std::round(normalized_lat * COORDINATE_PRECISION) / COORDINATE_PRECISION - 90.);
}
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 std::pair<double, FloatCoordinate> projectPointOnSegment(const FloatCoordinate &source,
                                                                const FloatCoordinate &target,
                                                                const FloatCoordinate &coordinate)
{
    const FloatCoordinate slope_vector{target.lon - source.lon, target.lat - source.lat};
    const FloatCoordinate rel_coordinate{coordinate.lon - source.lon, coordinate.lat - source.lat};
    // dot product of two un-normed vectors
    const auto unnormed_ratio = static_cast<double>(slope_vector.lon * rel_coordinate.lon) +
                                static_cast<double>(slope_vector.lat * rel_coordinate.lat);
    // squared length of the slope vector
    const auto squared_length = static_cast<double>(slope_vector.lon * slope_vector.lon) +
                                static_cast<double>(slope_vector.lat * slope_vector.lat);

    if (squared_length < std::numeric_limits<double>::epsilon())
    {
        return {0, source};
    }

    const double normed_ratio = unnormed_ratio / squared_length;
    double clamped_ratio = normed_ratio;
    if (clamped_ratio > 1.)
    {
        clamped_ratio = 1.;
    }
    else if (clamped_ratio < 0.)
    {
        clamped_ratio = 0.;
    }

    return {clamped_ratio,
            {
                FloatLongitude(1.0 - clamped_ratio) * source.lon +
                    target.lon * FloatLongitude(clamped_ratio),
                FloatLatitude(1.0 - clamped_ratio) * source.lat +
                    target.lat * FloatLatitude(clamped_ratio),
            }};
}
示例#4
0
bool FloatCoordinate::IsValid() const
{
    return !(lat > FloatLatitude(90) || lat < FloatLatitude(-90) || lon > FloatLongitude(180) ||
             lon < FloatLongitude(-180));
}
inline FloatLatitude clamp(const FloatLatitude lat)
{
    return std::max(std::min(lat, FloatLatitude(detail::MAX_LATITUDE)),
                    FloatLatitude(-detail::MAX_LATITUDE));
}