[core] Rewrite TileCoordinate in terms of geometry.hpp point

This commit is contained in:
John Firebaugh
2016-05-12 12:38:12 -07:00
parent 3e21e3887a
commit 7e5d0ff49e
6 changed files with 68 additions and 113 deletions

View File

@@ -109,14 +109,9 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
// Find the shortest path otherwise.
else startLatLng.unwrapForShortestPath(latLng);
const ScreenCoordinate startPoint = {
state.lngX(startLatLng.longitude),
state.latY(startLatLng.latitude),
};
const ScreenCoordinate endPoint = {
state.lngX(latLng.longitude),
state.latY(latLng.latitude),
};
const Point<double> startPoint = state.project(startLatLng);
const Point<double> endPoint = state.project(latLng);
ScreenCoordinate center = getScreenCoordinate(padding);
center.y = state.height - center.y;
@@ -145,11 +140,8 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
state.rotating = angle != startAngle;
startTransition(camera, animation, [=](double t) {
ScreenCoordinate framePoint = util::interpolate(startPoint, endPoint, t);
LatLng frameLatLng = {
state.yLat(framePoint.y, startWorldSize),
state.xLng(framePoint.x, startWorldSize)
};
Point<double> framePoint = util::interpolate(startPoint, endPoint, t);
LatLng frameLatLng = state.unproject(framePoint, startWorldSize);
double frameScale = util::interpolate(startScale, scale, t);
state.setLatLngZoom(frameLatLng, state.scaleZoom(frameScale));
@@ -191,14 +183,9 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
LatLng startLatLng = getLatLng(padding).wrapped();
startLatLng.unwrapForShortestPath(latLng);
const ScreenCoordinate startPoint = {
state.lngX(startLatLng.longitude),
state.latY(startLatLng.latitude),
};
const ScreenCoordinate endPoint = {
state.lngX(latLng.longitude),
state.latY(latLng.latitude),
};
const Point<double> startPoint = state.project(startLatLng);
const Point<double> endPoint = state.project(latLng);
ScreenCoordinate center = getScreenCoordinate(padding);
center.y = state.height - center.y;
@@ -316,14 +303,11 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
double us = u(s);
// Calculate the current point and zoom level along the flight path.
ScreenCoordinate framePoint = util::interpolate(startPoint, endPoint, us);
Point<double> framePoint = util::interpolate(startPoint, endPoint, us);
double frameZoom = startZoom + state.scaleZoom(1 / w(s));
// Convert to geographic coordinates and set the new viewpoint.
LatLng frameLatLng = {
state.yLat(framePoint.y, startWorldSize),
state.xLng(framePoint.x, startWorldSize),
};
LatLng frameLatLng = state.unproject(framePoint, startWorldSize);
state.setLatLngZoom(frameLatLng, frameZoom);
if (angle != startAngle) {

View File

@@ -201,22 +201,20 @@ bool TransformState::isGestureInProgress() const {
#pragma mark - Projection
double TransformState::lngX(double lng) const {
return (util::LONGITUDE_MAX + lng) * worldSize() / util::DEGREES_MAX;
Point<double> TransformState::project(const LatLng& ll) const {
return Point<double>(
(util::LONGITUDE_MAX + ll.longitude),
(util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + ll.latitude * M_PI / util::DEGREES_MAX)))
) * worldSize() / util::DEGREES_MAX;
}
double TransformState::latY(double lat) const {
double y_ = util::RAD2DEG * std::log(std::tan(M_PI / 4 + lat * M_PI / util::DEGREES_MAX));
return (util::LONGITUDE_MAX - y_) * worldSize() / util::DEGREES_MAX;
}
double TransformState::xLng(double x_, double worldSize_) const {
return x_ * util::DEGREES_MAX / worldSize_ - util::LONGITUDE_MAX;
}
double TransformState::yLat(double y_, double worldSize_) const {
double y2 = util::LONGITUDE_MAX - y_ * util::DEGREES_MAX / worldSize_;
return util::DEGREES_MAX / M_PI * std::atan(std::exp(y2 * util::DEG2RAD)) - 90.0f;
LatLng TransformState::unproject(const Point<double>& p, double worldSize, LatLng::WrapMode wrapMode) const {
Point<double> p2 = p * util::DEGREES_MAX / worldSize;
return LatLng(
util::DEGREES_MAX / M_PI * std::atan(std::exp((util::LONGITUDE_MAX - p2.y) * util::DEG2RAD)) - 90.0f,
p2.x - util::LONGITUDE_MAX,
wrapMode
);
}
double TransformState::zoomScale(double zoom) const {
@@ -234,7 +232,8 @@ double TransformState::worldSize() const {
ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const {
mat4 mat = coordinatePointMatrix(getZoom());
vec4 p;
vec4 c = {{ lngX(latLng.longitude) / util::tileSize, latY(latLng.latitude) / util::tileSize, 0, 1 }};
Point<double> pt = project(latLng) / double(util::tileSize);
vec4 c = {{ pt.x, pt.y, 0, 1 }};
matrix::transformMat4(p, c, mat);
return { p[0] / p[3], height - p[1] / p[3] };
}
@@ -263,19 +262,15 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L
double w0 = coord0[3];
double w1 = coord1[3];
double x0 = coord0[0] / w0;
double x1 = coord1[0] / w1;
double y0 = coord0[1] / w0;
double y1 = coord1[1] / w1;
Point<double> p0 = Point<double>(coord0[0], coord0[1]) / w0;
Point<double> p1 = Point<double>(coord1[0], coord1[1]) / w1;
double z0 = coord0[2] / w0;
double z1 = coord1[2] / w1;
double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0);
return {
yLat(util::interpolate(y0, y1, t), scale),
xLng(util::interpolate(x0, x1, t), scale),
wrapMode
};
return unproject(util::interpolate(p0, p1, t), scale, wrapMode);
}
mat4 TransformState::coordinatePointMatrix(double z) const {
@@ -322,18 +317,10 @@ void TransformState::constrain(double& scale_, double& x_, double& y_) const {
}
void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& anchor) {
auto latLngToTileCoord = [&](const LatLng& ll) -> Point<double> {
return { lngX(ll.longitude), latY(ll.latitude) };
};
auto tileCoordToLatLng = [&](const Point<double> coord) -> LatLng {
return { yLat(coord.y, worldSize()), xLng(coord.x, worldSize()) };
};
auto centerCoord = latLngToTileCoord(getLatLng(LatLng::Unwrapped));
auto latLngCoord = latLngToTileCoord(latLng);
auto anchorCoord = latLngToTileCoord(screenCoordinateToLatLng(anchor));
setLatLngZoom(tileCoordToLatLng(centerCoord + latLngCoord - anchorCoord), getZoom());
auto centerCoord = project(getLatLng(LatLng::Unwrapped));
auto latLngCoord = project(latLng);
auto anchorCoord = project(screenCoordinateToLatLng(anchor));
setLatLngZoom(unproject(centerCoord + latLngCoord - anchorCoord, worldSize()), getZoom());
}
void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) {

View File

@@ -3,6 +3,7 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat4.hpp>
@@ -69,10 +70,8 @@ public:
ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const;
LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Unwrapped) const;
double xLng(double x, double worldSize) const;
double yLat(double y, double worldSize) const;
double lngX(double lon) const;
double latY(double lat) const;
Point<double> project(const LatLng&) const;
LatLng unproject(const Point<double>&, double worldSize, LatLng::WrapMode = LatLng::Unwrapped) const;
private:
bool rotatedNorth() const;

View File

@@ -335,10 +335,10 @@ std::vector<TileCoordinate> pointsToCoordinates(const std::vector<ScreenCoordina
static Point<int16_t> coordinateToTilePoint(const CanonicalTileID& tileID, const TileCoordinate& coord) {
auto zoomedCoord = coord.zoomTo(tileID.z);
return {
int16_t(util::clamp<int64_t>((zoomedCoord.x - tileID.x) * util::EXTENT,
int16_t(util::clamp<int64_t>((zoomedCoord.p.x - tileID.x) * util::EXTENT,
std::numeric_limits<int16_t>::min(),
std::numeric_limits<int16_t>::max())),
int16_t(util::clamp<int64_t>((zoomedCoord.y - tileID.y) * util::EXTENT,
int16_t(util::clamp<int64_t>((zoomedCoord.p.y - tileID.y) * util::EXTENT,
std::numeric_limits<int16_t>::min(),
std::numeric_limits<int16_t>::max()))
};
@@ -364,10 +364,10 @@ std::unordered_map<std::string, std::vector<Feature>> Source::queryRenderedFeatu
double z = queryGeometry[0].z;
for (const auto& c : queryGeometry) {
minX = util::min(minX, c.x);
minY = util::min(minY, c.y);
maxX = util::max(maxX, c.x);
maxY = util::max(maxY, c.y);
minX = util::min(minX, c.p.x);
minY = util::min(minY, c.p.y);
maxX = util::max(maxX, c.p.x);
maxY = util::max(maxY, c.p.y);
}
std::map<CanonicalTileID, TileQuery> tileQueries;
@@ -375,8 +375,8 @@ std::unordered_map<std::string, std::vector<Feature>> Source::queryRenderedFeatu
for (const auto& tilePtr : tiles) {
const auto& tile = tilePtr.second;
auto tileSpaceBoundsMin = coordinateToTilePoint(tile.id.canonical, { minX, minY, z });
auto tileSpaceBoundsMax = coordinateToTilePoint(tile.id.canonical, { maxX, maxY, z });
auto tileSpaceBoundsMin = coordinateToTilePoint(tile.id.canonical, { { minX, minY }, z });
auto tileSpaceBoundsMax = coordinateToTilePoint(tile.id.canonical, { { maxX, maxY }, z });
if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT ||
tileSpaceBoundsMax.x < 0 || tileSpaceBoundsMax.y < 0) continue;

View File

@@ -1,27 +1,20 @@
#ifndef MBGL_UTIL_TILE_COORDINATE
#define MBGL_UTIL_TILE_COORDINATE
#pragma once
#include <mbgl/style/types.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/map/transform_state.hpp>
namespace mbgl {
class TransformState;
// 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, z;
Point<double> p;
double z;
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,
zoom
};
return { state.project(latLng) * scale / double(util::tileSize), zoom };
}
static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& point) {
@@ -29,11 +22,8 @@ public:
}
TileCoordinate zoomTo(double zoom) const {
double scale = std::pow(2, zoom - z);
return { x * scale, y * scale, zoom };
return { p * std::pow(2, zoom - z), zoom };
}
};
} // namespace mbgl
#endif

View File

@@ -16,7 +16,7 @@ struct edge {
double x1 = 0, y1 = 0;
double dx = 0, dy = 0;
edge(TileCoordinate a, TileCoordinate b) {
edge(Point<double> a, Point<double> b) {
if (a.y > b.y) std::swap(a, b);
x0 = a.x;
y0 = a.y;
@@ -54,7 +54,7 @@ static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine sca
}
// scan-line conversion
static void scanTriangle(const TileCoordinate& a, const TileCoordinate& b, const TileCoordinate& c, int32_t ymin, int32_t ymax, ScanLine& scanLine) {
static void scanTriangle(const Point<double>& a, const Point<double>& b, const Point<double>& c, int32_t ymin, int32_t ymax, ScanLine& scanLine) {
edge ab = edge(a, b);
edge bc = edge(b, c);
edge ca = edge(c, a);
@@ -75,17 +75,12 @@ namespace util {
namespace {
std::vector<UnwrappedTileID> tileCover(const TileCoordinate& tl,
const TileCoordinate& tr,
const TileCoordinate& br,
const TileCoordinate& bl,
const TileCoordinate& c,
std::vector<UnwrappedTileID> tileCover(const Point<double>& tl,
const Point<double>& tr,
const Point<double>& br,
const Point<double>& bl,
const Point<double>& c,
int32_t z) {
assert(tl.z == z);
assert(tr.z == z);
assert(br.z == z);
assert(bl.z == z);
assert(c.z == z);
const int32_t tiles = 1 << z;
struct ID {
@@ -154,11 +149,11 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
const TransformState state;
return tileCover(
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()),
TileCoordinate::fromLatLng(state, z, bounds.northwest()).p,
TileCoordinate::fromLatLng(state, z, bounds.northeast()).p,
TileCoordinate::fromLatLng(state, z, bounds.southeast()).p,
TileCoordinate::fromLatLng(state, z, bounds.southwest()).p,
TileCoordinate::fromLatLng(state, z, bounds.center()).p,
z);
}
@@ -166,11 +161,11 @@ std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
const double w = state.getWidth();
const double h = state.getHeight();
return tileCover(
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 }),
TileCoordinate::fromScreenCoordinate(state, z, { 0, 0 }).p,
TileCoordinate::fromScreenCoordinate(state, z, { w, 0 }).p,
TileCoordinate::fromScreenCoordinate(state, z, { w, h }).p,
TileCoordinate::fromScreenCoordinate(state, z, { 0, h }).p,
TileCoordinate::fromScreenCoordinate(state, z, { w/2, h/2 }).p,
z);
}