source: subversion/applications/utils/where_are_they/where_am_i.py @ 2605

Last change on this file since 2605 was 2189, checked in by nickburch, 13 years ago

Add "where are they" stuff (http://wiki.openstreetmap.org/index.php/Where_Are_They) to svn

  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 8.3 KB
Line 
1#!/usr/bin/python
2#                                       Where am I?
3#                                       -----------
4#
5# An OpenStreetMap powered python script to answer the question.
6#
7# Supports the following:
8#   What main road am I on?
9#     lat=...,long=....,dist=....,road
10#   What main roads am I near?
11#     lat=...,long=....,dist=....,roads
12#   What place am I in?
13#     lat=...,long=....,dist=....,place
14#   What places am I near?
15#     lat=...,long=....,dist=....,places
16#
17# Can output as html (format=html - default) or xml (format=xml)
18#  or OSM XML (format=osm) or GPX XML (format=gpx)
19#
20# Requires that Plant.OSM has been loaded into a local postgres database
21#
22# See http://wiki.openstreetmap.org/index.php/Where_Are_They
23#
24# GPL
25#
26# Nick Burch
27#               v0.07  (07/08/2006)
28
29import sys
30from osm_io_helper import hasOpt, getOpt, hasAnyOpts, printHTTPHeaders, renderResults
31from geo_helper import calculate_distance_and_bearing
32from mini_osm import mini_osm_pgsql
33
34# What highway and class options we want
35segment_types = [ "highway", "class" ]
36main_roads = [ "motorway", "trunk", "primary", "secondary" ]
37
38# Where are they?
39lat = None
40long = None
41if hasOpt("lat"):
42        lat = getOpt("lat")
43if hasOpt("latitude"):
44        lat = getOpt("latitude")
45if hasOpt("long"):
46        long = getOpt("long")
47if hasOpt("longitude"):
48        long = getOpt("longitude")
49
50# Ensure we turn lat/long of "" into None
51if (not lat == None) and (not len(lat)):
52        lat = None
53if (not long == None) and (not len(long)):
54        long = None
55
56# Do they want HTML, XML, or OSM?
57formats = [ "html", "xml", "osm", "gpx" ]
58format = ""
59if hasOpt("format"):
60        format = getOpt("format")
61if not formats.__contains__(format):
62        format = formats[0]
63
64# Do the HTTP headers
65printHTTPHeaders(format)
66
67# What did they request?
68type = 'help'
69subtype = None
70single = 0
71if hasOpt("type"):
72        type = getOpt("type")
73if hasOpt("road"):
74        type = "road"
75        single = 1
76if hasOpt("roads"):
77        type = "road"
78if hasOpt("place"):
79        type = "node"
80        subtype = ("place",None)
81        single = 1
82if hasOpt("places"):
83        type = "node"
84        subtype = ("place",None)
85if hasOpt("node_type") and not getOpt("node_type") == '':
86        type = "node"
87        if hasOpt("node_value") and not getOpt("node_value") == '':
88                subtype = (getOpt("node_type"), getOpt("node_value"))
89        else:
90                subtype = (getOpt("node_type"), None)
91
92# What distance do they want to search over?
93distance = 250
94if hasOpt("dist"):
95        distance = getOpt("dist")
96if hasOpt("distance"):
97        distance = getOpt("distance")
98distance = int(distance)
99# Max distance - depends on search type
100if type == "node" and not subtype == None:
101        # Can afford to allow it to be quite big (500km)
102        if distance > 500000:
103                distance = 500000
104else:
105        # Limit to 5km, as will fetch all nodes on way or another (5km)
106        if distance > 5000:
107                distance = 5000
108
109
110# Avoid XSS from user string inputs
111if not subtype == None:
112        new_st0 = subtype[0]
113        new_st1 = subtype[1]
114        new_st0 = new_st0.replace('<','&gt;')
115        if not new_st1 == None:
116                new_st1 = new_st1.replace('<','&gt;')
117        subtype = (new_st0,new_st1)
118
119# Work out the name for this type
120type_name = type
121if not subtype == None:
122        if subtype[1] == None:
123                type_name = subtype[0]
124        else:
125                type_name = subtype[1]
126type_name = type_name[0:1].upper() + type_name[1:]
127if not type_name[-1:] == 's':
128        if type_name[-1:] == 'y':
129                type_name = type_name[0:-1] + "ie"
130        type_name = type_name + 's'
131
132# Connect to the database
133miniosm = mini_osm_pgsql()
134
135# ##########################################################################
136
137def displayError(message):
138        global format
139        global type
140        global subtype
141
142        global lat
143        global long
144        global distance
145
146        if format == "xml" or format == "osm" or format == "gpx":
147                print '<?xml version="1.0" encoding="UTF-8"?>'
148                print '<error>%s</error>' % message
149        if format == "html":
150                title = "Error - %s" % message
151                if not hasAnyOpts():
152                        title = "Where Am I?"
153
154                if lat == None:
155                        lat = ""
156                if long == None:
157                        long = ""
158
159                print "<html><head><title>%s</title></head><body>" % title
160                print "<h1>%s</h1>" % title
161                print "<h3>More Information:</h3>"
162                print "<p>For more information, see <a href='http://wiki.openstreetmap.org/index.php/Where_Are_They'>http://wiki.openstreetmap.org/index.php/Where_Are_They</a>.</p>"
163                print "<form method='get'>"
164                print "<h3>Where to search:</h3>"
165                print "<p><label for='lat'>Latitude:</label> <input type='text' name='lat' value='%s' ></p>" % lat
166                print "<p><label for='long'>Longitude:</label> <input type='text' name='long' value='%s' /></p>" % long
167                print "<p><label for='dist'>Distance:</label> <input type='text' name='dist' value='%s' /> meters (max 5000, or 500,000 when doing node type search)</p>" % distance
168                print "<h3>What to search for:</h3>"
169                print "<p><input type='checkbox' name='roads' checked='yes' />Find Roads</p>"
170                print "<p><i>or</i> <input type='checkbox' name='places' />Find Places</p>"
171                print "<p><i>or</i> <label for='node_type'>Node Type:</label> <input type='text' name='node_type' /><br />"
172                print "   <i>and</i> <label for='node_value'>Node Type Value:</label> <input type='text' name='node_value' /></p>"
173                print "<h3>Output Format:</h3>"
174                print "<p><select name='format'>"
175                print "  <option value='html' selected>HTML</option>"
176                print "  <option value='xml'>XML (simple)</option>"
177                print "  <option value='osm'>OSM</option>"
178                print "  <option value='gpx'>GPX (waypoints)</option>"
179                print "</select></p>"
180                print "<h3>Perform search:</h3>"
181                print "<p><input type='submit' value='search' /></p>"
182                print "</form>"
183                print "</body></html>"
184
185        sys.exit()
186
187def displayResults(type,objects):
188        global format
189        global lat
190        global long
191        title = "%s near to %f,%f" % (type,lat,long)
192        renderResults(type,objects,format,title,"distbearing")
193
194# ##########################################################################
195
196def sortByDistance(x,y):
197        if x["distance"] == y["distance"]:
198                return 0
199        if x["distance"] > y["distance"]:
200                return 1
201        return -1
202
203# ##########################################################################
204
205# Check we have lat and long
206if lat == None:
207        displayError("Latitude must be supplied")
208if long == None:
209        displayError("Longitude must be supplied")
210lat = float(lat)
211long = float(long)
212
213# Do the work
214if type == "road":
215        # We want to know about nodes, segments and ways
216        # So, go and fetch them for our area
217        nodes = miniosm.getNodesInArea(lat,long,distance)
218
219        segs = {}
220        ways = {}
221        if len(nodes):
222                segs = miniosm.getSegmentsForNodes(nodes)
223                if len(segs):
224                        ways = miniosm.getWaysForSegments(segs)
225
226        # Push tags from ways down onto segments
227        miniosm.splatWayTagsOntoSegments(ways,segs)
228
229        # Push interesting tags down as main keys
230        interesting_tags = ["name","ref"] + segment_types
231        miniosm.splatTagsOntoObjects(segs, interesting_tags)
232
233        # Grab just the segments of interest
234        highways = miniosm.filterSegmentsByTags(segs,nodes,segment_types,main_roads)
235
236        # Calculate the distance from the segment waypoints
237        miniosm.calculateDistanceToSegments(lat,long,highways,nodes)
238        highways.sort(sortByDistance)
239
240        # Sort out the type, and only have one with each name+ref
241        seen_segments = {}
242        want_highways = []
243        for seg in (highways):
244                tup = (seg["name"],seg["ref"])
245                if not seen_segments.has_key(tup):
246                        seen_segments[tup] = seg
247
248                        # Now do type
249                        type = None
250                        for tag in (segment_types):
251                                if not seg[tag] == None:
252                                        type = seg[tag]
253                        seg["type"] = type
254                        want_highways.append(seg)
255
256        # All done, display
257        if len(want_highways) == 0:
258                displayResults("Roads", want_highways)
259        elif single:
260                displayResults("Road", [want_highways[0]])
261        else:
262                displayResults("Roads", want_highways)
263
264elif type =="node":
265        # We only need to get nodes
266        # When we do, filter by tag name, and optionally also tag value
267        nodes = miniosm.getNodesInAreaWithTag(lat,long,distance,subtype[0],subtype[1])
268
269        if len(nodes) == 0:
270                displayResults(type_name, [])
271                sys.exit(0)
272
273        # Push the tags that are interesting down to the nodes
274        miniosm.splatTagsOntoObjects(nodes, ["name",subtype[0]])
275
276        # Sort these nodes by their distance
277        for node in (nodes.values()):
278                dist_bearing = calculate_distance_and_bearing(lat,long,node["lat"],node["long"])
279                node["distance"] = dist_bearing[0]
280                node["bearing"] = dist_bearing[1]
281                # Also splat into type
282                node["type"] = node[subtype[0]]
283        node_array = nodes.values()
284        node_array.sort(sortByDistance)
285
286        # All done, display
287        if len(node_array) == 0:
288                displayResults(type_name, [])
289        elif single:
290                displayResults(type_name, [node_array[0]])
291        else:
292                displayResults(type_name, node_array)
293else:
294        displayError("No search type given")
Note: See TracBrowser for help on using the repository browser.