Branch data Line data Source code
1 : : /* 2 : : * Copyright (C) 2014 Lieven van der Heide 3 : : * Copyright (C) 2021 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> 4 : : * 5 : : * This library is free software; you can redistribute it and/or 6 : : * modify it under the terms of the GNU Lesser General Public 7 : : * License as published by the Free Software Foundation; either 8 : : * version 2.1 of the License, or (at your option) any later version. 9 : : * 10 : : * This library is distributed in the hope that it will be useful, 11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 : : * Lesser General Public License for more details. 14 : : * 15 : : * You should have received a copy of the GNU Lesser General Public 16 : : * License along with this library; if not, write to the Free Software 17 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 : : */ 19 : : 20 : : #include "shumate-kinetic-scrolling-private.h" 21 : : 22 : : #include <math.h> 23 : : #include <stdio.h> 24 : : 25 : : /* 26 : : * All our curves are second degree linear differential equations, and 27 : : * so they can always be written as linear combinations of 2 base 28 : : * solutions. c1 and c2 are the coefficients to these two base solutions, 29 : : * and are computed from the initial position and velocity. 30 : : * 31 : : * In the case of simple deceleration, the differential equation is 32 : : * 33 : : * y'' = -my' 34 : : * 35 : : * With m the resistance factor. For this we use the following 2 36 : : * base solutions: 37 : : * 38 : : * f1(x) = 1 39 : : * f2(x) = exp(-mx) 40 : : * 41 : : * In the case of overshoot, the differential equation is 42 : : * 43 : : * y'' = -my' - ky 44 : : * 45 : : * With m the resistance, and k the spring stiffness constant. We let 46 : : * k = m^2 / 4, so that the system is critically damped (ie, returns to its 47 : : * equilibrium position as quickly as possible, without oscillating), and offset 48 : : * the whole thing, such that the equilibrium position is at 0. This gives the 49 : : * base solutions 50 : : * 51 : : * f1(x) = exp(-mx / 2) 52 : : * f2(x) = t exp(-mx / 2) 53 : : */ 54 : : 55 : : typedef enum { 56 : : SHUMATE_KINETIC_SCROLLING_PHASE_DECELERATING, 57 : : SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED, 58 : : } ShumateKineticScrollingPhase; 59 : : 60 : : struct _ShumateKineticScrolling 61 : : { 62 : : ShumateKineticScrollingPhase phase; 63 : : double lower; 64 : : double upper; 65 : : double overshoot_width; 66 : : double decel_friction; 67 : : double overshoot_friction; 68 : : 69 : : double c1; 70 : : double c2; 71 : : double equilibrium_position; 72 : : 73 : : double t_s; 74 : : double position; 75 : : double velocity; 76 : : }; 77 : : 78 : : static inline double 79 : 0 : us_to_s (double t) 80 : : { 81 : 0 : return t / 1000000.0; 82 : : } 83 : : 84 : : ShumateKineticScrolling * 85 : 0 : shumate_kinetic_scrolling_new (double decel_friction, 86 : : double initial_velocity) 87 : : { 88 : 0 : ShumateKineticScrolling *data; 89 : : 90 : 0 : data = g_new0 (ShumateKineticScrolling, 1); 91 : 0 : data->phase = SHUMATE_KINETIC_SCROLLING_PHASE_DECELERATING; 92 : 0 : data->decel_friction = decel_friction; 93 : 0 : data->c1 = initial_velocity / decel_friction; 94 : 0 : data->c2 = -data->c1; 95 : 0 : data->t_s = 0.0; 96 : 0 : data->position = 0.0; 97 : 0 : data->velocity = initial_velocity; 98 : : 99 : 0 : return data; 100 : : } 101 : : 102 : : void 103 : 0 : shumate_kinetic_scrolling_free (ShumateKineticScrolling *kinetic) 104 : : { 105 : 0 : g_free (kinetic); 106 : 0 : } 107 : : 108 : : gboolean 109 : 0 : shumate_kinetic_scrolling_tick (ShumateKineticScrolling *data, 110 : : double time_delta_us, 111 : : double *position) 112 : : { 113 [ # # ]: 0 : switch(data->phase) 114 : : { 115 : 0 : case SHUMATE_KINETIC_SCROLLING_PHASE_DECELERATING: 116 : : { 117 : 0 : double last_position = data->position; 118 : 0 : double last_time_ms = data->t_s; 119 : 0 : double exp_part; 120 : : 121 : 0 : data->t_s += us_to_s (time_delta_us); 122 : : 123 : 0 : exp_part = exp (-data->decel_friction * data->t_s); 124 : 0 : data->position = data->c1 + data->c2 * exp_part; 125 : 0 : data->velocity = -data->decel_friction * data->c2 * exp_part; 126 : : 127 [ # # # # ]: 0 : if (fabs (data->velocity) < 1.0 || 128 [ # # ]: 0 : (last_time_ms != 0.0 && fabs (data->position - last_position) < 1.0)) 129 : : { 130 : 0 : data->phase = SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED; 131 : 0 : data->position = round (data->position); 132 : 0 : data->velocity = 0; 133 : : } 134 : : break; 135 : : } 136 : : 137 : : case SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED: 138 : : default: 139 : : break; 140 : : } 141 : : 142 [ # # ]: 0 : if (position) 143 : 0 : *position = data->position; 144 : : 145 : 0 : return data->phase != SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED; 146 : : }