diff options
Diffstat (limited to 'src/mbgl/map/transform_state.cpp')
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 153 |
1 files changed, 124 insertions, 29 deletions
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 { |