source: subversion/applications/routing/pyroute/loadOsm.py @ 5939

Last change on this file since 5939 was 5885, checked in by ojw, 12 years ago

fix wrong "if" statement

File size: 7.8 KB
Line 
1#!/usr/bin/python
2#----------------------------------------------------------------
3# load OSM data file into memory
4#
5#------------------------------------------------------
6# Usage:
7#   data = LoadOsm(filename)
8# or:
9#   loadOsm.py filename.osm
10#------------------------------------------------------
11# Copyright 2007, Oliver White
12#
13# This program is free software: you can redistribute it and/or modify
14# it under the terms of the GNU General Public License as published by
15# the Free Software Foundation, either version 3 of the License, or
16# (at your option) any later version.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program.  If not, see <http://www.gnu.org/licenses/>.
25#------------------------------------------------------
26# Changelog:
27#  2007-11-04  OJW  Modified from pyroute.py
28#  2007-11-05  OJW  Multiple forms of transport
29#------------------------------------------------------
30import sys
31import os
32from xml.sax import make_parser, handler
33import xml
34import urllib
35from time import clock
36
37execfile("weights.py")
38
39class LoadOsm(handler.ContentHandler):
40  """Parse an OSM file looking for routing information, and do routing with it"""
41  def __init__(self, filename, storeMap = 0):
42    """Initialise an OSM-file parser"""
43    self.routing = {}
44    self.routeTypes = ('cycle','car','train','foot','horse')
45    self.routeableNodes = {}
46    for routeType in self.routeTypes:
47      self.routing[routeType] = {}
48      self.routeableNodes[routeType] = {}
49    self.nodes = {}
50    self.ways = []
51    self.storeMap = storeMap
52   
53    if(filename == None):
54      return
55    self.loadfile(filename)
56   
57  def loadfile(self, filename):
58    if(not os.path.exists(filename)):
59      print "No such data file %s" % filename
60      return
61    try:
62      parser = make_parser()
63      parser.setContentHandler(self)
64      parser.parse(filename)
65    except xml.sax._exceptions.SAXParseException:
66      print "Error loading %s" % filename
67 
68  def download(self,lat,lon,size):
69    url = "http://osm.test.le.ac.uk/api/0.5/way[%1.4f,%1.4f,%1.4f,%1.4f][*=*]" % (lon-size,lat-size,lon+size,lat+size)
70    url = "http://api.openstreetmap.org/api/0.5/map?bbox=%1.4f,%1.4f,%1.4f,%1.4f" % (lon-size,lat-size,lon+size,lat+size)
71    print "downloading %s" % url
72    start = clock()
73    filename = "data/routing.osm"
74   
75    if(os.path.exists(filename)):
76      os.remove(filename)
77    urllib.urlretrieve(url, filename)
78    end = clock()
79    delay = end - start
80    print "finished downloading, took %1.1f s" % (delay)
81    self.loadfile(filename)
82   
83  def report(self):
84    """Display some info about the loaded data"""
85    report = "Loaded %d nodes,\n" % len(self.nodes.keys())
86    report = report + "%d ways, and...\n" % len(self.ways)
87    for routeType in self.routeTypes:
88      report = report + " %d %s routes\n" % ( \
89        len(self.routing[routeType].keys()),
90        routeType)
91    return(report)
92
93  def startElement(self, name, attrs):
94    """Handle XML elements"""
95    if name in('node','way','relation'):
96      self.tags = {}
97      self.waynodes = []
98      if name == 'node':
99        """Nodes need to be stored"""
100        id = int(attrs.get('id'))
101        lat = float(attrs.get('lat'))
102        lon = float(attrs.get('lon'))
103        self.nodes[id] = (lat,lon)
104    elif name == 'nd':
105      """Nodes within a way -- add them to a list"""
106      self.waynodes.append(int(attrs.get('ref')))
107    elif name == 'tag':
108      """Tags - store them in a hash"""
109      k,v = (attrs.get('k'), attrs.get('v'))
110      if not k in ('created_by'):
111        self.tags[k] = v
112 
113  def endElement(self, name):
114    """Handle ways in the OSM data"""
115    if name == 'way':
116      highway = self.equivalent(self.tags.get('highway', ''))
117      railway = self.equivalent(self.tags.get('railway', ''))
118      oneway = self.tags.get('oneway', '')
119      reversible = not oneway in('yes','true','1')
120   
121      # Calculate what vehicles can use this route
122      access = {}
123      access['cycle'] = highway in ('primary','secondary','tertiary','unclassified','minor','cycleway','residential', 'track','service')
124      access['car'] = highway in ('motorway','trunk','primary','secondary','tertiary','unclassified','minor','residential', 'service')
125      access['train'] = railway in('rail','light_rail','subway')
126      access['foot'] = access['cycle'] or highway in('footway','steps')
127      access['horse'] = highway in ('track','unclassified','bridleway')
128     
129      # Store routing information
130      last = -1
131      for i in self.waynodes:
132        if last != -1:
133          #print "%d -> %d & v.v." % (last, i)
134          for routeType in self.routeTypes:
135            if(access[routeType]):
136              weight = getWeight(routeType, highway)
137              self.addLink(last, i, routeType, weight)
138              if reversible or routeType == 'foot':
139                self.addLink(i, last, routeType, weight)
140        last = i
141     
142      # Store map information
143      if(self.storeMap):
144        wayType = self.WayType(self.tags)
145        if(wayType):
146          self.ways.append({ \
147            't':wayType,
148            'n':self.waynodes})
149 
150  def addLink(self,fr,to, routeType, weight=1):
151    """Add a routeable edge to the scenario"""
152    self.routeablefrom(fr,routeType)
153    try:
154      if to in self.routing[routeType][fr].keys():
155        return
156      self.routing[routeType][fr][to] = weight
157    except KeyError:
158      self.routing[routeType][fr] = {to: weight}
159
160  def WayType(self, tags):
161    # Look for a variety of tags (priority order - first one found is used)
162    for key in ('highway','railway','waterway','natural'):
163      value = tags.get('highway', '')
164      if value:
165        return(self.equivalent(value))
166    return('')
167  def equivalent(self,tag):
168    """Simplifies a bunch of tags to nearly-equivalent ones"""
169    equivalent = { \
170      "primary_link":"primary",
171      "trunk":"primary",
172      "trunk_link":"primary",
173      "secondary_link":"secondary",
174      "tertiary":"secondary",
175      "tertiary_link":"secondary",
176      "residential":"unclassified",
177      "minor":"unclassified",
178      "steps":"footway",
179      "driveway":"service",
180      "pedestrian":"footway",
181      "bridleway":"cycleway",
182      "track":"cycleway",
183      "arcade":"footway",
184      "canal":"river",
185      "riverbank":"river",
186      "lake":"river",
187      "light_rail":"railway"
188      }
189    try:
190      return(equivalent[tag])
191    except KeyError:
192      return(tag)
193   
194  def routeablefrom(self,fr,routeType):
195    self.routeableNodes[routeType][fr] = 1
196 
197  def save(self, filename):
198    """Saves routing data (to cache)"""
199    toStore = { \
200      'routing': self.routing,
201      'routeNodes':self.routeableNodes,
202      'nodes':self.nodes,
203      'ways':self.ways}
204    file = open(filename, "w")
205    file.write(str(toStore))
206    file.close()
207
208  def load(self, filename):
209    """Loads routing data (from cache)"""
210    file = open(filename, "r")
211    struct = eval(file.read())
212    self.routing = struct['routing']
213    self.routeableNodes = struct['routeNodes']
214    self.nodes = struct['nodes']
215    self.ways = struct['ways']
216    file.close()
217    print "done"
218   
219  def findNode(self,lat,lon,routeType):
220    """Find the nearest node to a point.
221    Filters for nodes which have a route leading from them"""
222    maxDist = 1000
223    nodeFound = None
224    for id in self.routeableNodes[routeType].keys():
225      n = self.nodes[id]
226      dlat = n[0] - lat
227      dlon = n[1] - lon
228      dist = dlat * dlat + dlon * dlon
229      if(dist < maxDist):
230        maxDist = dist
231        nodeFound = id
232    return(nodeFound)
233   
234# Parse the supplied OSM file
235if __name__ == "__main__":
236  print "Loading data..."
237  data = LoadOsm(sys.argv[1], True)
238  data.report()
Note: See TracBrowser for help on using the repository browser.