summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorJustin R. Miller <incanus@codesorcery.net>2015-02-16 09:52:36 -0800
committerJustin R. Miller <incanus@codesorcery.net>2015-02-16 09:52:36 -0800
commit6e41664cb033ee5edf6ae5ac66ed518d9f0d1f89 (patch)
treea70192b174ea6dc69b1fa0b13f9a33358a9110e5 /include
parentea31ad99a56f1e0afbcc7862ddc62dffd16bc5bb (diff)
downloadqtlocation-mapboxgl-6e41664cb033ee5edf6ae5ac66ed518d9f0d1f89.tar.gz
fixes #476 & #853: pixel/meter/latlng conversion routines in core & iOS
Diffstat (limited to 'include')
-rw-r--r--include/mbgl/ios/MGLMapView.h24
-rw-r--r--include/mbgl/map/map.hpp19
-rw-r--r--include/mbgl/map/transform.hpp12
-rw-r--r--include/mbgl/map/transform_state.hpp12
-rw-r--r--include/mbgl/util/constants.hpp7
-rw-r--r--include/mbgl/util/geo.hpp24
-rw-r--r--include/mbgl/util/projection.hpp65
7 files changed, 152 insertions, 11 deletions
diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h
index 6535138d3b..f954340262 100644
--- a/include/mbgl/ios/MGLMapView.h
+++ b/include/mbgl/ios/MGLMapView.h
@@ -131,6 +131,30 @@
/** Resets the map rotation to a northern heading. */
- (void)resetNorth;
+#pragma mark - Converting Map Coordinates
+
+/** @name Converting Map Coordinates */
+
+/** Converts a point in the specified view’s coordinate system to a map coordinate.
+* @param point The point you want to convert.
+* @param view The view that serves as the reference coordinate system for the `point` parameter.
+* @return The map coordinate at the specified point. */
+- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view;
+
+/** Converts a map coordinate to a point in the specified view.
+* @param coordinate The map coordinate for which you want to find the corresponding point.
+* @param view The view in whose coordinate system you want to locate the specified map coordinate. If this parameter is `nil`, the returned point is specified in the window’s coordinate system. If `view` is not `nil`, it must belong to the same window as the map view.
+* @return The point (in the appropriate view or window coordinate system) corresponding to the specified latitude and longitude value. */
+- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view;
+
+/** Returns the distance spanned by one pixel at the specified latitude and current zoom level.
+*
+* The distance between pixels decreases as the latitude approaches the poles. This relationship parallels the relationship between longitudinal coordinates at different latitudes.
+*
+* @param latitude The latitude for which to return the value.
+* @return The distance (in meters) spanned by a single pixel. */
+- (CLLocationDistance)metersPerPixelAtLatitude:(CLLocationDegrees)latitude;
+
#pragma mark - Styling the Map
/** @name Styling the Map */
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index ae0228544e..844970bb8f 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -2,9 +2,12 @@
#define MBGL_MAP_MAP
#include <mbgl/map/transform.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/projection.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/ptr.hpp>
+#include <mbgl/util/vec.hpp>
#include <cstdint>
#include <atomic>
@@ -94,8 +97,8 @@ public:
// Position
void moveBy(double dx, double dy, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
- void setLonLat(double lon, double lat, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
- void getLonLat(double &lon, double &lat) const;
+ void setLatLng(LatLng latLng, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
+ inline const LatLng getLatLng() const { return state.getLatLng(); }
void startPanning();
void stopPanning();
void resetPosition();
@@ -106,8 +109,7 @@ public:
double getScale() const;
void setZoom(double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
double getZoom() const;
- void setLonLatZoom(double lon, double lat, double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
- void getLonLatZoom(double &lon, double &lat, double &zoom) const;
+ void setLatLngZoom(LatLng latLng, double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void resetZoom();
void startScaling();
void stopScaling();
@@ -127,6 +129,15 @@ public:
void setAccessToken(const std::string &token);
const std::string &getAccessToken() const;
+ // Projection
+ inline void getWorldBoundsMeters(ProjectedMeters &sw, ProjectedMeters &ne) const { Projection::getWorldBoundsMeters(sw, ne); }
+ inline void getWorldBoundsLatLng(LatLng &sw, LatLng &ne) const { Projection::getWorldBoundsLatLng(sw, ne); }
+ inline double getMetersPerPixelAtLatitude(const double lat, const double zoom) const { return Projection::getMetersPerPixelAtLatitude(lat, zoom); }
+ inline const ProjectedMeters projectedMetersForLatLng(const LatLng latLng) const { return Projection::projectedMetersForLatLng(latLng); }
+ inline const LatLng latLngForProjectedMeters(const ProjectedMeters projectedMeters) const { return Projection::latLngForProjectedMeters(projectedMeters); }
+ inline const vec2<double> pixelForLatLng(const LatLng latLng) const { return state.pixelForLatLng(latLng); }
+ inline const LatLng latLngForPixel(const vec2<double> pixel) const { return state.latLngForPixel(pixel); }
+
// Debug
void setDebug(bool value);
void toggleDebug();
diff --git a/include/mbgl/map/transform.hpp b/include/mbgl/map/transform.hpp
index 246270da13..94bea11a45 100644
--- a/include/mbgl/map/transform.hpp
+++ b/include/mbgl/map/transform.hpp
@@ -2,7 +2,9 @@
#define MBGL_MAP_TRANSFORM
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/vec.hpp>
#include <cstdint>
#include <cmath>
@@ -26,10 +28,9 @@ public:
// Position
void moveBy(double dx, double dy, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
- void setLonLat(double lon, double lat, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
- void setLonLatZoom(double lon, double lat, double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
- void getLonLat(double& lon, double& lat) const;
- void getLonLatZoom(double& lon, double& lat, double& zoom) const;
+ void setLatLng(LatLng latLng, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
+ void setLatLngZoom(LatLng latLng, double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
+ inline const LatLng getLatLng() const { return current.getLatLng(); }
void startPanning();
void stopPanning();
@@ -91,9 +92,6 @@ private:
const double min_scale = std::pow(2, 0);
const double max_scale = std::pow(2, 18);
- // cache values for spherical mercator math
- double Bc, Cc;
-
std::forward_list<util::ptr<util::transition>> transitions;
util::ptr<util::transition> scale_timeout;
util::ptr<util::transition> rotate_timeout;
diff --git a/include/mbgl/map/transform_state.hpp b/include/mbgl/map/transform_state.hpp
index 6dc34bd873..5f2dfa49e4 100644
--- a/include/mbgl/map/transform_state.hpp
+++ b/include/mbgl/map/transform_state.hpp
@@ -4,6 +4,8 @@
#include <mbgl/map/tile.hpp>
#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/vec.hpp>
#include <cstdint>
#include <array>
@@ -34,6 +36,9 @@ public:
std::array<float, 2> locationCoordinate(float lon, float lat) const;
void getLonLat(double &lon, double &lat) const;
+ // Position
+ const LatLng getLatLng() const;
+
// Zoom
float getNormalizedZoom() const;
double getZoom() const;
@@ -44,6 +49,10 @@ public:
// Rotation
float getAngle() const;
+ // Projection
+ const vec2<double> pixelForLatLng(const LatLng latLng) const;
+ const LatLng latLngForPixel(const vec2<double> pixel) const;
+
// Changing
bool isChanging() const;
@@ -61,6 +70,9 @@ private:
// map scale factor
float pixelRatio = 0;
+ // cache values for spherical mercator math
+ double Bc, Cc;
+
// animation state
bool rotating = false;
bool scaling = false;
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 <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