Addition of API location_boundary_on_path 37/236937/2 accepted/tizen/unified/20200703.155128 submit/tizen/20200629.081950
authorchakradhar <v.pogiri@samsung.com>
Tue, 23 Jun 2020 09:59:05 +0000 (15:29 +0530)
committerchakradhar <v.pogiri@samsung.com>
Thu, 25 Jun 2020 07:57:06 +0000 (13:27 +0530)
Change-Id: Ia92f5315070c37285fd2fdaacdf1a23279e89477

location/manager/location-boundary.c
location/manager/location-boundary.h

index a5391ac..5c94ae2 100644 (file)
 #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(&center, 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)
 {
index 8b44794..e830d82 100644 (file)
@@ -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);