4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Youngae Kang <youngae.kang@samsung.com>, Yunhan Kim <yhan.kim@samsung.com>,
7 * Genie Kim <daejins.kim@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * location_boundary_if_inside(LocationBoundary* boundary,
24 * LocationPosition* position)
27 * Copyright (c) 1970-2003, Wm. Randolph Franklin
29 * Permission is hereby granted, free of charge, to any person obtaining a copy
30 * of this software and associated documentation files (the "Software"),
31 * to deal in the Software without restriction, including without limitation
32 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
33 * and/or sell copies of the Software, and to permit persons to whom
34 * the Software is furnished to do so, subject to the following conditions:
36 * 1.Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimers.
38 * 2.Redistributions in binary form must reproduce the above copyright notice
39 * in the documentation and/or other materials provided with the distribution.
40 * 3.The name of W. Randolph Franklin may not be used to endorse or promote
41 * products derived from this Software without specific prior written permission.
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
47 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
59 #include "location-boundary.h"
60 #include "location-log.h"
63 location_boundary_get_type (void)
65 static volatile gsize type_volatile = 0;
66 if(g_once_init_enter(&type_volatile)) {
67 GType type = g_boxed_type_register_static (
68 g_intern_static_string ("LocationBoundary"),
69 (GBoxedCopyFunc) location_boundary_copy,
70 (GBoxedFreeFunc) location_boundary_free);
71 g_once_init_leave(&type_volatile, type);
76 static void _append_polygon_position(gpointer data, gpointer user_data)
78 g_return_if_fail(data);
79 g_return_if_fail(user_data);
81 LocationBoundary* boundary = (LocationBoundary*)user_data;
82 LocationPosition* position = (LocationPosition *)data;
83 LocationPosition* new_position = location_position_copy(position);
85 boundary->polygon.position_list = g_list_append(boundary->polygon.position_list, new_position);
88 static void _free_polygon_position(gpointer data)
90 g_return_if_fail(data);
92 LocationPosition* position = (LocationPosition *)data;
93 location_position_free(position);
97 EXPORT_API LocationBoundary *
98 location_boundary_new_for_rect (LocationPosition* left_top,
99 LocationPosition* right_bottom)
101 g_return_val_if_fail(left_top, NULL);
102 g_return_val_if_fail(right_bottom, NULL);
104 gdouble lon_interval = right_bottom->longitude - left_top->longitude;
106 if(lon_interval < 180 && lon_interval > -180) {
107 if(right_bottom->longitude <= left_top->longitude || right_bottom->latitude >= left_top->latitude)
111 if(right_bottom->longitude >= left_top->longitude || right_bottom->latitude >= left_top->latitude)
115 LocationBoundary* boundary = g_slice_new0 (LocationBoundary);
116 boundary->type = LOCATION_BOUNDARY_RECT;
117 boundary->rect.left_top = location_position_copy(left_top);
118 boundary->rect.right_bottom = location_position_copy(right_bottom);
122 EXPORT_API LocationBoundary *
123 location_boundary_new_for_circle (LocationPosition* center,
126 g_return_val_if_fail(center, NULL);
127 g_return_val_if_fail(radius > 0, NULL);
128 LocationBoundary* boundary = g_slice_new0 (LocationBoundary);
129 boundary->type = LOCATION_BOUNDARY_CIRCLE;
130 boundary->circle.center = location_position_copy(center);
131 boundary->circle.radius = radius;
135 EXPORT_API LocationBoundary *
136 location_boundary_new_for_polygon(GList *position_list)
138 g_return_val_if_fail(position_list, NULL);
139 g_return_val_if_fail(g_list_length(position_list) > 2, NULL);
141 LocationBoundary *boundary = g_slice_new0 (LocationBoundary);
143 g_list_foreach(position_list, (GFunc)_append_polygon_position, boundary);
144 boundary->type = LOCATION_BOUNDARY_POLYGON;
145 boundary->polygon.position_list = g_list_first(boundary->polygon.position_list);
151 location_boundary_free (LocationBoundary* boundary)
153 g_return_if_fail(boundary);
155 if (boundary->type == LOCATION_BOUNDARY_RECT) {
156 location_position_free(boundary->rect.left_top);
157 location_position_free(boundary->rect.right_bottom);
158 } else if (boundary->type == LOCATION_BOUNDARY_CIRCLE) {
159 location_position_free(boundary->circle.center);
160 } else if (boundary->type == LOCATION_BOUNDARY_POLYGON) {
161 g_list_free_full(boundary->polygon.position_list, (GDestroyNotify)_free_polygon_position);
163 g_slice_free(LocationBoundary, boundary);
166 EXPORT_API LocationBoundary*
167 location_boundary_copy (const LocationBoundary* boundary)
169 g_return_val_if_fail(boundary, NULL);
170 if (boundary->type == LOCATION_BOUNDARY_RECT) {
171 return location_boundary_new_for_rect(boundary->rect.left_top, boundary->rect.right_bottom);
172 } else if (boundary->type == LOCATION_BOUNDARY_CIRCLE) {
173 return location_boundary_new_for_circle(boundary->circle.center, boundary->circle.radius);
174 } else if (boundary->type == LOCATION_BOUNDARY_POLYGON) {
175 return location_boundary_new_for_polygon(boundary->polygon.position_list);
182 location_boundary_if_inside (LocationBoundary* boundary,
183 LocationPosition* position)
185 g_return_val_if_fail(boundary, FALSE);
186 g_return_val_if_fail(position, FALSE);
188 gboolean is_inside = FALSE;
190 switch(boundary->type) {
192 case LOCATION_BOUNDARY_RECT: {
193 gdouble y = position->latitude;
194 gdouble x = position->longitude;
196 gdouble lt_y = boundary->rect.left_top->latitude;
197 gdouble lt_x = boundary->rect.left_top->longitude;
198 gdouble rb_y = boundary->rect.right_bottom->latitude;
199 gdouble rb_x = boundary->rect.right_bottom->longitude;
201 if (lt_x - rb_x < 180 && lt_x - rb_x > -180) {
202 if ((rb_y < y && y < lt_y) && ( lt_x < x && x < rb_x)) {
203 LOCATION_LOGD("\tInside of Rectangular boundary");
208 if ((rb_y < y && y < lt_y) && ( lt_x < x || x < rb_x)) {
209 LOCATION_LOGD("\tInside of Rectangular boundary near 180th meridian");
215 case LOCATION_BOUNDARY_CIRCLE: {
217 LocationPosition center;
220 center.latitude = boundary->circle.center->latitude;
221 center.longitude = boundary->circle.center->longitude;
223 location_get_distance(¢er, position, &distance);
224 if (distance < boundary->circle.radius){
225 LOCATION_LOGD("\tInside Circle boundary");
230 case LOCATION_BOUNDARY_POLYGON: {
233 double interval_x = 0.0, interval_y = 0.0;
236 int crossing_num = 0;
237 GList *position_list = boundary->polygon.position_list;
238 int count = g_list_length(position_list);
239 GList *pos1_list = NULL;
240 GList *pos2_list = NULL;
241 LocationPosition* pos1 = NULL;
242 LocationPosition* pos2 = NULL;
246 pos1_list = g_list_first(position_list);
247 pos2_list = g_list_last(position_list);
250 pos1 = pos1_list->data;
251 pos2 = pos2_list->data;
252 interval_y = pos1->longitude - pos2->longitude;
253 interval_x = pos1->latitude - pos2->latitude;
255 * Case 1. -180 < longitude2 - longitude1 < 180 : normal case
256 * Case 2. longitude2 - longitude1 < -180 : interval_y = longitude2 - longitude1 + 360
257 * Case 3. longitude2 - longitude1 > 180 : intreval_y = longitude2 - longitude1 - 360
259 if (interval_y > 180) {
260 interval_y = interval_y - 360;
263 else if (interval_y < -180) {
264 interval_y = interval_y + 360;
268 if (edge_area && (pos1->longitude > position->longitude) == (pos2->longitude > position->longitude)){
269 if (pos2->longitude * position->longitude > 0) {
271 y0 = pos2->longitude;
275 y0 = pos1->longitude;
278 if (position->latitude < ((interval_x/interval_y)*(position->longitude - y0) + x0)) {
280 LOCATION_LOGD("Reverse");
284 else if (!edge_area && (pos1->longitude > position->longitude) != (pos2->longitude > position->longitude)) {
286 y0 = pos2->longitude;
287 if (position->latitude < ((interval_x/interval_y)*(position->longitude - y0) + x0)) {
288 LOCATION_LOGD("Common");
292 else LOCATION_LOGD("It is not crossed.");
294 pos2_list = pos1_list;
295 pos1_list = g_list_next(pos1_list);
297 LOCATION_LOGW("num[%d]", crossing_num);
298 is_inside = crossing_num & 1; // Odd : inside, Even : outside
303 LOCATION_LOGW("\tboundary type is undefined.[%d]", boundary->type);
312 location_boundary_add(const LocationObject *obj, const LocationBoundary *boundary)
314 g_return_val_if_fail (obj, LOCATION_ERROR_PARAMETER);
315 g_return_val_if_fail (boundary, LOCATION_ERROR_PARAMETER);
317 GList *boundary_list = NULL;
319 boundary_list = g_list_append(boundary_list, (gpointer) boundary);
321 g_object_set(G_OBJECT(obj), "boundary", boundary_list, NULL);
324 return LOCATION_ERROR_NONE;
328 location_boundary_remove(const LocationObject *obj, const LocationBoundary *boundary)
330 g_return_val_if_fail (obj, LOCATION_ERROR_PARAMETER);
331 g_return_val_if_fail (boundary, LOCATION_ERROR_PARAMETER);
333 g_object_set(G_OBJECT(obj), "removal-boundary", boundary, NULL);
335 return LOCATION_ERROR_NONE;
339 location_boundary_foreach(const LocationObject *obj, LocationBoundaryFunc func, gpointer user_data)
341 g_return_val_if_fail (obj, LOCATION_ERROR_PARAMETER);
342 g_return_val_if_fail (func, LOCATION_ERROR_PARAMETER);
344 GList * boundary_list = NULL;
346 g_object_get(G_OBJECT(obj), "boundary", &boundary_list, NULL);
348 if (boundary_list == NULL) {
349 LOCATION_LOGD("There is no boundary.");
350 return LOCATION_ERROR_UNKNOWN;
352 g_list_foreach(boundary_list, (GFunc)func, user_data);
354 return LOCATION_ERROR_NONE;
357 EXPORT_API LocationBoundary *
358 location_boundary_get_bounding_box (LocationBoundary *boundary)
360 g_return_val_if_fail (boundary, NULL);
361 LocationBoundary *bbox = NULL;
366 EXPORT_API LocationPosition *
367 location_boundary_get_center_position (LocationBoundary *boundary)
369 g_return_val_if_fail (boundary, NULL);
370 LocationPosition *center = NULL;