Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Merge pull request #886 from mapbox/conversions-squash
Browse files Browse the repository at this point in the history
fixes #476 & #853: pixel/meter/latlng conversion routines in core & iOS
  • Loading branch information
incanus committed Feb 16, 2015
2 parents ea31ad9 + 6e41664 commit 1444e6f
Show file tree
Hide file tree
Showing 19 changed files with 403 additions and 146 deletions.
15 changes: 7 additions & 8 deletions android/cpp/jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,17 +467,16 @@ void JNICALL nativeSetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, j
return;
}

nativeMapView->getMap().setLonLat(lon, lat, std::chrono::milliseconds(duration));
nativeMapView->getMap().setLatLng(mbgl::LatLng(lat, lon), std::chrono::milliseconds(duration));
}

jobject JNICALL nativeGetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLonLat");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
double lon = 0.0, lat = 0.0;
nativeMapView->getMap().getLonLat(lon, lat);
mbgl::LatLng latLng = nativeMapView->getMap().getLatLng();

jobject ret = env->NewObject(lonLatClass, lonLatConstructorId, lon, lat);
jobject ret = env->NewObject(lonLatClass, lonLatConstructorId, latLng.longitude, latLng.latitude);
if (ret == nullptr) {
env->ExceptionDescribe();
return nullptr;
Expand Down Expand Up @@ -569,17 +568,17 @@ void JNICALL nativeSetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPt
return;
}

nativeMapView->getMap().setLonLatZoom(lon, lat, zoom, std::chrono::milliseconds(duration));
nativeMapView->getMap().setLatLngZoom(mbgl::LatLng(lat, lon), zoom, std::chrono::milliseconds(duration));
}

jobject JNICALL nativeGetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLonLatZoom");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
double lon = 0.0, lat = 0.0, zoom = 0.0;
nativeMapView->getMap().getLonLatZoom(lon, lat, zoom);
mbgl::LatLng latLng = nativeMapView->getMap().getLatLng();
double zoom = nativeMapView->getMap().getZoom();

jobject ret = env->NewObject(lonLatZoomClass, lonLatZoomConstructorId, lon, lat, zoom);
jobject ret = env->NewObject(lonLatZoomClass, lonLatZoomConstructorId, latLng.longitude, latLng.latitude, zoom);
if (ret == nullptr) {
env->ExceptionDescribe();
return nullptr;
Expand Down
2 changes: 1 addition & 1 deletion bin/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) {

view.resize(width, height, pixelRatio);
map.resize(width, height, pixelRatio);
map.setLonLatZoom(lon, lat, zoom);
map.setLatLonZoom(LatLng(lat, lon), zoom);
map.setBearing(bearing);

std::unique_ptr<uint32_t[]> pixels;
Expand Down
24 changes: 24 additions & 0 deletions include/mbgl/ios/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
19 changes: 15 additions & 4 deletions include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -94,8 +97,8 @@ class Map : private util::noncopyable {

// 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();
Expand All @@ -106,8 +109,7 @@ class Map : private util::noncopyable {
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();
Expand All @@ -127,6 +129,15 @@ class Map : private util::noncopyable {
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();
Expand Down
12 changes: 5 additions & 7 deletions include/mbgl/map/transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -26,10 +28,9 @@ class Transform : private util::noncopyable {

// 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();

Expand Down Expand Up @@ -91,9 +92,6 @@ class Transform : private util::noncopyable {
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;
Expand Down
12 changes: 12 additions & 0 deletions include/mbgl/map/transform_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -34,6 +36,9 @@ class TransformState {
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;
Expand All @@ -44,6 +49,10 @@ class TransformState {
// 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;

Expand All @@ -61,6 +70,9 @@ class TransformState {
// map scale factor
float pixelRatio = 0;

// cache values for spherical mercator math
double Bc, Cc;

// animation state
bool rotating = false;
bool scaling = false;
Expand Down
7 changes: 7 additions & 0 deletions include/mbgl/util/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
24 changes: 24 additions & 0 deletions include/mbgl/util/geo.hpp
Original file line number Diff line number Diff line change
@@ -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
65 changes: 65 additions & 0 deletions include/mbgl/util/projection.hpp
Original file line number Diff line number Diff line change
@@ -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
7 changes: 5 additions & 2 deletions linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) {

// Load settings
mbgl::Settings_JSON settings;
map.setLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom);
map.setBearing(settings.bearing);
map.setDebug(settings.debug);

Expand All @@ -94,7 +94,10 @@ int main(int argc, char *argv[]) {
int ret = view->run();

// Save settings
map.getLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
mbgl::LatLng latLng = map.getLatLng();
settings.latitude = latLng.latitude;
settings.longitude = latLng.longitude;
settings.zoom = map.getZoom();
settings.bearing = map.getBearing();
settings.debug = map.getDebug();
settings.save();
Expand Down
24 changes: 15 additions & 9 deletions macosx/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <mbgl/storage/default/sqlite_cache.hpp>
#include <mbgl/storage/network_status.hpp>

#include <mbgl/util/geo.hpp>

#import <Foundation/Foundation.h>

@interface URLHandler : NSObject
Expand All @@ -31,15 +33,16 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
[params setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]];
}

double latitude = 0, longitude = 0, zoom = 0, bearing = 0;
mbgl::LatLng latLng = mbgl::LatLng(0, 0);
double zoom = 0, bearing = 0;
bool hasCenter = false, hasZoom = false, hasBearing = false;

NSString *centerString = [params objectForKey:@"center"];
if (centerString) {
NSArray *latlon = [centerString componentsSeparatedByString:@","];
if ([latlon count] == 2) {
latitude = [[latlon objectAtIndex:0] doubleValue];
longitude = [[latlon objectAtIndex:1] doubleValue];
NSArray *latLngValues = [centerString componentsSeparatedByString:@","];
if ([latLngValues count] == 2) {
latLng.latitude = [latLngValues[0] doubleValue];
latLng.longitude = [latLngValues[1] doubleValue];
hasCenter = true;
}
}
Expand All @@ -58,9 +61,9 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event

if ([self map]) {
if (hasCenter && hasZoom) {
[self map]->setLonLatZoom(longitude, latitude, zoom);
[self map]->setLatLngZoom(latLng, zoom);
} else if (hasCenter) {
[self map]->setLonLat(longitude, latitude);
[self map]->setLatLng(latLng);
} else if (hasZoom) {
[self map]->setZoom(zoom);
}
Expand Down Expand Up @@ -120,7 +123,7 @@ int main() {

// Load settings
mbgl::Settings_NSUserDefaults settings;
map.setLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom);
map.setBearing(settings.bearing);
map.setDebug(settings.debug);

Expand All @@ -137,7 +140,10 @@ int main() {
[reachability stopNotifier];

// Save settings
map.getLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
mbgl::LatLng latLng = map.getLatLng();
settings.latitude = latLng.latitude;
settings.longitude = latLng.longitude;
settings.zoom = map.getZoom();
settings.bearing = map.getBearing();
settings.debug = map.getDebug();
settings.save();
Expand Down
Loading

0 comments on commit 1444e6f

Please sign in to comment.