[core] Group Map LatLngBounds, min and max zoom methods

Group bounds, minimum and maximum zoom related methods together using
the new BoundOptions.

v2: Document that getBounds() initializes all optional fields.
  - Add test for getBounds() on a map with default values.
This commit is contained in:
Ander Conselvan de Oliveira
2019-03-08 12:43:05 +02:00
parent 11de777628
commit 5733440747
11 changed files with 126 additions and 59 deletions

View File

@@ -0,0 +1,30 @@
#pragma once
#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
/**
* @brief Holds options to limit what parts of a map are visible. All fields are
* optional.
*/
struct BoundOptions {
/// Sets the latitude and longitude bounds to which the camera center are constrained
BoundOptions& withLatLngBounds(LatLngBounds b) { bounds = b; return *this; }
/// Sets the minimum zoom level
BoundOptions& withMinZoom(double z) { minZoom = z; return *this; }
/// Sets the maximum zoom level
BoundOptions& withMaxZoom(double z) { maxZoom = z; return *this; }
/// Constrain the center of the camera to be within these bounds.
optional<LatLngBounds> bounds;
/// Maximum zoom level allowed.
optional<double> maxZoom;
/// Minimum zoom level allowed.
optional<double> minZoom;
};
} // namespace mbgl

View File

@@ -2,6 +2,7 @@
#include <mbgl/util/optional.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/map/bound_options.hpp>
#include <mbgl/map/map_observer.hpp>
#include <mbgl/map/map_options.hpp>
#include <mbgl/map/mode.hpp>
@@ -76,13 +77,15 @@ public:
CameraOptions cameraForGeometry(const Geometry<double>&, const EdgeInsets&, optional<double> bearing = {}, optional<double> pitch = {}) const;
LatLngBounds latLngBoundsForCamera(const CameraOptions&) const;
// Bounds
void setLatLngBounds(LatLngBounds);
LatLngBounds getLatLngBounds() const;
void setMinZoom(double);
double getMinZoom() const;
void setMaxZoom(double);
double getMaxZoom() const;
/// @name Bounds
/// @{
void setBounds(const BoundOptions& options);
/// Returns the current map bound options. All optional fields in BoundOptions are set.
BoundOptions getBounds() const;
/// @}
// North Orientation
void setNorthOrientation(NorthOrientation);

View File

