1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "inertial_gesture.h"
19 #include "maps_util.h"
21 #include "gesture_detector_statemachine.h"
25 extern void _maps_view_set_idle_listener(maps_view_h view,
26 void (*callback)(void *user_data),
29 extern void _maps_view_halt_inertial_camera(maps_view_h view);
32 view::inertial_gesture::inertial_gesture(maps_view_h view)
33 : gesture_detector(view)
36 , transiting_trajectory(false)
40 _d = new gesture_detector_statemachine(view);
42 //_maps_view_set_idle_listener(view, on_idle, this);
45 view::inertial_gesture::~inertial_gesture()
47 //_maps_view_set_idle_listener(_view, NULL, NULL);
54 view::inertial_gesture::inertial_gesture(const inertial_gesture &src)
55 : gesture_detector(NULL)
58 , transiting_trajectory(false)
62 view::inertial_gesture &view::inertial_gesture::operator=(const inertial_gesture &src)
67 void view::inertial_gesture::tap(int finger_no, const touch_point &tp)
69 MAPS_LOGI("TRANSITION finger %d tap time: %d",
70 finger_no, tp._timestamp);
72 _maps_view_halt_inertial_camera(_view);
74 if (transiting) { /* Halt the transition */
75 for (int i = 0; i < MAX_FINGERS; i ++) {
76 if (!transiting_part[i])
79 unsigned int timestamp = _last[i]._timestamp + get_transition_time(i);
81 const touch_point tp(_cur_x[i], _cur_y[i], timestamp);
82 MAPS_LOGI("TRANSITION finger %d up FAKE BRAKE time: %d", i, tp._timestamp);
90 _down[finger_no] = tp;
91 _last[finger_no] = tp;
92 _prev[finger_no] = tp;
93 _cur_x[finger_no] = tp._x;
94 _cur_y[finger_no] = tp._y;
95 _inertial_start[finger_no] = tp;
98 _d->tap(finger_no, tp);
101 void view::inertial_gesture::move(int finger_no, const touch_point &tp)
103 MAPS_LOGI("TRANSITION finger %d move", finger_no);
105 _maps_view_halt_inertial_camera(_view);
106 update_inertial_start_point(finger_no);
108 _prev[finger_no] = _last[finger_no];
109 _last[finger_no] = tp;
110 _cur_x[finger_no] = tp._x;
111 _cur_y[finger_no] = tp._y;
113 /* check if moved enough as much as effective length */
114 int trajectory = get_trajectory_effective_length(_down[finger_no], tp);
115 MAPS_LOGD("trajectory=%d", trajectory);
116 if (trajectory >= __CLICK_AREA)
117 transiting_trajectory = true;
120 _d->move(finger_no, tp);
123 void view::inertial_gesture::up(int finger_no, const touch_point &tp)
125 MAPS_LOGI("TRANSITION finger %d up time: %d", finger_no, tp._timestamp);
127 _last[finger_no] = tp;
129 const int delta_x = _last[finger_no]._x - _inertial_start[finger_no]._x;
130 const int delta_y = _last[finger_no]._y - _inertial_start[finger_no]._y;
131 unsigned int dt = _last[finger_no]._timestamp - _inertial_start[finger_no]._timestamp;
133 /* check if moved enough as much as effective length */
134 int trajectory_total = get_trajectory_effective_length(_down[finger_no], tp);
135 int trajectory_last = get_trajectory_effective_length(_prev[finger_no], tp);
137 /* check minimal size of click-area to be recognized as a valid gesture */
138 if (trajectory_total >= __CLICK_AREA)
139 transiting_trajectory = true;
141 /* to prevent inertial movement even by tapping gesture */
142 if (trajectory_last <= __CLICK_AREA / 3.)
143 transiting_trajectory = false;
145 if (dt == 0 || !transiting_trajectory) {
146 _derivative_x[finger_no] = .0;
147 _derivative_y[finger_no] = .0;
149 _derivative_x[finger_no] = 10. * (delta_x) / dt;
150 _derivative_y[finger_no] = 10. * (delta_y) / dt;
152 _dt[finger_no] = MIN(1.*dt, 1.);
154 /* Continue "move" with negative acceleration */
155 transiting_part[finger_no] = true;
156 transiting_start[finger_no] = get_cur_time();
160 bool view::inertial_gesture::next_transition_step()
162 MAPS_LOGI("TRANSITION get next transition step");
165 //static const double dt = 1.;
166 for (int i = 0; i < MAX_FINGERS; i ++) {
167 if (!transiting_part[i])
170 transiting_part[i] = false;
172 if ((ABS(_derivative_x[i]) > __ACCURACY) || (ABS(_derivative_y[i]) > __ACCURACY)) {
173 _cur_x[i] = get_next_point(_cur_x[i], _derivative_x[i], _dt[i]);
174 _derivative_x[i] = get_next_derivative(_derivative_x[i], _dt[i]);
175 transiting_part[i] |= ABS(_derivative_x[i]) > __ACCURACY;
177 _cur_y[i] = get_next_point(_cur_y[i], _derivative_y[i], _dt[i]);
178 _derivative_y[i] = get_next_derivative(_derivative_y[i], _dt[i]);
179 transiting_part[i] |= ABS(_derivative_y[i]) > __ACCURACY;
182 unsigned int timestamp = _last[i]._timestamp + get_transition_time(i);
184 const touch_point tp(_cur_x[i], _cur_y[i], timestamp);
185 if (transiting_part[i]) {
186 /* MAPS_LOGI("TRANSITION finger %d move FAKE time: %d", i, tp._timestamp); */
189 /* MAPS_LOGI("TRANSITION finger %d up FAKE time: %d", i, tp._timestamp); */
193 transiting = true; /* There were changes, so may be one more
194 step in transient is needed */
203 double view::inertial_gesture::get_next_point(const double &start,
204 const double &derivative,
207 /* Simple square parabola */
208 return (start + derivative * dt);
211 double view::inertial_gesture::get_next_derivative(const double &derivative,
214 /* Simple square parabola */
215 /*if (derivative > 0)
216 return (derivative + __ACCEL * dt);
218 return (derivative - __ACCEL * dt);*/
220 /* Exponential spped down */
221 if (_d->_info._fingers_pressed <= 1)
222 return (derivative * .9);
224 return (derivative * .5);
227 unsigned int view::inertial_gesture::get_cur_time()
230 unsigned int theTick = 0U;
231 clock_gettime(CLOCK_REALTIME, &ts);
232 theTick = ts.tv_nsec / 1000000;
233 theTick += ts.tv_sec * 1000;
237 unsigned int view::inertial_gesture::get_transition_time(int finger_no) const
239 return get_cur_time() - transiting_start[finger_no];
243 void view::inertial_gesture::on_idle(void *data)
245 inertial_gesture *ig = (inertial_gesture *)data;
246 if (ig && ig->transiting) {
247 MAPS_LOGI("TRANSITION on idle");
248 ig->next_transition_step();
254 void view::inertial_gesture::reset()
257 transiting_trajectory = false;
258 for (int i = 0; i < MAX_FINGERS; i ++) {
259 transiting_part[i] = false;
260 transiting_start[i] = 0;
264 void view::inertial_gesture::update_inertial_start_point(int finger_no)
266 const int margin = 3;
267 if (((_last[finger_no]._x > _prev[finger_no]._x + margin) && (_last[finger_no]._x < _inertial_start[finger_no]._x - margin)) ||
268 ((_last[finger_no]._x < _prev[finger_no]._x - margin) && (_last[finger_no]._x > _inertial_start[finger_no]._x + margin)) ||
269 ((_last[finger_no]._y > _prev[finger_no]._y + margin) && (_last[finger_no]._y < _inertial_start[finger_no]._y - margin)) ||
270 ((_last[finger_no]._y < _prev[finger_no]._y - margin) && (_last[finger_no]._y > _inertial_start[finger_no]._y + margin))) {
271 _inertial_start[finger_no] = _last[finger_no];
272 MAPS_LOGD("reset inertial start (%d,%d)", _inertial_start[finger_no]._x, _inertial_start[finger_no]._y);