|
@@ -197,6 +197,36 @@ class Location(object):
|
|
|
|
|
|
return 'http://maps.google.com/maps?' + re.sub('%(2[89cC])', lambda match: chr(int(match.group(1), 16)), urllib.urlencode({'q': '%s (%s)' % (location, self.nick)}))
|
|
|
|
|
|
+ @property
|
|
|
+ def _accuracy(self):
|
|
|
+ return self.values.get('accuracy')
|
|
|
+
|
|
|
+ @property
|
|
|
+ def _latitude(self):
|
|
|
+ return self.values['coordinates'][0]
|
|
|
+
|
|
|
+ @property
|
|
|
+ def _longitude(self):
|
|
|
+ return self.values['coordinates'][1]
|
|
|
+
|
|
|
+ def has_changed_from(self, previous):
|
|
|
+ if self.location != previous.location:
|
|
|
+ return True
|
|
|
+
|
|
|
+ distance = self - previous
|
|
|
+
|
|
|
+ if distance < 60:
|
|
|
+ return False
|
|
|
+
|
|
|
+ if self._accuracy is not None and previous._accuracy is not None:
|
|
|
+ if distance > (self._accuracy + previous._accuracy) / 2:
|
|
|
+ return True
|
|
|
+
|
|
|
+ if distance > min(self._accuracy, previous._accuracy) and self._accuracy < previous._accuracy:
|
|
|
+ return True
|
|
|
+
|
|
|
+ return False
|
|
|
+
|
|
|
def __get_attr__(self, name):
|
|
|
if name not in VALUES:
|
|
|
raise AttributeError("'Location' object has no attribute '%s'" % name)
|
|
@@ -204,11 +234,11 @@ class Location(object):
|
|
|
value = self.values.get(name)
|
|
|
|
|
|
if info in ('accuracy', 'altitude', 'altitude_accuracy'):
|
|
|
- return distance(value)
|
|
|
+ return self.distance(value)
|
|
|
elif info in ('speed',):
|
|
|
- return speed(value)
|
|
|
+ return self.speed(value)
|
|
|
elif info in ('heading',):
|
|
|
- return heading(value)
|
|
|
+ return self.heading(value)
|
|
|
else:
|
|
|
return unicode(value)
|
|
|
|
|
@@ -229,7 +259,13 @@ class Location(object):
|
|
|
else:
|
|
|
aux = ''
|
|
|
|
|
|
- return '%s is%s in %s%s %s' % (self.nick, venue, self.values['location'], aux, self.url)
|
|
|
+ return '%s is%s in %s%s %s' % (self.nick, venue, self.location, aux, self.url)
|
|
|
+
|
|
|
+ def __sub__(self, other):
|
|
|
+ x = (math.cos(self.degrees_to_radians(self._latitude)) + math.cos(self.degrees_to_radians(other._latitude))) * self.longitude_to_nautical_miles(self._longitude - other._longitude) / 2
|
|
|
+ y = self.latitude_to_nautical_miles(self._latitude - other._latitude)
|
|
|
+
|
|
|
+ return self.nautical_miles_to_meters(abs(x) ** 2 + abs(y) ** 2)
|
|
|
|
|
|
@classmethod
|
|
|
def distance(cls, distance):
|
|
@@ -239,12 +275,28 @@ class Location(object):
|
|
|
@classmethod
|
|
|
def speed(cls, speed):
|
|
|
if speed is not None:
|
|
|
- return '%.1f m/s (%.1f mph)' % (speed, meters_per_second_to_miles_per_hour(speed))
|
|
|
+ return '%.1f m/s (%.1f mph)' % (speed, cls.meters_per_second_to_miles_per_hour(speed))
|
|
|
|
|
|
@classmethod
|
|
|
def heading(cls, heading):
|
|
|
if heading is not None:
|
|
|
- return u'%.1f\xb0 (%s)' % (heading, heading_to_direction(heading))
|
|
|
+ return u'%.1f\xb0 (%s)' % (heading, cls.heading_to_direction(heading))
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def degrees_to_radians(degrees):
|
|
|
+ return degrees * math.pi / 180
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def latitude_to_nautical_miles(latitude):
|
|
|
+ return latitude * 60.00721
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def longitude_to_nautical_miles(longitude):
|
|
|
+ return longitude * 60.10793
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def nautical_miles_to_meters(nautical_miles):
|
|
|
+ return nauticla_miles * 1852
|
|
|
|
|
|
@staticmethod
|
|
|
def meters_to_feet(meters):
|
|
@@ -293,7 +345,7 @@ class Location(object):
|
|
|
|
|
|
class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
def __init__(self, bot = None):
|
|
|
- self.__config = SafeConfigParser({'min_update_distance': "60"})
|
|
|
+ self.__config = SafeConfigParser()
|
|
|
|
|
|
self.__config.read('locationbot.ini')
|
|
|
|
|
@@ -323,9 +375,6 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
self.__admins = self.__config.get(nick, 'admins').split()
|
|
|
self.__channels = set(self.__config.get(nick, 'channels').split())
|
|
|
self.__dsn = self.__config.get(nick, 'dsn')
|
|
|
- #self.__latitude_client_id = self.__config.get(nick, 'latitude_client_id')
|
|
|
- #self.__latitude_consumer = oauth.Consumer(key = self.__latitude_client_id, secret = self.__config.get(nick, 'latitude_client_secret'))
|
|
|
- self.min_update_distance = self.__config.getint(nick, 'min_update_distance')
|
|
|
|
|
|
except NoOptionError, error:
|
|
|
sys.exit(error)
|
|
@@ -493,46 +542,6 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
self.__latitude_timer.start()
|
|
|
|
|
|
- def __location(self, nick, channels, granularity, old_location, new_location, old_coordinates, new_coordinates, old_accuracy, new_accuracy, old_speed, new_speed, old_heading, new_heading, old_altitude, new_altitude, old_altitude_accuracy, new_altitude_accuracy, old_updated, new_updated):
|
|
|
- def calc_distance(lat1, lon1, lat2, lon2): # returns meters
|
|
|
- nauticalMilePerLat = 60.00721
|
|
|
- nauticalMilePerLongitude = 60.10793
|
|
|
- rad = math.pi / 180.0
|
|
|
- milesPerNauticalMile = 1.15078
|
|
|
- metersPerNauticalMile = 1852
|
|
|
-
|
|
|
- yDistance = (lat2 - lat1) * nauticalMilePerLat
|
|
|
- xDistance = (math.cos(lat1 * rad) + math.cos(lat2 * rad)) * \
|
|
|
- (lon2 - lon1) * (nauticalMilePerLongitude / 2)
|
|
|
- distance = math.sqrt( yDistance**2 + xDistance**2 )
|
|
|
- return distance * metersPerNauticalMile
|
|
|
-
|
|
|
- def make_update_noise():
|
|
|
- with self.__locations_lock:
|
|
|
- for channel in self.__channels.intersection(channels):
|
|
|
- self.__locations.append((nick, channel, granularity, new_location, new_coordinates, new_accuracy, new_speed, new_heading, new_altitude, new_altitude_accuracy))
|
|
|
-
|
|
|
- if channels:
|
|
|
- if new_location != old_location: # old method
|
|
|
- return make_update_noise()
|
|
|
-
|
|
|
- distance = calc_distance(old_coordinates[0], old_coordinates[1],
|
|
|
- new_coordinates[0], new_coordinates[1])
|
|
|
-
|
|
|
- if distance < self.min_update_distance:
|
|
|
- return
|
|
|
-
|
|
|
- if old_accuracy is not None and new_accuracy is not None:
|
|
|
- avg_radius = (old_accuracy + new_accuracy) / 2
|
|
|
-
|
|
|
- if distance > avg_radius:
|
|
|
- return make_update_noise()
|
|
|
-
|
|
|
- min_radius = min(old_accuracy, new_accuracy)
|
|
|
-
|
|
|
- if distance > min_radius and new_accuracy < old_accuracy:
|
|
|
- return make_update_noise()
|
|
|
-
|
|
|
def __login(self, connection, nickmask, nick, arguments = ''):
|
|
|
login = nick
|
|
|
|