From 6e41664cb033ee5edf6ae5ac66ed518d9f0d1f89 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 16 Feb 2015 09:52:36 -0800 Subject: fixes #476 & #853: pixel/meter/latlng conversion routines in core & iOS --- include/mbgl/util/constants.hpp | 7 +++++ include/mbgl/util/geo.hpp | 24 +++++++++++++++ include/mbgl/util/projection.hpp | 65 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 include/mbgl/util/geo.hpp create mode 100644 include/mbgl/util/projection.hpp (limited to 'include/mbgl/util') diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp index 78c92643d2..069e6e41ae 100644 --- a/include/mbgl/util/constants.hpp +++ b/include/mbgl/util/constants.hpp @@ -8,6 +8,13 @@ namespace mbgl { namespace util { extern const float tileSize; + +extern const double DEG2RAD; +extern const double RAD2DEG; +extern const double M2PI; +extern const double EARTH_RADIUS_M; +extern const double LATITUDE_MAX; + } namespace debug { diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp new file mode 100644 index 0000000000..1d9986bd91 --- /dev/null +++ b/include/mbgl/util/geo.hpp @@ -0,0 +1,24 @@ +#ifndef MBGL_UTIL_GEO +#define MBGL_UTIL_GEO + +namespace mbgl { + +struct LatLng { + double latitude = 0; + double longitude = 0; + + inline LatLng(double lat = 0, double lon = 0) + : latitude(lat), longitude(lon) {} +}; + +struct ProjectedMeters { + double northing = 0; + double easting = 0; + + inline ProjectedMeters(double n = 0, double e = 0) + : northing(n), easting(e) {} +}; + +} + +#endif diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp new file mode 100644 index 0000000000..f301d93005 --- /dev/null +++ b/include/mbgl/util/projection.hpp @@ -0,0 +1,65 @@ +#ifndef MBGL_UTIL_PROJECTION +#define MBGL_UTIL_PROJECTION + +#include +#include + +#include + +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 -- cgit v1.2.1