source: subversion/applications/routing/pyroute-dev/loadOsm.py @ 18449

Last change on this file since 18449 was 18449, checked in by buerste, 10 years ago

-adding rev replacement

  • Property svn:keywords set to Rev
File size: 8.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""load OSM data file into memory
5
6Usage:
7  data = LoadOsm(filename)
8or:
9  loadOsm.py filename.osm
10"""
11
12__version__ = "$Rev: 18449 $"
13__license__ = """This program is free software: you can redistribute it and/or modify
14it under the terms of the GNU General Public License as published by
15the Free Software Foundation, either version 3 of the License, or
16(at your option) any later version.
17
18This program is distributed in the hope that it will be useful,
19but WITHOUT ANY WARRANTY; without even the implied warranty of
20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program. If not, see <http://www.gnu.org/licenses/>."""
25_debug = 0
26
27
28import sys
29import os
30from xml.sax import make_parser, handler
31import xml
32from util_binary import *
33from struct import *
34
35execfile(os.path.join(os.path.dirname(__file__), "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 savebin(self,filename):
77                self.newIDs = {}
78               
79                f = open(filename,"wb")
80                f.write(pack('L',len(self.nodes.keys())))
81                count = 0
82                for id, n in self.nodes.items():
83                        self.newIDs[id] = count
84                        f.write(encodeLL(n[0],n[1]))
85                        count = count + 1
86                       
87                f.write(pack('B', len(self.routing.keys())))
88                errors = 0
89                for routeType, data in self.routing.items():
90                        f.write(pack('B', len(routeType)))
91                        f.write(routeType)
92                       
93                        f.write(pack('L', len(data.keys())))
94                        for fr, destinations in data.items():
95                                try:
96                                        f.write(pack('L', self.newIDs[fr]))
97                                except KeyError:
98                                        f.write(pack('L', 0))
99                                        errors = errors + 1
100                                        continue
101
102                                f.write(pack('B', len(destinations.keys())))
103                                for to, weight in destinations.items():
104                                        try:
105                                                f.write(pack('Lf', self.newIDs[to], weight))
106                                        except KeyError:
107                                                f.write(pack('Lf', 0, 0))
108                                                errors = errors + 1
109               
110                print "%d key errors" % errors
111                f.close()
112               
113        def loadbin(self,filename):
114                f = open(filename,"rb")
115                n = unpack('L', f.read(4))[0]
116                print "%u nodes" % n
117                id = 0
118                for i in range(n):
119                        lat,lon = decodeLL(f.read(8))
120                        #print "%u: %f, %f" % (id,lat,lon)
121                        id = id + 1
122               
123                numTypes = unpack('B', f.read(1))[0]
124                print "%u types:" % numTypes
125                for typ in range(numTypes):
126                        lenName = unpack('B', f.read(1))[0]
127                        name = f.read(lenName)
128                        numLinks = 0
129                       
130                        numHubs = unpack('L', f.read(4))[0]
131                        for hub in range(numHubs):
132                                fr = unpack('L', f.read(4))[0]
133                                numDest = unpack('B', f.read(1))[0]
134                                for dest in range(numDest):
135                                        to,weight = unpack('Lf', f.read(8))
136                                        numLinks = numLinks + 1
137                        print \"%s\" (%u segments)" % (name, numLinks)
138
139                f.close()
140
141        def startElement(self, name, attrs):
142                """Handle XML elements"""
143                if name in('node','way','relation'):
144                        self.tags = {}
145                        self.waynodes = []
146                        if name == 'node':
147                                """Nodes need to be stored"""
148                                id = int(attrs.get('id'))
149                                lat = float(attrs.get('lat'))
150                                lon = float(attrs.get('lon'))
151                                self.nodes[id] = (lat,lon)
152                elif name == 'nd':
153                        """Nodes within a way -- add them to a list"""
154                        self.waynodes.append(int(attrs.get('ref')))
155                elif name == 'tag':
156                        """Tags - store them in a hash"""
157                        k,v = (attrs.get('k'), attrs.get('v'))
158                        if not k in ('created_by'):
159                                self.tags[k] = v
160 
161        def endElement(self, name):
162                """Handle ways in the OSM data"""
163                if name == 'way':
164                        highway = self.equivalent(self.tags.get('highway', ''))
165                        railway = self.equivalent(self.tags.get('railway', ''))
166                        oneway = self.tags.get('oneway', '')
167                        reversible = not oneway in('yes','true','1')
168               
169                        # Calculate what vehicles can use this route
170                        access = {}
171                        access['cycle'] = highway in ('primary','secondary','tertiary','unclassified','minor','cycleway','residential', 'track','service')
172                        access['car'] = highway in ('motorway','trunk','primary','secondary','tertiary','unclassified','minor','residential', 'service')
173                        access['train'] = railway in('rail','light_rail','subway')
174                        access['foot'] = access['cycle'] or highway in('footway','steps')
175                        access['horse'] = highway in ('track','unclassified','bridleway')
176                       
177                        # Store routing information
178                        last = -1
179                        for i in self.waynodes:
180                                if last != -1:
181                                        #print "%d -> %d & v.v." % (last, i)
182                                        for routeType in self.routeTypes:
183                                                if(access[routeType]):
184                                                        weight = getWeight(routeType, highway)
185                                                        self.addLink(last, i, routeType, weight)
186                                                        if reversible or routeType == 'foot':
187                                                                self.addLink(i, last, routeType, weight)
188                                last = i
189                       
190                        # Store map information
191                        if(self.storeMap):
192                                wayType = self.WayType(self.tags)
193                                if(wayType):
194                                        self.ways.append({ \
195                                                't':wayType,
196                                                'n':self.waynodes})
197       
198        def addLink(self,fr,to, routeType, weight=1):
199                """Add a routeable edge to the scenario"""
200                self.routeablefrom(fr,routeType)
201                try:
202                        if to in self.routing[routeType][fr].keys():
203                                return
204                        self.routing[routeType][fr][to] = weight
205                except KeyError:
206                        self.routing[routeType][fr] = {to: weight}
207
208        def WayType(self, tags):
209                # Look for a variety of tags (priority order - first one found is used)
210                for key in ('highway','railway','waterway','natural'):
211                        value = tags.get('highway', '')
212                        if value:
213                                return(self.equivalent(value))
214                return('')
215        def equivalent(self,tag):
216                """Simplifies a bunch of tags to nearly-equivalent ones"""
217                equivalent = { \
218                        "primary_link":"primary",
219                        "trunk":"primary",
220                        "trunk_link":"primary",
221                        "secondary_link":"secondary",
222                        "tertiary":"secondary",
223                        "tertiary_link":"secondary",
224                        "residential":"unclassified",
225                        "minor":"unclassified",
226                        "steps":"footway",
227                        "driveway":"service",
228                        "pedestrian":"footway",
229                        "bridleway":"cycleway",
230                        "track":"cycleway",
231                        "arcade":"footway",
232                        "canal":"river",
233                        "riverbank":"river",
234                        "lake":"river",
235                        "light_rail":"railway"
236                        }
237                try:
238                        return(equivalent[tag])
239                except KeyError:
240                        return(tag)
241               
242        def routeablefrom(self,fr,routeType):
243                self.routeableNodes[routeType][fr] = 1
244
245        def findNode(self,lat,lon,routeType):
246                """Find the nearest node to a point.
247                Filters for nodes which have a route leading from them"""
248                maxDist = 1000
249                nodeFound = None
250                for id in self.routeableNodes[routeType].keys():
251                        if id not in self.nodes:
252                                print "Ignoring undefined node %s" % id
253                                continue
254                        n = self.nodes[id]
255                        dlat = n[0] - lat
256                        dlon = n[1] - lon
257                        dist = dlat * dlat + dlon * dlon
258                        if(dist < maxDist):
259                                maxDist = dist
260                                nodeFound = id
261                return(nodeFound)
262               
263# Parse the supplied OSM file
264if __name__ == "__main__":
265        #print "Loading data..."
266        #data = LoadOsm(sys.argv[1], True)
267        #print data.report()
268        #print "Saving binary..."
269        #data.savebin("data/routing.bin")
270        print "Loading binary..."
271        data2 = LoadOsm(None, False)
272        data2.loadbin("data/routing.bin")
273        print "Done"
Note: See TracBrowser for help on using the repository browser.