def find_closest(self, position, params): """ Find the closest location to the (lat, long) position specified, querying the database with dictionary params, of the format { Column Name : value }. Returns an object of class returned_object, or None if none found nearby """ # GPSes use WGS84 model of Globe, but Easting/Northing based on OSGB36, so convert to an easting/northing logging.debug("Position in WGS84 determined as lat/long: %s %s", position[0], position[1]) easting, northing = convertWGS84toOSEastingNorthing(*position) logging.debug("Translated into OS Easting %s, Northing %s", easting, northing) # Do a funny bit of Pythagoras to work out closest stop. We can't find square root of a number in sqlite # but then again, we don't need to, the smallest square will do. Sort by this column in ascending order # and find the first row (where_statement, where_values) = self.database.make_where_statement('locations', params) query = """ SELECT (location_easting - %d)*(location_easting - %d) + (location_northing - %d)*(location_northing - %d) AS dist_squared, * FROM locations WHERE %s ORDER BY dist_squared LIMIT 1 """ % (easting, easting, northing, northing, where_statement) row = self.database.get_row(query, where_values) if row: obj = self.returned_object(Distance=sqrt(row['dist_squared']), **row) logging.debug("Have found nearest location %s", obj) return obj else: logging.debug("No location found near %s, sorry", position) return None
def get_tweet_geolocation(self, tweet, user_request): """ Ensure any geolocation on a Tweet is valid, and return the co-ordinates as a (latitude, longitude) tuple """ if self.tweet_has_geolocation(tweet): logging.debug("Detecting geolocation on Tweet") position = tweet.geo['coordinates'] easting, northing = convertWGS84toOSEastingNorthing(*position) # Grid reference provides us an easy way with checking to see if in the UK - it returns blank string if not in UK bounds if not gridrefNumToLet(easting, northing): raise WhensMyTransportException('not_in_uk') # Check minimums & maximum numeric grid references - corresponding to Chesham (W), Shenfield (E), Dorking (S) and Potters Bar (N) elif not (495000 <= easting <= 565000 and 145000 <= northing <= 205000): raise WhensMyTransportException('not_in_london') else: return position # Some people (especially Tweetdeck users) add a Place on the Tweet, but not an accurate enough lat & long elif hasattr(tweet, 'place') and tweet.place: raise WhensMyTransportException('placeinfo_only', user_request) # If there's no geoinformation at all then raise the appropriate exception else: if hasattr(tweet, 'geo'): raise WhensMyTransportException('no_geotag', user_request) else: raise WhensMyTransportException('dms_not_taggable', user_request)
def test_geo(self): """ Unit test for geo conversion methods """ # Test co-ordinate conversions on the location of St James's Park Station wgs84 = (51.4995893, -0.1342974) osgb36 = (51.4990781, -0.1326920) easting_northing = (529600, 179500) gridref = "TQ2960079500" self.assertEqual(convertWGS84toOSGB36(*wgs84)[:2], osgb36) self.assertEqual(LatLongToOSGrid(*osgb36), easting_northing) self.assertEqual(convertWGS84toOSEastingNorthing(*wgs84), easting_northing) self.assertEqual(gridrefNumToLet(*easting_northing), gridref) # Test heading_to_direction with a series of preset values for (heading, direction) in ((0, "North"), (90, "East"), (135, "SE"), (225, "SW"),): self.assertEqual(heading_to_direction(heading), direction)