GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 34
Functions: 0.0% 0 / 0 / 3
Branches: 0.0% 0 / 0 / 12

shumate/shumate-kinetic-scrolling.c
Line Branch Exec Source
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 ✗ us_to_s (double t)
80 {
81 ✗ return t / 1000000.0;
82 }
83
84 ShumateKineticScrolling *
85 ✗ shumate_kinetic_scrolling_new (double decel_friction,
86 double initial_velocity)
87 {
88 ✗ ShumateKineticScrolling *data;
89
90 ✗ data = g_new0 (ShumateKineticScrolling, 1);
91 ✗ data->phase = SHUMATE_KINETIC_SCROLLING_PHASE_DECELERATING;
92 ✗ data->decel_friction = decel_friction;
93 ✗ data->c1 = initial_velocity / decel_friction;
94 ✗ data->c2 = -data->c1;
95 ✗ data->t_s = 0.0;
96 ✗ data->position = 0.0;
97 ✗ data->velocity = initial_velocity;
98
99 ✗ return data;
100 }
101
102 void
103 ✗ shumate_kinetic_scrolling_free (ShumateKineticScrolling *kinetic)
104 {
105 ✗ g_free (kinetic);
106 ✗ }
107
108 gboolean
109 ✗ shumate_kinetic_scrolling_tick (ShumateKineticScrolling *data,
110 double time_delta_us,
111 double *position)
112 {
113 ✗ switch(data->phase)
114 {
115 ✗ case SHUMATE_KINETIC_SCROLLING_PHASE_DECELERATING:
116 {
117 ✗ double last_position = data->position;
118 ✗ double last_time_ms = data->t_s;
119 ✗ double exp_part;
120
121 ✗ data->t_s += us_to_s (time_delta_us);
122
123 ✗ exp_part = exp (-data->decel_friction * data->t_s);
124 ✗ data->position = data->c1 + data->c2 * exp_part;
125 ✗ data->velocity = -data->decel_friction * data->c2 * exp_part;
126
127 ✗ if (fabs (data->velocity) < 1.0 ||
128 ✗ (last_time_ms != 0.0 && fabs (data->position - last_position) < 1.0))
129 {
130 ✗ data->phase = SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED;
131 ✗ data->position = round (data->position);
132 ✗ data->velocity = 0;
133 }
134 break;
135 }
136
137 case SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED:
138 default:
139 break;
140 }
141
142 ✗ if (position)
143 ✗ *position = data->position;
144
145 ✗ return data->phase != SHUMATE_KINETIC_SCROLLING_PHASE_FINISHED;
146 }
147