Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] AddedMap::{set,get}LatLngBounds #8583

Merged
merged 4 commits into from
Apr 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,18 @@ class Map : private util::noncopyable {
CameraOptions cameraForLatLngs(const std::vector<LatLng>&, optional<EdgeInsets>) const;
LatLngBounds latLngBoundsForCamera(const CameraOptions&) const;
void resetZoom();
void setMinZoom(const double minZoom);

// Bounds
void setLatLngBounds(const LatLngBounds&);
LatLngBounds getLatLngBounds() const;
void setMinZoom(double);
double getMinZoom() const;
void setMaxZoom(const double maxZoom);
void setMaxZoom(double);
double getMaxZoom() const;
void setMinPitch(double);
double getMinPitch() const;
void setMaxPitch(double);
double getMaxPitch() const;

// Rotation
void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
Expand Down
15 changes: 15 additions & 0 deletions include/mbgl/util/geo.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <mbgl/math/clamp.hpp>
#include <mbgl/math/wrap.hpp>
#include <mbgl/util/constants.hpp>

Expand Down Expand Up @@ -120,6 +121,10 @@ class LatLngBounds {
// Constructs a LatLngBounds object with the tile's exact boundaries.
LatLngBounds(const CanonicalTileID&);

bool valid() const {
return (sw.latitude() <= ne.latitude()) && (sw.longitude() <= ne.longitude());
}

double south() const { return sw.latitude(); }
double west() const { return sw.longitude(); }
double north() const { return ne.latitude(); }
Expand All @@ -135,6 +140,16 @@ class LatLngBounds {
(sw.longitude() + ne.longitude()) / 2);
}

LatLng constrain(const LatLng& p) const {
if (contains(p)) {
return p;
}
return LatLng {
util::clamp(p.latitude(), sw.latitude(), ne.latitude()),
util::clamp(p.longitude(), sw.longitude(), ne.longitude())
};
}

void extend(const LatLng& point) {
sw = LatLng(std::min(point.latitude(), sw.latitude()),
std::min(point.longitude(), sw.longitude()));
Expand Down
34 changes: 34 additions & 0 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,18 @@ void Map::resetZoom() {
setZoom(0);
}

#pragma mark - Bounds

LatLngBounds Map::getLatLngBounds() const {
return impl->transform.getState().getLatLngBounds();
}

void Map::setLatLngBounds(const LatLngBounds& bounds) {
impl->cameraMutated = true;
impl->transform.setLatLngBounds(bounds);
impl->onUpdate(Update::Repaint);
}

void Map::setMinZoom(const double minZoom) {
impl->transform.setMinZoom(minZoom);
if (getZoom() < minZoom) {
Expand All @@ -686,6 +698,28 @@ double Map::getMaxZoom() const {
return impl->transform.getState().getMaxZoom();
}

void Map::setMinPitch(double minPitch) {
impl->transform.setMinPitch(minPitch * util::DEG2RAD);
if (getPitch() < minPitch) {
setPitch(minPitch);
}
}

double Map::getMinPitch() const {
return impl->transform.getState().getMinPitch() * util::RAD2DEG;
}

void Map::setMaxPitch(double maxPitch) {
impl->transform.setMaxPitch(maxPitch * util::DEG2RAD);
if (getPitch() > maxPitch) {
setPitch(maxPitch);
}
}

double Map::getMaxPitch() const {
return impl->transform.getState().getMaxPitch() * util::RAD2DEG;
}

#pragma mark - Size

void Map::setSize(const Size size) {
Expand Down
22 changes: 20 additions & 2 deletions src/mbgl/map/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
const double scale = state.zoomScale(zoom);
pitch = util::clamp(pitch, 0., util::PITCH_MAX);
pitch = util::clamp(pitch, state.min_pitch, state.max_pitch);

Update update = state.getZoom() == zoom ? Update::Repaint : Update::RecalculateStyle;

Expand Down Expand Up @@ -188,7 +188,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima

// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
pitch = util::clamp(pitch, 0., util::PITCH_MAX);
pitch = util::clamp(pitch, state.min_pitch, state.max_pitch);

// Minimize rotation by taking the shorter path around the circle.
angle = _normalizeAngle(angle, state.angle);
Expand Down Expand Up @@ -433,6 +433,14 @@ void Transform::setScale(double scale, optional<EdgeInsets> padding, const Anima
setScale(scale, anchor, animation);
}

#pragma mark - Bounds

void Transform::setLatLngBounds(const LatLngBounds& bounds) {
if (bounds.valid()) {
state.setLatLngBounds(bounds);
}
}

void Transform::setMinZoom(const double minZoom) {
if (std::isnan(minZoom)) return;
state.setMinZoom(minZoom);
Expand All @@ -443,6 +451,16 @@ void Transform::setMaxZoom(const double maxZoom) {
state.setMaxZoom(maxZoom);
}

void Transform::setMinPitch(double minPitch) {
if (std::isnan(minPitch)) return;
state.setMinPitch(minPitch);
}

void Transform::setMaxPitch(double maxPitch) {
if (std::isnan(maxPitch)) return;
state.setMaxPitch(maxPitch);
}

#pragma mark - Angle

void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
Expand Down
11 changes: 8 additions & 3 deletions src/mbgl/map/transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ class Transform : private util::noncopyable {
LatLng getLatLng(optional<EdgeInsets> = {}) const;
ScreenCoordinate getScreenCoordinate(optional<EdgeInsets> = {}) const;

// Bounds

void setLatLngBounds(const LatLngBounds&);
void setMinZoom(double);
void setMaxZoom(double);
void setMinPitch(double);
void setMaxPitch(double);

// Zoom

/** Scales the map, keeping the given point fixed within the view.
Expand Down Expand Up @@ -94,9 +102,6 @@ class Transform : private util::noncopyable {
/** Returns the scale factor. */
double getScale() const;

void setMinZoom(const double minZoom);
void setMaxZoom(const double maxZoom);

// Angle

void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
Expand Down
36 changes: 34 additions & 2 deletions src/mbgl/map/transform_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ double TransformState::getScale() const {
return scale;
}

#pragma mark - Bounds

void TransformState::setLatLngBounds(const LatLngBounds& bounds_) {
bounds = bounds_;
setLatLngZoom(getLatLng(LatLng::Unwrapped), getZoom());
}

LatLngBounds TransformState::getLatLngBounds() const {
return bounds;
}

void TransformState::setMinZoom(const double minZoom) {
if (minZoom <= getMaxZoom()) {
min_scale = zoomScale(util::clamp(minZoom, util::MIN_ZOOM, util::MAX_ZOOM));
Expand All @@ -165,6 +176,25 @@ double TransformState::getMaxZoom() const {
return scaleZoom(max_scale);
}

void TransformState::setMinPitch(double minPitch) {
if (minPitch <= getMaxPitch()) {
min_pitch = minPitch;
}
}

double TransformState::getMinPitch() const {
return min_pitch;
}

void TransformState::setMaxPitch(double maxPitch) {
if (maxPitch >= getMinPitch()) {
max_pitch = maxPitch;
}
}

double TransformState::getMaxPitch() const {
return max_pitch;
}

#pragma mark - Rotation

Expand Down Expand Up @@ -322,16 +352,18 @@ void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& an
}

void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) {
const LatLng constrained = bounds.constrain(latLng);

double newScale = zoomScale(zoom);
const double newWorldSize = newScale * util::tileSize;
Bc = newWorldSize / util::DEGREES_MAX;
Cc = newWorldSize / util::M2PI;

const double m = 1 - 1e-15;
const double f = util::clamp(std::sin(util::DEG2RAD * latLng.latitude()), -m, m);
const double f = util::clamp(std::sin(util::DEG2RAD * constrained.latitude()), -m, m);

ScreenCoordinate point = {
-latLng.longitude() * Bc,
-constrained.longitude() * Bc,
0.5 * Cc * std::log((1 + f) / (1 - f)),
};
setScalePoint(newScale, point);
Expand Down
16 changes: 14 additions & 2 deletions src/mbgl/map/transform_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,18 @@ class TransformState {
double getZoom() const;
int32_t getIntegerZoom() const;
double getZoomFraction() const;
void setMinZoom(const double minZoom);

// Bounds
void setLatLngBounds(const LatLngBounds&);
LatLngBounds getLatLngBounds() const;
void setMinZoom(double);
double getMinZoom() const;
void setMaxZoom(const double maxZoom);
void setMaxZoom(double);
double getMaxZoom() const;
void setMinPitch(double);
double getMinPitch() const;
void setMaxPitch(double);
double getMaxPitch() const;

// Rotation
float getAngle() const;
Expand Down Expand Up @@ -82,9 +90,13 @@ class TransformState {
bool rotatedNorth() const;
void constrain(double& scale, double& x, double& y) const;

LatLngBounds bounds = LatLngBounds::world();

// Limit the amount of zooming possible on the map.
double min_scale = std::pow(2, 0);
double max_scale = std::pow(2, 20);
double min_pitch = 0.0;
double max_pitch = util::PITCH_MAX;

NorthOrientation orientation = NorthOrientation::Upwards;

Expand Down
57 changes: 57 additions & 0 deletions test/map/transform.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,60 @@ TEST(Transform, DefaultTransform) {
ASSERT_DOUBLE_EQ(point.x, center.x);
ASSERT_DOUBLE_EQ(point.y, center.y);
}

TEST(Transform, LatLngBounds) {
const LatLng nullIsland {};
const LatLng sanFrancisco { 37.7749, -122.4194 };

Transform transform;
transform.resize({ 1000, 1000 });
transform.setLatLngZoom({ 0, 0 }, transform.getState().getMaxZoom());

// Default bounds.
ASSERT_EQ(transform.getState().getLatLngBounds(), LatLngBounds::world());
ASSERT_EQ(transform.getLatLng(), nullIsland);

// Invalid bounds.
transform.setLatLngBounds(LatLngBounds::empty());
ASSERT_EQ(transform.getState().getLatLngBounds(), LatLngBounds::world());

transform.setLatLng(sanFrancisco);
ASSERT_EQ(transform.getLatLng(), sanFrancisco);

// Single location.
transform.setLatLngBounds(LatLngBounds::singleton(sanFrancisco));
ASSERT_EQ(transform.getLatLng(), sanFrancisco);

transform.setLatLngBounds(LatLngBounds::hull({ -90.0, -180.0 }, { 0.0, 180.0 }));
transform.setLatLng(sanFrancisco);
ASSERT_EQ(transform.getLatLng().latitude(), 0.0);
ASSERT_EQ(transform.getLatLng().longitude(), sanFrancisco.longitude());

transform.setLatLngBounds(LatLngBounds::hull({ -90.0, 0.0 }, { 90.0, 180.0 }));
transform.setLatLng(sanFrancisco);
ASSERT_EQ(transform.getLatLng().latitude(), sanFrancisco.latitude());
ASSERT_EQ(transform.getLatLng().longitude(), 0.0);

transform.setLatLngBounds(LatLngBounds::hull({ -90.0, 0.0 }, { 0.0, 180.0 }));
transform.setLatLng(sanFrancisco);
ASSERT_EQ(transform.getLatLng().latitude(), 0.0);
ASSERT_EQ(transform.getLatLng().longitude(), 0.0);
}

TEST(Transform, PitchBounds) {
Transform transform;
transform.resize({ 1000, 1000 });
transform.setLatLngZoom({ 0, 0 }, transform.getState().getMaxZoom());

ASSERT_DOUBLE_EQ(transform.getState().getPitch() * util::RAD2DEG, 0.0);
ASSERT_DOUBLE_EQ(transform.getState().getMinPitch() * util::RAD2DEG, 0.0);
ASSERT_DOUBLE_EQ(transform.getState().getMaxPitch() * util::RAD2DEG, 60.0);

transform.setMinPitch(45.0 * util::DEG2RAD);
transform.setPitch(0.0 * util::DEG2RAD);
ASSERT_NEAR(transform.getState().getPitch() * util::RAD2DEG, 45.0, 1e-5);

transform.setMaxPitch(55.0 * util::DEG2RAD);
transform.setPitch(60.0 * util::DEG2RAD);
ASSERT_NEAR(transform.getState().getPitch() * util::RAD2DEG, 55.0, 1e-5);
}