diff options
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 92 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.hpp | 11 | ||||
-rw-r--r-- | src/mbgl/util/tile_coordinate.hpp | 17 | ||||
-rw-r--r-- | src/mbgl/util/tile_cover.cpp | 75 | ||||
-rw-r--r-- | test/map/transform.cpp | 16 |
5 files changed, 85 insertions, 126 deletions
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 99126809ef..b7671058e7 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -1,7 +1,6 @@ #include <mbgl/map/transform_state.hpp> #include <mbgl/map/tile_id.hpp> #include <mbgl/util/constants.hpp> -#include <mbgl/util/tile_coordinate.hpp> #include <mbgl/util/interpolate.hpp> #include <mbgl/util/math.hpp> @@ -89,15 +88,14 @@ ConstrainMode TransformState::getConstrainMode() const { #pragma mark - Position -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); +LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const { + LatLng ll { + util::RAD2DEG * (2 * std::atan(std::exp(y / Cc)) - 0.5 * M_PI), + -x / Bc, + wrapMode + }; - // adjust for world wrap - while (ll.longitude > util::LONGITUDE_MAX) ll.longitude -= util::LONGITUDE_MAX; - while (ll.longitude < -util::LONGITUDE_MAX) ll.longitude += util::LONGITUDE_MAX; + if (wrapMode == LatLng::Unwrapped) return ll; // adjust for date line double w = util::tileSize * scale / 2; @@ -250,46 +248,16 @@ double TransformState::worldSize() const { } ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const { - return coordinateToPoint(latLngToCoordinate(latLng)); -} - -LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point) const { - return coordinateToLatLng(pointToCoordinate(point)); -} - -TileCoordinate TransformState::latLngToCoordinate(const LatLng& latLng) const { - return { - lngX(latLng.longitude) / util::tileSize, - latY(latLng.latitude) / util::tileSize, - getZoom() - }; -} - -LatLng TransformState::coordinateToLatLng(const TileCoordinate& coord) const { - const double worldSize_ = zoomScale(coord.zoom); - LatLng latLng = { - yLat(coord.row, worldSize_), - xLng(coord.column, worldSize_) - }; - while (latLng.longitude < -util::LONGITUDE_MAX) latLng.longitude += 360.0f; - while (latLng.longitude > util::LONGITUDE_MAX) latLng.longitude -= 360.0f; - return latLng; -} - -ScreenCoordinate TransformState::coordinateToPoint(const TileCoordinate& coord) const { - mat4 mat = coordinatePointMatrix(coord.zoom); + mat4 mat = coordinatePointMatrix(getZoom()); vec4<double> p; - vec4<double> c = { coord.column, coord.row, 0, 1 }; + vec4<double> c = { lngX(latLng.longitude) / util::tileSize, latY(latLng.latitude) / util::tileSize, 0, 1 }; matrix::transformMat4(p, c, mat); return { p.x / p.w, height - p.y / p.w }; } -TileCoordinate TransformState::pointToCoordinate(const ScreenCoordinate& point) const { - +LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const { float targetZ = 0; - const double tileZoom = getZoom(); - - mat4 mat = coordinatePointMatrix(tileZoom); + mat4 mat = coordinatePointMatrix(getZoom()); mat4 inverted; bool err = matrix::invert(inverted, mat); @@ -319,8 +287,11 @@ TileCoordinate TransformState::pointToCoordinate(const ScreenCoordinate& point) double z1 = coord1.z / w1; double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0); - - return { util::interpolate(x0, x1, t), util::interpolate(y0, y1, t), tileZoom }; + return { + yLat(util::interpolate(y0, y1, t), scale), + xLng(util::interpolate(x0, x1, t), scale), + wrapMode + }; } mat4 TransformState::coordinatePointMatrix(double z) const { @@ -367,23 +338,20 @@ void TransformState::constrain(double& scale_, double& x_, double& y_) const { } void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& anchor) { - if (!latLng || !anchor) { - return; - } - - auto coord = latLngToCoordinate(latLng); - auto coordAtPoint = pointToCoordinate(anchor); - auto coordCenter = pointToCoordinate({ width / 2.0f, height / 2.0f }); - - float columnDiff = coordAtPoint.column - coord.column; - float rowDiff = coordAtPoint.row - coord.row; - - auto newLatLng = coordinateToLatLng({ - coordCenter.column - columnDiff, - coordCenter.row - rowDiff, - coordCenter.zoom - }); - setLatLngZoom(newLatLng, coordCenter.zoom); + if (!latLng || !anchor) return; + + auto latLngToTileCoord = [&](const LatLng& ll) -> vec2<double> { + return { lngX(ll.longitude) / util::tileSize, latY(ll.latitude) / util::tileSize }; + }; + + auto tileCoordToLatLng = [&](const vec2<double> coord) -> LatLng { + return { yLat(coord.y, scale), xLng(coord.x, scale) }; + }; + + auto centerCoord = latLngToTileCoord(getLatLng(LatLng::Unwrapped)); + auto latLngCoord = latLngToTileCoord(latLng); + auto anchorCoord = latLngToTileCoord(screenCoordinateToLatLng(anchor, LatLng::Unwrapped)); + setLatLngZoom(tileCoordToLatLng(centerCoord + latLngCoord - anchorCoord), getZoom()); } void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 9f5f3a744d..e122fd8ac1 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -14,7 +14,6 @@ namespace mbgl { class TileID; -class TileCoordinate; class TransformState { friend class Transform; @@ -38,7 +37,7 @@ public: ConstrainMode getConstrainMode() const; // Position - LatLng getLatLng() const; + LatLng getLatLng(LatLng::WrapMode = LatLng::Wrapped) const; double pixel_x() const; double pixel_y() const; @@ -66,13 +65,7 @@ public: // Conversion and projection ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const; - LatLng screenCoordinateToLatLng(const ScreenCoordinate&) const; - - TileCoordinate latLngToCoordinate(const LatLng&) const; - LatLng coordinateToLatLng(const TileCoordinate&) const; - - ScreenCoordinate coordinateToPoint(const TileCoordinate&) const; - TileCoordinate pointToCoordinate(const ScreenCoordinate&) const; + LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Wrapped) const; double xLng(double x, double worldSize) const; double yLat(double y, double worldSize) const; diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp deleted file mode 100644 index a989bef0c9..0000000000 --- a/src/mbgl/util/tile_coordinate.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MBGL_UTIL_TILE_COORDINATE -#define MBGL_UTIL_TILE_COORDINATE - -#include <mbgl/util/vec.hpp> - -namespace mbgl { - -class TileCoordinate { -public: - double column; - double row; - double zoom; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index 7af3ebd8b1..0fae940271 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -1,20 +1,40 @@ #include <mbgl/util/tile_cover.hpp> #include <mbgl/util/vec.hpp> -#include <mbgl/util/tile_coordinate.hpp> #include <mbgl/util/constants.hpp> +#include <mbgl/util/interpolate.hpp> #include <mbgl/map/transform_state.hpp> namespace mbgl { +namespace { + +// Has floating point x/y coordinates. +// Used for computing the tiles that need to be visible in the viewport. +class TileCoordinate { +public: + double x, y; + + static TileCoordinate fromLatLng(const TransformState& state, double zoom, const LatLng& latLng) { + const double scale = std::pow(2, zoom - state.getZoom()); + return { + state.lngX(latLng.longitude) * scale / util::tileSize, + state.latY(latLng.latitude) * scale / util::tileSize, + }; + } + + static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& point) { + return fromLatLng(state, zoom, state.screenCoordinateToLatLng(point, LatLng::Unwrapped)); + } +}; + // Taken from polymaps src/Layer.js // https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383 - struct edge { double x0 = 0, y0 = 0; double x1 = 0, y1 = 0; double dx = 0, dy = 0; - edge(ScreenCoordinate a, ScreenCoordinate b) { + edge(TileCoordinate a, TileCoordinate b) { if (a.y > b.y) std::swap(a, b); x0 = a.x; y0 = a.y; @@ -25,7 +45,7 @@ struct edge { } }; -typedef const std::function<void(int32_t x0, int32_t x1, int32_t y)> ScanLine; +using ScanLine = const std::function<void(int32_t x0, int32_t x1, int32_t y)>; // scan-line conversion static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine) { @@ -52,7 +72,7 @@ static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine sca } // scan-line conversion -static void scanTriangle(const ScreenCoordinate& a, const ScreenCoordinate& b, const ScreenCoordinate& c, int32_t ymin, int32_t ymax, ScanLine& scanLine) { +static void scanTriangle(const TileCoordinate& a, const TileCoordinate& b, const TileCoordinate& c, int32_t ymin, int32_t ymax, ScanLine& scanLine) { edge ab = edge(a, b); edge bc = edge(b, c); edge ca = edge(c, a); @@ -67,6 +87,8 @@ static void scanTriangle(const ScreenCoordinate& a, const ScreenCoordinate& b, c if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine); } +} // namespace + int32_t coveringZoomLevel(double zoom, SourceType type, uint16_t tileSize) { zoom += std::log(util::tileSize / tileSize) / std::log(2); if (type == SourceType::Raster || type == SourceType::Video) { @@ -76,16 +98,11 @@ int32_t coveringZoomLevel(double zoom, SourceType type, uint16_t tileSize) { } } -static ScreenCoordinate zoomTo(const TileCoordinate& c, double z) { - double scale = std::pow(2, z - c.zoom); - return { c.column * scale, c.row * scale }; -} - -std::vector<TileID> tileCover(const TileCoordinate& tl_, - const TileCoordinate& tr_, - const TileCoordinate& br_, - const TileCoordinate& bl_, - const TileCoordinate& center, +std::vector<TileID> tileCover(const TileCoordinate& tl, + const TileCoordinate& tr, + const TileCoordinate& br, + const TileCoordinate& bl, + const TileCoordinate& c, int32_t z, int32_t actualZ) { int32_t tiles = 1 << z; @@ -94,18 +111,12 @@ std::vector<TileID> tileCover(const TileCoordinate& tl_, auto scanLine = [&](int32_t x0, int32_t x1, int32_t y) { int32_t x; if (y >= 0 && y <= tiles) { - for (x = x0; x < x1; x++) { + for (x = x0; x < x1; ++x) { t.emplace_front(actualZ, x, y, z); } } }; - const ScreenCoordinate tl(zoomTo(tl_, z)); - const ScreenCoordinate tr(zoomTo(tr_, z)); - const ScreenCoordinate br(zoomTo(br_, z)); - const ScreenCoordinate bl(zoomTo(bl_, z)); - const ScreenCoordinate c(zoomTo(center, z)); - // Divide the screen up in two triangles and scan each of them: // \---+ // | \ | @@ -138,11 +149,11 @@ std::vector<TileID> tileCover(const LatLngBounds& bounds_, int32_t z, int32_t ac const TransformState state; return tileCover( - state.latLngToCoordinate(bounds.northwest()), - state.latLngToCoordinate(bounds.northeast()), - state.latLngToCoordinate(bounds.southeast()), - state.latLngToCoordinate(bounds.southwest()), - state.latLngToCoordinate(bounds.center()), + TileCoordinate::fromLatLng(state, z, bounds.northwest()), + TileCoordinate::fromLatLng(state, z, bounds.northeast()), + TileCoordinate::fromLatLng(state, z, bounds.southeast()), + TileCoordinate::fromLatLng(state, z, bounds.southwest()), + TileCoordinate::fromLatLng(state, z, bounds.center()), z, actualZ); } @@ -150,11 +161,11 @@ std::vector<TileID> tileCover(const TransformState& state, int32_t z, int32_t ac const double w = state.getWidth(); const double h = state.getHeight(); return tileCover( - state.pointToCoordinate({ 0, 0 }), - state.pointToCoordinate({ w, 0 }), - state.pointToCoordinate({ w, h }), - state.pointToCoordinate({ 0, h }), - state.pointToCoordinate({ w/2, h/2 }), + TileCoordinate::fromScreenCoordinate(state, z, { 0, 0 }), + TileCoordinate::fromScreenCoordinate(state, z, { w, 0 }), + TileCoordinate::fromScreenCoordinate(state, z, { w, h }), + TileCoordinate::fromScreenCoordinate(state, z, { 0, h }), + TileCoordinate::fromScreenCoordinate(state, z, { w/2, h/2 }), z, actualZ); } diff --git a/test/map/transform.cpp b/test/map/transform.cpp index 15b86f3d30..98fc1223e5 100644 --- a/test/map/transform.cpp +++ b/test/map/transform.cpp @@ -150,17 +150,21 @@ TEST(Transform, UnwrappedLatLng) { const TransformState& state = transform.getState(); + LatLng fromGetLatLng = state.getLatLng(); + ASSERT_DOUBLE_EQ(fromGetLatLng.latitude, 38); + ASSERT_DOUBLE_EQ(fromGetLatLng.longitude, -77); + LatLng fromScreenCoordinate = state.screenCoordinateToLatLng({ 500, 500 }); ASSERT_NEAR(fromScreenCoordinate.latitude, 37.999999999999829, 0.0001); // 1.71E-13 ASSERT_NEAR(fromScreenCoordinate.longitude, -76.999999999999773, 0.0001); // 2.27E-13 - LatLng unwrappedForwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, 283 })); - ASSERT_NEAR(unwrappedForwards.latitude, 37.999999999999716, 0.0001); // 2.84E-13 - ASSERT_DOUBLE_EQ(unwrappedForwards.longitude, fromScreenCoordinate.longitude); + LatLng wrappedForwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, 283, LatLng::Wrapped })); + ASSERT_NEAR(wrappedForwards.latitude, 37.999999999999716, 0.0001); // 2.84E-13 + ASSERT_DOUBLE_EQ(wrappedForwards.longitude, fromScreenCoordinate.longitude); - LatLng unwrappedBackwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, -437 })); - ASSERT_DOUBLE_EQ(unwrappedBackwards.latitude, unwrappedForwards.latitude); - ASSERT_DOUBLE_EQ(unwrappedBackwards.longitude, fromScreenCoordinate.longitude); + LatLng wrappedBackwards = state.screenCoordinateToLatLng(state.latLngToScreenCoordinate({ 38, -437, LatLng::Wrapped })); + ASSERT_DOUBLE_EQ(wrappedBackwards.latitude, wrappedForwards.latitude); + ASSERT_DOUBLE_EQ(wrappedBackwards.longitude, fromScreenCoordinate.longitude); } TEST(Transform, ConstrainHeightOnly) { |