1. Code synchronization with tizen_2.4
[platform/core/location/lbs-location.git] / location / manager / location-position.c
1 /*
2  * libslp-location
3  *
4  * Copyright (c) 2010-2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
7  *          Genie Kim <daejins.kim@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "location-position.h"
31 #include "location-setting.h"
32 #include "location-log.h"
33
34 #define         DEG2RAD(x)      ((x) * M_PI / 180)
35
36 GType
37 location_position_get_type(void)
38 {
39         static volatile gsize type_volatile = 0;
40         if (g_once_init_enter(&type_volatile)) {
41                 GType type = g_boxed_type_register_static(
42                                  g_intern_static_string("LocationPosition"),
43                                  (GBoxedCopyFunc) location_position_copy,
44                                  (GBoxedFreeFunc) location_position_free);
45                 g_once_init_leave(&type_volatile, type);
46         }
47         return type_volatile;
48 }
49
50 EXPORT_API LocationPosition *
51 location_position_new(guint timestamp,
52                       gdouble latitude,
53                       gdouble longitude,
54                       gdouble altitude,
55                       LocationStatus status)
56 {
57         if (latitude < -90 || latitude > 90) return NULL;
58         if (longitude < -180 || longitude > 180) return NULL;
59
60         LocationPosition *position = g_slice_new0(LocationPosition);
61         g_return_val_if_fail(position, NULL);
62
63         position->timestamp = timestamp;
64         position->latitude = latitude;
65         position->longitude = longitude;
66         position->altitude = altitude;
67         position->status = status;
68         return position;
69 }
70
71 EXPORT_API void
72 location_position_free(LocationPosition *position)
73 {
74         g_return_if_fail(position);
75         g_slice_free(LocationPosition, position);
76 }
77
78 EXPORT_API gboolean
79 location_position_equal(const LocationPosition *position1, const LocationPosition *position2)
80 {
81         g_return_val_if_fail(position1, FALSE);
82         g_return_val_if_fail(position2, FALSE);
83
84         if (position1->latitude == position2->latitude &&
85             position1->longitude == position2->longitude &&
86             position1->altitude == position2->altitude)
87                 return TRUE;
88         return FALSE;
89 }
90
91 EXPORT_API LocationPosition *
92 location_position_copy(const LocationPosition *position)
93 {
94         g_return_val_if_fail(position, NULL);
95
96         LocationPosition *new_position = NULL;
97
98         new_position = location_position_new(position->timestamp,
99                                              position->latitude,
100                                              position->longitude,
101                                              position->altitude,
102                                              position->status);
103
104         return new_position;
105
106 }
107
108 /* Vincenty formula. WGS-84 */
109 EXPORT_API int
110 location_get_distance(const LocationPosition *pos1, const LocationPosition *pos2, gulong *distance)
111 {
112         g_return_val_if_fail(pos1, LOCATION_ERROR_PARAMETER);
113         g_return_val_if_fail(pos2, LOCATION_ERROR_PARAMETER);
114         g_return_val_if_fail(distance, LOCATION_ERROR_PARAMETER);
115
116         *distance = 0;
117
118         const double a = 6378137.0, b = 6356752.314245, f = 1 / 298.257223563;
119         double delta_lon = DEG2RAD(pos2->longitude - pos1->longitude);
120         double u_1 = atan((1 - f) * tan(DEG2RAD(pos1->latitude)));
121         double u_2 = atan((1 - f) * tan(DEG2RAD(pos2->latitude)));
122
123         double lambdaP, iter_limit = 100.0;
124         double lambda = delta_lon;
125
126         double sin_sigma, sin_alpha, cos_sigma, sigma, sq_cos_alpha, cos_2sigma, C;
127         double sq_u, cal1, cal2, delta_sigma, cal_dist;
128         double sin_lambda, cos_lambda;
129
130         double sin_u1 = sin(u_1);
131         double cos_u1 = cos(u_1);
132         double sin_u2 = sin(u_2);
133         double cos_u2 = cos(u_2);
134
135         do {
136                 sin_lambda = sin(lambda);
137                 cos_lambda = cos(lambda);
138
139                 sin_sigma = sqrt((cos_u2 * sin_lambda) * (cos_u2 * sin_lambda) + \
140                                  (cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda) * \
141                                  (cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda));
142
143                 if (sin_sigma == 0)
144                         return LOCATION_ERROR_NONE;     /* co-incident points */
145
146                 cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda;
147                 sigma = atan2(sin_sigma, cos_sigma);
148
149                 sin_alpha = cos_u1 * cos_u2 * sin_lambda / sin_sigma;
150                 sq_cos_alpha = 1.0 - sin_alpha * sin_alpha;
151                 cos_2sigma = cos_sigma - 2.0 * sin_u1 * sin_u2 / sq_cos_alpha;
152
153                 if (isnan(cos_2sigma))
154                         cos_2sigma = 0;
155
156                 C = f / 16.0 * sq_cos_alpha * (4.0 + f * (4.0 - 3.0 * sq_cos_alpha));
157
158                 lambdaP = lambda;
159                 lambda = delta_lon + (1.0 - C) * f * sin_alpha * \
160                          (sigma + C * sin_sigma * (cos_2sigma + C * cos_sigma * (-1.0 + 2.0 * cos_2sigma * cos_2sigma)));
161
162         } while (abs(lambda - lambdaP) > 1e-12 && --iter_limit > 0);
163
164         if (iter_limit == 0) return LOCATION_ERROR_UNKNOWN;
165
166         sq_u = sq_cos_alpha * (a * a - b * b) / (b * b);
167
168         cal1 = 1.0 + sq_u / 16384.0 * (4096.0 + sq_u * (-768.0 + sq_u * (320.0 - 175.0 * sq_u)));
169         cal2 = sq_u / 1024.0 * (256.0 + sq_u * (-128.0 + sq_u * (74.0 - 47.0 * sq_u)));
170
171         delta_sigma = cal2 * sin_sigma * (cos_2sigma + cal2 / 4.0 * (cos_sigma * (-1.0 + 2.0 * cos_2sigma * cos_2sigma) - \
172                                                                      cal2 / 6.0 * cos_2sigma * (-3.0 + 4.0 * sin_sigma * sin_sigma) * (-3.0 + 4.0 * cos_2sigma * cos_2sigma)));
173         cal_dist = b * cal1 * (sigma - delta_sigma);
174
175         *distance = (gulong) cal_dist;
176
177         return LOCATION_ERROR_NONE;
178
179 }
180
181 EXPORT_API void
182 location_last_position_a2i(char *position, int *lat, int *lon)
183 {
184         char *d_lat, *d_lon;
185         char latitude[HALF_KEY_LENGTH];
186         char longitude[HALF_KEY_LENGTH];
187
188         memcpy(latitude, position + 1, HALF_KEY_LENGTH - 1);
189         memcpy(longitude, position + HALF_KEY_LENGTH + 1, HALF_KEY_LENGTH - 1);
190         latitude[HALF_KEY_LENGTH - 1] = '\0';
191         longitude[HALF_KEY_LENGTH - 1] = '\0';
192         d_lat = position;
193         d_lon = position + HALF_KEY_LENGTH;
194
195         *lat = atoi(latitude);
196         *lon = atoi(longitude);
197
198         if (*d_lat == 'S') {
199                 *lat = *lat * -1;
200         }
201         if (*d_lon == 'W') {
202                 *lon = *lon * -1;
203         }
204 }