Merge lp:~max-rabkin/ibid/coords-892484 into lp:ibid

Proposed by Max Rabkin
Status: Merged
Approved by: Stefano Rivera
Approved revision: 1048
Merged at revision: 1042
Proposed branch: lp:~max-rabkin/ibid/coords-892484
Merge into: lp:ibid
Diff against target: 142 lines (+97/-4)
1 file modified
ibid/plugins/geography.py (+97/-4)
To merge this branch: bzr merge lp:~max-rabkin/ibid/coords-892484
Reviewer Review Type Date Requested Status
Keegan Carruthers-Smith Approve
Stefano Rivera Approve
Review via email: mp+82773@code.launchpad.net

Commit message

Add lookup for coordinates of places

To post a comment you must log in.
lp:~max-rabkin/ibid/coords-892484 updated
1045. By Max Rabkin

Allow 'coords'

1046. By Max Rabkin

More (needless) precision

1047. By Max Rabkin

Add names for zones

Revision history for this message
Stefano Rivera (stefanor) :
review: Approve
lp:~max-rabkin/ibid/coords-892484 updated
1048. By Max Rabkin

handle non-existent places

Revision history for this message
Keegan Carruthers-Smith (keegan-csmith) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ibid/plugins/geography.py'
--- ibid/plugins/geography.py 2011-06-26 22:44:41 +0000
+++ ibid/plugins/geography.py 2011-11-20 15:02:24 +0000
@@ -1,7 +1,9 @@
1# -*- coding: utf-8 -*-
1# Copyright (c) 2009-2010, Jonathan Hitchcock, Michael Gorven, Stefano Rivera2# Copyright (c) 2009-2010, Jonathan Hitchcock, Michael Gorven, Stefano Rivera
2# Released under terms of the MIT/X/Expat Licence. See COPYING for details.3# Released under terms of the MIT/X/Expat Licence. See COPYING for details.
4from __future__ import division
35
4from math import acos, sin, cos, radians6from math import acos, sin, cos, degrees, radians
5from urllib import quote, urlencode7from urllib import quote, urlencode
6from urlparse import urljoin8from urlparse import urljoin
7import re9import re
@@ -29,15 +31,20 @@
29 'description': u'Returns the distance between two places',31 'description': u'Returns the distance between two places',
30 'categories': ('lookup', 'calculate',),32 'categories': ('lookup', 'calculate',),
31}33}
34features['coordinates'] = {
35 'description': u'Gives the coordinates of a place',
36 'categories': ('lookup',),
37}
32class Distance(Processor):38class Distance(Processor):
33 usage = u"""distance [in <unit>] between <source> and <destination>39 usage = u"""distance [in <unit>] between <source> and <destination>
34 place search for <placename>"""40 place search for <place>
41 coordinates for <place>"""
3542
36 # For Mathematics, see:43 # For Mathematics, see:
37 # http://www.mathforum.com/library/drmath/view/51711.html44 # http://www.mathforum.com/library/drmath/view/51711.html
38 # http://mathworld.wolfram.com/GreatCircle.html45 # http://mathworld.wolfram.com/GreatCircle.html
3946
40 features = ('distance',)47 features = ('distance', 'coordinates')
4148
42 default_unit_names = {49 default_unit_names = {
43 'km': "kilometres",50 'km': "kilometres",
@@ -59,10 +66,19 @@
59 if js['totalResultsCount'] == 0:66 if js['totalResultsCount'] == 0:
60 return None67 return None
61 info = js['geonames'][0]68 info = js['geonames'][0]
62 return {'name': "%s, %s, %s" % (info['name'], info['adminName1'], info['countryName']),69 return {'name': self.format_name(info),
63 'lng': radians(info['lng']),70 'lng': radians(info['lng']),
64 'lat': radians(info['lat'])}71 'lat': radians(info['lat'])}
6572
73 def format_name(self, info):
74 parts = info['name'], info['adminName1'], info['countryName']
75 parts = filter(None, parts)
76 uniq_parts = [parts[0]]
77 for part in parts[1:]:
78 if part != uniq_parts[-1]:
79 uniq_parts.append(part)
80 return ', '.join(uniq_parts)
81
66 @match(r'^(?:(?:search\s+for\s+place)|(?:place\s+search\s+for)|(?:places\s+for))\s+(\S.+?)\s*$')82 @match(r'^(?:(?:search\s+for\s+place)|(?:place\s+search\s+for)|(?:places\s+for))\s+(\S.+?)\s*$')
67 def placesearch(self, event, place):83 def placesearch(self, event, place):
68 js = self.get_place_data(place, 10)84 js = self.get_place_data(place, 10)
@@ -110,6 +126,83 @@
110 conjunction=u'or'),126 conjunction=u'or'),
111 })127 })
112128
129 def degrees_minutes_seconds(self, degrees, kind):
130 degs = int(degrees)
131 minutes = abs(degrees - degs)*60
132 mins = int(minutes)
133 secs = int((minutes-mins)*60)
134
135 dirn = ''
136 if kind == 'lat':
137 if degs > 0:
138 dirn = ' N'
139 elif degs < 0:
140 dirn = ' S'
141 else:
142 if degs > 0:
143 dirn = ' E'
144 elif degs < 0:
145 dirn = ' W'
146 degs = abs(degs)
147 return u'%i° %iʹ %iʺ%s' % (degs, mins, secs, dirn)
148
149 @match(r"coord(?:inate)?s (?:for|of|to) (.*)")
150 def coordinates(self, event, place):
151 place_data = self.get_place(place)
152 if not place_data:
153 event.addresponse("I've never heard of %s", place)
154 return
155
156 lat_deg = degrees(place_data['lat'])
157 lng_deg = degrees(place_data['lng'])
158 place_data.update({
159 'lat_deg': lat_deg,
160 'lng_deg': lng_deg,
161 'lat_dms': self.degrees_minutes_seconds(lat_deg, 'lat'),
162 'lng_dms': self.degrees_minutes_seconds(lng_deg, 'lng'),
163 })
164
165 latitudes = [('North Pole', 90, 'back of beyond'),
166 ('Arctic Circle', 66+33/60+39/3600,
167 'Arctic'),
168 ('Tropic of Cancer', 23+26/30+21/3600,
169 'north temperate zone'),
170 ('Equator', 0,
171 'northern tropics'),
172 ('Tropic of Capricorn', -(23+26/30+21/3600),
173 'southern tropics'),
174 ('Antarctic Circle', -(66+33/60+39/3600),
175 'south temperate zone'),
176 ('South Pole', -90,
177 'Antarctic'),
178 ]
179 for name, lat, zone in latitudes:
180 if abs(lat-lat_deg) <= 1/60:
181 if name.endswith('Pole'):
182 place_data['lat_desc'] = 'at the ' + name
183 else:
184 place_data['lat_desc'] = 'on the ' + name
185 break
186 elif abs(lat-lat_deg) <= 2:
187 place_data['lat_desc'] = 'near the ' + name
188 break
189 else:
190 for (name1, lat1, _), (name2, lat2, zone) in zip(latitudes, latitudes[1:]):
191 if lat1 > lat_deg > lat2:
192 place_data['lat_desc'] = 'in the ' + zone
193 break
194 else:
195 place_data['lat_desc'] = 'beyond the fields we know'
196
197 place_data['tz'] = round(lng_deg/15)
198
199 event.addresponse("%(name)s is at %(lat_dms)s, %(lng_dms)s "
200 u"(%(lat_deg)0.4f°, %(lng_deg)0.4f°). "
201 "That's in nautical time zone GMT%(tz)+i, "
202 "%(lat_desc)s.",
203 place_data)
204
205
113features['weather'] = {206features['weather'] = {
114 'description': u'Retrieves current weather and forecasts for cities.',207 'description': u'Retrieves current weather and forecasts for cities.',
115 'categories': ('lookup', 'web',),208 'categories': ('lookup', 'web',),

Subscribers

People subscribed via source and target branches

to all changes: