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

fixes #476: pixel / projected meter / lat/long conversions #853

Closed
wants to merge 39 commits into from
Closed
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7e7a896
fixes #97: add LatLng struct & refactor function calls
incanus Sep 30, 2014
6dc3c3f
refs #476: projected meters/pixel/coordinate conversions
incanus Oct 1, 2014
da5b5d4
bring various calculations in line style-wise
incanus Oct 1, 2014
ab5d361
better struct definitions
incanus Oct 2, 2014
846a469
more stylistic consistency tweaks
incanus Oct 2, 2014
291f43b
Merge branch 'conversions' of github.com:mapbox/mapbox-gl-native into…
incanus Oct 2, 2014
07871a3
more precision on max lat
incanus Oct 3, 2014
7762616
wrap longitude
incanus Oct 3, 2014
3c1c80f
correct lat/lon <-> viewport pixel values
incanus Oct 3, 2014
42a5bb9
bump Cocoa
incanus Oct 3, 2014
6ec8db7
properly consider rotation angle in pixel <-> projected meters <-> co…
incanus Oct 7, 2014
3701978
viewport conversions don't make sense in the context of rotations
incanus Oct 8, 2014
6dd3b86
Merge remote-tracking branch 'origin' into conversions
incanus Oct 17, 2014
77ec1dd
bump Cocoa
incanus Oct 17, 2014
3592d93
bump Cocoa
incanus Oct 17, 2014
d9ebdaf
Merge branch 'master' into conversions
incanus Feb 11, 2015
2a06f2d
post-megamerge API updates
incanus Feb 11, 2015
05e6718
iOS API tweaks & ports
incanus Feb 11, 2015
9473aa5
refactor Transform/TransformState/Painter for conversion routines
incanus Feb 12, 2015
d7eca6b
Merge remote-tracking branch 'origin/master' into conversions
incanus Feb 12, 2015
0ab5299
Merge branch 'master' into conversions
incanus Feb 12, 2015
a2a924f
move transform state method to static projection class
incanus Feb 12, 2015
2e11768
renames & reorgs
incanus Feb 12, 2015
aaa3710
cleanup
incanus Feb 12, 2015
ad0890f
LatLng/ProjectedMeters constructors
incanus Feb 12, 2015
72c3ef4
fixes & cleanups
incanus Feb 12, 2015
1455670
use constructors
incanus Feb 12, 2015
2f834f1
fix animation bugs (finalState -> currentState)
incanus Feb 12, 2015
e424f09
fix submodule
incanus Feb 12, 2015
6dc802d
Merge branch 'master' into conversions
incanus Feb 12, 2015
a46750c
headless test fix
incanus Feb 12, 2015
5f7f033
render latlng fix
incanus Feb 12, 2015
5555216
Android latlng fix
incanus Feb 12, 2015
9538a35
fixes for date line & world wrap
incanus Feb 13, 2015
bc3ef1b
Merge remote-tracking branch 'origin/master' into conversions
incanus Feb 13, 2015
429f7cf
get rid of redundant getLatLngZoom() combo function
incanus Feb 14, 2015
f13ea06
x, y by ref -> vec2<double>
incanus Feb 14, 2015
c2a9adb
take transform back out of painter
incanus Feb 14, 2015
4fa1776
Merge remote-tracking branch 'origin/master' into conversions
incanus Feb 14, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 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,18 @@ 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);
double zoom = 0.0;
mbgl::LatLng latLng = mbgl::LatLng();
nativeMapView->getMap().getLatLngZoom(latLng, zoom);

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,6 +2,8 @@
#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>
Expand Down Expand Up @@ -94,8 +96,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());
const LatLng getLatLng() const;
void startPanning();
void stopPanning();
void resetPosition();
Expand All @@ -106,8 +108,8 @@ 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 getLatLngZoom(LatLng &latLng, double &zoom) const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this method and use separate calls to getLatLng() and getZoom()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think so. This was just ported for historical reasons. Good reason to scrap it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of passing out args via reference, there should be a template <class T> class Bounds and the return type of this function should be Bounds<ProjectedMeters>.

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 void pixelForLatLng(const LatLng latLng, double &x, double &y) const { transform.pixelForLatLng(latLng, x, y); }
inline const LatLng latLngForPixel(const double x, const double y) const { return transform.latLngForPixel(x, y); }

// Debug
void setDebug(bool value);
void toggleDebug();
Expand Down
13 changes: 9 additions & 4 deletions include/mbgl/map/transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define MBGL_MAP_TRANSFORM

#include <mbgl/map/transform_state.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>

#include <cstdint>
Expand All @@ -26,10 +27,10 @@ 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());
const LatLng getLatLng() const;
void getLatLngZoom(LatLng &latLng, double& zoom) const;
void startPanning();
void stopPanning();

Expand All @@ -52,6 +53,10 @@ class Transform : private util::noncopyable {
void startRotating();
void stopRotating();

// Projection
void pixelForLatLng(const LatLng latLng, double &x, double &y) const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return vec2<double>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const LatLng latLngForPixel(const double x, const double y) const;

// Transitions
bool needsTransition() const;
void updateTransitions(std::chrono::steady_clock::time_point now);
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
68 changes: 68 additions & 0 deletions include/mbgl/util/projection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#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);

while (longitude > 180) longitude -= 180;
while (longitude < -180) longitude += 180;

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 = mbgl::LatLng();
map.getLatLngZoom(latLng, settings.zoom);
settings.latitude = latLng.latitude;
settings.longitude = latLng.longitude;
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.getLatLngZoom(latLng, settings.zoom);
settings.latitude = latLng.latitude;
settings.longitude = latLng.longitude;
settings.bearing = map.getBearing();
settings.debug = map.getDebug();
settings.save();
Expand Down
Loading