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

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

move OSM data into module

File size: 6.6 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
34
35execfile("weights.py")
36
37class LoadOsm(handler.ContentHandler):
38  """Parse an OSM file looking for routing information, and do routing with it"""
39  def __init__(self, filename, storeMap = 0):
40    """Initialise an OSM-file parser"""
41    self.routing = {}
42    self.routeTypes = ('cycle','car','train','foot','horse')
43    self.routeableNodes = {}
44    for routeType in self.routeTypes:
45      self.routing[routeType] = {}
46      self.routeableNodes[routeType] = {}
47    self.nodes = {}
48    self.ways = []
49    self.storeMap = storeMap
50   
51    if(filename == None):
52      return
53    self.loadOsm(filename)
54   
55  def loadOsm(self, filename):
56    if(not os.path.exists(filename)):
57      print "No such data file %s" % filename
58      return
59    try:
60      parser = make_parser()
61      parser.setContentHandler(self)
62      parser.parse(filename)
63    except xml.sax._exceptions.SAXParseException:
64      print "Error loading %s" % filename
65   
66  def report(self):
67    """Display some info about the loaded data"""
68    report = "Loaded %d nodes,\n" % len(self.nodes.keys())
69    report = report + "%d ways, and...\n" % len(self.ways)
70    for routeType in self.routeTypes:
71      report = report + " %d %s routes\n" % ( \
72        len(self.routing[routeType].keys()),
73        routeType)
74    return(report)
75
76  def startElement(self, name, attrs):
77    """Handle XML elements"""
78    if name in('node','way','relation'):
79      self.tags = {}
80      self.waynodes = []
81      if name == 'node':
82        """Nodes need to be stored"""
83        id = int(attrs.get('id'))
84        lat = float(attrs.get('lat'))
85        lon = float(attrs.get('lon'))
86        self.nodes[id] = (lat,lon)
87    elif name == 'nd':
88      """Nodes within a way -- add them to a list"""
89      self.waynodes.append(int(attrs.get('ref')))
90    elif name == 'tag':
91      """Tags - store them in a hash"""
92      k,v = (attrs.get('k'), attrs.get('v'))
93      if not k in ('created_by'):
94        self.tags[k] = v
95 
96  def endElement(self, name):
97    """Handle ways in the OSM data"""
98    if name == 'way':
99      highway = self.equivalent(self.tags.get('highway', ''))
100      railway = self.equivalent(self.tags.get('railway', ''))
101      oneway = self.tags.get('oneway', '')
102      reversible = not oneway in('yes','true','1')
103   
104      # Calculate what vehicles can use this route
105      access = {}
106      access['cycle'] = highway in ('primary','secondary','tertiary','unclassified','minor','cycleway','residential', 'track','service')
107      access['car'] = highway in ('motorway','trunk','primary','secondary','tertiary','unclassified','minor','residential', 'service')
108      access['train'] = railway in('rail','light_rail','subway')
109      access['foot'] = access['cycle'] or highway in('footway','steps')
110      access['horse'] = highway in ('track','unclassified','bridleway')
111     
112      # Store routing information
113      last = -1
114      for i in self.waynodes:
115        if last != -1:
116          #print "%d -> %d & v.v." % (last, i)
117          for routeType in self.routeTypes:
118            if(access[routeType]):
119              weight = getWeight(routeType, highway)
120              self.addLink(last, i, routeType, weight)
121              if reversible or routeType == 'foot':
122                self.addLink(i, last, routeType, weight)
123        last = i
124     
125      # Store map information
126      if(self.storeMap):
127        wayType = self.WayType(self.tags)
128        if(wayType):
129          self.ways.append({ \
130            't':wayType,
131            'n':self.waynodes})
132 
133  def addLink(self,fr,to, routeType, weight=1):
134    """Add a routeable edge to the scenario"""
135    self.routeablefrom(fr,routeType)
136    try:
137      if to in self.routing[routeType][fr].keys():
138        return
139      self.routing[routeType][fr][to] = weight
140    except KeyError:
141      self.routing[routeType][fr] = {to: weight}
142
143  def WayType(self, tags):
144    # Look for a variety of tags (priority order - first one found is used)
145    for key in ('highway','railway','waterway','natural'):
146      value = tags.get('highway', '')
147      if value:
148        return(self.equivalent(value))
149    return('')
150  def equivalent(self,tag):
151    """Simplifies a bunch of tags to nearly-equivalent ones"""
152    equivalent = { \
153      "primary_link":"primary",
154      "trunk":"primary",
155      "trunk_link":"primary",
156      "secondary_link":"secondary",
157      "tertiary":"secondary",
158      "tertiary_link":"secondary",
159      "residential":"unclassified",
160      "minor":"unclassified",
161      "steps":"footway",
162      "driveway":"service",
163      "pedestrian":"footway",
164      "bridleway":"cycleway",
165      "track":"cycleway",
166      "arcade":"footway",
167      "canal":"river",
168      "riverbank":"river",
169      "lake":"river",
170      "light_rail":"railway"
171      }
172    try:
173      return(equivalent[tag])
174    except KeyError:
175      return(tag)
176   
177  def routeablefrom(self,fr,routeType):
178    self.routeableNodes[routeType][fr] = 1
179
180  def findNode(self,lat,lon,routeType):
181    """Find the nearest node to a point.
182    Filters for nodes which have a route leading from them"""
183    maxDist = 1000
184    nodeFound = None
185    for id in self.routeableNodes[routeType].keys():
186      n = self.nodes[id]
187      dlat = n[0] - lat
188      dlon = n[1] - lon
189      dist = dlat * dlat + dlon * dlon
190      if(dist < maxDist):
191        maxDist = dist
192        nodeFound = id
193    return(nodeFound)
194   
195# Parse the supplied OSM file
196if __name__ == "__main__":
197  print "Loading data..."
198  data = LoadOsm(sys.argv[1], True)
199  data.report()
Note: See TracBrowser for help on using the repository browser.