diff options
author | Justin R. Miller <incanus@codesorcery.net> | 2015-02-16 09:52:36 -0800 |
---|---|---|
committer | Justin R. Miller <incanus@codesorcery.net> | 2015-02-16 09:52:36 -0800 |
commit | 6e41664cb033ee5edf6ae5ac66ed518d9f0d1f89 (patch) | |
tree | a70192b174ea6dc69b1fa0b13f9a33358a9110e5 /src | |
parent | ea31ad99a56f1e0afbcc7862ddc62dffd16bc5bb (diff) | |
download | qtlocation-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.cpp | 20 | ||||
-rw-r--r-- | src/mbgl/map/transform.cpp | 52 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 153 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 13 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_raster.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/util/constants.cpp | 6 |
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; |