From c3822922680599dc27d1a5f2a81eaab4dc5790d2 Mon Sep 17 00:00:00 2001 From: Adam Hunter Date: Mon, 26 Oct 2015 12:54:43 -0700 Subject: [PATCH] [ios] Fix for #2259 - perspective tilt and cameraForLatLngs --- include/mbgl/map/map.hpp | 2 ++ src/mbgl/map/map.cpp | 49 +++++++++++++++++++++++++++++++- src/mbgl/map/transform.hpp | 1 + src/mbgl/map/transform_state.cpp | 13 +++++---- src/mbgl/map/transform_state.hpp | 2 +- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 65f988b5bfa..626e06d084e 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -183,6 +183,8 @@ class Map : private util::noncopyable { }; RenderState renderState = RenderState::never; + + CameraOptions cameraForLatLngsHelper(std::vector latLngs, EdgeInsets padding); }; } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 729726837d9..1ab13a5d682 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -219,8 +219,31 @@ CameraOptions Map::cameraForLatLngBounds(LatLngBounds bounds, EdgeInsets padding }; return cameraForLatLngs(segment, padding); } - + + CameraOptions Map::cameraForLatLngs(std::vector latLngs, EdgeInsets padding) { + if (getPitch() < 0.01f) { + return cameraForLatLngsHelper(latLngs, padding); + } else { + TransformState oldTransform = this->transform->getState(); + double oldZoom = getZoom(); + + //10 is a magic number; the process is iterative, so we get closer with each call, + //and 10 was chosen to produce good results without taking overly long. It could + //probably be lower, like 4 or 5, without affecting much. + for (int i = 0; i < 10; ++i) { + CameraOptions o = cameraForLatLngsHelper(latLngs, padding); + easeTo(o); + } + CameraOptions result = cameraForLatLngsHelper(latLngs, padding); + this->transform->restoreState(oldTransform); + setZoom(oldZoom); + return result; + } +} + + +CameraOptions Map::cameraForLatLngsHelper(std::vector latLngs, EdgeInsets padding) { CameraOptions options; if (latLngs.empty()) { return options; @@ -259,6 +282,30 @@ CameraOptions Map::cameraForLatLngs(std::vector latLngs, EdgeInsets padd options.center = centerLatLng; options.zoom = zoom; + + if (getPitch() > 0.f) { + TransformState oldTransform = this->transform->getState(); + double oldZoom = getZoom(); + //Now set that camera + easeTo(options); + + //Now calculate the x dimension size relative to the screen width + for (LatLng latLng : latLngs) { + vec2<> pixel = pixelForLatLng(latLng); + swPixel.x = std::min(swPixel.x, pixel.x); + nePixel.x = std::max(nePixel.x, pixel.x); + swPixel.y = std::min(swPixel.y, pixel.y); + nePixel.y = std::max(nePixel.y, pixel.y); + } + size = nePixel - swPixel; + scaleX = (getWidth() - padding.left - padding.right) / size.x; + zoom = ::log2(getScale() * scaleX); + zoom = ::fmax(::fmin(zoom, getMaxZoom()), getMinZoom()); + options.zoom = zoom; + + this->transform->restoreState(oldTransform); + setZoom(oldZoom); + } return options; } diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index 545d8a3b214..1bbc5e524f4 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -60,6 +60,7 @@ class Transform : private util::noncopyable { // Transform state const TransformState getState() const { return state; } + void restoreState(TransformState oldState) { state = oldState; } bool isRotating() const { return state.isRotating(); } bool isScaling() const { return state.isScaling(); } bool isPanning() const { return state.isPanning(); } diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index dd67a17c67f..ef6977cc63b 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -19,16 +19,17 @@ void TransformState::matrixFor(mat4& matrix, const TileID& id, const int8_t z) c } void TransformState::getProjMatrix(mat4& projMatrix) const { - double halfFov = std::atan(0.5 / getAltitude()); - double topHalfSurfaceDistance = std::sin(halfFov) * getAltitude() / + double halfFov = FOV * 0.5f * M_PI / 180.f;//std::atan(0.5 / getAltitude()); + double altitude = 0.5 / std::tan(halfFov); + double topHalfSurfaceDistance = std::sin(halfFov) * altitude / std::sin(M_PI / 2.0f - getPitch() - halfFov); // Calculate z value of the farthest fragment that should be rendered. - double farZ = std::cos(M_PI / 2.0f - getPitch()) * topHalfSurfaceDistance + getAltitude(); + double farZ = std::cos(M_PI / 2.0f - getPitch()) * topHalfSurfaceDistance + altitude; - matrix::perspective(projMatrix, 2.0f * std::atan((getHeight() / 2.0f) / getAltitude()), + matrix::perspective(projMatrix, 2.0f * std::atan((getHeight() / 2.0f) / altitude), double(getWidth()) / getHeight(), 0.1, farZ); - matrix::translate(projMatrix, projMatrix, 0, 0, -getAltitude()); + matrix::translate(projMatrix, projMatrix, 0, 0, -altitude); // After the rotateX, z values are in pixel units. Convert them to // altitude unites. 1 altitude unit = the screen height. @@ -157,6 +158,8 @@ float TransformState::getAngle() const { } float TransformState::getAltitude() const { + double halfFov = FOV * 0.5f * M_PI / 180.f;//std::atan(0.5 / getAltitude()); + double altitude = 0.5 / std::tan(halfFov); return altitude; } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index bb65e0ce711..8d7edf8b42c 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -101,7 +101,7 @@ class TransformState { double x = 0, y = 0; double angle = 0; double scale = 1; - double altitude = 1.5; + double FOV = 36.87; double pitch = 0.0; // cache values for spherical mercator math