[geocode-glib] lib: Add function to calculate distance between 2 locations



commit 6d20e9f79333d79c34b6f1b948162140d3fb8969
Author: Bastien Nocera <hadess hadess net>
Date:   Sun Nov 25 21:48:40 2012 +0100

    lib: Add function to calculate distance between 2 locations

 geocode-glib/geocode-glib.symbols |    1 +
 geocode-glib/geocode-location.c   |   37 +++++++++++++++++++++++++++++++++++++
 geocode-glib/geocode-location.h   |    3 +++
 geocode-glib/test-gcglib.c        |   16 ++++++++++++++++
 4 files changed, 57 insertions(+), 0 deletions(-)
---
diff --git a/geocode-glib/geocode-glib.symbols b/geocode-glib/geocode-glib.symbols
index 7760f10..0436a5a 100644
--- a/geocode-glib/geocode-glib.symbols
+++ b/geocode-glib/geocode-glib.symbols
@@ -2,6 +2,7 @@ geocode_location_get_type
 geocode_location_new
 geocode_location_new_with_description
 geocode_location_free
+geocode_location_get_distance_from
 geocode_forward_get_type
 geocode_forward_new_for_string
 geocode_forward_new_for_params
diff --git a/geocode-glib/geocode-location.c b/geocode-glib/geocode-location.c
index abf31b8..7fe4642 100644
--- a/geocode-glib/geocode-location.c
+++ b/geocode-glib/geocode-location.c
@@ -21,6 +21,9 @@
  */
 
 #include <geocode-location.h>
+#include <math.h>
+
+#define EARTH_RADIUS_KM 6372.795
 
 /**
  * SECTION:geocode-location
@@ -115,3 +118,37 @@ geocode_location_new_with_description (gdouble     latitude,
 
 	return ret;
 }
+
+/**
+ * geocode_location_get_distance_from:
+ * @loca: a #GeocodeLocation
+ * @locb: a #GeocodeLocation
+ *
+ * Calculates the distance in km, along the curvature of the Earth,
+ * between 2 locations. Note that altitude changes are not
+ * taken into account.
+ *
+ * Returns: a distance in km.
+ **/
+double
+geocode_location_get_distance_from (GeocodeLocation *loca,
+				    GeocodeLocation *locb)
+{
+	gdouble dlat, dlon, lat1, lat2;
+	gdouble a, c;
+
+	g_return_val_if_fail (loca != NULL || locb != NULL, 0.0);
+
+	/* Algorithm from:
+	 * http://www.movable-type.co.uk/scripts/latlong.html */
+
+	dlat = (locb->latitude - loca->latitude) * M_PI / 180.0;
+	dlon = (locb->longitude - loca->longitude) * M_PI / 180.0;
+	lat1 = loca->latitude * M_PI / 180.0;
+	lat2 = locb->latitude * M_PI / 180.0;
+
+	a = sin (dlat / 2) * sin (dlat / 2) +
+		sin (dlon / 2) * sin (dlon / 2) * cos (lat1) * cos (lat2);
+	c = 2 * atan2 (sqrt (a), sqrt (1-a));
+	return EARTH_RADIUS_KM * c;
+}
diff --git a/geocode-glib/geocode-location.h b/geocode-glib/geocode-location.h
index 0b817f1..a16525d 100644
--- a/geocode-glib/geocode-location.h
+++ b/geocode-glib/geocode-location.h
@@ -57,6 +57,9 @@ GeocodeLocation *geocode_location_new_with_description (gdouble     latitude,
 							gdouble     longitude,
 							const char *description);
 
+double geocode_location_get_distance_from (GeocodeLocation *loca,
+					   GeocodeLocation *locb);
+
 void geocode_location_free (GeocodeLocation *loc);
 
 G_END_DECLS
diff --git a/geocode-glib/test-gcglib.c b/geocode-glib/test-gcglib.c
index 0348beb..ab92d74 100644
--- a/geocode-glib/test-gcglib.c
+++ b/geocode-glib/test-gcglib.c
@@ -260,6 +260,21 @@ test_search_lat_long (void)
 	g_list_free_full (res, (GDestroyNotify) geocode_location_free);
 }
 
+/* Test case from:
+ * http://andrew.hedges.name/experiments/haversine/ */
+static void
+test_distance (void)
+{
+	GeocodeLocation *loca, *locb;
+
+	/* 1600 Pennsylvania Ave NW, Washington, DC */
+	loca = geocode_location_new (38.898556, -77.037852);
+	/* 1600 Pennsylvania Ave NW, Washington, DC */
+	locb = geocode_location_new (38.897147, -77.043934);
+
+	g_assert_cmpfloat (geocode_location_get_distance_from (loca, locb) - 0.549311, <, 0.000001);
+}
+
 static void
 test_locale (void)
 {
@@ -408,6 +423,7 @@ int main (int argc, char **argv)
 		g_test_add_func ("/geocode/locale", test_locale);
 		g_test_add_func ("/geocode/search", test_search);
 		g_test_add_func ("/geocode/search_lat_long", test_search_lat_long);
+		g_test_add_func ("/geocode/distance", test_distance);
 		return g_test_run ();
 	}
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]