-
Notifications
You must be signed in to change notification settings - Fork 0
Developers
For a start which requires only the JRE have a look here. Windows user can find a quick guide here.
Now, before you proceed install git and jdk6 or jdk7. Then do:
$ git clone git://github.com/graphhopper/graphhopper.git
$ cd graphhopper; ./graphhopper.sh web europe_germany_berlin.pbf
now go to http://localhost:8989/
- These steps make the Berlin area routable. It'll download and unzip the osm file.
- It builds the graphhopper jars. If Maven is not available it will automatically download it.
- Then it creates routable files for graphhopper in europe_germany_berlin-gh. It'll skip this step if files are already present.
- Also check the android version
For you favourite area do
$ ./graphhopper.sh web europe_france.pbf
$ ./graphhopper.sh web north-america_us_new-york.pbf
# the format follows the link structure at http://download.geofabrik.de
Open the project with NetBeans or enable Maven in your IDE. Maven is downloaded to graphhopper/maven
if not installed when executing graphhopper.sh.
Use one of the following snippets to start development with GraphHopper
// Initialization for the API to be used on a desktop or server pc
GraphHopperAPI gh = new GraphHopper().forServer();
// if you use example configuration you need to enable CH shortcuts
((GraphHopper) gh).setCHShortcuts(true, true);
gh.load("graph-hopper-folder");
// Offline API on Android
GraphHopperAPI gh = new GraphHopper().forMobile();
gh.load("graph-hopper-folder");
// Online: Connect to your own hosted graphhopper web service, for GraphHopperWeb see the 'web' sub project
GraphHopperAPI gh = new GraphHopperWeb();
gh.load("http://your-graphhopper-service.com/api");
GHRequest request = new GHRequest(fromLat, fromLon, toLat, toLon);
request.setAlgorithm("astarbi");
GHResponse response = gh.route(request);
print(response.getDistance() + " " + response.getTime());
PointList points = response.getPoints();
for(int i = 0; i < points.getSize(); i++) {
add(point.getLatitude(i), point.getLongitude(i));
}
If you want direct access to the more low-level API you can use this snippet. For more details on Android-usage have a look into this Android site
No special setup is required. Although it could make some problems to debug the web project. For NetBeans you need to add an action into nbactions.xml
<action>
<actionName>CUSTOM-jetty:run debug</actionName>
<displayName>jetty:run debug</displayName>
<goals>
<goal>jetty:run</goal>
</goals>
<properties>
<maven.test.skip>true</maven.test.skip>
<!-- for germany we need a bit more RAM -->
<Env.MAVEN_OPTS>-Dgraphhopper.config=../config.properties -Dgraphhopper.osmreader.osm=/media/SAMSUNG/maps/bayern.osm -Xms1500m -Xms1500m -XX:PermSize=50m -XX:MaxPermSize=50m -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000</Env.MAVEN_OPTS>
</properties>
</action>
Take the MAVEN_OPTS to setup a different IDE e.g. the -Dgraphhopper.config 'trick'
- For an example of how to use graphhopper in a web application see the web subfolder
- For an Android example see the android folder
- You can use graphhopper on the Desktop with the help of the yet outdated mapsforge swing library. The new 'rewrite' branch of mapsforge will help here soon.
In order to integrate GraphHopper into your application you could use some lower level classes. E.g. query the graph by a geo point (latitude,longitude) - for that you get one of the implementations of LocationIndex. Then use the QueryResult to query a RoutingAlgorithm implementation.
If you develop for Android have a look into the android subfolder. For smallish graph (e.g. size of Berlin) use a RAMDataAccess driven GraphStorage (loads all into memory). For larger ones use the ContractionHierarchies preparation class and MMapDataAccess to avoid OutOfMemoryErrors.
If you develop a web application have a look into the web demo ('web' subfolder). The simple API (json,jsonp,binary) in this demo is optimized regarding several aspects:
- It tries to return a smallish data set (encoded polyline, gzip filter)
- It enables cross-site scripting on the server- and client-site (jQuery, header setting)
- To make things simple it uses the GeoCoder called Nominatim to get the name for a latitude+longitude point or vice versa.
- Where it utilizes the jquery Deferred object to chain ajax requests and avoids browser UI blocking when resolving locations in parallel.
For simplicity you could just start jetty from maven and schedule it as background job: nohup ./graphhopper.sh web europe_germany_berlin.pbf
. Then your service should be accessible on port 8989.
For production usage you can install the latest jetty (8 or 9) as a service. Tomcat should also work. Then create a war file via mvn clean war:war
and copy it from the target/ folder to your jetty installation. Then copy web/config.properties also there and change this properties file to point to the required graphhopper folder. Increase the Xmx/Xms values of your jetty server e.g. for world wide coverage with a hierarchical graph I do the following in bin/jetty.sh
export JAVA=java-home/bin/java
export JAVA_OPTIONS="-server -Xconcurrentio -Xmx15000m -Xms15000m"
For World-Wide-Road-Network we have a separate wiki page.
Important notes:
- none-hierarchical graphs should be limited to a certain distance otherwise you'll require lots of RAM per request! See https://github.com/graphhopper/graphhopper/issues/104
- if you have strange speed problems which could be related to low memory you can try to entire disable swap. Or just try it out via
sudo swapoff -a
. Swapping out is very harmful to Java programs especially when the GC kicks in.
To get a better understanding also take a look in the source code, especially in the unit tests! There are mainly three parts:
The default import is done via OSMReader which imports OpenStreetMap data. You can configure it via API or use the graphhopper.sh script which utilizes the config.properties where you can specify if it should read CAR, FOOT etc or all at once. You'll have to make sure that you allocate enough memory for your specific graph (E.g. ~1GB for Germany) e.g. export JAVA_OPTS="-Xmx1g"
. The import process is fast e.g. complete germany takes about 10 minutes on my oldish laptop. Additionally it will take time if you choose osmreader.chShortcuts=fastest in the config.properties which will dramatically improve query time.
To process algorithms you need a Graph. At the moment there is one main implementation GraphHopperStorage which can be used:
- in-memory with a safe/flush option (RAMDataAccess) and
- a memory mapped (MMapDataAccess).
The interface Graph is developed in the sense that the implementation can be as much efficient as possible - i.e. node ids and edge ids are successive (and so are just indices) and in the range of 0 to MAX-1. This design could be used to have an array-like structure in the underlying DataAccess implementation like it is currently the case.
The data layout for the DataAccess objects in GraphHopperStorage called 'nodes' and 'edges' is the following:
Some explanations:
- One 'node row' consists of latitude,longitude (not shown) and an edgeID
- One 'edge row' consists of two edgeIDs: nextA and nextB, then two nodeIDs nodeA and nodeB, and finally some properties like the distance and the flags.
- One node has several edges which is implemented as a linked list. E.g. node 3 points to its first edge in the edge area at position 0 to edge 0-3 (nodeA-nodeB where nodeA is always smaller than nodeB). To get the next edge of node 3 you need nextB and this goes to edge 1-3, again node 3 is nodeB, but for the next edge 3-5 node 3 is nodeA ... and so on.
- For you custom data import keep in mind that although the nodes 4 and 6 have no edges they still 'exist' and consume space in the current implementations of DataAccess. For OSMReader this cannot be the case as separate networks with only a small number of nodes are removed (very likely OSM bugs).
For some algorithms there are special implementations of the Graph. E.g. there is a LevelGraphStorage which is a Graph with the possibility to store shortcut edges and a level for every node. This special storage is necessary for Contraction Hierarchies. For this the graph needs also some preprocessing (which can take several hours for bigger areas like Europe) which is done in the OSMReader when configured (osmreader.chShortcuts=fastest) or via API in PrepareContractionHierarchies. In order to use the shortcuts and get the benefits of the optimized graph you must use the algorithm returned from createAlgo() in the preparation class.
A LevelGraphStorage (and all subclasses of GraphStorage) cannot read files created with GraphStorage and vice versa. Also there is a file version which is changed if the data structure of GraphHopper gets incompatible to the previous versions.
In the routing package you'll find some shortest path algorithms like Dijkstra or A* etc. For those algorithms you need a Graph.
An algorithm needs a kind of path extraction: from the shortest-path-tree one needs to determine the route (list of edges) including the distance and time. Afterwards from this list the exact point (latitude,longitude) can be determined. For bidirectional algorithms this is a bit more complicated and done in PathBidirRef. For Contraction Hierarchies one needs to additionally find the shortcutted edges and process them recursivly - this is done in Path4CH.