source: subversion/applications/routing/pyroutelib2/loadOsm.py @ 8024

Last change on this file since 8024 was 8024, checked in by ojw, 11 years ago

filter by transport type at load-time

File size: 6.4 KB
Line 
1#!/usr/bin/python
2#----------------------------------------------------------------
3# load OSM data file into memory
4#
5#------------------------------------------------------
6# Copyright 2007, Oliver White
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20#------------------------------------------------------
21# Changelog:
22#  2007-11-04  OJW  Modified from pyroute.py
23#  2007-11-05  OJW  Multiple forms of transport
24#------------------------------------------------------
25import sys
26import os
27import tiledata
28import tilenames
29import re
30
31execfile("weights.py")
32
33class LoadOsm:
34  """Parse an OSM file looking for routing information, and do routing with it"""
35  def __init__(self, transport, storeMap = 0):
36    """Initialise an OSM-file parser"""
37    self.routing = {}
38    self.routeableNodes = {}
39    self.nodes = {}
40    self.ways = []
41    self.storeMap = storeMap
42    self.transport = transport
43 
44  def getArea(self, lat, lon):
45    z = tiledata.DownloadLevel()
46    (x,y) = tilenames.tileXY(lat, lon, z)
47    print "Downloading %d,%d at z%d" % (x,y,z)
48    filename = tiledata.GetOsmTileData(z,x,y)
49    return(self.loadOsm(filename))
50
51  def loadOsm(self, filename):
52    if(not os.path.exists(filename)):
53      print "No such data file %s" % filename
54      return(False)
55    fp = open(filename, "r")
56    re_way = re.compile("<way id='(\d+)'>\s*$")
57    re_nd = re.compile("\s+<nd id='(\d+)' x='(\d+)' y='(\d+)' />\s*$")
58    re_tag = re.compile("\s+<tag k='(.*)' v='(.*)' />\s*$")
59    re_endway = re.compile("</way>$")
60    in_way = 0
61
62    way_tags = {}
63    way_nodes = []
64
65    for line in fp:
66      result_way = re_way.match(line)
67      result_endway = re_endway.match(line)
68      if(result_way):
69        in_way = True
70        way_tags = {}
71        way_nodes = []
72        way_id = int(result_way.group(1))
73      elif(result_endway):
74        in_way = False
75        self.storeWay(way_id, way_tags, way_nodes)
76      elif(in_way):
77        result_nd = re_nd.match(line)
78        if(result_nd):
79          way_nodes.append([
80            int(result_nd.group(1)),
81            int(result_nd.group(2)),
82            int(result_nd.group(3))])
83        else:
84          result_tag = re_tag.match(line)
85          if(result_tag):
86            way_tags[result_tag.group(1)] = result_tag.group(2)
87    return(True)
88 
89  def storeWay(self, wayID, tags, nodes):
90    highway = self.equivalent(tags.get('highway', ''))
91    railway = self.equivalent(tags.get('railway', ''))
92    oneway = tags.get('oneway', '')
93    reversible = not oneway in('yes','true','1')
94
95    # Calculate what vehicles can use this route
96    access = {}
97    access['cycle'] = highway in ('primary','secondary','tertiary','unclassified','minor','cycleway','residential', 'track','service')
98    access['car'] = highway in ('motorway','trunk','primary','secondary','tertiary','unclassified','minor','residential', 'service')
99    access['train'] = railway in('rail','light_rail','subway')
100    access['foot'] = access['cycle'] or highway in('footway','steps')
101    access['horse'] = highway in ('track','unclassified','bridleway')
102
103    # Store routing information
104    last = -1
105    for i_obj in nodes:
106      i = i_obj[0]
107      if last != -1:
108        if(access[self.transport]):
109          weight = getWeight(self.transport, highway)
110          self.addLink(last, i, weight)
111          if reversible or self.transport == 'foot':
112            self.addLink(i, last, weight)
113      last = i
114
115    # Store map information
116    if(self.storeMap):
117      wayType = self.WayType(tags)
118      if(wayType):
119        self.ways.append({ \
120          't':wayType,
121          'n':nodes})
122
123  def addLink(self,fr,to, weight=1):
124    """Add a routeable edge to the scenario"""
125    self.routeablefrom(fr)
126    try:
127      if to in self.routing[fr].keys():
128        return
129      self.routing[fr][to] = weight
130    except KeyError:
131      self.routing[fr] = {to: weight}
132
133  def WayType(self, tags):
134    # Look for a variety of tags (priority order - first one found is used)
135    for key in ('highway','railway','waterway','natural'):
136      value = tags.get('highway', '')
137      if value:
138        return(self.equivalent(value))
139    return('')
140  def equivalent(self,tag):
141    """Simplifies a bunch of tags to nearly-equivalent ones"""
142    equivalent = { \
143      "primary_link":"primary",
144      "trunk":"primary",
145      "trunk_link":"primary",
146      "secondary_link":"secondary",
147      "tertiary":"secondary",
148      "tertiary_link":"secondary",
149      "residential":"unclassified",
150      "minor":"unclassified",
151      "steps":"footway",
152      "driveway":"service",
153      "pedestrian":"footway",
154      "bridleway":"cycleway",
155      "track":"cycleway",
156      "arcade":"footway",
157      "canal":"river",
158      "riverbank":"river",
159      "lake":"river",
160      "light_rail":"railway"
161      }
162    try:
163      return(equivalent[tag])
164    except KeyError:
165      return(tag)
166   
167  def routeablefrom(self,fr):
168    self.routeableNodes[fr] = 1
169
170  def findNode(self,lat,lon,routeType):
171    """Find the nearest node to a point.
172    Filters for nodes which have a route leading from them"""
173    maxDist = 1000
174    nodeFound = None
175    for id in self.routeableNodes[routeType].keys():
176      if id not in self.nodes:
177        print "Ignoring undefined node %s" % id
178        continue
179      n = self.nodes[id]
180      dlat = n[0] - lat
181      dlon = n[1] - lon
182      dist = dlat * dlat + dlon * dlon
183      if(dist < maxDist):
184        maxDist = dist
185        nodeFound = id
186    return(nodeFound)
187     
188  def report(self):
189    """Display some info about the loaded data"""
190    report = "Loaded %d nodes,\n" % len(self.nodes.keys())
191    report = report + "%d ways, and...\n" % len(self.ways)
192    report = report + "%d %s routes\n" % (len(self.routing.keys()), self.transport)
193    return(report)
194
195# Parse the supplied OSM file
196if __name__ == "__main__":
197  data = LoadOsm("cycle", True)
198  if(data.getArea(52.55291,-1.81824)):
199    print data.report()
200  else:
201    print "Failed to get data"
Note: See TracBrowser for help on using the repository browser.