summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno de Oliveira Abinader <bruno@mapbox.com>2015-11-17 17:19:54 +0200
committerBruno de Oliveira Abinader <bruno@mapbox.com>2015-11-18 09:37:27 +0200
commitadfac6f0615b7f79da2c80d0580428a92e9f0089 (patch)
treeb6cac5234e13cdd5148efdbb8f3cd1e9c7ed349f
parentcb9b397985b98a75aa9fa5e6f2b135c205f7cafd (diff)
downloadqtlocation-mapboxgl-adfac6f0615b7f79da2c80d0580428a92e9f0089.tar.gz
[core] Added ConstrainMode::{HeightOnly,WidthAndHeight}
ConstrainMode gives flexibility to our engine to choose between constraining both vertically and horizontally, or just vertically (default behavior). Constrain in both axis means we can no longer pan the map beyond the map boundaries. This fixes an issue where e.g. annotations disappear upon crossing the map boundaries.
-rw-r--r--include/mbgl/map/map.hpp3
-rw-r--r--include/mbgl/map/mode.hpp7
-rw-r--r--src/mbgl/map/map.cpp4
-rw-r--r--src/mbgl/map/transform.cpp9
-rw-r--r--src/mbgl/map/transform.hpp7
-rw-r--r--src/mbgl/map/transform_state.cpp29
-rw-r--r--src/mbgl/map/transform_state.hpp7
-rw-r--r--test/miscellaneous/transform.cpp58
-rw-r--r--test/style/resource_loading.cpp2
9 files changed, 93 insertions, 33 deletions
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index f2e605141b..c190088088 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -45,7 +45,8 @@ class Map : private util::noncopyable {
public:
explicit Map(View&, FileSource&,
MapMode mapMode = MapMode::Continuous,
- GLContextMode contextMode = GLContextMode::Unique);
+ GLContextMode contextMode = GLContextMode::Unique,
+ ConstrainMode constrainMode = ConstrainMode::HeightOnly);
~Map();
// Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed.
diff --git a/include/mbgl/map/mode.hpp b/include/mbgl/map/mode.hpp
index 6ad9af5c74..8b65baf99f 100644
--- a/include/mbgl/map/mode.hpp
+++ b/include/mbgl/map/mode.hpp
@@ -19,6 +19,13 @@ enum class GLContextMode : uint8_t {
Shared,
};
+// We can choose to constrain the map both horizontally or vertically, or only
+// vertically e.g. while panning.
+enum class ConstrainMode : uint8_t {
+ HeightOnly,
+ WidthAndHeight,
+};
+
} // namespace mbgl
#endif // MBGL_MAP_MODE
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 69931ed29d..713222fe54 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -14,9 +14,9 @@
namespace mbgl {
-Map::Map(View& view_, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode)
+Map::Map(View& view_, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode)
: view(view_),
- transform(std::make_unique<Transform>(view)),
+ transform(std::make_unique<Transform>(view, constrainMode)),
data(std::make_unique<MapData>(mapMode, contextMode, view.getPixelRatio())),
context(std::make_unique<util::Thread<MapContext>>(util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, *data))
{
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 91fe87791e..55a492c493 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -34,8 +34,9 @@ static double _normalizeAngle(double angle, double anchorAngle)
return angle;
}
-Transform::Transform(View &view_)
+Transform::Transform(View &view_, ConstrainMode constrainMode)
: view(view_)
+ , state(constrainMode)
{
}
@@ -48,7 +49,7 @@ bool Transform::resize(const std::array<uint16_t, 2> size) {
state.width = size[0];
state.height = size[1];
- state.constrain(state.scale, state.y);
+ state.constrain(state.scale, state.x, state.y);
view.notifyMapChange(MapChangeRegionDidChange);
@@ -105,7 +106,7 @@ void Transform::_moveBy(const PrecisionPoint& point, const Duration& duration) {
double x = state.x + std::cos(state.angle) * point.x + std::sin( state.angle) * point.y;
double y = state.y + std::cos(state.angle) * point.y + std::sin(-state.angle) * point.x;
- state.constrain(state.scale, y);
+ state.constrain(state.scale, x, y);
CameraOptions options;
options.duration = duration;
@@ -239,7 +240,7 @@ void Transform::_easeTo(const CameraOptions& options, double new_scale, double n
double x = xn;
double y = yn;
- state.constrain(scale, y);
+ state.constrain(scale, x, y);
double angle = _normalizeAngle(new_angle, state.angle);
state.angle = _normalizeAngle(state.angle, angle);
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index 0fc900dac7..7f424eba2b 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -1,10 +1,11 @@
#ifndef MBGL_MAP_TRANSFORM
#define MBGL_MAP_TRANSFORM
-#include <mbgl/map/transform_state.hpp>
#include <mbgl/map/camera.hpp>
-#include <mbgl/util/chrono.hpp>
+#include <mbgl/map/mode.hpp>
+#include <mbgl/map/transform_state.hpp>
#include <mbgl/map/update.hpp>
+#include <mbgl/util/chrono.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -18,7 +19,7 @@ class View;
class Transform : private util::noncopyable {
public:
- Transform(View&);
+ Transform(View&, ConstrainMode);
// Map view
bool resize(std::array<uint16_t, 2> size);
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index f58bfde8df..44a4c29402 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -7,7 +7,8 @@
using namespace mbgl;
-TransformState::TransformState()
+TransformState::TransformState(ConstrainMode constrainMode_)
+ : constrainMode(constrainMode_)
{
}
@@ -143,8 +144,9 @@ double TransformState::getScale() const {
double TransformState::getMinZoom() const {
double test_scale = scale;
- double test_y = y;
- constrain(test_scale, test_y);
+ double unused_x = x;
+ double unused_y = y;
+ constrain(test_scale, unused_x, unused_y);
return ::log2(::fmin(min_scale, test_scale));
}
@@ -316,17 +318,22 @@ mat4 TransformState::getPixelMatrix() const {
#pragma mark - (private helper functions)
-void TransformState::constrain(double& scale_, double& y_) const {
- // Constrain minimum zoom to avoid zooming out far enough to show off-world areas.
- if (scale_ < height / util::tileSize) {
- scale_ = height / util::tileSize;
+void TransformState::constrain(double& scale_, double& x_, double& y_) const {
+ // Constrain minimum scale to avoid zooming out far enough to show off-world areas.
+ if (constrainMode == ConstrainMode::WidthAndHeight) {
+ scale_ = std::max(scale_, static_cast<double>(width / util::tileSize));
}
- // Constrain min/max vertical pan to avoid showing off-world areas.
- double max_y = ((scale_ * util::tileSize) - height) / 2;
+ scale_ = std::max(scale_, static_cast<double>(height / util::tileSize));
- if (y_ > max_y) y_ = max_y;
- if (y_ < -max_y) y_ = -max_y;
+ // Constrain min/max pan to avoid showing off-world areas.
+ if (constrainMode == ConstrainMode::WidthAndHeight) {
+ double max_x = (scale_ * util::tileSize - width) / 2;
+ x_ = std::max(-max_x, std::min(x_, max_x));
+ }
+
+ double max_y = (scale_ * util::tileSize - height) / 2;
+ y_ = std::max(-max_y, std::min(y_, max_y));
}
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 0373798f00..37ea7fa0f4 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -1,6 +1,7 @@
#ifndef MBGL_MAP_TRANSFORM_STATE
#define MBGL_MAP_TRANSFORM_STATE
+#include <mbgl/map/mode.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/vec.hpp>
@@ -21,7 +22,7 @@ class TransformState {
friend class Transform;
public:
- TransformState();
+ TransformState(ConstrainMode = ConstrainMode::HeightOnly);
// Matrix
void matrixFor(mat4& matrix, const TileID& id, const int8_t z) const;
@@ -73,7 +74,7 @@ public:
TileCoordinate pointToCoordinate(const PrecisionPoint&) const;
private:
- void constrain(double& scale, double& y) const;
+ void constrain(double& scale, double& x, double& y) const;
// Limit the amount of zooming possible on the map.
double min_scale = std::pow(2, 0);
@@ -93,6 +94,8 @@ private:
mat4 getPixelMatrix() const;
private:
+ ConstrainMode constrainMode;
+
// animation state
bool rotating = false;
bool scaling = false;
diff --git a/test/miscellaneous/transform.cpp b/test/miscellaneous/transform.cpp
index 426e9e534d..a5c91b84ef 100644
--- a/test/miscellaneous/transform.cpp
+++ b/test/miscellaneous/transform.cpp
@@ -7,13 +7,13 @@ using namespace mbgl;
TEST(Transform, InvalidScale) {
MockView view;
- Transform transform(view);
+ Transform transform(view, ConstrainMode::HeightOnly);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(1, transform.getScale());
- transform.setScale(2);
+ transform.setScale(2 << 0);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude);
@@ -47,13 +47,13 @@ TEST(Transform, InvalidScale) {
TEST(Transform, InvalidLatLng) {
MockView view;
- Transform transform(view);
+ Transform transform(view, ConstrainMode::HeightOnly);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(1, transform.getScale());
- transform.setScale(2);
+ transform.setScale(2 << 0);
transform.setLatLng({ 8, 10 });
ASSERT_DOUBLE_EQ(8, transform.getLatLng().latitude);
@@ -83,13 +83,13 @@ TEST(Transform, InvalidLatLng) {
TEST(Transform, InvalidBearing) {
MockView view;
- Transform transform(view);
+ Transform transform(view, ConstrainMode::HeightOnly);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude);
ASSERT_DOUBLE_EQ(1, transform.getScale());
- transform.setScale(2);
+ transform.setScale(2 << 0);
transform.setAngle(2);
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
@@ -108,10 +108,10 @@ TEST(Transform, InvalidBearing) {
TEST(Transform, PerspectiveProjection) {
MockView view;
- Transform transform(view);
+ Transform transform(view, ConstrainMode::HeightOnly);
transform.resize({{ 1000, 1000 }});
- transform.setScale(1024);
+ transform.setScale(2 << 9);
transform.setPitch(0.9);
transform.setLatLng(LatLng(38, -77));
@@ -129,7 +129,7 @@ TEST(Transform, PerspectiveProjection) {
ASSERT_NEAR(-76.75823239205641, loc.longitude, 0.0001);
ASSERT_NEAR(37.692872969426375, loc.latitude, 0.0001);
- vec2<double> point = transform.getState().latLngToPoint({38.74661326302018, -77.59198961199148});
+ PrecisionPoint point = transform.getState().latLngToPoint({38.74661326302018, -77.59198961199148});
ASSERT_NEAR(point.x, 0, 0.01);
ASSERT_NEAR(point.y, 1000, 0.01);
@@ -137,3 +137,43 @@ TEST(Transform, PerspectiveProjection) {
ASSERT_NEAR(point.x, 1000, 0.02);
ASSERT_NEAR(point.y, 0, 0.02);
}
+
+TEST(Transform, ConstrainHeightOnly) {
+ MockView view;
+ LatLng loc;
+ LatLngBounds bounds;
+
+ Transform transform(view, ConstrainMode::HeightOnly);
+ transform.resize({{ 1000, 1000 }});
+ transform.setScale(1024);
+
+ transform.setLatLng(bounds.sw);
+ loc = transform.getState().pointToLatLng({ 500, 500 });
+ ASSERT_NEAR(-85.021422866378714, loc.latitude, 0.0001);
+ ASSERT_NEAR(180, std::abs(loc.longitude), 0.0001);
+
+ transform.setLatLng(bounds.ne);
+ loc = transform.getState().pointToLatLng({ 500, 500 });
+ ASSERT_NEAR(85.021422866378742, loc.latitude, 0.0001);
+ ASSERT_NEAR(180, std::abs(loc.longitude), 0.0001);
+}
+
+TEST(Transform, ConstrainWidthAndHeight) {
+ MockView view;
+ LatLng loc;
+ LatLngBounds bounds;
+
+ Transform transform(view, ConstrainMode::WidthAndHeight);
+ transform.resize({{ 1000, 1000 }});
+ transform.setScale(1024);
+
+ transform.setLatLng(bounds.sw);
+ loc = transform.getState().pointToLatLng({ 500, 500 });
+ ASSERT_NEAR(-85.021422866378714, loc.latitude, 0.0001);
+ ASSERT_NEAR(-179.65667724609375, loc.longitude, 0.0001);
+
+ transform.setLatLng(bounds.ne);
+ loc = transform.getState().pointToLatLng({ 500, 500 });
+ ASSERT_NEAR(85.021422866378742, loc.latitude, 0.0001);
+ ASSERT_NEAR(179.65667724609358, std::abs(loc.longitude), 0.0001);
+}
diff --git a/test/style/resource_loading.cpp b/test/style/resource_loading.cpp
index c6f1c1dfae..cdc84e96b2 100644
--- a/test/style/resource_loading.cpp
+++ b/test/style/resource_loading.cpp
@@ -24,7 +24,7 @@ public:
FileSource& fileSource,
const std::function<void(std::exception_ptr error)>& callback)
: data_(MapMode::Still, GLContextMode::Unique, view.getPixelRatio()),
- transform_(view),
+ transform_(view, ConstrainMode::HeightOnly),
callback_(callback) {
util::ThreadContext::setFileSource(&fileSource);