summaryrefslogtreecommitdiff
path: root/src/mbgl/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/map')
-rw-r--r--src/mbgl/map/camera.cpp1
-rw-r--r--src/mbgl/map/map.cpp42
-rw-r--r--src/mbgl/map/transform.cpp182
-rw-r--r--src/mbgl/map/transform.hpp11
4 files changed, 131 insertions, 105 deletions
diff --git a/src/mbgl/map/camera.cpp b/src/mbgl/map/camera.cpp
new file mode 100644
index 0000000000..4a45e904f8
--- /dev/null
+++ b/src/mbgl/map/camera.cpp
@@ -0,0 +1 @@
+#include <mbgl/map/camera.hpp>
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 82ab72db2d..9195f6b583 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -9,6 +9,7 @@
#include <mbgl/util/projection.hpp>
#include <mbgl/util/thread.hpp>
+#include <mbgl/util/math.hpp>
namespace mbgl {
@@ -114,6 +115,18 @@ void Map::setGestureInProgress(bool inProgress) {
update(Update::Repaint);
}
+#pragma mark -
+
+void Map::jumpTo(CameraOptions options) {
+ transform->jumpTo(options);
+ update(Update::Repaint);
+}
+
+void Map::easeTo(CameraOptions options) {
+ transform->easeTo(options);
+ update(options.zoom ? Update::Zoom : Update::Repaint);
+}
+
#pragma mark - Position
void Map::moveBy(double dx, double dy, const Duration& duration) {
@@ -131,9 +144,11 @@ LatLng Map::getLatLng() const {
}
void Map::resetPosition() {
- transform->setAngle(0);
- transform->setLatLng(LatLng(0, 0));
- transform->setZoom(0);
+ CameraOptions options;
+ options.angle = 0;
+ options.center = LatLng(0, 0);
+ options.zoom = 0;
+ transform->jumpTo(options);
update(Update::Zoom);
}
@@ -168,25 +183,26 @@ void Map::setLatLngZoom(LatLng latLng, double zoom, const Duration& duration) {
update(Update::Zoom);
}
-void Map::fitBounds(LatLngBounds bounds, EdgeInsets padding, const Duration& duration) {
+CameraOptions Map::cameraForLatLngBounds(LatLngBounds bounds, EdgeInsets padding) {
AnnotationSegment segment = {
{bounds.ne.latitude, bounds.sw.longitude},
bounds.sw,
{bounds.sw.latitude, bounds.ne.longitude},
bounds.ne,
};
- fitBounds(segment, padding, duration);
+ return cameraForLatLngs(segment, padding);
}
-void Map::fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duration& duration) {
- if (segment.empty()) {
- return;
+CameraOptions Map::cameraForLatLngs(std::vector<LatLng> latLngs, EdgeInsets padding) {
+ CameraOptions options;
+ if (latLngs.empty()) {
+ return options;
}
// Calculate the bounds of the possibly rotated shape with respect to the viewport.
vec2<> nePixel = {-INFINITY, -INFINITY};
vec2<> swPixel = {INFINITY, INFINITY};
- for (LatLng latLng : segment) {
+ for (LatLng latLng : latLngs) {
vec2<> pixel = pixelForLatLng(latLng);
swPixel.x = std::min(swPixel.x, pixel.x);
nePixel.x = std::max(nePixel.x, pixel.x);
@@ -214,7 +230,9 @@ void Map::fitBounds(AnnotationSegment segment, EdgeInsets padding, const Duratio
vec2<> centerPixel = (paddedNEPixel + paddedSWPixel) * 0.5;
LatLng centerLatLng = latLngForPixel(centerPixel);
- setLatLngZoom(centerLatLng, zoom, duration);
+ options.center = centerLatLng;
+ options.zoom = zoom;
+ return options;
}
void Map::resetZoom() {
@@ -270,8 +288,8 @@ void Map::resetNorth() {
#pragma mark - Pitch
-void Map::setPitch(double pitch) {
- transform->setPitch(std::min(pitch, 60.0) * M_PI / 180);
+void Map::setPitch(double pitch, const Duration& duration) {
+ transform->setPitch(util::clamp(pitch, 0., 60.) * M_PI / 180, duration);
update(Update::Repaint);
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 60c55c3f0c..bb55909149 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -1,3 +1,4 @@
+#include <mbgl/map/camera.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/util/constants.hpp>
@@ -53,6 +54,38 @@ bool Transform::resize(const std::array<uint16_t, 2> size) {
#pragma mark - Position
+void Transform::jumpTo(const CameraOptions options) {
+ CameraOptions jumpOptions = options;
+ jumpOptions.duration.reset();
+ easeTo(jumpOptions);
+}
+
+void Transform::easeTo(CameraOptions options) {
+ LatLng latLng = options.center ? *options.center : getLatLng();
+ double zoom = options.zoom ? *options.zoom : getZoom();
+ double angle = options.angle ? *options.angle : getAngle();
+ if (std::isnan(latLng.latitude) || std::isnan(latLng.longitude) || std::isnan(zoom)) {
+ return;
+ }
+
+ double new_scale = std::pow(2.0, zoom);
+
+ const double s = new_scale * util::tileSize;
+ state.Bc = s / 360;
+ state.Cc = s / util::M2PI;
+
+ const double m = 1 - 1e-15;
+ const double f = std::fmin(std::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
+
+ double xn = -latLng.longitude * state.Bc;
+ double yn = 0.5 * state.Cc * std::log((1 + f) / (1 - f));
+
+ options.center.reset();
+ options.zoom.reset();
+ options.angle.reset();
+ _easeTo(options, new_scale, angle, xn, yn);
+}
+
void Transform::moveBy(const double dx, const double dy, const Duration& duration) {
if (std::isnan(dx) || std::isnan(dy)) {
return;
@@ -62,71 +95,30 @@ void Transform::moveBy(const double dx, const double dy, const Duration& duratio
}
void Transform::_moveBy(const double dx, const double dy, const Duration& duration) {
+
double x = state.x + std::cos(state.angle) * dx + std::sin( state.angle) * dy;
double y = state.y + std::cos(state.angle) * dy + std::sin(-state.angle) * dx;
state.constrain(state.scale, y);
-
- if (duration == Duration::zero()) {
- view.notifyMapChange(MapChangeRegionWillChange);
-
- state.x = x;
- state.y = y;
-
- view.notifyMapChange(MapChangeRegionDidChange);
- } else {
- view.notifyMapChange(MapChangeRegionWillChangeAnimated);
-
- const double startX = state.x;
- const double startY = state.y;
- state.panning = true;
-
- startTransition(
- [=](double t) {
- state.x = util::interpolate(startX, x, t);
- state.y = util::interpolate(startY, y, t);
- view.notifyMapChange(MapChangeRegionIsChanging);
- return Update::Repaint;
- },
- [=] {
- state.panning = false;
- view.notifyMapChange(MapChangeRegionDidChangeAnimated);
- }, duration);
- }
+
+ CameraOptions options;
+ options.duration = duration;
+ _easeTo(options, state.scale, state.angle, x, y);
}
void Transform::setLatLng(const LatLng latLng, const Duration& duration) {
- if (std::isnan(latLng.latitude) || std::isnan(latLng.longitude)) {
- return;
- }
-
- const double m = 1 - 1e-15;
- const double f = ::fmin(::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
-
- double xn = -latLng.longitude * state.Bc;
- double yn = 0.5 * state.Cc * std::log((1 + f) / (1 - f));
-
- _setScaleXY(state.scale, xn, yn, duration);
+ CameraOptions options;
+ options.center = latLng;
+ options.duration = duration;
+ easeTo(options);
}
void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Duration& duration) {
- if (std::isnan(latLng.latitude) || std::isnan(latLng.longitude) || std::isnan(zoom)) {
- return;
- }
-
- double new_scale = std::pow(2.0, zoom);
-
- const double s = new_scale * util::tileSize;
- state.Bc = s / 360;
- state.Cc = s / util::M2PI;
-
- const double m = 1 - 1e-15;
- const double f = ::fmin(::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
-
- double xn = -latLng.longitude * state.Bc;
- double yn = 0.5 * state.Cc * std::log((1 + f) / (1 - f));
-
- _setScaleXY(new_scale, xn, yn, duration);
+ CameraOptions options;
+ options.center = latLng;
+ options.zoom = zoom;
+ options.duration = duration;
+ easeTo(options);
}
@@ -206,13 +198,27 @@ void Transform::_setScale(double new_scale, double cx, double cy, const Duration
void Transform::_setScaleXY(const double new_scale, const double xn, const double yn,
const Duration& duration) {
+ CameraOptions options;
+ options.duration = duration;
+ _easeTo(options, new_scale, state.angle, xn, yn);
+}
+
+void Transform::_easeTo(CameraOptions options, const double new_scale, const double new_angle, const double xn, const double yn) {
+ Update update = state.scale == new_scale ? Update::Repaint : Update::Zoom;
double scale = new_scale;
double x = xn;
double y = yn;
state.constrain(scale, y);
+
+ double angle = _normalizeAngle(new_angle, state.angle);
+ state.angle = _normalizeAngle(state.angle, angle);
+ double pitch = options.pitch ? *options.pitch : state.pitch;
- if (duration == Duration::zero()) {
+ if (!options.duration) {
+ options.duration = Duration::zero();
+ }
+ if (!options.duration || *options.duration == Duration::zero()) {
view.notifyMapChange(MapChangeRegionWillChange);
state.scale = scale;
@@ -221,33 +227,46 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
const double s = state.scale * util::tileSize;
state.Bc = s / 360;
state.Cc = s / util::M2PI;
+
+ state.angle = angle;
+ state.pitch = pitch;
view.notifyMapChange(MapChangeRegionDidChange);
} else {
view.notifyMapChange(MapChangeRegionWillChangeAnimated);
const double startS = state.scale;
+ const double startA = state.angle;
+ const double startP = state.pitch;
const double startX = state.x;
const double startY = state.y;
state.panning = true;
state.scaling = true;
+ state.rotating = true;
startTransition(
[=](double t) {
+ util::UnitBezier ease = options.easing ? *options.easing : util::UnitBezier(0, 0, 0.25, 1);
+ return ease.solve(t, 0.001);
+ },
+ [=](double t) {
state.scale = util::interpolate(startS, scale, t);
state.x = util::interpolate(startX, x, t);
state.y = util::interpolate(startY, y, t);
const double s = state.scale * util::tileSize;
state.Bc = s / 360;
state.Cc = s / util::M2PI;
+ state.angle = util::wrap(util::interpolate(startA, angle, t), -M_PI, M_PI);
+ state.pitch = util::interpolate(startP, pitch, t);
view.notifyMapChange(MapChangeRegionIsChanging);
- return Update::Zoom;
+ return update;
},
[=] {
state.panning = false;
state.scaling = false;
+ state.rotating = false;
view.notifyMapChange(MapChangeRegionDidChangeAnimated);
- }, duration);
+ }, *options.duration);
}
}
@@ -307,7 +326,7 @@ void Transform::setAngle(const double new_angle, const double cx, const double c
_moveBy(dx, dy, Duration::zero());
}
- _setAngle(new_angle, Duration::zero());
+ _setAngle(new_angle);
if (cx >= 0 && cy >= 0) {
_moveBy(-dx, -dy, Duration::zero());
@@ -315,32 +334,10 @@ void Transform::setAngle(const double new_angle, const double cx, const double c
}
void Transform::_setAngle(double new_angle, const Duration& duration) {
- double angle = _normalizeAngle(new_angle, state.angle);
- state.angle = _normalizeAngle(state.angle, angle);
-
- if (duration == Duration::zero()) {
- view.notifyMapChange(MapChangeRegionWillChange);
-
- state.angle = angle;
-
- view.notifyMapChange(MapChangeRegionDidChange);
- } else {
- view.notifyMapChange(MapChangeRegionWillChangeAnimated);
-
- const double startA = state.angle;
- state.rotating = true;
-
- startTransition(
- [=](double t) {
- state.angle = util::wrap(util::interpolate(startA, angle, t), -M_PI, M_PI);
- view.notifyMapChange(MapChangeRegionIsChanging);
- return Update::Repaint;
- },
- [=] {
- state.rotating = false;
- view.notifyMapChange(MapChangeRegionDidChangeAnimated);
- }, duration);
- }
+ CameraOptions options;
+ options.angle = new_angle;
+ options.duration = duration;
+ easeTo(options);
}
double Transform::getAngle() const {
@@ -349,8 +346,11 @@ double Transform::getAngle() const {
#pragma mark - Pitch
-void Transform::setPitch(double pitch) {
- state.pitch = pitch;
+void Transform::setPitch(double pitch, const Duration& duration) {
+ CameraOptions options;
+ options.pitch = pitch;
+ options.duration = duration;
+ easeTo(options);
}
double Transform::getPitch() const {
@@ -359,7 +359,8 @@ double Transform::getPitch() const {
#pragma mark - Transition
-void Transform::startTransition(std::function<Update(double)> frame,
+void Transform::startTransition(std::function<double(double)> easing,
+ std::function<Update(double)> frame,
std::function<void()> finish,
const Duration& duration) {
if (transitionFinishFn) {
@@ -369,7 +370,7 @@ void Transform::startTransition(std::function<Update(double)> frame,
transitionStart = Clock::now();
transitionDuration = duration;
- transitionFrameFn = [frame, this](const TimePoint now) {
+ transitionFrameFn = [easing, frame, this](const TimePoint now) {
float t = std::chrono::duration<float>(now - transitionStart) / transitionDuration;
if (t >= 1.0) {
Update result = frame(1.0);
@@ -378,8 +379,7 @@ void Transform::startTransition(std::function<Update(double)> frame,
transitionFinishFn = nullptr;
return result;
} else {
- util::UnitBezier ease(0, 0, 0.25, 1);
- return frame(ease.solve(t, 0.001));
+ return frame(easing(t));
}
};
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index 1671983449..56001fad81 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -2,6 +2,7 @@
#define MBGL_MAP_TRANSFORM
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/map/camera.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/map/update.hpp>
#include <mbgl/util/geo.hpp>
@@ -22,6 +23,9 @@ public:
// Map view
bool resize(std::array<uint16_t, 2> size);
+ void jumpTo(const CameraOptions options);
+ void easeTo(const CameraOptions options);
+
// Position
void moveBy(double dx, double dy, const Duration& = Duration::zero());
void setLatLng(LatLng latLng, const Duration& = Duration::zero());
@@ -42,7 +46,7 @@ public:
double getAngle() const;
// Pitch
- void setPitch(double pitch);
+ void setPitch(double pitch, const Duration& = Duration::zero());
double getPitch() const;
// Transitions
@@ -60,13 +64,16 @@ private:
void _moveBy(double dx, double dy, const Duration& = Duration::zero());
void _setScale(double scale, double cx, double cy, const Duration& = Duration::zero());
void _setScaleXY(double new_scale, double xn, double yn, const Duration& = Duration::zero());
+ void _easeTo(CameraOptions options, const double new_scale, const double new_angle,
+ const double xn, const double yn);
void _setAngle(double angle, const Duration& = Duration::zero());
View &view;
TransformState state;
- void startTransition(std::function<Update(double)> frame,
+ void startTransition(std::function<double(double)> easing,
+ std::function<Update(double)> frame,
std::function<void()> finish,
const Duration& duration);