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);
31 view::inertial_gesture::inertial_gesture(maps_view_h view)
32 : gesture_detector(view)
35 , transiting_trajectory(false)
39 _d = new gesture_detector_statemachine(view);
41 //_maps_view_set_idle_listener(view, on_idle, this);
44 view::inertial_gesture::~inertial_gesture()
46 //_maps_view_set_idle_listener(_view, NULL, NULL);
53 view::inertial_gesture::inertial_gesture(const inertial_gesture &src)
54 : gesture_detector(NULL)
57 , transiting_trajectory(false)
61 view::inertial_gesture &view::inertial_gesture::operator=(const inertial_gesture &src)
66 void view::inertial_gesture::tap(int finger_no, const touch_point &tp)
68 MAPS_LOGI("TRANSITION finger %d tap time: %d",
69 finger_no, tp._timestamp);
71 _maps_view_halt_inertial_camera(_view);
73 if (transiting) { /* Halt the transition */
74 for (int i = 0; i < MAX_FINGERS; i ++) {
75 if (!transiting_part[i])
78 unsigned int timestamp = _last[i]._timestamp + get_transition_time(i);
80 const touch_point tp(_cur_x[i], _cur_y[i], timestamp);
81 MAPS_LOGI("TRANSITION finger %d up FAKE BRAKE time: %d", i, tp._timestamp);
89 _down[finger_no] = tp;
90 _last[finger_no] = tp;
91 _prev[finger_no] = tp;
92 _cur_x[finger_no] = tp._x;
93 _cur_y[finger_no] = tp._y;
94 _inertial_start[finger_no] = tp;
97 _d->tap(finger_no, tp);
100 void view::inertial_gesture::move(int finger_no, const touch_point &tp)
102 MAPS_LOGI("TRANSITION finger %d move", finger_no);
104 _maps_view_halt_inertial_camera(_view);
105 update_inertial_start_point(finger_no);
107 _prev[finger_no] = _last[finger_no];
108 _last[finger_no] = tp;
109 _cur_x[finger_no] = tp._x;
110 _cur_y[finger_no] = tp._y;
112 /* check if moved enough as much as effective length */
113 int trajectory = get_trajectory_effective_length(_down[finger_no], tp);
114 MAPS_LOGD("trajectory=%d", trajectory);
115 if (trajectory >= __CLICK_AREA)
116 transiting_trajectory = true;
119 _d->move(finger_no, tp);
122 void view::inertial_gesture::up(int finger_no, const touch_point &tp)
124 MAPS_LOGI("TRANSITION finger %d up time: %d", finger_no, tp._timestamp);
126 _last[finger_no] = tp;
128 const int delta_x = _last[finger_no]._x - _inertial_start[finger_no]._x;
129 const int delta_y = _last[finger_no]._y - _inertial_start[finger_no]._y;
130 unsigned int dt = _last[finger_no]._timestamp - _inertial_start[finger_no]._timestamp;
132 /* check if moved enough as much as effective length */
133 int trajectory_total = get_trajectory_effective_length(_down[finger_no], tp);
134 int trajectory_last = get_trajectory_effective_length(_prev[finger_no], tp);
136 /* check minimal size of click-area to be recognized as a valid gesture */
137 if (trajectory_total >= __CLICK_AREA)
138 transiting_trajectory = true;
140 /* to prevent inertial movement even by tapping gesture */
141 if (trajectory_last <= __CLICK_AREA / 3.)
142 transiting_trajectory = false;
144 if (dt == 0 || !transiting_trajectory) {
145 _derivative_x[finger_no] = .0;
146 _derivative_y[finger_no] = .0;
148 _derivative_x[finger_no] = 10. * (delta_x) / dt;
149 _derivative_y[finger_no] = 10. * (delta_y) / dt;
151 _dt[finger_no] = MIN(1.*dt, 1.);
153 /* Continue "move" with negative acceleration */
154 transiting_part[finger_no] = true;
155 transiting_start[finger_no] = get_cur_time();
159 bool view::inertial_gesture::next_transition_step()
161 MAPS_LOGI("TRANSITION get next transition step");
164 //static const double dt = 1.;
165 for (int i = 0; i < MAX_FINGERS; i ++) {
166 if (!transiting_part[i])
169 transiting_part[i] = false;
171 if ((ABS(_derivative_x[i]) > __ACCURACY) || (ABS(_derivative_y[i]) > __ACCURACY)) {
172 _cur_x[i] = get_next_point(_cur_x[i], _derivative_x[i], _dt[i]);
173 _derivative_x[i] = get_next_derivative(_derivative_x[i], _dt[i]);
174 transiting_part[i] |= ABS(_derivative_x[i]) > __ACCURACY;
176 _cur_y[i] = get_next_point(_cur_y[i], _derivative_y[i], _dt[i]);
177 _derivative_y[i] = get_next_derivative(_derivative_y[i], _dt[i]);
178 transiting_part[i] |= ABS(_derivative_y[i]) > __ACCURACY;
181 unsigned int timestamp = _last[i]._timestamp + get_transition_time(i);
183 const touch_point tp(_cur_x[i], _cur_y[i], timestamp);
184 if (transiting_part[i]) {
185 /* MAPS_LOGI("TRANSITION finger %d move FAKE time: %d", i, tp._timestamp); */
188 /* MAPS_LOGI("TRANSITION finger %d up FAKE time: %d", i, tp._timestamp); */
192 transiting = true; /* There were changes, so may be one more
193 step in transient is needed */
202 double view::inertial_gesture::get_next_point(const double &start,
203 const double &derivative,
206 /* Simple square parabola */
207 return (start + derivative * dt);
210 double view::inertial_gesture::get_next_derivative(const double &derivative,
213 /* Simple square parabola */
214 /*if (derivative > 0)
215 return (derivative + __ACCEL * dt);
217 return (derivative - __ACCEL * dt);*/
219 /* Exponential spped down */
220 if (_d->_info._fingers_pressed <= 1)
221 return (derivative * .9);
223 return (derivative * .5);
226 unsigned int view::inertial_gesture::get_cur_time()
229 unsigned int theTick = 0U;
230 clock_gettime(CLOCK_REALTIME, &ts);
231 theTick = ts.tv_nsec / 1000000;
232 theTick += ts.tv_sec * 1000;
236 unsigned int view::inertial_gesture::get_transition_time(int finger_no) const
238 return get_cur_time() - transiting_start[finger_no];
242 void view::inertial_gesture::on_idle(void *data)
244 inertial_gesture *ig = (inertial_gesture *)data;
245 if (ig && ig->transiting) {
246 MAPS_LOGI("TRANSITION on idle");
247 ig->next_transition_step();
253 void view::inertial_gesture::reset()
256 transiting_trajectory = false;
257 for (int i = 0; i < MAX_FINGERS; i ++) {
258 transiting_part[i] = false;
259 transiting_start[i] = 0;
263 void view::inertial_gesture::update_inertial_start_point(int finger_no)
265 const int margin = 3;
266 if (((_last[finger_no]._x > _prev[finger_no]._x + margin) && (_last[finger_no]._x < _inertial_start[finger_no]._x - margin)) ||
267 ((_last[finger_no]._x < _prev[finger_no]._x - margin) && (_last[finger_no]._x > _inertial_start[finger_no]._x + margin)) ||
268 ((_last[finger_no]._y > _prev[finger_no]._y + margin) && (_last[finger_no]._y < _inertial_start[finger_no]._y - margin)) ||
269 ((_last[finger_no]._y < _prev[finger_no]._y - margin) && (_last[finger_no]._y > _inertial_start[finger_no]._y + margin))) {
270 _inertial_start[finger_no] = _last[finger_no];
271 MAPS_LOGD("reset inertial start (%d,%d)", _inertial_start[finger_no]._x, _inertial_start[finger_no]._y);