summaryrefslogtreecommitdiff
path: root/src/mbgl/map/transform_state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/map/transform_state.cpp')
-rw-r--r--src/mbgl/map/transform_state.cpp153
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 {