From e7af647f42f8d6815dc1d5f20f7b231af4e03608 Mon Sep 17 00:00:00 2001 From: chakradhar Date: Tue, 23 Jun 2020 15:29:05 +0530 Subject: [PATCH] Addition of API location_boundary_on_path Change-Id: Ia92f5315070c37285fd2fdaacdf1a23279e89477 --- location/manager/location-boundary.c | 206 +++++++++++++++++++++++++++++++++++ location/manager/location-boundary.h | 13 +++ 2 files changed, 219 insertions(+) diff --git a/location/manager/location-boundary.c b/location/manager/location-boundary.c index a5391ac..5c94ae2 100644 --- a/location/manager/location-boundary.c +++ b/location/manager/location-boundary.c @@ -62,6 +62,25 @@ #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) @@ -301,6 +320,193 @@ location_boundary_if_inside(LocationBoundary *boundary, LocationPosition *positi 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) { diff --git a/location/manager/location-boundary.h b/location/manager/location-boundary.h index 8b44794..e830d82 100644 --- a/location/manager/location-boundary.h +++ b/location/manager/location-boundary.h @@ -198,6 +198,19 @@ int location_boundary_foreach(const LocationObject *obj, LocationBoundaryFunc fu gboolean location_boundary_if_inside(LocationBoundary *boundary, LocationPosition *position); /** + * @brief Check if #LocationPosition is on path of within given tolerance #LocationBoundary. + * @remarks None. + * @pre #location_init should be called before.\n + * @post None. + * @param [in] boundary - a #LocationBoundary + * @param [in] position - a #LocationPosition + * @param [in] tolerance - a #double + * @return gboolean + * @retval\n TRUE - if on path within tolerance\n FALSE - if not on path within tolerance\n + */ +gboolean location_boundary_on_path(LocationBoundary *boundary, LocationPosition *position, double tolerance); + +/** * @brief Get bounding box of #LocationBoundary */ LocationBoundary *location_boundary_get_bounding_box(LocationBoundary *boundary); -- 2.7.4