Addition of API location_bounds_contains_coordinates_on_edge
[platform/core/api/location-manager.git] / src / location_bounds.c
1 /*
2  * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd All Rights Reserved
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 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <system_info.h>
21 #include "location_bounds.h"
22 #include "location_internal.h"
23
24
25 //LCOV_EXCL_START
26 static void __free_position_list(gpointer data)
27 {
28         if (data == NULL)
29                 return;
30
31         LocationPosition *position = (LocationPosition *) data;
32         location_position_free(position);
33 }
34 //LCOV_EXCL_STOP
35
36 static location_bounds_type_e __convert_bounds_type(LocationBoundaryType type)
37 {
38         location_bounds_type_e ret;
39         switch (type) {
40         case LOCATION_BOUNDARY_CIRCLE:
41                 ret = LOCATION_BOUNDS_CIRCLE;
42                 break;
43         case LOCATION_BOUNDARY_POLYGON:
44                 ret = LOCATION_BOUNDS_POLYGON;
45                 break;
46         case LOCATION_BOUNDARY_NONE:
47         case LOCATION_BOUNDARY_RECT:
48         default:
49                 ret = LOCATION_BOUNDS_RECT;
50                 break;
51         }
52         return ret;
53 }
54
55 EXPORT_API int location_bounds_create_rect(location_coords_s top_left, location_coords_s bottom_right, location_bounds_h *bounds)
56 {
57         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
58         LOCATIONS_NULL_ARG_CHECK(bounds);
59         LOCATIONS_CHECK_CONDITION(top_left.latitude >= -90 && top_left.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
60         LOCATIONS_CHECK_CONDITION(top_left.longitude >= -180 && top_left.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
61         LOCATIONS_CHECK_CONDITION(bottom_right.latitude >= -90 && bottom_right.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
62         LOCATIONS_CHECK_CONDITION(bottom_right.longitude >= -180 && bottom_right.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
63
64         if ((bottom_right.longitude - top_left.longitude) < 180 && (bottom_right.longitude - top_left.longitude) > -180) {
65                 if (bottom_right.longitude <= top_left.longitude || bottom_right.latitude >= top_left.latitude)
66                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
67         } else {
68                 if (bottom_right.latitude >= top_left.latitude)
69                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
70         }
71
72         LocationPosition *lt = location_position_new(0, top_left.latitude, top_left.longitude, 0, LOCATION_STATUS_2D_FIX);
73         if (lt == NULL) {
74                 //LCOV_EXCL_START
75                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
76                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
77                 //LCOV_EXCL_STOP
78         }
79
80         LocationPosition *rb = location_position_new(0, bottom_right.latitude, bottom_right.longitude, 0, LOCATION_STATUS_2D_FIX);
81         if (rb == NULL) {
82                 //LCOV_EXCL_START
83                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
84                 location_position_free(lt);
85                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
86                 //LCOV_EXCL_STOP
87         }
88
89         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
90         if (handle == NULL) {
91                 //LCOV_EXCL_START
92                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
93                 location_position_free(rb);
94                 location_position_free(lt);
95                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
96                 //LCOV_EXCL_STOP
97         }
98         memset(handle, 0, sizeof(location_bounds_s));
99
100         handle->is_added = FALSE;
101         handle->boundary = location_boundary_new_for_rect(lt, rb);
102         location_position_free(rb);
103         location_position_free(lt);
104         if (handle->boundary == NULL) {
105                 //LCOV_EXCL_START
106                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_rect", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
107                 free(handle);
108                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
109                 //LCOV_EXCL_STOP
110         }
111
112         *bounds = (location_bounds_h) handle;
113         return LOCATION_BOUNDS_ERROR_NONE;
114 }
115
116 EXPORT_API int location_bounds_create_circle(location_coords_s center, double radius, location_bounds_h *bounds)
117 {
118         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
119         LOCATIONS_NULL_ARG_CHECK(bounds);
120         LOCATIONS_CHECK_CONDITION(radius > 0, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
121         LOCATIONS_CHECK_CONDITION(center.latitude >= -90 && center.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
122         LOCATIONS_CHECK_CONDITION(center.longitude >= -180 && center.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
123
124         LocationPosition *ct = location_position_new(0, center.latitude, center.longitude, 0, LOCATION_STATUS_2D_FIX);
125         if (ct == NULL) {
126                 //LCOV_EXCL_START
127                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
128                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
129                 //LCOV_EXCL_STOP
130         }
131
132         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
133         if (handle == NULL) {
134                 //LCOV_EXCL_START
135                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
136                 location_position_free(ct);
137                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
138                 //LCOV_EXCL_STOP
139         }
140         memset(handle, 0, sizeof(location_bounds_s));
141
142         handle->is_added = FALSE;
143         handle->boundary = location_boundary_new_for_circle(ct, radius);
144         location_position_free(ct);
145         if (handle->boundary == NULL) {
146                 //LCOV_EXCL_START
147                 free(handle);
148                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_circle", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
149                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
150                 //LCOV_EXCL_STOP
151         }
152
153         *bounds = (location_bounds_h) handle;
154         return LOCATION_BOUNDS_ERROR_NONE;
155 }
156
157 EXPORT_API int location_bounds_create_polygon(location_coords_s *coords_list, int length, location_bounds_h *bounds)
158 {
159         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
160         LOCATIONS_NULL_ARG_CHECK(coords_list);
161         LOCATIONS_NULL_ARG_CHECK(bounds);
162         LOCATIONS_CHECK_CONDITION(length >= 3, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
163
164         int i;
165         GList *position_list = NULL;
166         LocationPosition *position = NULL;
167         bool isValid;
168
169         for (i = 0; i < length; i++) {
170                 if (coords_list[i].latitude < -90 || coords_list[i].latitude > 90 || coords_list[i].longitude < -180 || coords_list[i].longitude > 180) {
171                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x)", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
172                         isValid = FALSE;
173                         break;
174                 }
175                 position = location_position_new(0, coords_list[i].latitude, coords_list[i].longitude, 0.0, LOCATION_STATUS_2D_FIX);
176                 position_list = g_list_append(position_list, position);
177                 /* We should not remove position.
178                 location_position_free(position);
179                 */
180                 isValid = TRUE;
181         }
182
183         if (!isValid) {
184                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
185                 return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
186         }
187
188         if (position_list == NULL) {
189                 //LCOV_EXCL_START
190                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
191                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
192                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
193                 //LCOV_EXCL_STOP
194         }
195
196         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
197         if (handle == NULL) {
198                 //LCOV_EXCL_START
199                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
200                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
201                 //LCOV_EXCL_STOP
202         }
203         memset(handle, 0, sizeof(location_bounds_s));
204
205         handle->is_added = FALSE;
206         handle->boundary = location_boundary_new_for_polygon(position_list);
207         if (handle->boundary == NULL) {
208                 //LCOV_EXCL_START
209                 free(handle);
210                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
211                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
212                 //LCOV_EXCL_STOP
213         }
214
215         *bounds = (location_bounds_h) handle;
216         return LOCATION_BOUNDS_ERROR_NONE;
217 }
218
219 EXPORT_API bool location_bounds_contains_coordinates(location_bounds_h bounds, location_coords_s coords)
220 {
221         if (__is_location_supported() == LOCATIONS_ERROR_NOT_SUPPORTED) {
222                 //LCOV_EXCL_START
223                 set_last_result(LOCATIONS_ERROR_NOT_SUPPORTED);
224                 return FALSE;
225                 //LCOV_EXCL_STOP
226         }
227
228         if (!bounds) {
229                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
230                 return FALSE;
231         }
232
233         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180) {
234                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
235                 return FALSE;
236         }
237
238         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
239         if (pos == NULL) {
240                 //LCOV_EXCL_START
241                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
242                 set_last_result(LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
243                 return FALSE;
244                 //LCOV_EXCL_STOP
245         }
246         location_bounds_s *handle = (location_bounds_s *) bounds;
247         gboolean is_inside = location_boundary_if_inside(handle->boundary, pos);
248         location_position_free(pos);
249         bool result = is_inside ? TRUE : FALSE;
250
251         set_last_result(LOCATION_BOUNDS_ERROR_NONE);
252         return result;
253 }
254
255 EXPORT_API bool location_bounds_contains_coordinates_on_edge(location_bounds_h bounds, location_coords_s coords, double tolerance)
256 {
257         if (__is_location_supported() == LOCATIONS_ERROR_NOT_SUPPORTED) {
258                 //LCOV_EXCL_START
259                 set_last_result(LOCATIONS_ERROR_NOT_SUPPORTED);
260                 return FALSE;
261                 //LCOV_EXCL_STOP
262         }
263
264         if (!bounds) {
265                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
266                 return FALSE;
267         }
268
269         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180) {
270                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
271                 return FALSE;
272         }
273
274         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
275         if (pos == NULL) {
276                 //LCOV_EXCL_START
277                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
278                 set_last_result(LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
279                 return FALSE;
280                 //LCOV_EXCL_STOP
281         }
282         location_bounds_s *handle = (location_bounds_s *) bounds;
283         gboolean on_path = location_boundary_on_path(handle->boundary, pos, tolerance);
284         location_position_free(pos);
285         bool result = on_path ? TRUE : FALSE;
286
287         set_last_result(LOCATION_BOUNDS_ERROR_NONE);
288         return result;
289 }
290
291 EXPORT_API int location_bounds_get_type(location_bounds_h bounds, location_bounds_type_e *type)
292 {
293         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
294         LOCATIONS_NULL_ARG_CHECK(bounds);
295         LOCATIONS_NULL_ARG_CHECK(type);
296
297         location_bounds_s *handle = (location_bounds_s *) bounds;
298         *type = __convert_bounds_type(handle->boundary->type);
299         return LOCATION_BOUNDS_ERROR_NONE;
300 }
301
302 EXPORT_API int location_bounds_get_rect_coords(location_bounds_h bounds, location_coords_s *top_left, location_coords_s *bottom_right)
303 {
304         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
305         LOCATIONS_NULL_ARG_CHECK(bounds);
306         LOCATIONS_NULL_ARG_CHECK(top_left);
307         LOCATIONS_NULL_ARG_CHECK(bottom_right);
308
309         location_bounds_s *handle = (location_bounds_s *) bounds;
310         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_RECT) {
311                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
312                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
313         }
314
315         top_left->latitude = handle->boundary->rect.left_top->latitude;
316         top_left->longitude = handle->boundary->rect.left_top->longitude;
317         bottom_right->latitude = handle->boundary->rect.right_bottom->latitude;
318         bottom_right->longitude = handle->boundary->rect.right_bottom->longitude;
319         return LOCATION_BOUNDS_ERROR_NONE;
320 }
321
322 EXPORT_API int location_bounds_get_circle_coords(location_bounds_h bounds, location_coords_s *center, double *radius)
323 {
324         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
325         LOCATIONS_NULL_ARG_CHECK(bounds);
326         LOCATIONS_NULL_ARG_CHECK(center);
327         LOCATIONS_NULL_ARG_CHECK(radius);
328
329         location_bounds_s *handle = (location_bounds_s *) bounds;
330         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_CIRCLE) {
331                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
332                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
333         }
334
335         center->latitude = handle->boundary->circle.center->latitude;
336         center->longitude = handle->boundary->circle.center->longitude;
337         *radius = handle->boundary->circle.radius;
338         return LOCATION_BOUNDS_ERROR_NONE;
339 }
340
341 EXPORT_API int location_bounds_foreach_polygon_coords(location_bounds_h bounds, polygon_coords_cb callback, void *user_data)
342 {
343         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
344         LOCATIONS_NULL_ARG_CHECK(bounds);
345         LOCATIONS_NULL_ARG_CHECK(callback);
346
347         location_bounds_s *handle = (location_bounds_s *) bounds;
348         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_POLYGON) {
349                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
350                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
351         }
352
353         GList *list = handle->boundary->polygon.position_list;
354         while (list) {
355                 LocationPosition *pos = list->data;
356                 location_coords_s coords;
357                 coords.latitude = pos->latitude;
358                 coords.longitude = pos->longitude;
359
360                 if (callback(coords, user_data) != TRUE) {
361                         LOCATIONS_LOGI("User quit the loop ");
362                         break;
363                 }
364                 list = g_list_next(list);
365         }
366         return LOCATION_BOUNDS_ERROR_NONE;
367 }
368
369 EXPORT_API int location_bounds_destroy(location_bounds_h bounds)
370 {
371         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
372         LOCATIONS_NULL_ARG_CHECK(bounds);
373
374         location_bounds_s *handle = (location_bounds_s *) bounds;
375         if (handle->is_added) {
376                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_IS_ADDED(0x%08x)", LOCATION_BOUNDS_ERROR_IS_ADDED);
377                 return LOCATION_BOUNDS_ERROR_IS_ADDED;
378         }
379         location_boundary_free(handle->boundary);
380         handle->user_cb = NULL;
381         handle->user_data = NULL;
382         free(handle);
383         LOCATIONS_LOGE("");
384         return LOCATION_BOUNDS_ERROR_NONE;
385 }
386
387 EXPORT_API int location_bounds_set_state_changed_cb(location_bounds_h bounds, location_bounds_state_changed_cb callback, void *user_data)
388 {
389         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
390         LOCATIONS_NULL_ARG_CHECK(bounds);
391         LOCATIONS_NULL_ARG_CHECK(callback);
392
393         location_bounds_s *handle = (location_bounds_s *) bounds;
394         handle->user_cb = callback;
395         handle->user_data = user_data;
396         return LOCATION_BOUNDS_ERROR_NONE;
397 }
398
399 EXPORT_API int location_bounds_unset_state_changed_cb(location_bounds_h bounds)
400 {
401         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
402         LOCATIONS_NULL_ARG_CHECK(bounds);
403
404         location_bounds_s *handle = (location_bounds_s *) bounds;
405         handle->user_cb = NULL;
406         handle->user_data = NULL;
407         return LOCATION_BOUNDS_ERROR_NONE;
408 }