[libgweather] location: Add a utility function to find the nearest city to a coordinate
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgweather] location: Add a utility function to find the nearest city to a coordinate
- Date: Wed, 23 Oct 2013 15:17:57 +0000 (UTC)
commit 3e82e323f0f228c96b5effe6d2cf4f201fe0f27e
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Wed May 16 12:28:58 2012 -0400
location: Add a utility function to find the nearest city to a coordinate
https://bugzilla.gnome.org/show_bug.cgi?id=677268
libgweather/gweather-location.c | 86 ++++++++++++++++++++++++++++++++++++--
libgweather/gweather-location.h | 1 +
2 files changed, 82 insertions(+), 5 deletions(-)
---
diff --git a/libgweather/gweather-location.c b/libgweather/gweather-location.c
index 6ab6ee9..0b7da66 100644
--- a/libgweather/gweather-location.c
+++ b/libgweather/gweather-location.c
@@ -504,6 +504,85 @@ gweather_location_get_children (GWeatherLocation *loc)
return &no_children;
}
+static void
+foreach_cities (GWeatherLocation *loc,
+ GFunc callback,
+ gpointer user_data)
+{
+ if (loc->level == GWEATHER_LOCATION_CITY) {
+ callback (loc, user_data);
+ } else if (loc->children) {
+ GWeatherLocation *child;
+ for (child = *loc->children; child != NULL; child++)
+ foreach_cities (child, callback, user_data);
+ }
+}
+
+struct FindNearestCityData {
+ double latitude;
+ double longitude;
+ GWeatherLocation *location;
+ double distance;
+};
+
+static double
+location_distance (double lat1, double long1,
+ double lat2, double long2)
+{
+ /* average radius of the earth in km */
+ static const double radius = 6372.795;
+
+ return acos (cos (lat1) * cos (lat2) * cos (long1 - long2) +
+ sin (lat1) * sin (lat2)) * radius;
+}
+
+static void
+find_nearest_city (GWeatherLocation *location,
+ gpointer user_data) {
+ struct FindNearestCityData *data = user_data;
+
+ double distance = location_distance (location->latitude, location->longitude,
+ data->latitude, data->longitude);
+
+ if (data->location == NULL || data->distance < distance) {
+ data->location = location;
+ data->distance = distance;
+ }
+}
+
+/**
+ * gweather_location_find_nearest_city:
+ * @loc: The parent location, which will be searched recursively
+ * @lat: Latitude, in degrees
+ * @long_: Longitude, in degrees
+ *
+ * Finds the nearest city to the passed latitude and
+ * longitude.
+ *
+ * Returns: (transfer full): the closest city
+ */
+GWeatherLocation *
+gweather_location_find_nearest_city (double lat, double long_)
+{
+ /* The data set really isn't too big. Don't concern ourselves
+ * with a proper nearest neighbors search. Instead, just do
+ * an O(n) search. */
+ GWeatherLocation *world = gweather_location_get_world ();
+ struct FindNearestCityData data;
+
+ lat = lat * M_PI / 180.0;
+ long_ = long_ * M_PI / 180.0;
+
+ data.latitude = lat;
+ data.longitude = long_;
+ data.location = NULL;
+ data.distance = 0.0;
+
+ foreach_cities (world, (GFunc) find_nearest_city, &data);
+
+ return gweather_location_ref (data.location);
+}
+
/**
* gweather_location_has_coords:
* @loc: a #GWeatherLocation
@@ -553,17 +632,14 @@ gweather_location_get_coords (GWeatherLocation *loc,
double
gweather_location_get_distance (GWeatherLocation *loc, GWeatherLocation *loc2)
{
- /* average radius of the earth in km */
- static const double radius = 6372.795;
-
g_return_val_if_fail (loc != NULL, 0);
g_return_val_if_fail (loc2 != NULL, 0);
//g_return_val_if_fail (loc->latlon_valid, 0.0);
//g_return_val_if_fail (loc2->latlon_valid, 0.0);
- return acos (cos (loc->latitude) * cos (loc2->latitude) * cos (loc->longitude - loc2->longitude) +
- sin (loc->latitude) * sin (loc2->latitude)) * radius;
+ return location_distance (loc->latitude, loc->longitude,
+ loc2->latitude, loc2->longitude);
}
/**
diff --git a/libgweather/gweather-location.h b/libgweather/gweather-location.h
index c221ea6..5a64f06 100644
--- a/libgweather/gweather-location.h
+++ b/libgweather/gweather-location.h
@@ -69,6 +69,7 @@ void gweather_location_get_coords (GWeatherLocation *loc,
double *longitude);
double gweather_location_get_distance (GWeatherLocation *loc,
GWeatherLocation *loc2);
+GWeatherLocation *gweather_location_find_nearest_city (double lat, double long_);
const char *gweather_location_get_country (GWeatherLocation *loc);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]