Route altitude profiles SRTM

From OpenStreetMap Wiki
Jump to navigation Jump to search
Altitude-profile.png

Goal of this project is to create an altitude profile for (cycle) routes based on the freely available NASA SRTM3 altitude data. Sjors worked on this during the Google Summer of Code 2008 and blogged about his progress.

Objectives and ideas

Striked items are done. The objectives may change however the core objectives will remain. There is a list of open issues on Google Code.

Core objectives

  1. Import SRTM data
    1. Australia in Postgres
    2. A few example tiles in the Google App Engine
  2. Refactor code to:
    1. support both a standalone Postgres installation as well as the Google App engine
  3. Provide a RESTFUL interface
    1. Input: HTTP/POST (xml, protocol buffers), HTTP/GET
    2. Output: xml, protocol buffers, gchart
  4. Build demonstration website : Done by Artem
  5. Calculate altitudes in route:
    1. return route with altitude points included
    2. interpolate between points in the route that a far apart compared to image resolution
    3. Bilinear Interpolation between SRTM data points
  6. Performance testing : Partially done
  7. Provide summary information (nett altitude difference, greatest : Not implemented yet

altitude difference)

Secondary objectives

  1. Orientation points in profile (from OSM database)
  2. Full testing suite
  3. Security
  4. Use memcache
  5. Deal with short spikes (shorter than resolution)
  6. Proper OpenLS support
  7. Serve entire planet

The Code

Subversion:

There are also two Git repositories:

Dependencies

The following packages are needed by the profile server:

Debian

aptitude install postgresql-8.3-postgis python-pygresql python-psycopg2 python-gdal python-beautifulsoup python-simplejson libapache2-mod-python libapache2-mod-wsgi

Components

Server

This will be the main component.

The server can receive input in three ways and can provide 4 types of output.

http://altitude.sprovoost.nl/profile/output_format/input_format/

output_format can be gchart, gchart_url or xml, see below.

Input format can be xml, protobuf or a GET request.

There are two demonstration servers running at the moment:

  • http://altitude.sprovoost.nl/ : runs on the Google App Engine. Only supports the area around Heidelberg and Berlin at the moment. Can probably handle quite a bit of traffic though.
  • http://altitude-pg.sprovoost.nl/ : runs on my home computer. Supports all of Europe as far east as Moscow and as far south as Cyprus. Can probably not deal with massive traffic though.

Input

I will demonstrate how to use the different input methods to generate a Google Chart url.

The sequence of coordinates will be the input for the profile. This input could come from a future route planner such as http://www.openrouteservice.org/. I will not create this planner.

XML

The XML document has to be sent through an HTTP/POST request to:

http://altitude.sprovoost.nl/profile/gchart_url/xml/

The XML document should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<xls:XLS xmlns:xls="http://www.opengis.net/xls"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gml="http://www.opengis.net/gml" version="1.1"
xsi:schemaLocation="http://www.opengis.net/xls
http://schemas.opengis.net/ols/1.1.0/RouteService.xsd">
 <xls:RouteGeometry>
   <gml:LineString srsName="EPSG:4326">
     <gml:pos>8.68108 49.40781</gml:pos>
     <gml:pos>8.68421 49.40777</gml:pos>
     <gml:pos>8.692368 49.40895</gml:pos>
     <gml:pos>8.69267 49.40704</gml:pos>
     <gml:pos>8.693919 49.40688</gml:pos>
     <gml:pos>8.69427 49.40762</gml:pos>
     <gml:pos>8.6923 49.41336</gml:pos>
     <gml:pos>8.69211 49.4148</gml:pos>
     <gml:pos>8.69311 49.41473</gml:pos>
   </gml:LineString>
 </xls:RouteGeometry>
</xls:XLS>

I will try to comply with OpenLS Core Service 5 - the Route Service

Google Protocol Buffers

Learn all about them here.

Obtain altitudeprofile_pb2.py.

If your client is written in Python do something like this:

import altitudeprofile_pb2
import urllib
route = [\
{'lat' : 49.407810, 'lon' : 8.681080},
{'lat' : 49.407770, 'lon' : 8.684210},
{'lat' : 49.408950, 'lon' : 8.692368},
{'lat' : 49.407040, 'lon' : 8.692670},
{'lat' : 49.406880, 'lon' : 8.693919},
{'lat' : 49.407620, 'lon' : 8.694270},
{'lat' : 49.413360, 'lon' : 8.692300},
{'lat' : 49.414800, 'lon' : 8.692110},
{'lat' : 49.414730, 'lon' : 8.693110}\
]
route_pb = altitudeprofile_pb2.Route()

for p in route:
  point = route_pb.point.add()
  point.lat = p['lat']
  point.lon = p['lon']

route_pb_string = route_pb.SerializeToString()
               
return urllib.urlopen(http://altitude.sprovoost.nl/profile/gchart_url/protobuf/", route_pb_string)

Alternatively you can receive the altitude profile as a protocol buffer, so you can build your own visualization:

return urllib.urlopen(http://altitude.sprovoost.nl/profile/protobuf/protobuf/", route_pb_string)
HTTP/GET

You can obtain either the URL to a Google Chart or the chart itself:

http://altitude.sprovoost.nl/profile/gchart_url?lats=49.407810,49.407770,49.408950,49.407040,49.406880,49.407620,49.413360,49.414800,49.414730&lons=8.681080,8.684210,8.692368,8.692670,8.693919,8.694270,8.692300,8.692110,8.693110
http://altitude.sprovoost.nl/profile/gchart?lats=49.407810,49.407770,49.408950,49.407040,49.406880,49.407620,49.413360,49.414800,49.414730&lons=8.681080,8.684210,8.692368,8.692670,8.693919,8.694270,8.692300,8.692110,8.693110

Example route server

An example route server that shows how to integrate the server into a website. It will allow the user to click on one of the example routes and send the corresponding XML request to the main server. Then it will return the resulting altitude profile to the users browser.

Initial SRTM import

I wrote a script that imports the SRTM data in a PostGIS (PostgreSQL) database. It can import a whole continent or just the area within a bounding box.

I have also written a script that can import 1 SRTM tile into the Google App Engine data store. It's solution is far from perfect.

Methodology

Estimate heights

For each point on the route the script considers the 4 points on the SRTM grid that lay around it and uses bilinear interpolation to estimate the height.

For long straight roads there is another problem: a road may go up and down several times between two consecutive nodes. Additional points are added to the route to deal with this.

Visualization

I will create the actual chart either server side with the Google Chart API or the matplotlib library for python, or client side in some other way.

The profile will be an array of (x,y) coordinates, one for each point along a route, where x is the distance from the origin, via the path and y is the altitude of each point. A point could be a node or any other point along a way.

References