summaryrefslogtreecommitdiff
path: root/src
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 /src
parentea31ad99a56f1e0afbcc7862ddc62dffd16bc5bb (diff)
downloadqtlocation-mapboxgl-6e41664cb033ee5edf6ae5ac66ed518d9f0d1f89.tar.gz
fixes #476 & #853: pixel/meter/latlng conversion routines in core & iOS
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/map/map.cpp20
-rw-r--r--src/mbgl/map/transform.cpp52
-rw-r--r--src/mbgl/map/transform_state.cpp153
-rw-r--r--src/mbgl/renderer/painter.cpp13
-rw-r--r--src/mbgl/renderer/painter_raster.cpp1
-rw-r--r--src/mbgl/util/constants.cpp6
6 files changed, 162 insertions, 83 deletions
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 5aff7a2b78..ed20ec24a6 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -407,15 +407,11 @@ void Map::moveBy(double dx, double dy, std::chrono::steady_clock::duration durat
update();
}
-void Map::setLonLat(double lon, double lat, std::chrono::steady_clock::duration duration) {
- transform.setLonLat(lon, lat, duration);
+void Map::setLatLng(LatLng latLng, std::chrono::steady_clock::duration duration) {
+ transform.setLatLng(latLng, duration);
update();
}
-void Map::getLonLat(double& lon, double& lat) const {
- transform.getLonLat(lon, lat);
-}
-
void Map::startPanning() {
transform.startPanning();
update();
@@ -428,7 +424,7 @@ void Map::stopPanning() {
void Map::resetPosition() {
transform.setAngle(0);
- transform.setLonLat(0, 0);
+ transform.setLatLng(LatLng(0, 0));
transform.setZoom(0);
update();
}
@@ -459,15 +455,11 @@ double Map::getZoom() const {
return transform.getZoom();
}
-void Map::setLonLatZoom(double lon, double lat, double zoom, std::chrono::steady_clock::duration duration) {
- transform.setLonLatZoom(lon, lat, zoom, duration);
+void Map::setLatLngZoom(LatLng latLng, double zoom, std::chrono::steady_clock::duration duration) {
+ transform.setLatLngZoom(latLng, zoom, duration);
update();
}
-void Map::getLonLatZoom(double& lon, double& lat, double& zoom) const {
- transform.getLonLatZoom(lon, lat, zoom);
-}
-
void Map::resetZoom() {
setZoom(0);
}
@@ -697,7 +689,7 @@ void Map::prepare() {
void Map::render() {
assert(painter);
painter->render(*style, activeSources,
- state, animationTime);
+ state, animationTime);
// Schedule another rerender when we definitely need a next frame.
if (transform.needsTransition() || style->hasTransitions()) {
update();
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 7952531192..f3b14731e1 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -11,9 +11,6 @@
using namespace mbgl;
-const double D2R = M_PI / 180.0;
-const double M2PI = 2 * M_PI;
-
Transform::Transform(View &view_)
: view(view_)
{
@@ -83,44 +80,34 @@ void Transform::_moveBy(const double dx, const double dy, const std::chrono::ste
duration);
}
-void Transform::setLonLat(const double lon, const double lat, const std::chrono::steady_clock::duration duration) {
+void Transform::setLatLng(const LatLng latLng, const std::chrono::steady_clock::duration duration) {
std::lock_guard<std::recursive_mutex> lock(mtx);
- const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999);
- double xn = -lon * Bc;
- double yn = 0.5 * Cc * std::log((1 + f) / (1 - f));
+ const double m = 1 - 1e-15;
+ const double f = std::fmin(std::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
+
+ double xn = -latLng.longitude * current.Bc;
+ double yn = 0.5 * current.Cc * std::log((1 + f) / (1 - f));
_setScaleXY(current.scale, xn, yn, duration);
}
-void Transform::setLonLatZoom(const double lon, const double lat, const double zoom,
- const std::chrono::steady_clock::duration duration) {
+void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const std::chrono::steady_clock::duration duration) {
std::lock_guard<std::recursive_mutex> lock(mtx);
double new_scale = std::pow(2.0, zoom);
const double s = new_scale * util::tileSize;
- Bc = s / 360;
- Cc = s / (2 * M_PI);
-
- const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999);
- double xn = -lon * Bc;
- double yn = 0.5 * Cc * log((1 + f) / (1 - f));
-
- _setScaleXY(new_scale, xn, yn, duration);
-}
+ current.Bc = s / 360;
+ current.Cc = s / util::M2PI;
-void Transform::getLonLat(double &lon, double &lat) const {
- std::lock_guard<std::recursive_mutex> lock(mtx);
-
- final.getLonLat(lon, lat);
-}
+ const double m = 1 - 1e-15;
+ const double f = std::fmin(std::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
-void Transform::getLonLatZoom(double &lon, double &lat, double &zoom) const {
- std::lock_guard<std::recursive_mutex> lock(mtx);
+ double xn = -latLng.longitude * current.Bc;
+ double yn = 0.5 * current.Cc * std::log((1 + f) / (1 - f));
- getLonLat(lon, lat);
- zoom = getZoom();
+ _setScaleXY(new_scale, xn, yn, duration);
}
void Transform::startPanning() {
@@ -181,7 +168,7 @@ void Transform::setZoom(const double zoom, const std::chrono::steady_clock::dura
double Transform::getZoom() const {
std::lock_guard<std::recursive_mutex> lock(mtx);
- return std::log(final.scale) / M_LN2;
+ return final.getZoom();
}
double Transform::getScale() const {
@@ -293,8 +280,8 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
}
const double s = final.scale * util::tileSize;
- Bc = s / 360;
- Cc = s / (2 * M_PI);
+ current.Bc = s / 360;
+ current.Cc = s / util::M2PI;
view.notifyMapChange(duration != std::chrono::steady_clock::duration::zero() ?
MapChangeRegionDidChangeAnimated :
@@ -380,9 +367,9 @@ void Transform::_setAngle(double new_angle, const std::chrono::steady_clock::dur
MapChangeRegionWillChange);
while (new_angle > M_PI)
- new_angle -= M2PI;
+ new_angle -= util::M2PI;
while (new_angle <= -M_PI)
- new_angle += M2PI;
+ new_angle += util::M2PI;
final.angle = new_angle;
@@ -434,6 +421,7 @@ void Transform::_clearRotating() {
}
}
+
#pragma mark - Transition
bool Transform::needsTransition() const {
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index a7da8ccab2..8c007210e0 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -1,11 +1,10 @@
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/projection.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/box.hpp>
using namespace mbgl;
-const double R2D = 180.0 / M_PI;
-
#pragma mark - Matrix
void TransformState::matrixFor(mat4& matrix, const Tile::ID& id) const {
@@ -90,34 +89,43 @@ float TransformState::getPixelRatio() const {
return pixelRatio;
}
-float TransformState::worldSize() const {
- return scale * util::tileSize;
-}
-
-float TransformState::lngX(float lon) const {
- return (180 + lon) * worldSize() / 360;
-}
-
-float TransformState::latY(float lat) const {
- float lat_y = 180 / M_PI * std::log(std::tan(M_PI / 4 + lat * M_PI / 360));
- return (180 - lat_y) * worldSize() / 360;
-}
-std::array<float, 2> TransformState::locationCoordinate(float lon, float lat) const {
- float k = std::pow(2, getIntegerZoom()) / worldSize();
- return {{
- lngX(lon) * k,
- latY(lat) * k
- }};
-}
-
-void TransformState::getLonLat(double &lon, double &lat) const {
- const double s = scale * util::tileSize;
- const double Bc = s / 360;
- const double Cc = s / (2 * M_PI);
-
- lon = -x / Bc;
- lat = R2D * (2 * std::atan(std::exp(y / Cc)) - 0.5 * M_PI);
+#pragma mark - Position
+
+const LatLng TransformState::getLatLng() const {
+ LatLng ll;
+
+ ll.longitude = -x / Bc;
+ ll.latitude = util::RAD2DEG * (2 * std::atan(std::exp(y / Cc)) - 0.5 * M_PI);
+
+ // adjust for world wrap
+ while (ll.longitude > 180) ll.longitude -= 180;
+ while (ll.longitude < -180) ll.longitude += 180;
+
+ // adjust for date line
+ double w = util::tileSize * scale / 2;
+ double x_ = x;
+ if (x_ > w) {
+ while (x_ > w) {
+ x_ -= w;
+ if (ll.longitude < 0) {
+ ll.longitude += 180;
+ } else if (ll.longitude > 0) {
+ ll.longitude -= 180;
+ }
+ }
+ } else if (x_ < -w) {
+ while (x_ < -w) {
+ x_ += w;
+ if (ll.longitude < 0) {
+ ll.longitude -= 180;
+ } else if (ll.longitude > 0) {
+ ll.longitude -= 180;
+ }
+ }
+ }
+
+ return ll;
}
@@ -151,6 +159,93 @@ float TransformState::getAngle() const {
}
+#pragma mark - Projection
+
+const vec2<double> TransformState::pixelForLatLng(const LatLng latLng) const {
+ LatLng ll = getLatLng();
+ double zoom = getZoom();
+
+ const double centerX = width / 2;
+ const double centerY = height / 2;
+
+ const double m = Projection::getMetersPerPixelAtLatitude(0, zoom);
+
+ const double angle_sin = std::sin(-angle);
+ const double angle_cos = std::cos(-angle);
+
+ const ProjectedMeters givenMeters = Projection::projectedMetersForLatLng(latLng);
+
+ const double givenAbsoluteX = givenMeters.easting / m;
+ const double givenAbsoluteY = givenMeters.northing / m;
+
+ const ProjectedMeters centerMeters = Projection::projectedMetersForLatLng(ll);
+
+ const double centerAbsoluteX = centerMeters.easting / m;
+ const double centerAbsoluteY = centerMeters.northing / m;
+
+ const double deltaX = givenAbsoluteX - centerAbsoluteX;
+ const double deltaY = givenAbsoluteY - centerAbsoluteY;
+
+ const double translatedX = deltaX + centerX;
+ const double translatedY = deltaY + centerY;
+
+ const double rotatedX = translatedX * angle_cos - translatedY * angle_sin;
+ const double rotatedY = translatedX * angle_sin + translatedY * angle_cos;
+
+ const double rotatedCenterX = centerX * angle_cos - centerY * angle_sin;
+ const double rotatedCenterY = centerX * angle_sin + centerY * angle_cos;
+
+ double x_ = rotatedX + (centerX - rotatedCenterX);
+ double y_ = rotatedY + (centerY - rotatedCenterY);
+
+ return vec2<double>(x_, y_);
+}
+
+const LatLng TransformState::latLngForPixel(const vec2<double> pixel) const {
+ LatLng ll = getLatLng();
+ double zoom = getZoom();
+
+ const double centerX = width / 2;
+ const double centerY = height / 2;
+
+ const double m = Projection::getMetersPerPixelAtLatitude(0, zoom);
+
+ const double angle_sin = std::sin(angle);
+ const double angle_cos = std::cos(angle);
+
+ const double unrotatedCenterX = centerX * angle_cos - centerY * angle_sin;
+ const double unrotatedCenterY = centerX * angle_sin + centerY * angle_cos;
+
+ const double unrotatedX = pixel.x * angle_cos - pixel.y * angle_sin;
+ const double unrotatedY = pixel.x * angle_sin + pixel.y * angle_cos;
+
+ const double givenX = unrotatedX + (centerX - unrotatedCenterX);
+ const double givenY = unrotatedY + (centerY - unrotatedCenterY);
+
+ const ProjectedMeters centerMeters = Projection::projectedMetersForLatLng(ll);
+
+ const double centerAbsoluteX = centerMeters.easting / m;
+ const double centerAbsoluteY = centerMeters.northing / m;
+
+ const double givenAbsoluteX = givenX + centerAbsoluteX - centerX;
+ const double givenAbsoluteY = givenY + centerAbsoluteY - centerY;
+
+ ProjectedMeters givenMeters = ProjectedMeters(givenAbsoluteY * m, givenAbsoluteX * m);
+
+ // adjust for date line
+ ProjectedMeters sw, ne;
+ Projection::getWorldBoundsMeters(sw, ne);
+ double d = ne.easting - sw.easting;
+ if (ll.longitude > 0 && givenMeters.easting > centerMeters.easting) givenMeters.easting -= d;
+
+ // adjust for world wrap
+ while (givenMeters.easting < sw.easting) givenMeters.easting += d;
+ while (givenMeters.easting > ne.easting) givenMeters.easting -= d;
+
+ return Projection::latLngForProjectedMeters(givenMeters);
+}
+
+
#pragma mark - Changing
bool TransformState::isChanging() const {
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 116ae3ad2f..044604f5b4 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -392,9 +392,8 @@ void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) {
patternShader->u_mix = properties.image.t;
patternShader->u_opacity = properties.opacity;
- double lon, lat;
- state.getLonLat(lon, lat);
- std::array<float, 2> center = state.locationCoordinate(lon, lat);
+ LatLng latLng = state.getLatLng();
+ vec2<double> center = state.pixelForLatLng(latLng);
float scale = 1 / std::pow(2, zoomFraction);
std::array<float, 2> sizeA = imagePosA.size;
@@ -404,8 +403,8 @@ void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) {
1.0f / (sizeA[0] * properties.image.fromScale),
1.0f / (sizeA[1] * properties.image.fromScale));
matrix::translate(matrixA, matrixA,
- std::fmod(center[0] * 512, sizeA[0] * properties.image.fromScale),
- std::fmod(center[1] * 512, sizeA[1] * properties.image.fromScale));
+ std::fmod(center.x * 512, sizeA[0] * properties.image.fromScale),
+ std::fmod(center.y * 512, sizeA[1] * properties.image.fromScale));
matrix::rotate(matrixA, matrixA, -state.getAngle());
matrix::scale(matrixA, matrixA,
scale * state.getWidth() / 2,
@@ -418,8 +417,8 @@ void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) {
1.0f / (sizeB[0] * properties.image.toScale),
1.0f / (sizeB[1] * properties.image.toScale));
matrix::translate(matrixB, matrixB,
- std::fmod(center[0] * 512, sizeB[0] * properties.image.toScale),
- std::fmod(center[1] * 512, sizeB[1] * properties.image.toScale));
+ std::fmod(center.x * 512, sizeB[0] * properties.image.toScale),
+ std::fmod(center.y * 512, sizeB[1] * properties.image.toScale));
matrix::rotate(matrixB, matrixB, -state.getAngle());
matrix::scale(matrixB, matrixB,
scale * state.getWidth() / 2,
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index a85b773788..4ece54977b 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -5,7 +5,6 @@
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/transform.hpp>
using namespace mbgl;
diff --git a/src/mbgl/util/constants.cpp b/src/mbgl/util/constants.cpp
index 3d1422e6c7..ccdbeba23a 100644
--- a/src/mbgl/util/constants.cpp
+++ b/src/mbgl/util/constants.cpp
@@ -2,6 +2,12 @@
const float mbgl::util::tileSize = 512.0f;
+const double mbgl::util::DEG2RAD = M_PI / 180.0;
+const double mbgl::util::RAD2DEG = 180.0 / M_PI;
+const double mbgl::util::M2PI = 2 * M_PI;
+const double mbgl::util::EARTH_RADIUS_M = 6378137;
+const double mbgl::util::LATITUDE_MAX = 85.05112878;
+
#if defined(DEBUG)
const bool mbgl::debug::tileParseWarnings = false;
const bool mbgl::debug::styleParseWarnings = false;