43ea5b291ba4ed4f4bb95cf3b8692c5c583b97bb
[platform/core/api/maps-service.git] / src / view / inertial_camera.cpp
1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
2  *
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17
18 #include "inertial_camera.h"
19 #include "maps_util.h"
20 #include "maps_view_plugin.h"
21 #include <glib.h>
22
23 int _maps_coordinates_copy(maps_coordinates_h orig, maps_coordinates_h dest);
24
25 view::inertial_camera::inertial_camera(maps_view_h view)
26         : _view(view)
27           , target_zoom_factor(.0)
28           , target_rotation_angle(.0)
29           , target_center(NULL)
30           , cur_zoom_factor(.0)
31           , cur_rotation_angle(.0)
32           , cur_center(NULL)
33           , transiting(false)
34 {
35 }
36
37 view::inertial_camera::inertial_camera(const inertial_camera &src)
38         : _view(NULL)
39           , target_zoom_factor(.0)
40           , target_rotation_angle(.0)
41           , target_center(NULL)
42           , cur_zoom_factor(.0)
43           , cur_rotation_angle(.0)
44           , cur_center(NULL)
45           , transiting(false)
46 {
47 }
48
49 view::inertial_camera &view::inertial_camera::operator=(const inertial_camera
50                                                         &src)
51 {
52         return *this;
53 }
54
55 view::inertial_camera::~inertial_camera()
56 {
57         maps_coordinates_destroy(target_center);
58         maps_coordinates_destroy(cur_center);
59 }
60
61 void view::inertial_camera::set_cur_state()
62 {
63         if (!_view)
64                 return;
65
66         if (!cur_center)
67                 maps_coordinates_destroy(cur_center);
68         maps_view_get_center(_view, &cur_center);
69         maps_view_get_zoom_factor(_view, &cur_zoom_factor);
70         maps_view_get_orientation(_view, &cur_rotation_angle);
71 }
72
73 void view::inertial_camera::set_targets(const maps_coordinates_h center,
74                                         const double &zoom_factor,
75                                         const double &rotation_angle)
76 {
77         if (!_view)
78                 return;
79
80         /* Store the targets */
81         if (!target_center) {
82                 maps_coordinates_clone(center, &target_center);
83         } else {
84                 _maps_coordinates_copy(center, target_center);
85         }
86
87         target_zoom_factor = zoom_factor;
88         target_rotation_angle = rotation_angle;
89
90         /* Store current state */
91         if (!transiting)
92                 set_cur_state();
93
94         /* Start transition */
95         transiting = true;
96 }
97
98 void view::inertial_camera::set_center_target(const maps_coordinates_h center)
99 {
100         if (!_view)
101                 return;
102
103         /* Store the target */
104         if (!target_center) {
105                 maps_coordinates_clone(center, &target_center);
106         } else {
107                 _maps_coordinates_copy(center, target_center);
108         }
109
110         /* Store current state */
111         if (!transiting)
112                 set_cur_state();
113
114         /* Start transition */
115         transiting = true;
116 }
117
118 void view::inertial_camera::set_zoom_target(const double &zoom_factor)
119 {
120         if (!_view)
121                 return;
122
123         /* Store the target */
124         target_zoom_factor = zoom_factor;
125
126         /* Store current state */
127         if (!transiting)
128                 set_cur_state();
129
130         /* Start transition */
131         transiting = true;
132 }
133
134 void view::inertial_camera::set_rotation_target(const double &rotation_angle)
135 {
136         if (!_view)
137                 return;
138
139         /* Store the target */
140         target_rotation_angle = rotation_angle;
141
142         /* Store current state */
143         if (!transiting)
144                 set_cur_state();
145
146         /* Start transition */
147         transiting = true;
148 }
149
150 double view::inertial_camera::calc_next_step(const double &start,
151                                              const double &finish,
152                                              const double step_ratio) const
153 {
154         if (start == finish)
155                 return start;
156
157         /* Expanential transition */
158         double step = (finish - start) * step_ratio;
159         double new_pos = start + step;
160         if (finish > start) {
161                 new_pos = MAX(new_pos, start);
162                 new_pos = MIN(new_pos, finish);
163         } else {
164                 new_pos = MIN(new_pos, start);
165                 new_pos = MAX(new_pos, finish);
166         }
167         return new_pos;
168 }
169
170 double view::inertial_camera::calc_next_step_lon(const double &start,
171                                              const double &finish,
172                                              const double step_ratio) const
173 {
174         if (start == finish)
175                 return start;
176
177         double _f = finish;
178         double _s = start;
179         if (_f < 0) _f += 360;
180         if (_s < 0) _s += 360;
181
182         double gap, gap1, gap2;
183         if (_f > _s) {
184                 gap1 = _f - _s;
185                 gap2 = (360 - _f) + _s;
186                 if (gap1 < gap2)
187                         gap = gap1;
188                 else
189                         gap = gap2 * -1;
190         } else {
191                 gap1 = _s - _f;
192                 gap2 = (360 - _s) + _f;
193                 if (gap1 < gap2)
194                         gap = gap1 * -1;
195                 else
196                         gap = gap2;
197         }
198
199         double step = gap * step_ratio;
200         double new_pos = start + step;
201         if (new_pos > 180)
202                 new_pos -= 360;
203         else if (new_pos < -180)
204                 new_pos += 360;
205
206         return new_pos;
207 }
208
209 bool view::inertial_camera::next_transition_step()
210 {
211         if (!_view)
212                 return false;
213
214         transiting = false;
215
216         double prev_lat = .0;
217         double prev_lon = .0;
218         double target_lat = .0;
219         double target_lon = .0;
220         maps_coordinates_get_latitude_longitude(cur_center, &prev_lat, &prev_lon);
221         maps_coordinates_get_latitude_longitude(target_center, &target_lat, &target_lon);
222
223         /* Transiting map center */
224         double next_lat = calc_next_step(prev_lat, target_lat, .15);
225         if (next_lat != prev_lat) transiting = true;
226
227         double next_lon = calc_next_step_lon(prev_lon, target_lon, .15);
228         if (next_lon != prev_lon) transiting = true;
229
230         if (transiting)
231         {
232                 int tx, ty, nx, ny;
233                 maps_coordinates_s next_center_s = { next_lat, next_lon };
234                 maps_view_geolocation_to_screen(_view, &next_center_s, &nx, &ny);
235                 maps_view_geolocation_to_screen(_view, target_center, &tx, &ty);
236                 if (nx == tx && ny == ty) {
237                         transiting = false;
238                         next_lat = target_lat;
239                         next_lon = target_lon;
240                 }
241         }
242
243         maps_coordinates_set_latitude_longitude(cur_center, next_lat, next_lon);
244
245         /* Transiting zoom */
246         cur_zoom_factor = calc_next_step(cur_zoom_factor, target_zoom_factor, .2);
247         if (ABS(cur_zoom_factor - target_zoom_factor) > __ZOOM_ACCURACY)
248                 transiting = true;
249         else
250                 cur_zoom_factor = target_zoom_factor;
251
252         /* Transizint orientation */
253         if (target_rotation_angle - cur_rotation_angle > 180.)
254                 target_rotation_angle -= 360.;
255         else if (target_rotation_angle - cur_rotation_angle < -180.)
256                 target_rotation_angle += 360.;
257
258         cur_rotation_angle = calc_next_step(cur_rotation_angle, target_rotation_angle, .5);
259         if (ABS(cur_rotation_angle - target_rotation_angle) > __ROTATE_ACCURACY)
260                 transiting = true;
261         else
262                 cur_rotation_angle = target_rotation_angle;
263
264         return transiting;
265 }