diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-01-17 13:33:39 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-01-17 13:33:39 +0100 |
commit | 509b223fbf63ea326b60e82dec2f0c0cdb160a66 (patch) | |
tree | b10a8529540fe11c4822d994a8dd893876b45150 | |
parent | fc8a0d00ac17dfaa16c363a88c4c4c14298ec1dc (diff) | |
download | qtlocation-mapboxgl-509b223fbf63ea326b60e82dec2f0c0cdb160a66.tar.gz |
animate northing
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | include/llmr/map/transform.hpp | 13 | ||||
-rw-r--r-- | include/llmr/platform/platform.hpp | 1 | ||||
-rw-r--r-- | include/llmr/util/animation.hpp | 30 | ||||
-rw-r--r-- | include/llmr/util/unitbezier.hpp | 121 | ||||
-rw-r--r-- | macosx/main.mm | 4 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/map/map.cpp | 6 | ||||
-rw-r--r-- | src/map/transform.cpp | 24 | ||||
-rw-r--r-- | src/util/animation.cpp | 26 |
10 files changed, 222 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore index 6bc0b9d208..d097e98f25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *.o /emscripten/main.js -/emscripten/main.js.map
\ No newline at end of file +/emscripten/main.js.map +/build +/xcode +*.sublime-*
\ No newline at end of file diff --git a/include/llmr/map/transform.hpp b/include/llmr/map/transform.hpp index cf1ae6fff3..cee9d32a6a 100644 --- a/include/llmr/map/transform.hpp +++ b/include/llmr/map/transform.hpp @@ -1,9 +1,12 @@ #ifndef LLMR_MAP_TRANSFORM #define LLMR_MAP_TRANSFORM -#include <cstdint> #include <llmr/util/vec2.hpp> +#include <llmr/util/animation.hpp> + +#include <cstdint> +#include <forward_list> namespace llmr { @@ -15,6 +18,10 @@ class transform { public: transform(); + // Animations + bool needsAnimation() const; + void updateAnimations(); + // Relative changes void moveBy(double dx, double dy); void scaleBy(double ds, double cx, double cy); @@ -22,7 +29,7 @@ public: // Absolute changes void setScale(double scale); - void setAngle(double angle); + void setAngle(double angle, double duration = 0); void setZoom(double zoom); void setLonLat(double lon, double lat); @@ -58,6 +65,8 @@ private: // cache values for spherical mercator math double zc, Bc, Cc; + + std::forward_list<util::animation> animations; }; } diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index e198f5331c..30dca6216b 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -11,6 +11,7 @@ namespace platform { void restart(void *obj); void request(void *obj, std::shared_ptr<tile> tile); +double time(); } diff --git a/include/llmr/util/animation.hpp b/include/llmr/util/animation.hpp new file mode 100644 index 0000000000..bb52614407 --- /dev/null +++ b/include/llmr/util/animation.hpp @@ -0,0 +1,30 @@ +#ifndef LLMR_UTIL_ANIMATION +#define LLMR_UTIL_ANIMATION + +namespace llmr { +namespace util { + +class animation { +public: + enum state { + running, + complete + }; + + animation(double from, double to, double &value, double duration); + animation(const animation &) = delete; + animation(const animation &&) = delete; + animation &operator=(const animation &) = delete; + + state update() const; + +private: + const double start, duration; + const double from, to; + double &value; +}; + +} +} + +#endif diff --git a/include/llmr/util/unitbezier.hpp b/include/llmr/util/unitbezier.hpp new file mode 100644 index 0000000000..e64f7abd4a --- /dev/null +++ b/include/llmr/util/unitbezier.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LLMR_UTIL_UNITBEZIER +#define LLMR_UTIL_UNITBEZIER + +#include <cmath> + +namespace llmr { +namespace util { + +struct UnitBezier { + UnitBezier(double p1x, double p1y, double p2x, double p2y) { + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + cx = 3.0 * p1x; + bx = 3.0 * (p2x - p1x) - cx; + ax = 1.0 - cx - bx; + + cy = 3.0 * p1y; + by = 3.0 * (p2y - p1y) - cy; + ay = 1.0 - cy - by; + } + + double sampleCurveX(double t) { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((ax * t + bx) * t + cx) * t; + } + + double sampleCurveY(double t) { + return ((ay * t + by) * t + cy) * t; + } + + double sampleCurveDerivativeX(double t) { + return (3.0 * ax * t + 2.0 * bx) * t + cx; + } + + // Given an x value, find a parametric value it came from. + double solveCurveX(double x, double epsilon) { + double t0; + double t1; + double t2; + double x2; + double d2; + int i; + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (fabs (x2) < epsilon) + return t2; + d2 = sampleCurveDerivativeX(t2); + if (fabs(d2) < 1e-6) + break; + t2 = t2 - x2 / d2; + } + + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) + return t0; + if (t2 > t1) + return t1; + + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (fabs(x2 - x) < epsilon) + return t2; + if (x > x2) + t0 = t2; + else + t1 = t2; + t2 = (t1 - t0) * .5 + t0; + } + + // Failure. + return t2; + } + + double solve(double x, double epsilon) { + return sampleCurveY(solveCurveX(x, epsilon)); + } + +private: + double ax; + double bx; + double cx; + + double ay; + double by; + double cy; +}; + +} +} + +#endif diff --git a/macosx/main.mm b/macosx/main.mm index 80a7df00d4..3f8d8a54f5 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -255,6 +255,10 @@ void request(void *, tile::ptr tile) { }]; } +double time() { + return glfwGetTime(); +} + } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4db400e113..8d596e65f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,7 @@ SET(llmr_SOURCES renderer/shader-line.cpp renderer/shader.cpp shader/shaders.c + util/animation.cpp util/mat4.c ) @@ -25,6 +26,7 @@ SET(llmr_HEADERS ../include/llmr/renderer/shader-fill.hpp ../include/llmr/renderer/shader-line.hpp ../include/llmr/renderer/shader.hpp + ../include/llmr/util/animation.hpp ../include/llmr/util/math.hpp ../include/llmr/util/vec2.hpp ) diff --git a/src/map/map.cpp b/src/map/map.cpp index f550d90967..0fff04d75a 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -65,7 +65,7 @@ void map::rotateBy(double cx, double cy, double sx, double sy, double ex, double } void map::resetNorth() { - transform->setAngle(0); + transform->setAngle(0, 0.5); // 500 ms update(); settings->angle = transform->getAngle(); @@ -261,6 +261,8 @@ void map::updateTiles() { } bool map::render() { + transform->updateAnimations(); + painter->clear(); for (tile::ptr& tile : tiles) { @@ -270,7 +272,7 @@ bool map::render() { } } - return false; + return transform->needsAnimation(); } void map::tileLoaded(tile::ptr tile) { diff --git a/src/map/transform.cpp b/src/map/transform.cpp index 6dbfad1711..e314bcd3a8 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -1,5 +1,4 @@ #include <llmr/map/transform.hpp> - #include <llmr/util/mat4.h> #include <llmr/util/math.hpp> #include <cmath> @@ -29,6 +28,16 @@ transform::transform() setAngle(angle); } +bool transform::needsAnimation() const { + return !animations.empty(); +} + +void transform::updateAnimations() { + animations.remove_if([](const util::animation& animation) { + return animation.update() == util::animation::complete; + }); +} + void transform::moveBy(double dx, double dy) { x += cos(angle) * dx + sin(angle) * dy; y += cos(angle) * dy + sin(-angle) * dx; @@ -82,10 +91,15 @@ void transform::rotateBy(double anchor_x, double anchor_y, double start_x, doubl setAngle(ang); } -void transform::setAngle(double new_angle) { - angle = new_angle; - while (angle > M_PI) angle -= M2PI; - while (angle <= -M_PI) angle += M2PI; +void transform::setAngle(double new_angle, double duration) { + while (new_angle > M_PI) new_angle -= M2PI; + while (new_angle <= -M_PI) new_angle += M2PI; + + if (duration == 0) { + angle = new_angle; + } else { + animations.emplace_front(angle, new_angle, angle, duration); + } } void transform::setScale(double new_scale) { diff --git a/src/util/animation.cpp b/src/util/animation.cpp new file mode 100644 index 0000000000..a2c3e778e8 --- /dev/null +++ b/src/util/animation.cpp @@ -0,0 +1,26 @@ +#include <llmr/util/animation.hpp> +#include <llmr/util/unitbezier.hpp> +#include <llmr/platform/platform.hpp> + +using namespace llmr::util; + +UnitBezier ease(0.25, 0.1, 0.25, 1); + +animation::animation(double from, double to, double &value, double duration) + : start(platform::time()), + duration(duration), + from(from), + to(to), + value(value) { +} + +animation::state animation::update() const { + double t = (platform::time() - start) / duration; + if (t >= 1) { + value = to; + return complete; + } else { + value = from + (to - from) * ease.solve(t, 0.001); + return running; + } +} |