[core] Moved TileCoordinate to tile cover scope
This commit is contained in:
@@ -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;
|
||||
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
|
||||
};
|
||||
|
||||
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 > 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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user