@@ -287,11 +287,13 @@ void NativeMapView::setStyleJson(jni::JNIEnv& env, const jni::String& json) {
}
void NativeMapView::setLatLngBounds(jni::JNIEnv& env, const jni::Object<mbgl::android::LatLngBounds>& jBounds) {
mbgl::BoundOptions bounds;
if (jBounds) {
map->setLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds));
bounds.withLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds));
} else {
map->setLatLngBounds(mbgl::LatLngBounds::world());
bounds.withLatLngBounds(mbgl::LatLngBounds::world());
}
map->setBounds(bounds);
}
void NativeMapView::cancelTransitions(jni::JNIEnv&) {
@@ -424,19 +426,19 @@ void NativeMapView::resetZoom(jni::JNIEnv&) {
}
void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMinZoom(zoom);
map->setBounds(BoundOptions().withMinZoom(zoom));
}
jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
return map->getMinZoom();
return *map->getBounds().minZoom;
}
void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMaxZoom(zoom);
map->setBounds(BoundOptions().withMaxZoom(zoom));
}
jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) {
return map->getMaxZoom();
return *map->getBounds().maxZoom;
}
void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey, jni::jlong duration) {

View File

@@ -296,7 +296,7 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
mbgl::LatLngBounds bound = bounds[nextBound++];
nextBound = nextBound % bounds.size();
view->map->setLatLngBounds(bound);
view->map->setBounds(mbgl::BoundOptions().withLatLngBounds(bound));
if (bound == mbgl::LatLngBounds::unbounded()) {
view->map->removeAnnotation(boundAnnotationID);

View File

@@ -1661,7 +1661,7 @@ public:
newScale += scale / (velocity * duration) * 0.1;
}
if (newScale <= 0 || log2(newScale) < self.mbglMap.getMinZoom())
if (newScale <= 0 || log2(newScale) < *self.mbglMap.getBounds().minZoom)
{
velocity = 0;
}
@@ -1927,7 +1927,7 @@ public:
if ( ! self.isZoomEnabled) return;
if ([self zoomLevel] == self.mbglMap.getMinZoom()) return;
if ([self zoomLevel] == *self.mbglMap.getBounds().minZoom) return;
[self cancelTransitions];
@@ -1979,7 +1979,7 @@ public:
{
CGFloat distance = [quickZoom locationInView:quickZoom.view].y - self.quickZoomStart;
CGFloat newZoom = MAX(log2f(self.scale) + (distance / 75), self.mbglMap.getMinZoom());
CGFloat newZoom = MAX(log2f(self.scale) + (distance / 75), *self.mbglMap.getBounds().minZoom);
if ([self zoomLevel] == newZoom) return;
@@ -3251,23 +3251,23 @@ public:
- (void)setMinimumZoomLevel:(double)minimumZoomLevel
{
MGLLogDebug(@"Setting minimumZoomLevel: %f", minimumZoomLevel);
self.mbglMap.setMinZoom(minimumZoomLevel);
self.mbglMap.setBounds(mbgl::BoundOptions().withMinZoom(minimumZoomLevel));
}
- (double)minimumZoomLevel
{
return self.mbglMap.getMinZoom();
return *self.mbglMap.getBounds().minZoom;
}
- (void)setMaximumZoomLevel:(double)maximumZoomLevel
{
MGLLogDebug(@"Setting maximumZoomLevel: %f", maximumZoomLevel);
self.mbglMap.setMaxZoom(maximumZoomLevel);
self.mbglMap.setBounds(mbgl::BoundOptions().withMaxZoom(maximumZoomLevel));
}
- (double)maximumZoomLevel
{
return self.mbglMap.getMaxZoom();
return *self.mbglMap.getBounds().maxZoom;
}
- (MGLCoordinateBounds)visibleCoordinateBounds
@@ -5847,7 +5847,7 @@ public:
- (CGFloat)currentMinimumZoom
{
return fmaxf(self.mbglMap.getMinZoom(), MGLMinimumZoom);
return fmaxf(*self.mbglMap.getBounds().minZoom, MGLMinimumZoom);
}
- (BOOL)isRotationAllowed

View File

@@ -328,7 +328,7 @@ public:
mbgl::CameraOptions options;
options.center = mbgl::LatLng(0, 0);
options.padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets);
options.zoom = _mbglMap->getMinZoom();
options.zoom = *_mbglMap->getBounds().minZoom;
_mbglMap->jumpTo(options);
_pendingLatitude = NAN;
_pendingLongitude = NAN;
@@ -1094,21 +1094,21 @@ public:
- (void)setMinimumZoomLevel:(double)minimumZoomLevel
{
MGLLogDebug(@"Setting minimumZoomLevel: %f", minimumZoomLevel);
_mbglMap->setMinZoom(minimumZoomLevel);
_mbglMap->setBounds(mbgl::BoundOptions().withMinZoom(minimumZoomLevel));
}
- (void)setMaximumZoomLevel:(double)maximumZoomLevel
{
MGLLogDebug(@"Setting maximumZoomLevel: %f", maximumZoomLevel);
_mbglMap->setMaxZoom(maximumZoomLevel);
_mbglMap->setBounds(mbgl::BoundOptions().withMaxZoom(maximumZoomLevel));
}
- (double)maximumZoomLevel {
return _mbglMap->getMaxZoom();
return *_mbglMap->getBounds().maxZoom;
}
- (double)minimumZoomLevel {
return _mbglMap->getMinZoom();
return *_mbglMap->getBounds().minZoom;
}
/// Respond to a click on the zoom control.

View File

@@ -765,7 +765,7 @@ void QMapboxGL::setZoom(double zoom_)
*/
double QMapboxGL::minimumZoom() const
{
return d_ptr->mapObj->getMinZoom();
return *d_ptr->mapObj->getBounds().minZoom;
}
/*!
@@ -775,7 +775,7 @@ double QMapboxGL::minimumZoom() const
*/
double QMapboxGL::maximumZoom() const
{
return d_ptr->mapObj->getMaxZoom();
return *d_ptr->mapObj->getBounds().maxZoom;
}
/*!

View File

@@ -328,6 +328,7 @@
"mbgl/layermanager/line_layer_factory.hpp": "include/mbgl/layermanager/line_layer_factory.hpp",
"mbgl/layermanager/raster_layer_factory.hpp": "include/mbgl/layermanager/raster_layer_factory.hpp",
"mbgl/layermanager/symbol_layer_factory.hpp": "include/mbgl/layermanager/symbol_layer_factory.hpp",
"mbgl/map/bound_options.hpp": "include/mbgl/map/bound_options.hpp",
"mbgl/map/camera.hpp": "include/mbgl/map/camera.hpp",
"mbgl/map/change.hpp": "include/mbgl/map/change.hpp",
"mbgl/map/map.hpp": "include/mbgl/map/map.hpp",

View File

@@ -275,36 +275,41 @@ LatLngBounds Map::latLngBoundsForCamera(const CameraOptions& camera) const {
#pragma mark - Bounds
LatLngBounds Map::getLatLngBounds() const {
return impl->transform.getState().getLatLngBounds();
}
void Map::setBounds(const BoundOptions& options) {
bool changeCamera = false;
CameraOptions cameraOptions;
void Map::setLatLngBounds(LatLngBounds bounds) {
impl->cameraMutated = true;
impl->transform.setLatLngBounds(std::move(bounds));
impl->onUpdate();
}
if (options.bounds) {
changeCamera = true;
impl->transform.setLatLngBounds(*options.bounds);
}
void Map::setMinZoom(const double minZoom) {
impl->transform.setMinZoom(minZoom);
if (impl->transform.getZoom() < minZoom) {
jumpTo(CameraOptions().withZoom(minZoom));
if (options.minZoom) {
impl->transform.setMinZoom(*options.minZoom);
if (impl->transform.getZoom() < *options.minZoom) {
changeCamera = true;
cameraOptions.withZoom(*options.minZoom);
}
}
if (options.maxZoom) {
impl->transform.setMaxZoom(*options.maxZoom);
if (impl->transform.getZoom() > *options.maxZoom) {
changeCamera = true;
cameraOptions.withZoom(*options.maxZoom);
}
}
if (changeCamera) {
jumpTo(cameraOptions);
}
}
double Map::getMinZoom() const {
return impl->transform.getState().getMinZoom();
}
void Map::setMaxZoom(const double maxZoom) {
impl->transform.setMaxZoom(maxZoom);
if (impl->transform.getZoom() > maxZoom) {
jumpTo(CameraOptions().withZoom(maxZoom));
}
}
double Map::getMaxZoom() const {
return impl->transform.getState().getMaxZoom();
BoundOptions Map::getBounds() const {
return BoundOptions()
.withLatLngBounds(impl->transform.getState().getLatLngBounds())
.withMinZoom(impl->transform.getState().getMinZoom())
.withMaxZoom(impl->transform.getState().getMaxZoom());
}
#pragma mark - Size

View File

@@ -85,7 +85,7 @@ TEST(Annotations, LineAnnotation) {
test.map.addAnnotation(annotation);
test.checkRendering("line_annotation");
test.map.jumpTo(CameraOptions().withZoom(test.map.getMaxZoom()));
test.map.jumpTo(CameraOptions().withZoom(*test.map.getBounds().maxZoom));
test.checkRendering("line_annotation_max_zoom");
}
@@ -100,7 +100,7 @@ TEST(Annotations, FillAnnotation) {
test.map.addAnnotation(annotation);
test.checkRendering("fill_annotation");
test.map.jumpTo(CameraOptions().withZoom(test.map.getMaxZoom()));
test.map.jumpTo(CameraOptions().withZoom(*test.map.getBounds().maxZoom));
test.checkRendering("fill_annotation_max_zoom");
}
@@ -481,11 +481,11 @@ TEST(Annotations, ChangeMaxZoom) {
annotation.color = Color::red();
annotation.width = { 5 };
test.map.setMaxZoom(6);
test.map.setBounds(BoundOptions().withMaxZoom(6));
test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json"));
test.map.addAnnotation(annotation);
test.map.setMaxZoom(14);
test.map.jumpTo(CameraOptions().withZoom(test.map.getMaxZoom()));
test.map.setBounds(BoundOptions().withMaxZoom(14));
test.map.jumpTo(CameraOptions().withZoom(*test.map.getBounds().maxZoom));
test.checkRendering("line_annotation_max_zoom");
}

View File

@@ -282,6 +282,32 @@ TEST(Map, ProjectionMode) {
EXPECT_EQ(*options.ySkew, 0.0);
}
TEST(Map, BoundOptions) {
MapTest<> test;
LatLngBounds llb = LatLngBounds::hull({-10, -10}, {10, 10});
test.map.setBounds(BoundOptions().withMinZoom(4).withMaxZoom(10).withLatLngBounds(llb));
auto bounds = test.map.getBounds();
EXPECT_EQ(*bounds.minZoom, 4);
EXPECT_EQ(*bounds.maxZoom, 10);
EXPECT_EQ(*bounds.bounds, llb);
}
TEST(Map, DefaultBoundOptions) {
MapTest<> test;
auto bounds = test.map.getBounds();
EXPECT_TRUE(bounds.minZoom);
EXPECT_TRUE(bounds.maxZoom);
EXPECT_TRUE(bounds.bounds);
EXPECT_EQ(*bounds.minZoom, util::MIN_ZOOM);
EXPECT_EQ(*bounds.maxZoom, util::DEFAULT_MAX_ZOOM);
EXPECT_EQ(*bounds.bounds, LatLngBounds::unbounded());
}
TEST(Map, SetStyleInvalidJSON) {
Log::setObserver(std::make_unique<FixtureLogObserver>());