diff options
-rw-r--r-- | include/mbgl/map/map.hpp | 3 | ||||
-rw-r--r-- | include/mbgl/map/mode.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/transform.cpp | 9 | ||||
-rw-r--r-- | src/mbgl/map/transform.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 29 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.hpp | 7 | ||||
-rw-r--r-- | test/miscellaneous/transform.cpp | 58 | ||||
-rw-r--r-- | test/style/resource_loading.cpp | 2 |
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); |