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

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

Search just for objects that can be routed from

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