From 45d59158350dee44629298526ba4d394f71d936f Mon Sep 17 00:00:00 2001 From: Ankit Date: Mon, 16 Mar 2015 01:30:58 +0530 Subject: [PATCH] dbus,location: Add & set 'Heading' prop Add a new property, 'Heading' on D-Bus location that reflects the heading direction in degrees with respect to North direction. This property is re-calculated and updated on each location update. This API will be helpful for apps that are interested in user's movements. https://bugs.freedesktop.org/show_bug.cgi?id=89395 --- src/gclue-location-source.c | 1 + src/gclue-location.c | 123 +++++++++++++++++++++++++++++++++++++++ src/gclue-location.h | 14 +++++ src/gclue-locator.c | 1 + src/gclue-service-location.c | 7 ++- src/org.freedesktop.GeoClue2.xml | 10 ++++ 6 files changed, 155 insertions(+), 1 deletion(-) diff --git a/src/gclue-location-source.c b/src/gclue-location-source.c index de191b2..1e362de 100644 --- a/src/gclue-location-source.c +++ b/src/gclue-location-source.c @@ -278,6 +278,7 @@ gclue_location_source_set_location (GClueLocationSource *source, "accuracy", geocode_location_get_accuracy (gloc), "description", geocode_location_get_description (gloc), "speed", gclue_location_get_speed (location), + "heading", gclue_location_get_heading (location), NULL); g_object_notify (G_OBJECT (source), "location"); diff --git a/src/gclue-location.c b/src/gclue-location.c index d7ae547..76aff53 100644 --- a/src/gclue-location.c +++ b/src/gclue-location.c @@ -24,15 +24,18 @@ */ #include "gclue-location.h" +#include struct _GClueLocationPrivate { gdouble speed; + gdouble heading; }; enum { PROP_0, PROP_SPEED, + PROP_HEADING, }; G_DEFINE_TYPE (GClueLocation, gclue_location, GEOCODE_TYPE_LOCATION); @@ -51,6 +54,11 @@ gclue_location_get_property (GObject *object, gclue_location_get_speed (location)); break; + case PROP_HEADING: + g_value_set_double (value, + gclue_location_get_heading (location)); + break; + default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -66,6 +74,13 @@ gclue_location_set_speed (GClueLocation *loc, } static void +gclue_location_set_heading (GClueLocation *loc, + gdouble heading) +{ + loc->priv->heading = heading; +} + +static void gclue_location_set_property (GObject *object, guint property_id, const GValue *value, @@ -79,6 +94,11 @@ gclue_location_set_property (GObject *object, g_value_get_double (value)); break; + case PROP_HEADING: + gclue_location_set_heading (location, + g_value_get_double (value)); + break; + default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -118,6 +138,25 @@ gclue_location_class_init (GClueLocationClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (glocation_class, PROP_SPEED, pspec); + + /** + * GClueLocation:heading + * + * The positive angle between the direction of movement and the North + * direction, in clockwise direction. The angle is measured in degrees. + */ + pspec = g_param_spec_double ("heading", + "Heading", + "The positive Angle between the direction" + " of movement and the North direction, in" + " clockwise direction. The angle is " + "measured in degrees.", + GCLUE_LOCATION_HEADING_UNKNOWN, + G_MAXDOUBLE, + GCLUE_LOCATION_HEADING_UNKNOWN, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property (glocation_class, PROP_HEADING, pspec); } static void @@ -128,6 +167,7 @@ gclue_location_init (GClueLocation *location) GClueLocationPrivate); location->priv->speed = GCLUE_LOCATION_SPEED_UNKNOWN; + location->priv->heading = GCLUE_LOCATION_HEADING_UNKNOWN; } /** @@ -195,6 +235,25 @@ gclue_location_get_speed (GClueLocation *loc) } /** + * gclue_location_get_heading: + * @loc: a #GClueLocation + * + * Gets the direction of movement in degrees due North direction in clockwise + * direction. + * + * Returns: The positive angle between the direction of movement and the North + * direction, in clockwise direction. The angle is measured in degrees. + **/ +gdouble +gclue_location_get_heading (GClueLocation *loc) +{ + g_return_val_if_fail (GCLUE_IS_LOCATION (loc), + GCLUE_LOCATION_HEADING_UNKNOWN); + + return loc->priv->heading; +} + +/** * gclue_location_set_speed_from_prev_location: * @location: a #GClueLocation * @prev_location: a #GClueLocation @@ -231,3 +290,67 @@ gclue_location_set_speed_from_prev_location (GClueLocation *location, location->priv->speed = speed; } + +/** + * gclue_location_set_heading_from_prev_location: + * @location: a #GClueLocation + * @prev_location: a #GClueLocation + * + * Calculates the heading direction in degrees with respect to North direction + * based on provided @prev_location and sets it on @location. + **/ +void +gclue_location_set_heading_from_prev_location (GClueLocation *location, + GClueLocation *prev_location) +{ + gdouble dx, dy, angle, lat, lon, prev_lat, prev_lon; + GeocodeLocation *gloc, *prev_gloc; + + g_return_if_fail (GCLUE_IS_LOCATION (location)); + g_return_if_fail (prev_location == NULL || + GCLUE_IS_LOCATION (prev_location)); + + if (prev_location == NULL) { + location->priv->heading = GCLUE_LOCATION_HEADING_UNKNOWN; + + return; + } + + gloc = GEOCODE_LOCATION (location); + prev_gloc = GEOCODE_LOCATION (prev_location); + + lat = geocode_location_get_latitude(gloc); + lon = geocode_location_get_longitude(gloc); + prev_lat = geocode_location_get_latitude(prev_gloc); + prev_lon = geocode_location_get_longitude(prev_gloc); + + dx = (lat - prev_lat); + dy = (lon - prev_lon); + + /* atan2 takes in coordinate values of a 2D space and returns the angle + * which the line from origin to that coordinate makes with the positive + * X-axis, in the range (-PI,+PI]. Converting it into degrees we get the + * angle in range (-180,180]. This means East = 0 degree, + * West = -180 degrees, North = 90 degrees, South = -90 degrees. + * + * Passing atan2 a negative value of dx will flip the angles about + * Y-axis. This means the angle now returned will be the angle with + * respect to negative X-axis. Which makes West = 0 degree, + * East = 180 degrees, North = 90 degrees, South = -90 degrees. */ + angle = atan2(dy, -dx) * 180.0 / M_PI; + + /* Now, North is supposed to be 0 degree. Lets subtract 90 degrees + * from angle. After this step West = -90 degrees, East = 90 degrees, + * North = 0 degree, South = -180 degrees. */ + angle -= 90.0; + + /* As we know, angle ≡ angle + 360; using this on negative values would + * bring the the angle in range [0,360). + * + * After this step West = 270 degrees, East = 90 degrees, + * North = 0 degree, South = 180 degrees. */ + if (angle < 0) + angle += 360.0; + + location->priv->heading = angle; +} diff --git a/src/gclue-location.h b/src/gclue-location.h index 115f0c9..48adec2 100644 --- a/src/gclue-location.h +++ b/src/gclue-location.h @@ -60,6 +60,13 @@ struct _GClueLocationClass GType gclue_location_get_type (void); /** + * GCLUE_LOCATION_HEADING_UNKNOWN: + * + * Constant representing unknown heading. + */ +#define GCLUE_LOCATION_HEADING_UNKNOWN -1.0 + +/** * GCLUE_LOCATION_SPEED_UNKNOWN: * * Constant representing unknown speed. @@ -84,6 +91,13 @@ void gclue_location_set_speed_from_prev_location (GClueLocation *location, GClueLocation *prev_location); +void gclue_location_set_heading_from_prev_location + (GClueLocation *location, + GClueLocation *prev_location); + gdouble gclue_location_get_speed (GClueLocation *loc); +gdouble gclue_location_get_heading + (GClueLocation *loc); + #endif /* GCLUE_LOCATION_H */ \ No newline at end of file diff --git a/src/gclue-locator.c b/src/gclue-locator.c index aee6c51..7e12041 100644 --- a/src/gclue-locator.c +++ b/src/gclue-locator.c @@ -97,6 +97,7 @@ set_location (GClueLocator *locator, } gclue_location_set_speed_from_prev_location (location, cur_location); + gclue_location_set_heading_from_prev_location (location, cur_location); gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (locator), location); diff --git a/src/gclue-service-location.c b/src/gclue-service-location.c index f38531b..83d8522 100644 --- a/src/gclue-service-location.c +++ b/src/gclue-service-location.c @@ -99,7 +99,10 @@ gclue_service_location_get_property (GObject *object, gclue_dbus_location_get_description (location)); g_object_set (loc, "speed", - gclue_dbus_location_get_speed (location), NULL); + gclue_dbus_location_get_speed (location), + "heading", + gclue_dbus_location_get_heading (location), + NULL); altitude = gclue_dbus_location_get_altitude (location); if (altitude != GEOCODE_LOCATION_ALTITUDE_UNKNOWN) g_object_set (loc, "altitude", altitude, NULL); @@ -153,6 +156,8 @@ gclue_service_location_set_property (GObject *object, (location, geocode_location_get_description (g_loc)); gclue_dbus_location_set_speed (location, gclue_location_get_speed (loc)); + gclue_dbus_location_set_heading + (location, gclue_location_get_heading (loc)); altitude = geocode_location_get_altitude (g_loc); if (altitude != GEOCODE_LOCATION_ALTITUDE_UNKNOWN) gclue_dbus_location_set_altitude (location, altitude); diff --git a/src/org.freedesktop.GeoClue2.xml b/src/org.freedesktop.GeoClue2.xml index 4d047d5..ce51779 100644 --- a/src/org.freedesktop.GeoClue2.xml +++ b/src/org.freedesktop.GeoClue2.xml @@ -192,6 +192,16 @@ + + +