#include "location-boundary.h"
#include "location-common-util.h"
#include "location-log.h"
+#include "location-position.h"
+#define DEG2RAD(x) ((x) * M_PI / 180)
+#define RAD2DEG(x) ((x) * 180 / M_PI)
+#define EARTH_RADIUS 6371009
+
+static double mercator(double latitude)
+{
+ return log(tan(latitude * 0.5 + M_PI / 4));
+}
+
+static double inverseMercator(double x)
+{
+ return 2 * atan(exp(x)) - M_PI / 2;
+}
+
+static double wrap(double n, double min, double max)
+{
+ return (n >= min && n < max) ? n : (fmod(n - min, max - min) + min);
+}
GType
location_boundary_get_type(void)
return is_inside;
}
+EXPORT_API gboolean
+location_boundary_on_path(LocationBoundary *boundary, LocationPosition *position, double tolerance)
+{
+ g_return_val_if_fail(boundary, FALSE);
+ g_return_val_if_fail(position, FALSE);
+ g_return_val_if_fail(tolerance, FALSE);
+
+ switch (boundary->type) {
+ case LOCATION_BOUNDARY_RECT: {
+ double lt_x = boundary->rect.left_top->latitude;
+ double lt_y = boundary->rect.left_top->longitude;
+ double rb_x = boundary->rect.right_bottom->latitude;
+ double rb_y = boundary->rect.right_bottom->longitude;
+ GList *pos1_list = NULL;
+ GList *pos2_list = NULL;
+ LocationPosition *_position = location_position_new(0, lt_x, lt_y, 0.0, LOCATION_STATUS_2D_FIX);
+ pos1_list = g_list_append(pos1_list, _position);
+ _position = location_position_new(0, rb_x, lt_y, 0.0, LOCATION_STATUS_2D_FIX);
+ pos1_list = g_list_append(pos1_list, _position);
+ _position = location_position_new(0, rb_x, rb_y, 0.0, LOCATION_STATUS_2D_FIX);
+ pos1_list = g_list_append(pos1_list, _position);
+ _position = location_position_new(0, lt_x, rb_y, 0.0, LOCATION_STATUS_2D_FIX);
+ pos1_list = g_list_append(pos1_list, _position);
+
+ LocationPosition *pos1 = NULL;
+ LocationPosition *pos2 = NULL;
+ LocationPosition *pos = position;
+ LocationPosition *posClose = NULL;
+ double lat3 = DEG2RAD(pos->latitude);
+ double lon3 = DEG2RAD(pos->longitude);
+ double lat1 = 0.0, lon1 = 0.0, lat2 = 0.0, lon2 = 0.0;
+ double x1 = 0.0, y1 = 0.0, x2 = 0.0, x3 = 0.0, y3 = 0.0, xClose = 0.0, yClose = 0.0, latClose = 0.0, px = 0.0, norm = 0.0, u = 0.0, distance = 0.0;
+ double minBound = lat3 - tolerance/EARTH_RADIUS;
+ double maxBound = lat3 + tolerance/EARTH_RADIUS;
+
+ pos1_list = g_list_first(pos1_list);
+ pos2_list = g_list_last(pos1_list);
+ while (pos1_list)
+ {
+ pos1 = pos1_list->data;
+ pos2 = pos2_list->data;
+
+ lat1 = DEG2RAD(pos1->latitude);
+ lon1 = DEG2RAD(pos1->longitude);
+
+ lat2 = DEG2RAD(pos2->latitude);
+ lon2 = DEG2RAD(pos2->longitude);
+
+ x2 = mercator(lat2);
+ x3 = mercator(lat3);
+
+ if(fmax(lat1, lat2) >= minBound && fmin(lat1, lat2) <= maxBound)
+ {
+ x1 = mercator(lat1);
+
+ // longitudes values are offset by -lon2; the implicit y2 is 0.
+ y1 = wrap(lon1-lon2, - M_PI, M_PI);
+ y3 = wrap(lon3-lon2, - M_PI, M_PI);
+
+ px = x1 - x2;
+ norm = y1 * y1 + px * px;
+ u = ( y3 * y1 + ( x3 - x2 ) * px ) / norm;
+ if(norm <= 0){
+ u = 0;
+ }else{
+ if( u > 1){
+ u = 1;
+ }else if (u < 0){
+ u = 0;
+ }
+ }
+ xClose = x2 + u * px;
+ yClose = u * y1;
+ latClose = inverseMercator(xClose);
+ posClose = location_position_new(0, RAD2DEG(latClose), RAD2DEG(yClose + lon2), 0.0, LOCATION_STATUS_2D_FIX);
+ location_get_distance(pos, posClose, &distance);
+ if (posClose) location_position_free(posClose);
+ if(distance < tolerance)
+ {
+ return TRUE;
+ }
+ }
+ pos2_list = pos1_list;
+ pos1_list = g_list_next(pos1_list);
+ lat2 = lat1;
+ lon2 = lon1;
+ x2 = x1;
+ }
+ if(_position) location_position_free(_position);
+ if(pos1_list) g_list_free(pos1_list);
+ if(pos2_list) g_list_free(pos2_list);
+ break;
+ }
+
+ case LOCATION_BOUNDARY_CIRCLE: {
+ LocationPosition center;
+ double distance = 0;
+
+ center.latitude = boundary->circle.center->latitude;
+ center.longitude = boundary->circle.center->longitude;
+
+ location_get_distance(¢er, position, &distance);
+ if (distance < boundary->circle.radius + tolerance) {
+ return TRUE;
+ }
+ break;
+ }
+
+ case LOCATION_BOUNDARY_POLYGON: {
+ GList *position_list = boundary->polygon.position_list;
+ GList *pos1_list = NULL;
+ GList *pos2_list = NULL;
+ LocationPosition *pos1 = NULL;
+ LocationPosition *pos2 = NULL;
+ LocationPosition *pos = position;
+ LocationPosition *posClose = NULL;
+ double lat3 = DEG2RAD(pos->latitude);
+ double lon3 = DEG2RAD(pos->longitude);
+ double lat1 = 0.0, lon1 = 0.0, lat2 = 0.0, lon2 = 0.0;
+ double x1 = 0.0, y1 = 0.0, x2 = 0.0, x3 = 0.0, y3 = 0.0, xClose = 0.0, yClose = 0.0, latClose = 0.0, px = 0.0, norm = 0.0, u = 0.0, distance = 0.0;
+ double minBound = lat3 - tolerance/EARTH_RADIUS;
+ double maxBound = lat3 + tolerance/EARTH_RADIUS;
+
+ pos1_list = g_list_first(position_list);
+ pos2_list = g_list_last(position_list);
+ while (pos1_list)
+ {
+ pos1 = pos1_list->data;
+ pos2 = pos2_list->data;
+
+ lat1 = DEG2RAD(pos1->latitude);
+ lon1 = DEG2RAD(pos1->longitude);
+
+ lat2 = DEG2RAD(pos2->latitude);
+ lon2 = DEG2RAD(pos2->longitude);
+
+ x2 = mercator(lat2);
+ x3 = mercator(lat3);
+
+ if(fmax(lat1, lat2) >= minBound && fmin(lat1, lat2) <= maxBound)
+ {
+ x1 = mercator(lat1);
+
+ // longitudes values are offset by -lon2; the implicit y2 is 0.
+ y1 = wrap(lon1-lon2, - M_PI, M_PI);
+ y3 = wrap(lon3-lon2, - M_PI, M_PI);
+
+ px = x1 - x2;
+ norm = y1 * y1 + px * px;
+ u = ( y3 * y1 + ( x3 - x2 ) * px ) / norm;
+ if(norm <= 0){
+ u = 0;
+ }else{
+ if( u > 1){
+ u = 1;
+ }else if (u < 0){
+ u = 0;
+ }
+ }
+ xClose = x2 + u * px;
+ yClose = u * y1;
+ latClose = inverseMercator(xClose);
+ posClose = location_position_new(0, RAD2DEG(latClose), RAD2DEG(yClose + lon2), 0.0, LOCATION_STATUS_2D_FIX);
+ location_get_distance(pos, posClose, &distance);
+ if (posClose) location_position_free(posClose);
+ if(distance < tolerance)
+ {
+ return TRUE;
+ }
+ }
+ pos2_list = pos1_list;
+ pos1_list = g_list_next(pos1_list);
+ lat2 = lat1;
+ lon2 = lon1;
+ x2 = x1;
+ }
+ break;
+ }
+ default: {
+ LOCATION_LOGW("\tboundary type is undefined.[%d]", boundary->type);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+
EXPORT_API int
location_boundary_add(const LocationObject *obj, const LocationBoundary *boundary)
{