summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);