4 * Copyright (c) 2010-2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * location_boundary_if_inside(LocationBoundary* boundary,
21 * LocationPosition* position)
24 * Copyright (c) 1970-2003, Wm. Randolph Franklin
26 * Permission is hereby granted, free of charge, to any person obtaining a copy
27 * of this software and associated documentation files (the "Software"),
28 * to deal in the Software without restriction, including without limitation
29 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
30 * and/or sell copies of the Software, and to permit persons to whom
31 * the Software is furnished to do so, subject to the following conditions:
33 * 1.Redistributions of source code must retain the above copyright notice,
34 * this list of conditions and the following disclaimers.
35 * 2.Redistributions in binary form must reproduce the above copyright notice
36 * in the documentation and/or other materials provided with the distribution.
37 * 3.The name of W. Randolph Franklin may not be used to endorse or promote
38 * products derived from this Software without specific prior written permission.
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
44 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
51 * location_boundary_get_center_position (LocationBoundary *boundary)
52 * algorithm from http://en.wikipedia.org/wiki/Centroid
62 #include "location-boundary.h"
63 #include "location-common-util.h"
64 #include "location-log.h"
67 location_boundary_get_type(void)
69 static volatile gsize type_volatile = 0;
70 if (g_once_init_enter(&type_volatile)) {
71 GType type = g_boxed_type_register_static(
72 g_intern_static_string("LocationBoundary"),
73 (GBoxedCopyFunc) location_boundary_copy,
74 (GBoxedFreeFunc) location_boundary_free);
75 g_once_init_leave(&type_volatile, type);
80 static void _append_polygon_position(gpointer data, gpointer user_data)
82 g_return_if_fail(data);
83 g_return_if_fail(user_data);
85 LocationBoundary *boundary = (LocationBoundary *)user_data;
86 LocationPosition *position = (LocationPosition *)data;
87 LocationPosition *new_position = location_position_copy(position);
89 boundary->polygon.position_list = g_list_append(boundary->polygon.position_list, new_position);
92 static void _free_polygon_position(gpointer data)
94 g_return_if_fail(data);
96 LocationPosition *position = (LocationPosition *)data;
97 location_position_free(position);
100 EXPORT_API LocationBoundary *
101 location_boundary_new_for_rect(LocationPosition *left_top, LocationPosition *right_bottom)
103 g_return_val_if_fail(left_top, NULL);
104 g_return_val_if_fail(right_bottom, NULL);
106 gdouble lon_interval = right_bottom->longitude - left_top->longitude;
108 if (lon_interval < 180 && lon_interval > -180) {
109 if (right_bottom->longitude <= left_top->longitude || right_bottom->latitude >= left_top->latitude)
112 if (right_bottom->latitude >= left_top->latitude)
116 LocationBoundary *boundary = g_slice_new0(LocationBoundary);
117 g_return_val_if_fail(boundary, NULL);
119 boundary->type = LOCATION_BOUNDARY_RECT;
120 boundary->rect.left_top = location_position_copy(left_top);
121 boundary->rect.right_bottom = location_position_copy(right_bottom);
125 EXPORT_API LocationBoundary *
126 location_boundary_new_for_circle(LocationPosition *center, gdouble radius)
128 g_return_val_if_fail(center, NULL);
129 g_return_val_if_fail(radius > 0, NULL);
130 LocationBoundary *boundary = g_slice_new0(LocationBoundary);
131 g_return_val_if_fail(boundary, NULL);
133 boundary->type = LOCATION_BOUNDARY_CIRCLE;
134 boundary->circle.center = location_position_copy(center);
135 boundary->circle.radius = radius;
139 EXPORT_API LocationBoundary *
140 location_boundary_new_for_polygon(GList *position_list)
142 g_return_val_if_fail(position_list, NULL);
143 g_return_val_if_fail(g_list_length(position_list) > 2, NULL);
145 LocationBoundary *boundary = g_slice_new0(LocationBoundary);
146 g_return_val_if_fail(boundary, NULL);
148 g_list_foreach(position_list, (GFunc)_append_polygon_position, boundary);
149 boundary->type = LOCATION_BOUNDARY_POLYGON;
150 boundary->polygon.position_list = g_list_first(boundary->polygon.position_list);
156 location_boundary_free(LocationBoundary *boundary)
158 g_return_if_fail(boundary);
160 if (boundary->type == LOCATION_BOUNDARY_RECT) {
161 location_position_free(boundary->rect.left_top);
162 location_position_free(boundary->rect.right_bottom);
163 } else if (boundary->type == LOCATION_BOUNDARY_CIRCLE) {
164 location_position_free(boundary->circle.center);
165 } else if (boundary->type == LOCATION_BOUNDARY_POLYGON) {
166 g_list_free_full(boundary->polygon.position_list, (GDestroyNotify)_free_polygon_position);
168 g_slice_free(LocationBoundary, boundary);
171 EXPORT_API LocationBoundary *
172 location_boundary_copy(const LocationBoundary *boundary)
174 g_return_val_if_fail(boundary, NULL);
175 if (boundary->type == LOCATION_BOUNDARY_RECT)
176 return location_boundary_new_for_rect(boundary->rect.left_top, boundary->rect.right_bottom);
177 else if (boundary->type == LOCATION_BOUNDARY_CIRCLE)
178 return location_boundary_new_for_circle(boundary->circle.center, boundary->circle.radius);
179 else if (boundary->type == LOCATION_BOUNDARY_POLYGON)
180 return location_boundary_new_for_polygon(boundary->polygon.position_list);
186 location_boundary_if_inside(LocationBoundary *boundary, LocationPosition *position)
188 g_return_val_if_fail(boundary, FALSE);
189 g_return_val_if_fail(position, FALSE);
191 gboolean is_inside = FALSE;
193 switch (boundary->type) {
194 case LOCATION_BOUNDARY_RECT: {
195 gdouble y = position->latitude;
196 gdouble x = position->longitude;
198 gdouble lt_y = boundary->rect.left_top->latitude;
199 gdouble lt_x = boundary->rect.left_top->longitude;
200 gdouble rb_y = boundary->rect.right_bottom->latitude;
201 gdouble rb_x = boundary->rect.right_bottom->longitude;
203 if (lt_x - rb_x < 180 && lt_x - rb_x > -180) {
204 if ((rb_y < y && y < lt_y) && (lt_x < x && x < rb_x)) {
205 LOCATION_LOGD("\tInside of Rectangular boundary");
209 if ((rb_y < y && y < lt_y) && (lt_x < x || x < rb_x)) {
210 LOCATION_LOGD("\tInside of Rectangular boundary near 180th meridian");
216 case LOCATION_BOUNDARY_CIRCLE: {
218 LocationPosition center;
221 center.latitude = boundary->circle.center->latitude;
222 center.longitude = boundary->circle.center->longitude;
224 location_get_distance(¢er, position, &distance);
225 if (distance < boundary->circle.radius) {
226 LOCATION_LOGD("\tInside Circle boundary");
231 case LOCATION_BOUNDARY_POLYGON: {
233 double interval_x = 0.0, interval_y = 0.0;
234 double x0 = 0.0, y0 = 0.0;
236 int crossing_num = 0;
237 GList *position_list = boundary->polygon.position_list;
238 GList *pos1_list = NULL;
239 GList *pos2_list = NULL;
240 LocationPosition *pos1 = NULL;
241 LocationPosition *pos2 = NULL;
243 pos1_list = g_list_first(position_list);
244 pos2_list = g_list_last(position_list);
247 pos1 = pos1_list->data;
248 pos2 = pos2_list->data;
249 interval_y = pos1->longitude - pos2->longitude;
250 interval_x = pos1->latitude - pos2->latitude;
252 * Case 1. -180 < longitude2 - longitude1 < 180 : normal case
253 * Case 2. longitude2 - longitude1 < -180 : interval_y = longitude2 - longitude1 + 360
254 * Case 3. longitude2 - longitude1 > 180 : intreval_y = longitude2 - longitude1 - 360
256 if (interval_y > 180) {
257 interval_y = interval_y - 360;
259 } else if (interval_y < -180) {
260 interval_y = interval_y + 360;
264 if (edge_area && (pos1->longitude > position->longitude) == (pos2->longitude > position->longitude)) {
265 if (pos2->longitude * position->longitude > 0) {
267 y0 = pos2->longitude;
270 y0 = pos1->longitude;
273 if (position->latitude < ((interval_x / interval_y) * (position->longitude - y0) + x0)) {
275 LOCATION_LOGD("Reverse");
278 } else if (!edge_area && (pos1->longitude > position->longitude) != (pos2->longitude > position->longitude)) {
280 y0 = pos2->longitude;
281 if (position->latitude < ((interval_x / interval_y) * (position->longitude - y0) + x0)) {
282 LOCATION_LOGD("Common");
285 } else LOCATION_LOGD("It is not crossed.");
287 pos2_list = pos1_list;
288 pos1_list = g_list_next(pos1_list);
290 LOCATION_LOGW("num[%d]", crossing_num);
291 is_inside = crossing_num & 1; /* Odd : inside, Even : outside */
296 LOCATION_LOGW("\tboundary type is undefined.[%d]", boundary->type);
305 location_boundary_add(const LocationObject *obj, const LocationBoundary *boundary)
307 g_return_val_if_fail(obj, LOCATION_ERROR_PARAMETER);
308 g_return_val_if_fail(boundary, LOCATION_ERROR_PARAMETER);
310 GList *boundary_priv_list = NULL;
312 LocationBoundaryPrivate *priv = g_slice_new0(LocationBoundaryPrivate);
313 g_return_val_if_fail(priv, LOCATION_ERROR_PARAMETER);
315 priv->boundary = location_boundary_copy(boundary);
316 priv->zone_status = ZONE_STATUS_NONE;
318 boundary_priv_list = g_list_append(boundary_priv_list, (gpointer) priv);
320 g_object_set(G_OBJECT(obj), "boundary", boundary_priv_list, NULL);
322 g_list_free(boundary_priv_list);
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);
345 GList *boundary_priv_list = NULL;
346 GList *boundary_list = NULL;
347 LocationBoundaryPrivate *priv;
349 g_object_get(G_OBJECT(obj), "boundary", &boundary_priv_list, NULL);
351 if (boundary_priv_list == NULL) {
352 LOCATION_LOGD("There is no boundary.");
353 return LOCATION_ERROR_UNKNOWN;
356 while ((priv = (LocationBoundaryPrivate *)g_list_nth_data(boundary_priv_list, index)) != NULL) {
357 boundary_list = g_list_append(boundary_list, (gpointer) priv->boundary);
361 g_list_foreach(boundary_list, (GFunc)func, user_data);
362 g_list_free(boundary_list);
364 return LOCATION_ERROR_NONE;
367 EXPORT_API LocationBoundary *
368 location_boundary_get_bounding_box(LocationBoundary *boundary)
370 g_return_val_if_fail(boundary, NULL);
371 LocationBoundary *bbox = NULL;
376 EXPORT_API LocationPosition *
377 location_boundary_get_center_position(LocationBoundary *boundary)
379 g_return_val_if_fail(boundary, NULL);
381 LocationPosition *center = NULL;
383 switch (boundary->type) {
384 case LOCATION_BOUNDARY_RECT: {
385 gdouble latitude, longitude, altitude;
386 latitude = (boundary->rect.left_top->latitude + boundary->rect.right_bottom->latitude) / 2.0;
387 longitude = (boundary->rect.left_top->longitude + boundary->rect.right_bottom->longitude) / 2.0;
388 altitude = (boundary->rect.left_top->altitude + boundary->rect.right_bottom->altitude) / 2.0;
390 center = location_position_new(boundary->rect.left_top->timestamp, latitude, longitude, altitude, boundary->rect.left_top->status);
393 case LOCATION_BOUNDARY_CIRCLE: {
394 center = location_position_copy(boundary->circle.center);
397 case LOCATION_BOUNDARY_POLYGON: {
398 gdouble center_latitude = 0.0;
399 gdouble center_longitude = 0.0;
404 GList *position_list = boundary->polygon.position_list;
405 GList *pos1_list = g_list_first(position_list);
406 GList *pos2_list = g_list_next(pos1_list);
407 LocationPosition *pos1 = NULL;
408 LocationPosition *pos2 = NULL;
411 pos1 = pos1_list->data;
412 pos2 = pos2_list->data;
414 x1 = pos1->latitude + 90.0;
415 y1 = pos1->longitude + 180.0;
416 x2 = pos2->latitude + 90.0;
417 y2 = pos2->longitude + 180.0;
419 center_latitude += (x1 + x2) * (x1 * y2 - x2 * y1);
420 center_longitude += (y1 + y2) * (x1 * y2 - x2 * y1);
421 area += x1 * y2 - x2 * y1;
423 pos1_list = pos2_list;
424 pos2_list = g_list_next(pos2_list);
427 pos2_list = g_list_first(position_list);
428 pos1 = pos1_list->data;
429 pos2 = pos2_list->data;
431 x1 = pos1->latitude + 90.0;
432 y1 = pos1->longitude + 180.0;
433 x2 = pos2->latitude + 90.0;
434 y2 = pos2->longitude + 180.0;
436 center_latitude += (x1 + x2) * (x1 * y2 - x2 * y1);
437 center_longitude += (y1 + y2) * (x1 * y2 - x2 * y1);
438 area += x1 * y2 - x2 * y1;
440 area = fabs(area / 2.0);
442 center_latitude = (center_latitude - 90.0) / (6.0 * area);
443 center_longitude = (center_longitude - 180.0) / (6.0 * area);
444 center = location_position_new(0, center_latitude, center_longitude, 0, LOCATION_STATUS_2D_FIX);