Rework easing transition code
This brings the easing transition code a bit closer to how easings work in gl-js. Instead of having an array of individual transitions for scale, rotate, and pan, there is a single transition function that does all the required calculations. This permits us to: * Eliminate the "timeout" transition. (Fixes #126) * Replace start/stopPanning() et al with setGestureInProgress(). Apps or SDKs are expected to make paired calls to setGestureInProgress(). This state will be ORed with the active easing state to determine when to use texture interpolation. (Fixes #79) * Run style recalculations only when an ease transition that affects the zoom is in progress. (Fixes #1155)
This commit is contained in:
@@ -461,20 +461,6 @@ jobject JNICALL nativeGetLatLng(JNIEnv *env, jobject obj, jlong nativeMapViewPtr
|
||||
return ret;
|
||||
}
|
||||
|
||||
void JNICALL nativeStartPanning(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStartPanning");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().startPanning();
|
||||
}
|
||||
|
||||
void JNICALL nativeStopPanning(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStopPanning");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().stopPanning();
|
||||
}
|
||||
|
||||
void JNICALL nativeResetPosition(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeResetPosition");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
@@ -570,20 +556,6 @@ void JNICALL nativeResetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
nativeMapView->getMap().resetZoom();
|
||||
}
|
||||
|
||||
void JNICALL nativeStartScaling(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStartScaling");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().startScaling();
|
||||
}
|
||||
|
||||
void JNICALL nativeStopScaling(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStopScaling");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
return nativeMapView->getMap().stopScaling();
|
||||
}
|
||||
|
||||
jdouble JNICALL nativeGetMinZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetMinZoom");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
@@ -636,20 +608,6 @@ void JNICALL nativeResetNorth(JNIEnv *env, jobject obj, jlong nativeMapViewPtr)
|
||||
nativeMapView->getMap().resetNorth();
|
||||
}
|
||||
|
||||
void JNICALL nativeStartRotating(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStartRotating");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().startRotating();
|
||||
}
|
||||
|
||||
void JNICALL nativeStopRotating(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStopRotating");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().stopRotating();
|
||||
}
|
||||
|
||||
void JNICALL nativeSetDebug(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean debug) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetDebug");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
@@ -1029,8 +987,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
reinterpret_cast<void *>(&nativeSetLatLng)},
|
||||
{"nativeGetLatLng", "(J)Lcom/mapbox/mapboxgl/geometry/LatLng;",
|
||||
reinterpret_cast<void *>(&nativeGetLatLng)},
|
||||
{"nativeStartPanning", "(J)V", reinterpret_cast<void *>(&nativeStartPanning)},
|
||||
{"nativeStopPanning", "(J)V", reinterpret_cast<void *>(&nativeStopPanning)},
|
||||
{"nativeResetPosition", "(J)V", reinterpret_cast<void *>(&nativeResetPosition)},
|
||||
{"nativeScaleBy", "(JDDDJ)V", reinterpret_cast<void *>(&nativeScaleBy)},
|
||||
{"nativeSetScale", "(JDDDJ)V", reinterpret_cast<void *>(&nativeSetScale)},
|
||||
@@ -1042,8 +998,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
{"nativeGetLatLngZoom", "(J)Lcom/mapbox/mapboxgl/geometry/LatLngZoom;",
|
||||
reinterpret_cast<void *>(&nativeGetLatLngZoom)},
|
||||
{"nativeResetZoom", "(J)V", reinterpret_cast<void *>(&nativeResetZoom)},
|
||||
{"nativeStartPanning", "(J)V", reinterpret_cast<void *>(&nativeStartScaling)},
|
||||
{"nativeStopPanning", "(J)V", reinterpret_cast<void *>(&nativeStopScaling)},
|
||||
{"nativeGetMinZoom", "(J)D", reinterpret_cast<void *>(&nativeGetMinZoom)},
|
||||
{"nativeGetMaxZoom", "(J)D", reinterpret_cast<void *>(&nativeGetMaxZoom)},
|
||||
{"nativeRotateBy", "(JDDDDJ)V", reinterpret_cast<void *>(&nativeRotateBy)},
|
||||
@@ -1057,8 +1011,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
&nativeSetBearing))},
|
||||
{"nativeGetBearing", "(J)D", reinterpret_cast<void *>(&nativeGetBearing)},
|
||||
{"nativeResetNorth", "(J)V", reinterpret_cast<void *>(&nativeResetNorth)},
|
||||
{"nativeStartRotating", "(J)V", reinterpret_cast<void *>(&nativeStartRotating)},
|
||||
{"nativeStopRotating", "(J)V", reinterpret_cast<void *>(&nativeStopRotating)},
|
||||
{"nativeSetDebug", "(JZ)V", reinterpret_cast<void *>(&nativeSetDebug)},
|
||||
{"nativeToggleDebug", "(J)V", reinterpret_cast<void *>(&nativeToggleDebug)},
|
||||
{"nativeGetDebug", "(J)Z", reinterpret_cast<void *>(&nativeGetDebug)},
|
||||
|
||||
@@ -213,14 +213,6 @@ class NativeMapView {
|
||||
return nativeGetLatLng(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void startPanning() {
|
||||
nativeStartPanning(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void stopPanning() {
|
||||
nativeStopPanning(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resetPosition() {
|
||||
nativeResetPosition(mNativeMapViewPtr);
|
||||
}
|
||||
@@ -281,14 +273,6 @@ class NativeMapView {
|
||||
nativeResetZoom(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void startScaling() {
|
||||
nativeStartScaling(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void stopScaling() {
|
||||
nativeStopScaling(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public double getMinZoom() {
|
||||
return nativeGetMinZoom(mNativeMapViewPtr);
|
||||
}
|
||||
@@ -326,14 +310,6 @@ class NativeMapView {
|
||||
nativeResetNorth(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void startRotating() {
|
||||
nativeStartRotating(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void stopRotating() {
|
||||
nativeStopRotating(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
nativeSetDebug(mNativeMapViewPtr, debug);
|
||||
}
|
||||
@@ -468,10 +444,6 @@ class NativeMapView {
|
||||
|
||||
private native LatLng nativeGetLatLng(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeStartPanning(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeStopPanning(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResetPosition(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeScaleBy(long nativeMapViewPtr, double ds,
|
||||
@@ -494,10 +466,6 @@ class NativeMapView {
|
||||
|
||||
private native void nativeResetZoom(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeStartScaling(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeStopScaling(long nativeMapViewPtr);
|
||||
|
||||
private native double nativeGetMinZoom(long nativeMapViewPtr);
|
||||
|
||||
private native double nativeGetMaxZoom(long nativeMapViewPtr);
|
||||
@@ -515,10 +483,6 @@ class NativeMapView {
|
||||
|
||||
private native void nativeResetNorth(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeStartRotating(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeStopRotating(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
|
||||
|
||||
private native void nativeToggleDebug(long nativeMapViewPtr);
|
||||
|
||||
@@ -100,13 +100,12 @@ public:
|
||||
|
||||
// Transition
|
||||
void cancelTransitions();
|
||||
void setGestureInProgress(bool);
|
||||
|
||||
// Position
|
||||
void moveBy(double dx, double dy, Duration = Duration::zero());
|
||||
void setLatLng(LatLng latLng, Duration = Duration::zero());
|
||||
LatLng getLatLng() const;
|
||||
void startPanning();
|
||||
void stopPanning();
|
||||
void resetPosition();
|
||||
|
||||
// Scale
|
||||
@@ -117,8 +116,6 @@ public:
|
||||
double getZoom() const;
|
||||
void setLatLngZoom(LatLng latLng, double zoom, Duration = Duration::zero());
|
||||
void resetZoom();
|
||||
void startScaling();
|
||||
void stopScaling();
|
||||
double getMinZoom() const;
|
||||
double getMaxZoom() const;
|
||||
|
||||
@@ -128,8 +125,6 @@ public:
|
||||
void setBearing(double degrees, double cx, double cy);
|
||||
double getBearing() const;
|
||||
void resetNorth();
|
||||
void startRotating();
|
||||
void stopRotating();
|
||||
|
||||
// API
|
||||
void setAccessToken(const std::string &token);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/map/update.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
@@ -31,8 +32,6 @@ public:
|
||||
void setLatLng(LatLng latLng, Duration = Duration::zero());
|
||||
void setLatLngZoom(LatLng latLng, double zoom, Duration = Duration::zero());
|
||||
inline const LatLng getLatLng() const { return current.getLatLng(); }
|
||||
void startPanning();
|
||||
void stopPanning();
|
||||
|
||||
// Zoom
|
||||
void scaleBy(double ds, double cx = -1, double cy = -1, Duration = Duration::zero());
|
||||
@@ -40,8 +39,6 @@ public:
|
||||
void setZoom(double zoom, Duration = Duration::zero());
|
||||
double getZoom() const;
|
||||
double getScale() const;
|
||||
void startScaling();
|
||||
void stopScaling();
|
||||
double getMinZoom() const;
|
||||
double getMaxZoom() const;
|
||||
|
||||
@@ -50,14 +47,15 @@ public:
|
||||
void setAngle(double angle, Duration = Duration::zero());
|
||||
void setAngle(double angle, double cx, double cy);
|
||||
double getAngle() const;
|
||||
void startRotating();
|
||||
void stopRotating();
|
||||
|
||||
// Transitions
|
||||
bool needsTransition() const;
|
||||
void updateTransitions(TimePoint now);
|
||||
UpdateType updateTransitions(TimePoint now);
|
||||
void cancelTransitions();
|
||||
|
||||
// Gesture
|
||||
void setGestureInProgress(bool);
|
||||
|
||||
// Transform state
|
||||
const TransformState currentState() const;
|
||||
const TransformState finalState() const;
|
||||
@@ -69,13 +67,9 @@ private:
|
||||
void _setScale(double scale, double cx, double cy, Duration = Duration::zero());
|
||||
void _setScaleXY(double new_scale, double xn, double yn, Duration = Duration::zero());
|
||||
void _setAngle(double angle, Duration = Duration::zero());
|
||||
void _clearPanning();
|
||||
void _clearRotating();
|
||||
void _clearScaling();
|
||||
|
||||
void constrain(double& scale, double& y) const;
|
||||
|
||||
private:
|
||||
View &view;
|
||||
|
||||
mutable std::recursive_mutex mtx;
|
||||
@@ -92,10 +86,14 @@ private:
|
||||
const double min_scale = std::pow(2, 0);
|
||||
const double max_scale = std::pow(2, 18);
|
||||
|
||||
std::forward_list<util::ptr<util::transition>> transitions;
|
||||
util::ptr<util::transition> scale_timeout;
|
||||
util::ptr<util::transition> rotate_timeout;
|
||||
util::ptr<util::transition> pan_timeout;
|
||||
void startTransition(std::function<Update(double)> frame,
|
||||
std::function<void()> finish,
|
||||
Duration);
|
||||
|
||||
TimePoint transitionStart;
|
||||
Duration transitionDuration;
|
||||
std::function<Update(TimePoint)> transitionFrameFn;
|
||||
std::function<void()> transitionFinishFn;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
bool rotating = false;
|
||||
bool scaling = false;
|
||||
bool panning = false;
|
||||
bool gestureInProgress = false;
|
||||
|
||||
// map position
|
||||
double x = 0, y = 0;
|
||||
|
||||
@@ -11,6 +11,7 @@ enum class Update : UpdateType {
|
||||
Debug = 1 << 1,
|
||||
DefaultTransitionDuration = 1 << 2,
|
||||
Classes = 1 << 3,
|
||||
Zoom = 1 << 4,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -212,7 +212,6 @@ void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset)
|
||||
scale = 1.0 / scale;
|
||||
}
|
||||
|
||||
view->map->startScaling();
|
||||
view->map->scaleBy(scale, view->lastX, view->lastY);
|
||||
}
|
||||
|
||||
@@ -231,14 +230,12 @@ void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modi
|
||||
if (button == GLFW_MOUSE_BUTTON_RIGHT ||
|
||||
(button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) {
|
||||
view->rotating = action == GLFW_PRESS;
|
||||
if (!view->rotating) {
|
||||
view->map->stopRotating();
|
||||
}
|
||||
view->map->setGestureInProgress(view->rotating);
|
||||
} else if (button == GLFW_MOUSE_BUTTON_LEFT) {
|
||||
view->tracking = action == GLFW_PRESS;
|
||||
view->map->setGestureInProgress(view->tracking);
|
||||
|
||||
if (action == GLFW_RELEASE) {
|
||||
view->map->stopPanning();
|
||||
double now = glfwGetTime();
|
||||
if (now - view->lastClick < 0.4 /* ms */) {
|
||||
if (modifiers & GLFW_MOD_SHIFT) {
|
||||
@@ -258,11 +255,9 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
|
||||
double dx = x - view->lastX;
|
||||
double dy = y - view->lastY;
|
||||
if (dx || dy) {
|
||||
view->map->startPanning();
|
||||
view->map->moveBy(dx, dy);
|
||||
}
|
||||
} else if (view->rotating) {
|
||||
view->map->startRotating();
|
||||
view->map->rotateBy(view->lastX, view->lastY, x, y);
|
||||
}
|
||||
view->lastX = x;
|
||||
|
||||
@@ -615,6 +615,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
|
||||
{
|
||||
[self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan];
|
||||
|
||||
mbglMap->setGestureInProgress(true);
|
||||
|
||||
self.centerPoint = CGPointMake(0, 0);
|
||||
|
||||
self.userTrackingMode = MGLUserTrackingModeNone;
|
||||
@@ -651,6 +653,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
|
||||
|
||||
mbglMap->moveBy(offset.x, offset.y, secondsAsDuration(duration));
|
||||
|
||||
mbglMap->setGestureInProgress(false);
|
||||
|
||||
if (duration)
|
||||
{
|
||||
self.animatingGesture = YES;
|
||||
@@ -694,7 +698,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
|
||||
{
|
||||
[self trackGestureEvent:MGLEventGesturePinchStart forRecognizer:pinch];
|
||||
|
||||
mbglMap->startScaling();
|
||||
mbglMap->setGestureInProgress(true);
|
||||
|
||||
self.scale = mbglMap->getScale();
|
||||
|
||||
@@ -712,7 +716,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
|
||||
}
|
||||
else if (pinch.state == UIGestureRecognizerStateEnded || pinch.state == UIGestureRecognizerStateCancelled)
|
||||
{
|
||||
mbglMap->stopScaling();
|
||||
mbglMap->setGestureInProgress(false);
|
||||
|
||||
[self unrotateIfNeededAnimated:YES];
|
||||
|
||||
@@ -730,7 +734,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
|
||||
{
|
||||
[self trackGestureEvent:MGLEventGestureRotateStart forRecognizer:rotate];
|
||||
|
||||
mbglMap->startRotating();
|
||||
mbglMap->setGestureInProgress(true);
|
||||
|
||||
self.angle = [MGLMapView degreesToRadians:mbglMap->getBearing()] * -1;
|
||||
|
||||
@@ -754,7 +758,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
|
||||
}
|
||||
else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
|
||||
{
|
||||
mbglMap->stopRotating();
|
||||
mbglMap->setGestureInProgress(false);
|
||||
|
||||
[self unrotateIfNeededAnimated:YES];
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
#include <mbgl/map/annotation.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/util/transition.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/clip_ids.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
@@ -72,7 +71,8 @@ Map::Map(View& view_, FileSource& fileSource_)
|
||||
texturePool(std::make_shared<TexturePool>()),
|
||||
painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas)),
|
||||
annotationManager(util::make_unique<AnnotationManager>()),
|
||||
data(util::make_unique<MapData>())
|
||||
data(util::make_unique<MapData>()),
|
||||
updated(static_cast<UpdateType>(Update::Nothing))
|
||||
{
|
||||
view.initialize(this);
|
||||
}
|
||||
@@ -449,10 +449,13 @@ void Map::resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth,
|
||||
|
||||
void Map::cancelTransitions() {
|
||||
transform.cancelTransitions();
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Map::setGestureInProgress(bool inProgress) {
|
||||
transform.setGestureInProgress(inProgress);
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
#pragma mark - Position
|
||||
|
||||
@@ -470,21 +473,11 @@ LatLng Map::getLatLng() const {
|
||||
return state.getLatLng();
|
||||
}
|
||||
|
||||
void Map::startPanning() {
|
||||
transform.startPanning();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Map::stopPanning() {
|
||||
transform.stopPanning();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Map::resetPosition() {
|
||||
transform.setAngle(0);
|
||||
transform.setLatLng(LatLng(0, 0));
|
||||
transform.setZoom(0);
|
||||
triggerUpdate();
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
|
||||
@@ -492,12 +485,12 @@ void Map::resetPosition() {
|
||||
|
||||
void Map::scaleBy(double ds, double cx, double cy, Duration duration) {
|
||||
transform.scaleBy(ds, cx, cy, duration);
|
||||
triggerUpdate();
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
void Map::setScale(double scale, double cx, double cy, Duration duration) {
|
||||
transform.setScale(scale, cx, cy, duration);
|
||||
triggerUpdate();
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
double Map::getScale() const {
|
||||
@@ -506,7 +499,7 @@ double Map::getScale() const {
|
||||
|
||||
void Map::setZoom(double zoom, Duration duration) {
|
||||
transform.setZoom(zoom, duration);
|
||||
triggerUpdate();
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
double Map::getZoom() const {
|
||||
@@ -515,23 +508,13 @@ double Map::getZoom() const {
|
||||
|
||||
void Map::setLatLngZoom(LatLng latLng, double zoom, Duration duration) {
|
||||
transform.setLatLngZoom(latLng, zoom, duration);
|
||||
triggerUpdate();
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
void Map::resetZoom() {
|
||||
setZoom(0);
|
||||
}
|
||||
|
||||
void Map::startScaling() {
|
||||
transform.startScaling();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Map::stopScaling() {
|
||||
transform.stopScaling();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
double Map::getMinZoom() const {
|
||||
return transform.getMinZoom();
|
||||
}
|
||||
@@ -567,16 +550,6 @@ void Map::resetNorth() {
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Map::startRotating() {
|
||||
transform.startRotating();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Map::stopRotating() {
|
||||
transform.stopRotating();
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
#pragma mark - Access Token
|
||||
|
||||
void Map::setAccessToken(const std::string &token) {
|
||||
@@ -802,44 +775,49 @@ void Map::loadStyleJSON(const std::string& json, const std::string& base) {
|
||||
const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken());
|
||||
glyphStore->setURL(glyphURL);
|
||||
|
||||
triggerUpdate();
|
||||
triggerUpdate(Update::Zoom);
|
||||
}
|
||||
|
||||
void Map::prepare() {
|
||||
assert(Environment::currentlyOn(ThreadType::Map));
|
||||
|
||||
const auto u = updated.exchange(static_cast<UpdateType>(Update::Nothing));
|
||||
if ((u & static_cast<UpdateType>(Update::StyleInfo)) || !style) {
|
||||
reloadStyle();
|
||||
}
|
||||
if (u & static_cast<UpdateType>(Update::Debug)) {
|
||||
assert(painter);
|
||||
painter->setDebug(data->getDebug());
|
||||
}
|
||||
if (u & static_cast<UpdateType>(Update::DefaultTransitionDuration)) {
|
||||
if (style) {
|
||||
style->setDefaultTransitionDuration(data->getDefaultTransitionDuration());
|
||||
}
|
||||
}
|
||||
if (u & static_cast<UpdateType>(Update::Classes)) {
|
||||
if (style) {
|
||||
style->cascade(data->getClasses());
|
||||
}
|
||||
}
|
||||
const auto now = Clock::now();
|
||||
data->setAnimationTime(now);
|
||||
|
||||
// Update transform transitions.
|
||||
auto u = updated.exchange(static_cast<UpdateType>(Update::Nothing)) |
|
||||
transform.updateTransitions(now);
|
||||
|
||||
const auto animationTime = Clock::now();
|
||||
data->setAnimationTime(animationTime);
|
||||
if (transform.needsTransition()) {
|
||||
transform.updateTransitions(animationTime);
|
||||
if (!style) {
|
||||
u |= static_cast<UpdateType>(Update::StyleInfo);
|
||||
}
|
||||
|
||||
state = transform.currentState();
|
||||
|
||||
if (u & static_cast<UpdateType>(Update::StyleInfo)) {
|
||||
reloadStyle();
|
||||
}
|
||||
|
||||
if (u & static_cast<UpdateType>(Update::Debug)) {
|
||||
assert(painter);
|
||||
painter->setDebug(data->getDebug());
|
||||
}
|
||||
|
||||
if (style) {
|
||||
if (u & static_cast<UpdateType>(Update::DefaultTransitionDuration)) {
|
||||
style->setDefaultTransitionDuration(data->getDefaultTransitionDuration());
|
||||
}
|
||||
|
||||
if (u & static_cast<UpdateType>(Update::Classes)) {
|
||||
style->cascade(data->getClasses());
|
||||
}
|
||||
|
||||
if (u & static_cast<UpdateType>(Update::StyleInfo) ||
|
||||
u & static_cast<UpdateType>(Update::Classes) ||
|
||||
u & static_cast<UpdateType>(Update::Zoom)) {
|
||||
style->recalculate(state.getNormalizedZoom(), now);
|
||||
}
|
||||
|
||||
updateSources();
|
||||
style->recalculate(state.getNormalizedZoom(), animationTime);
|
||||
|
||||
// Allow the sprite atlas to potentially pull new sprite images if needed.
|
||||
spriteAtlas->resize(state.getPixelRatio());
|
||||
@@ -863,6 +841,7 @@ void Map::render() {
|
||||
assert(painter);
|
||||
painter->render(*style, activeSources,
|
||||
state, data->getAnimationTime());
|
||||
|
||||
// Schedule another rerender when we definitely need a next frame.
|
||||
if (transform.needsTransition() || style->hasTransitions()) {
|
||||
triggerUpdate();
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/transition.hpp>
|
||||
#include <mbgl/util/unitbezier.hpp>
|
||||
#include <mbgl/util/interpolate.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
@@ -66,12 +67,19 @@ void Transform::_moveBy(const double dx, const double dy, const Duration duratio
|
||||
current.x = final.x;
|
||||
current.y = final.y;
|
||||
} else {
|
||||
// Use a common start time for all of the transitions to avoid divergent transitions.
|
||||
TimePoint start = Clock::now();
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition<double>>(current.x, final.x, current.x, start, duration));
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition<double>>(current.y, final.y, current.y, start, duration));
|
||||
const double startX = current.x;
|
||||
const double startY = current.y;
|
||||
current.panning = true;
|
||||
|
||||
startTransition(
|
||||
[=](double t) {
|
||||
current.x = util::interpolate(startX, final.x, t);
|
||||
current.y = util::interpolate(startY, final.y, t);
|
||||
return Update::Nothing;
|
||||
},
|
||||
[=] {
|
||||
current.panning = false;
|
||||
}, duration);
|
||||
}
|
||||
|
||||
view.notifyMapChange(duration != Duration::zero() ?
|
||||
@@ -110,31 +118,6 @@ void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Dura
|
||||
_setScaleXY(new_scale, xn, yn, duration);
|
||||
}
|
||||
|
||||
void Transform::startPanning() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
_clearPanning();
|
||||
|
||||
// Add a 200ms timeout for resetting this to false
|
||||
current.panning = true;
|
||||
TimePoint start = Clock::now();
|
||||
pan_timeout = std::make_shared<util::timeout<bool>>(false, current.panning, start, std::chrono::milliseconds(200));
|
||||
transitions.emplace_front(pan_timeout);
|
||||
}
|
||||
|
||||
void Transform::stopPanning() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
_clearPanning();
|
||||
}
|
||||
|
||||
void Transform::_clearPanning() {
|
||||
current.panning = false;
|
||||
if (pan_timeout) {
|
||||
transitions.remove(pan_timeout);
|
||||
pan_timeout.reset();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Zoom
|
||||
|
||||
@@ -177,24 +160,6 @@ double Transform::getScale() const {
|
||||
return final.scale;
|
||||
}
|
||||
|
||||
void Transform::startScaling() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
_clearScaling();
|
||||
|
||||
// Add a 200ms timeout for resetting this to false
|
||||
current.scaling = true;
|
||||
TimePoint start = Clock::now();
|
||||
scale_timeout = std::make_shared<util::timeout<bool>>(false, current.scaling, start, std::chrono::milliseconds(200));
|
||||
transitions.emplace_front(scale_timeout);
|
||||
}
|
||||
|
||||
void Transform::stopScaling() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
_clearScaling();
|
||||
}
|
||||
|
||||
double Transform::getMinZoom() const {
|
||||
double test_scale = current.scale;
|
||||
double test_y = current.y;
|
||||
@@ -207,16 +172,6 @@ double Transform::getMaxZoom() const {
|
||||
return std::log2(max_scale);
|
||||
}
|
||||
|
||||
void Transform::_clearScaling() {
|
||||
// This is only called internally, so we don't need a lock here.
|
||||
|
||||
current.scaling = false;
|
||||
if (scale_timeout) {
|
||||
transitions.remove(scale_timeout);
|
||||
scale_timeout.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Transform::_setScale(double new_scale, double cx, double cy, const Duration duration) {
|
||||
// This is only called internally, so we don't need a lock here.
|
||||
|
||||
@@ -269,14 +224,23 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
|
||||
current.x = final.x;
|
||||
current.y = final.y;
|
||||
} else {
|
||||
// Use a common start time for all of the transitions to avoid divergent transitions.
|
||||
TimePoint start = Clock::now();
|
||||
transitions.emplace_front(std::make_shared<util::ease_transition<double>>(
|
||||
current.scale, final.scale, current.scale, start, duration));
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition<double>>(current.x, final.x, current.x, start, duration));
|
||||
transitions.emplace_front(
|
||||
std::make_shared<util::ease_transition<double>>(current.y, final.y, current.y, start, duration));
|
||||
const double startS = current.scale;
|
||||
const double startX = current.x;
|
||||
const double startY = current.y;
|
||||
current.panning = true;
|
||||
current.scaling = true;
|
||||
|
||||
startTransition(
|
||||
[=](double t) {
|
||||
current.scale = util::interpolate(startS, final.scale, t);
|
||||
current.x = util::interpolate(startX, final.x, t);
|
||||
current.y = util::interpolate(startY, final.y, t);
|
||||
return Update::Zoom;
|
||||
},
|
||||
[=] {
|
||||
current.panning = false;
|
||||
current.scaling = false;
|
||||
}, duration);
|
||||
}
|
||||
|
||||
const double s = final.scale * util::tileSize;
|
||||
@@ -376,9 +340,17 @@ void Transform::_setAngle(double new_angle, const Duration duration) {
|
||||
if (duration == Duration::zero()) {
|
||||
current.angle = final.angle;
|
||||
} else {
|
||||
TimePoint start = Clock::now();
|
||||
transitions.emplace_front(std::make_shared<util::ease_transition<double>>(
|
||||
current.angle, final.angle, current.angle, start, duration));
|
||||
const double startA = current.angle;
|
||||
current.rotating = true;
|
||||
|
||||
startTransition(
|
||||
[=](double t) {
|
||||
current.angle = util::interpolate(startA, final.angle, t);
|
||||
return Update::Nothing;
|
||||
},
|
||||
[=] {
|
||||
current.rotating = false;
|
||||
}, duration);
|
||||
}
|
||||
|
||||
view.notifyMapChange(duration != Duration::zero() ?
|
||||
@@ -393,55 +365,61 @@ double Transform::getAngle() const {
|
||||
return final.angle;
|
||||
}
|
||||
|
||||
void Transform::startRotating() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
_clearRotating();
|
||||
|
||||
// Add a 200ms timeout for resetting this to false
|
||||
current.rotating = true;
|
||||
TimePoint start = Clock::now();
|
||||
rotate_timeout = std::make_shared<util::timeout<bool>>(false, current.rotating, start, std::chrono::milliseconds(200));
|
||||
transitions.emplace_front(rotate_timeout);
|
||||
}
|
||||
|
||||
void Transform::stopRotating() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
_clearRotating();
|
||||
}
|
||||
|
||||
void Transform::_clearRotating() {
|
||||
// This is only called internally, so we don't need a lock here.
|
||||
|
||||
current.rotating = false;
|
||||
if (rotate_timeout) {
|
||||
transitions.remove(rotate_timeout);
|
||||
rotate_timeout.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Transition
|
||||
|
||||
bool Transform::needsTransition() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
void Transform::startTransition(std::function<Update(double)> frame,
|
||||
std::function<void()> finish,
|
||||
Duration duration) {
|
||||
if (transitionFinishFn) {
|
||||
transitionFinishFn();
|
||||
}
|
||||
|
||||
return !transitions.empty();
|
||||
transitionStart = Clock::now();
|
||||
transitionDuration = duration;
|
||||
|
||||
transitionFrameFn = [frame, this](TimePoint now) {
|
||||
float t = std::chrono::duration<float>(now - transitionStart) / transitionDuration;
|
||||
if (t >= 1.0) {
|
||||
Update result = frame(1.0);
|
||||
transitionFinishFn();
|
||||
transitionFrameFn = nullptr;
|
||||
transitionFinishFn = nullptr;
|
||||
return result;
|
||||
} else {
|
||||
util::UnitBezier ease(0, 0, 0.25, 1);
|
||||
return frame(ease.solve(t, 0.001));
|
||||
}
|
||||
};
|
||||
|
||||
transitionFinishFn = finish;
|
||||
}
|
||||
|
||||
void Transform::updateTransitions(const TimePoint now) {
|
||||
bool Transform::needsTransition() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
return !!transitionFrameFn;
|
||||
}
|
||||
|
||||
transitions.remove_if([now](const util::ptr<util::transition> &transition) {
|
||||
return transition->update(now) == util::transition::complete;
|
||||
});
|
||||
UpdateType Transform::updateTransitions(const TimePoint now) {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
return static_cast<UpdateType>(transitionFrameFn ? transitionFrameFn(now) : Update::Nothing);
|
||||
}
|
||||
|
||||
void Transform::cancelTransitions() {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
transitions.clear();
|
||||
if (transitionFinishFn) {
|
||||
transitionFinishFn();
|
||||
}
|
||||
|
||||
transitionFrameFn = nullptr;
|
||||
transitionFinishFn = nullptr;
|
||||
}
|
||||
|
||||
void Transform::setGestureInProgress(bool inProgress) {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
current.gestureInProgress = inProgress;
|
||||
}
|
||||
|
||||
#pragma mark - Transform state
|
||||
|
||||
@@ -249,7 +249,7 @@ const LatLng TransformState::latLngForPixel(const vec2<double> pixel) const {
|
||||
#pragma mark - Changing
|
||||
|
||||
bool TransformState::isChanging() const {
|
||||
return rotating || scaling || panning;
|
||||
return rotating || scaling || panning || gestureInProgress;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user