summaryrefslogtreecommitdiff
path: root/include/mbgl/util/projection.hpp
blob: f301d93005937b59aadeecaeacef46240a3a9dce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#ifndef MBGL_UTIL_PROJECTION
#define MBGL_UTIL_PROJECTION

#include <mbgl/util/constants.hpp>
#include <mbgl/util/geo.hpp>

#include <cmath>

namespace mbgl {

class Projection {

public:
    static inline void getWorldBoundsMeters(ProjectedMeters &sw, ProjectedMeters &ne) {
        const double d = util::EARTH_RADIUS_M * M_PI;

        sw.easting  = -d;
        sw.northing = -d;

        ne.easting  =  d;
        ne.northing =  d;
    }

    static inline void getWorldBoundsLatLng(LatLng &sw, LatLng &ne) {
        ProjectedMeters projectedMetersSW = ProjectedMeters();
        ProjectedMeters projectedMetersNE = ProjectedMeters();

        getWorldBoundsMeters(projectedMetersSW, projectedMetersNE);

        sw = latLngForProjectedMeters(projectedMetersSW);
        ne = latLngForProjectedMeters(projectedMetersNE);
    }

    static inline double getMetersPerPixelAtLatitude(const double lat, const double zoom) {
        const double mapPixelWidthAtZoom = std::pow(2.0, zoom) * util::tileSize;
        const double constrainedLatitude = std::fmin(std::fmax(lat, -util::LATITUDE_MAX), util::LATITUDE_MAX);

        return std::cos(constrainedLatitude * util::DEG2RAD) * util::M2PI * util::EARTH_RADIUS_M / mapPixelWidthAtZoom;
    }

    static inline const ProjectedMeters projectedMetersForLatLng(const LatLng latLng) {
        const double constrainedLatitude = std::fmin(std::fmax(latLng.latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);

        const double m = 1 - 1e-15;
        const double f = std::fmin(std::fmax(std::sin(util::DEG2RAD * constrainedLatitude), -m), m);

        const double easting  = util::EARTH_RADIUS_M * latLng.longitude * util::DEG2RAD;
        const double northing = 0.5 * util::EARTH_RADIUS_M * std::log((1 + f) / (1 - f));

        return ProjectedMeters(northing, easting);
    }

    static inline const LatLng latLngForProjectedMeters(const ProjectedMeters projectedMeters) {
        double latitude = (2 * std::atan(std::exp(projectedMeters.northing / util::EARTH_RADIUS_M)) - (M_PI / 2)) * util::RAD2DEG;
        double longitude = projectedMeters.easting * util::RAD2DEG / util::EARTH_RADIUS_M;

        latitude = std::fmin(std::fmax(latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
        
        return LatLng(latitude, longitude);
    }
};

}

#endif