initial commit of BRouter Version 0.98

This commit is contained in:
Arndt Brenschede 2014-01-18 15:29:05 +01:00
parent e4ae2b37d3
commit 91e62f1164
120 changed files with 15382 additions and 0 deletions

View file

@ -2,3 +2,9 @@ brouter
======= =======
configurable OSM offline router with elevation awareness, Java + Android configurable OSM offline router with elevation awareness, Java + Android
For more infos see http://brensche.de/brouter
Compile with (Java 6!):
> mvn clean install -Dandroid.sdk.path=<your-sdk-path>

31
brouter-core/pom.xml Normal file
View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>0.98</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-core</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-mapaccess</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-expressions</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,56 @@
/**
* Information on matched way point
*
* @author ab
*/
package btools.router;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import btools.mapaccess.OsmNode;
final class MatchedWaypoint
{
public OsmNode node1;
public OsmNode node2;
public OsmNodeNamed crosspoint;
public OsmNodeNamed waypoint;
public double radius;
public int cost;
public void writeToStream( DataOutput dos ) throws IOException
{
dos.writeInt( node1.ilat );
dos.writeInt( node1.ilon );
dos.writeInt( node2.ilat );
dos.writeInt( node2.ilon );
dos.writeInt( crosspoint.ilat );
dos.writeInt( crosspoint.ilon );
dos.writeInt( waypoint.ilat );
dos.writeInt( waypoint.ilon );
dos.writeDouble( radius );
}
public static MatchedWaypoint readFromStream( DataInput dis ) throws IOException
{
MatchedWaypoint mwp = new MatchedWaypoint();
mwp.node1 = new OsmNode();
mwp.node2 = new OsmNode();
mwp.crosspoint = new OsmNodeNamed();
mwp.waypoint = new OsmNodeNamed();
mwp.node1.ilat = dis.readInt();
mwp.node1.ilon = dis.readInt();
mwp.node2.ilat = dis.readInt();
mwp.node2.ilon = dis.readInt();
mwp.crosspoint.ilat = dis.readInt();
mwp.crosspoint.ilon = dis.readInt();
mwp.waypoint.ilat = dis.readInt();
mwp.waypoint.ilon = dis.readInt();
mwp.radius = dis.readDouble();
return mwp;
}
}

View file

@ -0,0 +1,172 @@
/**
* Implementation for the open-set
* that should be somewhat faster
* and memory-efficient than the original
* version based on java.util.TreeSet
*
* It relies on the two double-linked
* lists implemented in OsmPath
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
public class OpenSet
{
private OsmPath start = new OsmPath();
private OsmPath index2 = new OsmPath();
private int addCount = 0;
private int size = 0;
public void clear()
{
start.nextInSet = null;
start.nextInIndexSet = null;
index2.nextInIndexSet = null;
size = 0;
addCount = 0;
}
public void add( OsmPath path )
{
int ac = path.adjustedCost;
OsmPath p1 = index2;
// fast forward along index2
while( p1.nextInIndexSet != null && p1.nextInIndexSet.adjustedCost < ac )
{
p1 = p1.nextInIndexSet;
}
if ( p1 == index2 )
{
p1 = start;
}
// search using index1
for(;;)
{
if ( p1.nextInIndexSet != null && p1.nextInIndexSet.adjustedCost < ac )
{
p1 = p1.nextInIndexSet;
}
else if ( p1.nextInSet != null && p1.nextInSet.adjustedCost < ac )
{
p1 = p1.nextInSet;
}
else
{
break;
}
}
OsmPath p2 = p1.nextInSet;
p1.nextInSet = path;
path.prevInSet = p1;
path.nextInSet = p2;
if ( p2 != null ) { p2.prevInSet = path; }
size++;
addCount++;
// feed random samples to the indices
if ( (addCount & 31) == 0 )
{
addIndex( path, start );
}
else if ( (addCount & 1023) == 1023 )
{
addIndex( path, index2 );
}
}
public void remove( OsmPath path )
{
OsmPath p1 = path.prevInSet;
OsmPath p2 = path.nextInSet;
if ( p1 == null )
{
return; // not in set
}
path.prevInSet = null;
path.nextInSet = null;
if ( p2 != null )
{
p2.prevInSet = p1;
}
p1.nextInSet = p2;
removeIndex( path );
size--;
}
public OsmPath first()
{
return start.nextInSet;
}
public int size()
{
return size;
}
public int[] getExtract()
{
int div = size / 1000 + 1;
int[] res = new int[size/div * 2];
int i = 0;
int cnt = 0;
for( OsmPath p = start.nextInSet; p != null; p = p.nextInSet )
{
if ( (++cnt) % div == 0 )
{
OsmNode n = p.getLink().targetNode;
res[i++] = n.ilon;
res[i++] = n.ilat;
}
}
return res;
}
// index operations
private void addIndex( OsmPath path, OsmPath index )
{
int ac = path.adjustedCost;
OsmPath p1 = index;
OsmPath p2 = p1.nextInIndexSet;
while( p2 != null && p2.adjustedCost < ac )
{
p1 = p2;
p2 = p2.nextInIndexSet;
}
p1.nextInIndexSet = path;
path.prevInIndexSet = p1;
path.nextInIndexSet = p2;
if ( p2 != null ) { p2.prevInIndexSet = path; }
}
private void removeIndex( OsmPath path )
{
OsmPath p1 = path.prevInIndexSet;
OsmPath p2 = path.nextInIndexSet;
if ( p1 == null )
{
return; // not in set
}
path.prevInIndexSet = null;
path.nextInIndexSet = null;
if ( p2 != null )
{
p2.prevInIndexSet = p1;
}
p1.nextInIndexSet = p2;
}
}

View file

@ -0,0 +1,33 @@
/**
* Container for an osm node
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
public class OsmNodeNamed extends OsmNode
{
public String name;
public double radius; // radius of nogopoint
public boolean isNogo = false;
@Override
public String toString()
{
return ilon + "," + ilat + "," + name;
}
public static OsmNodeNamed decodeNogo( String s )
{
OsmNodeNamed n = new OsmNodeNamed();
int idx1 = s.indexOf( ',' );
n.ilon = Integer.parseInt( s.substring( 0, idx1 ) );
int idx2 = s.indexOf( ',', idx1+1 );
n.ilat = Integer.parseInt( s.substring( idx1+1, idx2 ) );
n.name = s.substring( idx2+1 );
n.isNogo = true;
return n;
}
}

View file

@ -0,0 +1,371 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import btools.mapaccess.*;
final class OsmPath implements OsmLinkHolder
{
// double-linked lists for the openSet
public OsmPath nextInSet;
public OsmPath prevInSet;
public OsmPath nextInIndexSet;
public OsmPath prevInIndexSet;
/**
* The cost of that path (a modified distance)
*/
public int cost = 0;
/**
* The elevation-hysteresis-buffer (0-10 m)
*/
private int ehbd; // in micrometer
private int ehbu; // in micrometer
// the elevation assumed for that path can have a value
// if the corresponding node has not
public short selev;
private static final int MAX_EHB = 10000000;
public int adjustedCost = 0;
public void setAirDistanceCostAdjustment( int costAdjustment )
{
adjustedCost = cost + costAdjustment;
}
private OsmNode sourcenode;
private OsmLink link;
public OsmPathElement originElement;
private OsmLinkHolder nextForLink = null;
public int treedepth = 0;
// the position of the waypoint just before
// this path position (for angle calculation)
public int originLon;
public int originLat;
// the costfactor of the segment just before this paths position
public float lastCostfactor;
public String message;
OsmPath()
{
}
OsmPath( OsmLink link )
{
this();
this.link = link;
this.selev = link.targetNode.getSElev();
}
OsmPath( OsmNode sourcenode, OsmPath origin, OsmLink link, OsmTrack refTrack, boolean recordTransferNodes, RoutingContext rc )
{
this();
this.originElement = new OsmPathElement( origin );
this.link = link;
this.sourcenode = sourcenode;
this.cost = origin.cost;
this.ehbd = origin.ehbd;
this.ehbu = origin.ehbu;
this.lastCostfactor = origin.lastCostfactor;
addAddionalPenalty(refTrack, recordTransferNodes, origin, link, rc );
}
private void addAddionalPenalty(OsmTrack refTrack, boolean recordTransferNodes, OsmPath origin, OsmLink link, RoutingContext rc )
{
rc.nogomatch = false;
// extract the 3 positions of the first section
int lon0 = origin.originLon;
int lat0 = origin.originLat;
OsmNode p1 = origin.link.targetNode;
int lon1 = p1.getILon();
int lat1 = p1.getILat();
short ele1 = origin.selev;
int linkdisttotal = 0;
int linkdist = 0;
int linkelevationcost = 0;
int linkturncost = 0;
OsmTransferNode transferNode = link.decodeFirsttransfer();
OsmNode targetNode = link.targetNode;
long lastDescription = -1L;
String lastMessage = null;
for(;;)
{
originLon = lon1;
originLat = lat1;
int lon2;
int lat2;
short ele2;
long description;
if ( transferNode == null )
{
lon2 = targetNode.ilon;
lat2 = targetNode.ilat;
ele2 = targetNode.selev;
description = link.descriptionBitmap;
}
else
{
lon2 = transferNode.ilon;
lat2 = transferNode.ilat;
ele2 = transferNode.selev;
description = transferNode.descriptionBitmap;
}
// if way description changed, store message
if ( lastMessage != null && description != lastDescription )
{
originElement.message = lastMessage;
linkdist = 0;
linkelevationcost = 0;
linkturncost = 0;
}
lastDescription = description;
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
int elefactor = 250000;
boolean stopAtEndpoint = false;
if ( rc.shortestmatch )
{
elefactor = (int)(elefactor*rc.wayfraction);
if ( rc.isEndpoint )
{
stopAtEndpoint = true;
}
else
{
// we just start here, reset cost
cost = 0;
ehbd = 0;
ehbu = 0;
if ( recordTransferNodes )
{
if ( rc.wayfraction > 0. )
{
originElement = new OsmPathElement( rc.ilonshortest, rc.ilatshortest, ele2, null );
}
else
{
originElement = null; // prevent duplicate point
}
}
}
}
linkdist += dist;
linkdisttotal += dist;
rc.messageHandler.setCurrentPos( lon2, lat2 );
rc.expctxWay.evaluate( description, rc.messageHandler );
// *** penalty for way-change
if ( origin.originElement != null )
{
// penalty proportional to direction change
double cos = rc.calcCosAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
int turncost = (int)(cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
cost += turncost;
linkturncost += turncost;
}
// *** penalty for elevation (penalty is for descend! in a way that slow descends give no penalty)
// only the part of the descend that does not fit into the elevation-hysteresis-buffer
// leads to an immediate penalty
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1;
if ( ele1 != Short.MIN_VALUE )
{
ehbd += (ele1 - ele2)*elefactor - dist * rc.downhillcutoff;
ehbu += (ele2 - ele1)*elefactor - dist * rc.uphillcutoff;
}
if ( ehbd > MAX_EHB )
{
if ( rc.downhillcostdiv > 0 )
{
int elevationCost = (ehbd-MAX_EHB)/rc.downhillcostdiv;
cost += elevationCost;
linkelevationcost += elevationCost;
}
ehbd = MAX_EHB;
}
else if ( ehbd < 0 )
{
ehbd = 0;
}
if ( ehbu > MAX_EHB )
{
if ( rc.uphillcostdiv > 0 )
{
int elevationCost = (ehbu-MAX_EHB)/rc.uphillcostdiv;
cost += elevationCost;
linkelevationcost += elevationCost;
}
ehbu = MAX_EHB;
}
else if ( ehbu < 0 )
{
ehbu = 0;
}
// *** penalty for distance
float costfactor = rc.expctxWay.getCostfactor();
float fcost = dist * costfactor + 0.5f;
if ( costfactor >= 10000. || fcost + cost >= 2000000000. )
{
cost = -1;
return;
}
int waycost = (int)(fcost);
cost += waycost;
// *** add initial cost if factor changed
float costdiff = costfactor - lastCostfactor;
if ( costdiff > 0.0005 || costdiff < -0.0005 )
{
lastCostfactor = costfactor;
float initialcost = rc.expctxWay.getInitialcost();
int iicost = (int)initialcost;
cost += iicost;
}
if ( recordTransferNodes )
{
int iCost = (int)(rc.expctxWay.getCostfactor()*1000 + 0.5f);
lastMessage = (lon2-180000000) + "\t"
+ (lat2-90000000) + "\t"
+ ele2/4 + "\t"
+ linkdist + "\t"
+ iCost + "\t"
+ linkelevationcost
+ "\t" + linkturncost
+ rc.expctxWay.getCsvDescription( description );
}
if ( stopAtEndpoint )
{
if ( recordTransferNodes )
{
originElement = new OsmPathElement( rc.ilonshortest, rc.ilatshortest, ele2, originElement );
originElement.cost = cost;
}
if ( rc.nogomatch )
{
cost = -1;
}
return;
}
if ( transferNode == null )
{
// *** penalty for being part of the reference track
if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( origin.link.targetNode ) )
{
int reftrackcost = linkdisttotal;
cost += reftrackcost;
}
message = lastMessage;
selev = ele2;
break;
}
transferNode = transferNode.next;
if ( recordTransferNodes )
{
originElement = new OsmPathElement( lon2, lat2, ele2, originElement );
originElement.cost = cost;
}
lon0 = lon1;
lat0 = lat1;
lon1 = lon2;
lat1 = lat2;
ele1 = ele2;
}
// check for nogo-matches (after the *actual* start of segment)
if ( rc.nogomatch )
{
cost = -1;
return;
}
// finally add node-costs for target node
if ( targetNode.nodeDescription != 0L )
{
rc.messageHandler.setCurrentPos( targetNode.ilon, targetNode.ilat );
rc.expctxNode.evaluate( targetNode.nodeDescription, rc.messageHandler );
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
cost = -1;
return;
}
int iicost = (int)initialcost;
cost += iicost;
}
}
public int elevationCorrection( RoutingContext rc )
{
return ( rc.downhillcostdiv > 0 ? ehbd/rc.downhillcostdiv : 0 )
+ ( rc.uphillcostdiv > 0 ? ehbu/rc.uphillcostdiv : 0 );
}
public boolean definitlyWorseThan( OsmPath p, RoutingContext rc )
{
int c = p.cost;
if ( rc.downhillcostdiv > 0 )
{
int delta = p.ehbd - ehbd;
if ( delta > 0 ) c += delta/rc.downhillcostdiv;
}
if ( rc.uphillcostdiv > 0 )
{
int delta = p.ehbu - ehbu;
if ( delta > 0 ) c += delta/rc.uphillcostdiv;
}
return cost > c;
}
public OsmNode getSourceNode()
{
return sourcenode;
}
public OsmLink getLink()
{
return link;
}
public void setNextForLink( OsmLinkHolder holder )
{
nextForLink = holder;
}
public OsmLinkHolder getNextForLink()
{
return nextForLink;
}
}

View file

@ -0,0 +1,113 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmPos;
final class OsmPathElement implements OsmPos
{
private int ilat; // latitude
private int ilon; // longitude
private short selev; // longitude
public String message = null; // description
public int cost;
// interface OsmPos
public int getILat()
{
return ilat;
}
public int getILon()
{
return ilon;
}
public short getSElev()
{
return selev;
}
public double getElev()
{
return selev / 4.;
}
public long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
}
public int calcDistance( OsmPos p )
{
double l = (ilat-90000000) * 0.00000001234134;
double l2 = l*l;
double l4 = l2*l2;
double coslat = 1.- l2 + l4 / 6.;
double dlat = (ilat - p.getILat() )/1000000.;
double dlon = (ilon - p.getILon() )/1000000. * coslat;
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * (6378000. / 57.);
return (int)(d + 1.0 );
}
public OsmPathElement origin;
// construct a path element from a path
public OsmPathElement( OsmPath path )
{
OsmNode n = path.getLink().targetNode;
ilat = n.getILat();
ilon = n.getILon();
selev = path.selev;
cost = path.cost;
origin = path.originElement;
message = path.message;
}
public OsmPathElement( int ilon, int ilat, short selev, OsmPathElement origin )
{
this.ilon = ilon;
this.ilat = ilat;
this.selev = selev;
this.origin = origin;
}
private OsmPathElement()
{
}
public String toString()
{
return ilon + "_" + ilat;
}
public void writeToStream( DataOutput dos ) throws IOException
{
dos.writeInt( ilat );
dos.writeInt( ilon );
dos.writeShort( selev );
dos.writeInt( cost );
}
public static OsmPathElement readFromStream( DataInput dis ) throws IOException
{
OsmPathElement pe = new OsmPathElement();
pe.ilat = dis.readInt();
pe.ilon = dis.readInt();
pe.selev = dis.readShort();
pe.cost = dis.readInt();
return pe;
}
}

View file

@ -0,0 +1,365 @@
/**
* Container for a track
*
* @author ab
*/
package btools.router;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import btools.mapaccess.OsmPos;
import btools.util.CompactLongMap;
import btools.util.FrozenLongMap;
public final class OsmTrack
{
public MatchedWaypoint endPoint;
private class OsmPathElementHolder
{
public OsmPathElement node;
public OsmPathElementHolder nextHolder;
}
public ArrayList<OsmPathElement> nodes = new ArrayList<OsmPathElement>();
private CompactLongMap<OsmPathElementHolder> nodesMap;
public String message = null;
public ArrayList<String> messageList = null;
public String name = "unset";
public void addNode( OsmPathElement node )
{
nodes.add( 0, node );
}
public void buildMap()
{
nodesMap = new CompactLongMap<OsmPathElementHolder>();
for( OsmPathElement node: nodes )
{
long id = node.getIdFromPos();
OsmPathElementHolder nh = new OsmPathElementHolder();
nh.node = node;
OsmPathElementHolder h = nodesMap.get( id );
if ( h != null )
{
while( h.nextHolder != null )
{
h = h.nextHolder;
}
h.nextHolder = nh;
}
else
{
nodesMap.fastPut( id, nh );
}
}
nodesMap = new FrozenLongMap<OsmPathElementHolder>( nodesMap );
}
/**
* writes the track in binary-format to a file
* @param filename the filename to write to
*/
public void writeBinary( String filename ) throws Exception
{
DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( filename ) ) );
endPoint.writeToStream( dos );
dos.writeInt( nodes.size() );
for( OsmPathElement node: nodes )
{
node.writeToStream( dos );
}
dos.close();
}
public static OsmTrack readBinary( String filename, OsmNodeNamed newEp )
{
OsmTrack t = null;
if ( filename != null )
{
File f = new File( filename );
if ( f.exists() )
{
try
{
DataInputStream dis = new DataInputStream( new BufferedInputStream( new FileInputStream( f ) ) );
MatchedWaypoint ep = MatchedWaypoint.readFromStream( dis );
int dlon = ep.waypoint.ilon - newEp.ilon;
int dlat = ep.waypoint.ilat - newEp.ilat;
if ( dlon < 20 && dlon > -20 && dlat < 20 && dlat > -20 )
{
t = new OsmTrack();
t.endPoint = ep;
int n = dis.readInt();
OsmPathElement last_pe = null;
for( int i=0; i<n; i++ )
{
OsmPathElement pe = OsmPathElement.readFromStream( dis );
pe.origin = last_pe;
last_pe = pe;
t.nodes.add( pe );
}
t.cost = last_pe.cost;
t.buildMap();
}
dis.close();
}
catch( Exception e )
{
throw new RuntimeException( "Exception reading rawTrack: " + e );
}
}
}
return t;
}
public void addNodes( OsmTrack t )
{
for( OsmPathElement n : t.nodes ) addNode( n );
buildMap();
}
public boolean containsNode( OsmPos node )
{
return nodesMap.contains( node.getIdFromPos() );
}
public OsmPathElement getLink( long n1, long n2 )
{
OsmPathElementHolder h = nodesMap.get( n2 );
while( h != null )
{
OsmPathElement e1 = h.node.origin;
if ( e1 != null && e1.getIdFromPos() == n1 )
{
return h.node;
}
h = h.nextHolder;
}
return null;
}
public void appendTrack( OsmTrack t )
{
for( int i=0; i<t.nodes.size(); i++ )
{
if ( i > 0 || nodes.size() == 0 )
{
nodes.add( t.nodes.get(i) );
}
}
distance += t.distance;
ascend += t.ascend;
plainAscend += t.plainAscend;
cost += t.cost;
}
public int distance;
public int ascend;
public int plainAscend;
public int cost;
/**
* writes the track in gpx-format to a file
* @param filename the filename to write to
*/
public void writeGpx( String filename ) throws Exception
{
BufferedWriter bw = new BufferedWriter( new FileWriter( filename ) );
bw.write( formatAsGpx() );
bw.close();
}
public String formatAsGpx()
{
StringBuilder sb = new StringBuilder(8192);
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
for( int i=messageList.size()-1; i >= 0; i-- )
{
String message = messageList.get(i);
if ( i < messageList.size()-1 ) message = "(alt-index " + i + ": " + message + " )";
if ( message != null ) sb.append( "<!-- " + message + " -->\n" );
}
sb.append( "<gpx \n" );
sb.append( " xmlns=\"http://www.topografix.com/GPX/1/1\" \n" );
sb.append( " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" );
sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" );
sb.append( " creator=\"BRouter-0.98\" version=\"1.1\">\n" );
sb.append( " <trk>\n" );
sb.append( " <name>" + name + "</name>\n" );
sb.append( " <trkseg>\n" );
for( OsmPathElement n : nodes )
{
String sele = n.getSElev() == Short.MIN_VALUE ? "" : "<ele>" + n.getElev() + "</ele>";
sb.append( " <trkpt lon=\"" + formatPos( n.getILon() - 180000000 ) + "\" lat=\"" + formatPos( n.getILat() - 90000000 ) + "\">" + sele + "</trkpt>\n" );
}
sb.append( " </trkseg>\n" );
sb.append( " </trk>\n" );
sb.append( "</gpx>\n" );
return sb.toString();
}
public void writeKml( String filename ) throws Exception
{
BufferedWriter bw = new BufferedWriter( new FileWriter( filename ) );
bw.write( formatAsKml() );
bw.close();
}
public String formatAsKml()
{
StringBuilder sb = new StringBuilder(8192);
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
sb.append( "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n" );
sb.append( " <Document>\n" );
sb.append( " <name>KML Samples</name>\n" );
sb.append( " <open>1</open>\n" );
sb.append( " <distance>3.497064</distance>\n" );
sb.append( " <traveltime>872</traveltime>\n" );
sb.append( " <description>To enable simple instructions add: 'instructions=1' as parameter to the URL</description>\n" );
sb.append( " <Folder>\n" );
sb.append( " <name>Paths</name>\n" );
sb.append( " <visibility>0</visibility>\n" );
sb.append( " <description>Examples of paths.</description>\n" );
sb.append( " <Placemark>\n" );
sb.append( " <name>Tessellated</name>\n" );
sb.append( " <visibility>0</visibility>\n" );
sb.append( " <description><![CDATA[If the <tessellate> tag has a value of 1, the line will contour to the underlying terrain]]></description>\n" );
sb.append( " <LineString>\n" );
sb.append( " <tessellate>1</tessellate>\n" );
sb.append( " <coordinates> " );
for( OsmPathElement n : nodes )
{
sb.append( formatPos( n.getILon() - 180000000 ) + "," + formatPos( n.getILat() - 90000000 ) + "\n" );
}
sb.append( " </coordinates>\n" );
sb.append( " </LineString>\n" );
sb.append( " </Placemark>\n" );
sb.append( " </Folder>\n" );
sb.append( " </Document>\n" );
sb.append( "</kml>\n" );
return sb.toString();
}
private static String formatPos( int p )
{
boolean negative = p < 0;
if ( negative ) p = -p;
char[] ac = new char[12];
int i = 11;
while( p != 0 || i > 3 )
{
ac[i--] = (char)('0' + (p % 10));
p /= 10;
if ( i == 5 ) ac[i--] = '.';
}
if ( negative ) ac[i--] = '-';
return new String( ac, i+1, 11-i );
}
public void dumpMessages( String filename, RoutingContext rc ) throws Exception
{
BufferedWriter bw = filename == null ? null : new BufferedWriter( new FileWriter( filename ) );
// csv-header-line
String header = "Longitude\tLatitude\tElevation\tDistance\tCostPerKm\tElevCost\tTurnCost";
if ( rc.expctxWay != null )
{
header += rc.expctxWay.getCsvHeader();
}
dumpLine( bw, header );
for( OsmPathElement n : nodes )
{
if ( n.message != null )
{
dumpLine( bw, n.message );
}
}
if ( bw != null ) bw.close();
}
private void dumpLine( BufferedWriter bw, String s) throws Exception
{
if ( bw == null )
{
System.out.println( s );
}
else
{
bw.write( s );
bw.write( "\n" );
}
}
public void readGpx( String filename ) throws Exception
{
File f = new File( filename );
if ( !f.exists() ) return;
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream( f ) ) );
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
int idx0 = line.indexOf( "<trkpt lon=\"" );
if ( idx0 >= 0 )
{
idx0 += 12;
int idx1 = line.indexOf( '"', idx0 );
int ilon = (int)((Double.parseDouble( line.substring( idx0, idx1 ) ) + 180. )*1000000. + 0.5);
int idx2 = line.indexOf( " lat=\"" );
if ( idx2 < 0 ) continue;
idx2 += 6;
int idx3 = line.indexOf( '"', idx2 );
int ilat = (int)((Double.parseDouble( line.substring( idx2, idx3 ) ) + 90. )*1000000. + 0.5);
nodes.add( new OsmPathElement( ilon, ilat, (short)0, null ) );
}
}
br.close();
}
public boolean equalsTrack( OsmTrack t )
{
if ( nodes.size() != t.nodes.size() ) return false;
for( int i=0; i<nodes.size(); i++ )
{
OsmPathElement e1 = nodes.get(i);
OsmPathElement e2 = t.nodes.get(i);
if ( e1.getILon() != e2.getILon() || e1.getILat() != e2.getILat() ) return false;
}
return true;
}
}

View file

@ -0,0 +1,241 @@
/**
* Container for routig configs
*
* @author ab
*/
package btools.router;
import java.util.ArrayList;
import java.util.List;
import btools.mapaccess.*;
import btools.expressions.*;
public final class RoutingContext implements DistanceChecker
{
public void setAlternativeIdx( int idx )
{
if ( idx < 0 ) idx = 0;
if ( idx > 3 ) idx = 3;
alternativeIdx = idx;
}
public int getAlternativeIdx()
{
return alternativeIdx;
}
public int alternativeIdx = 0;
public String localFunction;
public String rawTrackPath;
public String getProfileName()
{
String name = localFunction == null ? "unknown" : localFunction;
if ( name.endsWith( ".brf" ) ) name = name.substring( 0, localFunction.length() - 4 );
int idx = name.lastIndexOf( '/' );
if ( idx >= 0 ) name = name.substring( idx+1 );
return name;
}
public BExpressionContext expctxWay;
public BExpressionContext expctxNode;
public int downhillcostdiv;
public int downhillcutoff;
public int uphillcostdiv;
public int uphillcutoff;
public boolean carMode;
public double pass1coefficient;
public double pass2coefficient;
public void readGlobalConfig( BExpressionContext expctxGlobal )
{
downhillcostdiv = (int)expctxGlobal.getVariableValue( "downhillcost" );
downhillcutoff = (int)(expctxGlobal.getVariableValue( "downhillcutoff" )*10000);
uphillcostdiv = (int)expctxGlobal.getVariableValue( "uphillcost" );
uphillcutoff = (int)(expctxGlobal.getVariableValue( "uphillcutoff" )*10000);
if ( downhillcostdiv != 0 ) downhillcostdiv = 1000000/downhillcostdiv;
if ( uphillcostdiv != 0 ) uphillcostdiv = 1000000/uphillcostdiv;
carMode = 0.f != expctxGlobal.getVariableValue( "validForCars" );
pass1coefficient = expctxGlobal.getVariableValue( "pass1coefficient", 1.5f );
pass2coefficient = expctxGlobal.getVariableValue( "pass2coefficient", 0.f );
}
public RoutingMessageHandler messageHandler = new RoutingMessageHandler();
public List<OsmNodeNamed> nogopoints = null;
private List<OsmNodeNamed> keepnogopoints = null;
private double coslat;
public boolean nogomatch = false;
public boolean isEndpoint = false;
public boolean shortestmatch = false;
public double wayfraction;
public int ilatshortest;
public int ilonshortest;
public void prepareNogoPoints( List<OsmNodeNamed> nogos )
{
for( OsmNodeNamed nogo : nogos )
{
String s = nogo.name;
int idx = s.indexOf( ' ' );
if ( idx > 0 ) s = s.substring( 0 , idx );
int ir = 20; // default radius
if ( s.length() > 4 )
{
try { ir = Integer.parseInt( s.substring( 4 ) ); }
catch( Exception e ) { /* ignore */ }
}
nogo.radius = ir / 111894.; // 6378000. / 57.;
}
}
public void setWaypoint( OsmNodeNamed wp, boolean endpoint )
{
keepnogopoints = nogopoints;
nogopoints = new ArrayList<OsmNodeNamed>();
nogopoints.add( wp );
if ( keepnogopoints != null ) nogopoints.addAll( keepnogopoints );
isEndpoint = endpoint;
}
public void unsetWaypoint()
{
nogopoints = keepnogopoints;
isEndpoint = false;
}
public int calcDistance( int lon1, int lat1, int lon2, int lat2 )
{
double l = (lat2 - 90000000) * 0.00000001234134;
double l2 = l*l;
double l4 = l2*l2;
coslat = 1.- l2 + l4 / 6.;
double coslat6 = coslat*0.000001;
double dx = (lon2 - lon1 ) * coslat6;
double dy = (lat2 - lat1 ) * 0.000001;
double d = Math.sqrt( dy*dy + dx*dx );
shortestmatch = false;
if ( d > 0. && nogopoints != null )
{
for( OsmNodeNamed nogo : nogopoints )
{
double x1 = (lon1 - nogo.ilon) * coslat6;
double y1 = (lat1 - nogo.ilat) * 0.000001;
double x2 = (lon2 - nogo.ilon) * coslat6;
double y2 = (lat2 - nogo.ilat) * 0.000001;
double r12 = x1*x1 + y1*y1;
double r22 = x2*x2 + y2*y2;
double radius = Math.abs( r12 < r22 ? y1*dx - x1*dy : y2*dx - x2*dy ) / d;
if ( radius < nogo.radius ) // 20m
{
double s1 = x1*dx + y1*dy;
double s2 = x2*dx + y2*dy;
if ( s1 < 0. ) { s1 = -s1; s2 = -s2; }
if ( s2 > 0. )
{
radius = Math.sqrt( s1 < s2 ? r12 : r22 );
if ( radius > nogo.radius ) continue; // 20m ^ 2
}
if ( nogo.isNogo ) nogomatch = true;
else
{
shortestmatch = true;
nogo.radius = radius; // shortest distance to way
// calculate remaining distance
if ( s2 < 0. )
{
double distance = d > 0. ? -s2 / d : 0.;
wayfraction = d > 0. ? distance / d : 0.;
double xm = x2 - wayfraction*dx;
double ym = y2 - wayfraction*dy;
ilonshortest = (int)(xm / coslat6 + nogo.ilon);
ilatshortest = (int)(ym / 0.000001 + nogo.ilat);
}
else if ( s1 > s2 )
{
wayfraction = 0.;
ilonshortest = lon2;
ilatshortest = lat2;
}
else
{
wayfraction = 1.;
ilonshortest = lon1;
ilatshortest = lat1;
}
// here it gets nasty: there can be nogo-points in the list
// *after* the shortest distance point. In case of a shortest-match
// we use the reduced way segment for nogo-matching, in order not
// to cut our escape-way if we placed a nogo just in front of where we are
if ( isEndpoint )
{
wayfraction = 1. - wayfraction;
lon2 = ilonshortest;
lat2 = ilatshortest;
}
else
{
nogomatch = false;
lon1 = ilonshortest;
lat1 = ilatshortest;
}
dx = (lon2 - lon1 ) * coslat6;
dy = (lat2 - lat1 ) * 0.000001;
d = Math.sqrt( dy*dy + dx*dx );
}
}
}
}
double dd = d * 111894.7368; // 6378000. / 57.;
return (int)(dd + 1.0 );
}
// assumes that calcDistance/calcCosAngle called in sequence, so coslat valid
public double calcCosAngle( int lon0, int lat0, int lon1, int lat1, int lon2, int lat2 )
{
double dlat1 = (lat1 - lat0);
double dlon1 = (lon1 - lon0) * coslat;
double dlat2 = (lat2 - lat1);
double dlon2 = (lon2 - lon1) * coslat;
double dd = Math.sqrt( (dlat1*dlat1 + dlon1*dlon1)*(dlat2*dlat2 + dlon2*dlon2) );
if ( dd == 0. ) return 0.;
double cosp = (dlat1*dlat2 + dlon1*dlon2)/dd;
return 1.-cosp; // don't care to really do acos..
}
@Override
public boolean isWithinRadius( int ilon0, int ilat0, OsmTransferNode firstTransfer, int ilon1, int ilat1 )
{
OsmNodeNamed wp = nogopoints.get(0);
double keepRadius = wp.radius;
try
{
int ilon = ilon0;
int ilat = ilat0;
for( OsmTransferNode trans = firstTransfer; trans != null; trans = trans.next )
{
calcDistance( ilon, ilat, trans.ilon, trans.ilat );
ilon = trans.ilon;
ilat = trans.ilat;
}
calcDistance( ilon, ilat, ilon1, ilat1 );
return wp.radius < keepRadius;
}
finally
{
wp.radius = keepRadius;
}
}
}

View file

@ -0,0 +1,968 @@
package btools.router;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import btools.expressions.BExpressionContext;
import btools.mapaccess.NodesCache;
import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmNodesMap;
public class RoutingEngine extends Thread
{
private OsmNodesMap nodesMap;
private NodesCache nodesCache;
private OpenSet openSet = new OpenSet();
private boolean finished = false;
private List<OsmNodeNamed> waypoints = null;
private int linksProcessed = 0;
private OsmTrack foundTrack = new OsmTrack();
private OsmTrack foundRawTrack = null;
private int alternativeIndex = 0;
private String errorMessage = null;
private volatile boolean terminated;
private String segmentDir;
private String outfileBase;
private String logfileBase;
private boolean infoLogEnabled;
private RoutingContext routingContext;
private double airDistanceCostFactor;
private OsmTrack guideTrack;
private OsmPathElement matchPath;
private long startTime;
private long maxRunningTime;
public boolean quite = false;
public RoutingEngine( String outfileBase, String logfileBase, String segmentDir,
List<OsmNodeNamed> waypoints, RoutingContext rc )
{
this.segmentDir = segmentDir;
this.outfileBase = outfileBase;
this.logfileBase = logfileBase;
this.waypoints = waypoints;
this.infoLogEnabled = outfileBase != null;
this.routingContext = rc;
if ( rc.localFunction != null )
{
String profileBaseDir = System.getProperty( "profileBaseDir" );
File profileDir;
File profileFile;
if ( profileBaseDir == null )
{
profileDir = new File( rc.localFunction ).getParentFile();
profileFile = new File( rc.localFunction ) ;
}
else
{
profileDir = new File( profileBaseDir );
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ;
}
BExpressionContext expctxGlobal = new BExpressionContext( "global" );
expctxGlobal.readMetaData( new File( profileDir, "lookups.dat" ) );
expctxGlobal.parseFile( profileFile, null );
expctxGlobal.evaluate( 1L, rc.messageHandler );
rc.readGlobalConfig(expctxGlobal);
rc.expctxWay = new BExpressionContext( "way", 4096 );
rc.expctxWay.readMetaData( new File( profileDir, "lookups.dat" ) );
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode = new BExpressionContext( "node", 1024 );
rc.expctxNode.readMetaData( new File( profileDir, "lookups.dat" ) );
rc.expctxNode.parseFile( profileFile, "global" );
}
}
private void logInfo( String s )
{
if ( infoLogEnabled )
{
System.out.println( s );
}
}
public void run()
{
doRun( 0 );
}
public void doRun( long maxRunningTime )
{
try
{
startTime = System.currentTimeMillis();
this.maxRunningTime = maxRunningTime;
OsmTrack sum = null;
OsmTrack track = null;
ArrayList<String> messageList = new ArrayList<String>();
for( int i=0; !terminated; i++ )
{
track = findTrack( sum );
track.message = "track-length = " + track.distance + " filtered ascend = " + track.ascend
+ " plain-ascend = " + track.plainAscend + " cost=" + track.cost;
track.name = "brouter_" + routingContext.getProfileName() + "_" + i;
messageList.add( track.message );
track.messageList = messageList;
if ( outfileBase != null )
{
String filename = outfileBase + i + ".gpx";
OsmTrack oldTrack = new OsmTrack();
oldTrack.readGpx(filename);
if ( track.equalsTrack( oldTrack ) )
{
if ( sum == null ) sum = new OsmTrack();
sum.addNodes( track );
continue;
}
track.writeGpx( filename );
foundTrack = track;
alternativeIndex = i;
}
else
{
if ( i == routingContext.getAlternativeIdx() )
{
if ( "CSV".equals( System.getProperty( "reportFormat" ) ) )
{
track.dumpMessages( null, routingContext );
}
else
{
if ( !quite )
{
System.out.println( track.formatAsGpx() );
}
}
foundTrack = track;
}
else
{
if ( sum == null ) sum = new OsmTrack();
sum.addNodes( track );
continue;
}
}
if ( logfileBase != null )
{
String logfilename = logfileBase + i + ".csv";
track.dumpMessages( logfilename, routingContext );
}
break;
}
long endTime = System.currentTimeMillis();
logInfo( "execution time = " + (endTime-startTime)/1000. + " seconds" );
}
catch( Exception e)
{
errorMessage = e instanceof IllegalArgumentException ? e.getMessage() : e.toString();
logInfo( "Exception (linksProcessed=" + linksProcessed + ": " + errorMessage );
e.printStackTrace();
}
catch( Error e)
{
String hint = cleanOnOOM();
errorMessage = e.toString() + hint;
logInfo( "Error (linksProcessed=" + linksProcessed + ": " + errorMessage );
e.printStackTrace();
}
finally
{
openSet.clear();
finished = true; // this signals termination to outside
}
}
public String cleanOnOOM()
{
boolean oom_carsubset_hint = nodesCache == null ? false : nodesCache.oom_carsubset_hint;
nodesMap = null;
nodesCache = null;
terminate();
return oom_carsubset_hint ? "\nPlease use 'carsubset' maps for long-distance car-routing" : "";
}
private OsmTrack findTrack( OsmTrack refTrack )
{
OsmTrack totaltrack = new OsmTrack();
MatchedWaypoint[] wayointIds = new MatchedWaypoint[waypoints.size()];
// check for a track for that target
OsmTrack nearbyTrack = null;
if ( refTrack == null )
{
nearbyTrack = OsmTrack.readBinary( routingContext.rawTrackPath, waypoints.get( waypoints.size()-1) );
if ( nearbyTrack != null )
{
wayointIds[waypoints.size()-1] = nearbyTrack.endPoint;
}
}
// match waypoints to nodes
for( int i=0; i<waypoints.size(); i++ )
{
if ( wayointIds[i] == null )
{
wayointIds[i] = matchNodeForPosition( waypoints.get(i) );
}
}
for( int i=0; i<waypoints.size() -1; i++ )
{
OsmTrack seg = searchTrack( wayointIds[i], wayointIds[i+1], i == waypoints.size()-2 ? nearbyTrack : null, refTrack );
if ( seg == null ) return null;
totaltrack.appendTrack( seg );
}
return totaltrack;
}
// geometric position matching finding the nearest routable way-section
private MatchedWaypoint matchNodeForPosition( OsmNodeNamed wp )
{
try
{
routingContext.setWaypoint( wp, false );
int minRingWith = 1;
for(;;)
{
MatchedWaypoint mwp = _matchNodeForPosition( wp, minRingWith );
if ( mwp.node1 != null )
{
int mismatch = wp.calcDistance( mwp.crosspoint );
if ( mismatch < 50*minRingWith )
{
return mwp;
}
}
if ( minRingWith++ == 5 )
{
throw new IllegalArgumentException( wp.name + "-position not mapped" );
}
}
}
finally
{
routingContext.unsetWaypoint();
}
}
private MatchedWaypoint _matchNodeForPosition( OsmNodeNamed wp, int minRingWidth )
{
wp.radius = 1e9;
resetCache();
preloadPosition( wp, minRingWidth, 2000 );
nodesCache.distanceChecker = routingContext;
List<OsmNode> nodeList = nodesCache.getAllNodes();
MatchedWaypoint mwp = new MatchedWaypoint();
mwp.waypoint = wp;
// first loop just to expand reverse links
for( OsmNode n : nodeList )
{
if ( !nodesCache.obtainNonHollowNode( n ) )
{
continue;
}
expandHollowLinkTargets( n, false );
OsmLink startLink = new OsmLink();
startLink.targetNode = n;
OsmPath startPath = new OsmPath( startLink );
startLink.addLinkHolder( startPath );
for( OsmLink link = n.firstlink; link != null; link = link.next )
{
if ( link.counterLinkWritten ) continue; // reverse link not found
OsmNode nextNode = link.targetNode;
if ( nextNode.isHollow() ) continue; // border node?
if ( nextNode.firstlink == null ) continue; // don't care about dead ends
if ( nextNode == n ) continue; // ?
double oldRadius = wp.radius;
OsmPath testPath = new OsmPath( n, startPath, link, null, false, routingContext );
if ( wp.radius < oldRadius )
{
if ( testPath.cost < 0 )
{
wp.radius = oldRadius; // no valid way
}
else
{
mwp.node1 = n;
mwp.node2 = nextNode;
mwp.radius = wp.radius;
mwp.cost = testPath.cost;
mwp.crosspoint = new OsmNodeNamed();
mwp.crosspoint.ilon = routingContext.ilonshortest;
mwp.crosspoint.ilat = routingContext.ilatshortest;
}
}
}
}
return mwp;
}
// expand hollow link targets and resolve reverse links
private void expandHollowLinkTargets( OsmNode n, boolean failOnReverseNotFound )
{
for( OsmLink link = n.firstlink; link != null; link = link.next )
{
if ( ! nodesCache.obtainNonHollowNode( link.targetNode ) )
{
continue;
}
if ( link.counterLinkWritten )
{
OsmLink rlink = link.targetNode.getReverseLink( n.getILon(), n.getILat() );
if ( rlink == null )
{
if ( failOnReverseNotFound ) throw new RuntimeException( "reverse link not found!" );
}
else
{
link.descriptionBitmap = rlink.descriptionBitmap;
link.firsttransferBytes = rlink.firsttransferBytes;
link.counterLinkWritten = false;
}
}
}
n.wasProcessed = true;
}
private OsmTrack searchTrack( MatchedWaypoint startWp, MatchedWaypoint endWp, OsmTrack nearbyTrack, OsmTrack refTrack )
{
OsmTrack track = null;
double[] airDistanceCostFactors = new double[]{ routingContext.pass1coefficient, routingContext.pass2coefficient };
boolean isDirty = false;
if ( nearbyTrack != null )
{
airDistanceCostFactor = 0.;
try
{
track = findTrack( "re-routing", startWp, endWp, nearbyTrack , refTrack, true );
}
catch( IllegalArgumentException iae )
{
// fast partial recalcs: if that timed out, but we had a match,
// build the concatenation from the partial and the nearby track
if ( matchPath != null )
{
track = mergeTrack( matchPath, nearbyTrack );
isDirty = true;
}
maxRunningTime += System.currentTimeMillis() - startTime; // reset timeout...
}
}
if ( track == null )
{
for( int cfi = 0; cfi < airDistanceCostFactors.length && !terminated; cfi++ )
{
airDistanceCostFactor = airDistanceCostFactors[cfi];
if ( airDistanceCostFactor < 0. )
{
continue;
}
OsmTrack t = findTrack( cfi == 0 ? "pass0" : "pass1", startWp, endWp, track , refTrack, false );
if ( t == null && track != null && matchPath != null )
{
// ups, didn't find it, use a merge
t = mergeTrack( matchPath, track );
}
if ( t != null )
{
track = t;
}
else
{
throw new IllegalArgumentException( "no track found at pass=" + cfi );
}
}
}
if ( track == null ) throw new IllegalArgumentException( "no track found" );
if ( refTrack == null && !isDirty )
{
track.endPoint = endWp;
foundRawTrack = track;
}
// final run for verbose log info and detail nodes
airDistanceCostFactor = 0.;
guideTrack = track;
try
{
OsmTrack tt = findTrack( "re-tracking", startWp, endWp, null , refTrack, false );
if ( tt == null ) throw new IllegalArgumentException( "error re-tracking track" );
return tt;
}
finally
{
guideTrack = null;
}
}
private void resetCache()
{
nodesMap = new OsmNodesMap();
nodesCache = new NodesCache(segmentDir, nodesMap, routingContext.expctxWay.lookupVersion, routingContext.carMode, nodesCache );
}
private OsmNode getStartNode( long startId )
{
// initialize the start-node
OsmNode start = nodesMap.get( startId );
if ( start == null )
{
start = new OsmNode( startId );
start.setHollow();
nodesMap.put( startId, start );
}
if ( !nodesCache.obtainNonHollowNode( start ) )
{
return null;
}
expandHollowLinkTargets( start, true );
return start;
}
private OsmPath getStartPath( OsmNode n1, OsmNode n2, MatchedWaypoint mwp, MatchedWaypoint endWp, boolean sameSegmentSearch )
{
OsmPath p = getStartPath( n1, n2, mwp.waypoint, endWp.crosspoint );
// special case: start+end on same segment
if ( sameSegmentSearch )
{
OsmPath pe = getEndPath( n1, p.getLink(), endWp.crosspoint, endWp.crosspoint );
OsmPath pt = getEndPath( n1, p.getLink(), null, endWp.crosspoint );
int costdelta = pt.cost - p.cost;
if ( pe.cost >= costdelta )
{
pe.cost -= costdelta;
pe.adjustedCost -= costdelta;
if ( guideTrack != null )
{
// nasty stuff: combine the path cause "new OsmPath()" cannot handle start+endpoint
OsmPathElement startElement = p.originElement;
while( startElement.origin != null )
{
startElement = startElement.origin;
}
if ( pe.originElement.cost > costdelta )
{
OsmPathElement e = pe.originElement;
while( e.origin != null && e.origin.cost > costdelta )
{
e = e.origin;
e.cost -= costdelta;
}
e.origin = startElement;
}
else
{
pe.originElement = startElement;
}
}
return pe;
}
}
return p;
}
private OsmPath getStartPath( OsmNode n1, OsmNode n2, OsmNodeNamed wp, OsmNode endPos )
{
try
{
routingContext.setWaypoint( wp, false );
OsmPath bestPath = null;
OsmLink bestLink = null;
OsmLink startLink = new OsmLink();
startLink.targetNode = n1;
OsmPath startPath = new OsmPath( startLink );
startLink.addLinkHolder( startPath );
double minradius = 1e10;
for( OsmLink link = n1.firstlink; link != null; link = link.next )
{
OsmNode nextNode = link.targetNode;
if ( nextNode.isHollow() ) continue; // border node?
if ( nextNode.firstlink == null ) continue; // don't care about dead ends
if ( nextNode == n1 ) continue; // ?
if ( nextNode != n2 ) continue; // just that link
wp.radius = 1e9;
OsmPath testPath = new OsmPath( null, startPath, link, null, guideTrack != null, routingContext );
testPath.setAirDistanceCostAdjustment( (int)( nextNode.calcDistance( endPos ) * airDistanceCostFactor ) );
if ( wp.radius < minradius )
{
bestPath = testPath;
minradius = wp.radius;
bestLink = link;
}
}
if ( bestLink != null )
{
bestLink.addLinkHolder( bestPath );
}
bestPath.treedepth = 1;
return bestPath;
}
finally
{
routingContext.unsetWaypoint();
}
}
private OsmPath getEndPath( OsmNode n1, OsmLink link, OsmNodeNamed wp, OsmNode endPos )
{
try
{
if ( wp != null ) routingContext.setWaypoint( wp, true );
OsmLink startLink = new OsmLink();
startLink.targetNode = n1;
OsmPath startPath = new OsmPath( startLink );
startLink.addLinkHolder( startPath );
if ( wp != null ) wp.radius = 1e-5;
OsmPath testPath = new OsmPath( n1, startPath, link, null, guideTrack != null, routingContext );
testPath.setAirDistanceCostAdjustment( 0 );
return testPath;
}
finally
{
if ( wp != null ) routingContext.unsetWaypoint();
}
}
private OsmTrack findTrack( String operationName, MatchedWaypoint startWp, MatchedWaypoint endWp, OsmTrack costCuttingTrack, OsmTrack refTrack, boolean reducedTimeoutWhenUnmatched )
{
boolean verbose = guideTrack != null;
int maxTotalCost = 1000000000;
logInfo( "findtrack with maxTotalCost=" + maxTotalCost + " airDistanceCostFactor=" + airDistanceCostFactor );
matchPath = null;
int nodesVisited = 0;
resetCache();
long endNodeId1 = endWp.node1.getIdFromPos();
long endNodeId2 = endWp.node2.getIdFromPos();
long startNodeId1 = startWp.node1.getIdFromPos();
long startNodeId2 = startWp.node2.getIdFromPos();
OsmNode endPos = endWp.crosspoint;
boolean sameSegmentSearch = ( startNodeId1 == endNodeId1 && startNodeId2 == endNodeId2 )
|| ( startNodeId1 == endNodeId2 && startNodeId2 == endNodeId1 );
OsmNode start1 = getStartNode( startNodeId1 );
OsmNode start2 = getStartNode( startNodeId2 );
if ( start1 == null || start2 == null ) return null;
OsmPath startPath1 = getStartPath( start1, start2, startWp, endWp, sameSegmentSearch );
OsmPath startPath2 = getStartPath( start2, start1, startWp, endWp, sameSegmentSearch );
int maxAdjCostFromQueue = 0;
synchronized( openSet )
{
openSet.clear();
if ( startPath1.cost >= 0 ) openSet.add( startPath1 );
if ( startPath2.cost >= 0 ) openSet.add( startPath2 );
}
while(!terminated)
{
if ( maxRunningTime > 0 )
{
long timeout = ( matchPath == null && reducedTimeoutWhenUnmatched ) ? maxRunningTime/3 : maxRunningTime;
if ( System.currentTimeMillis() - startTime > timeout )
{
throw new IllegalArgumentException( operationName + " timeout after " + (timeout/1000) + " seconds" );
}
}
OsmPath path = null;
synchronized( openSet )
{
if ( openSet.size() == 0 ) break;
path = openSet.first();
openSet.remove( path );
}
if ( path.adjustedCost < maxAdjCostFromQueue && airDistanceCostFactor == 0.)
{
throw new RuntimeException( "assertion failed: path.adjustedCost < maxAdjCostFromQueue: " + path.adjustedCost + "<" + maxAdjCostFromQueue );
}
maxAdjCostFromQueue = path.adjustedCost;
nodesVisited++;
linksProcessed++;
OsmLink currentLink = path.getLink();
OsmNode currentNode = currentLink.targetNode;
OsmNode sourceNode = path.getSourceNode();
long currentNodeId = currentNode.getIdFromPos();
if ( sourceNode != null )
{
long sourceNodeId = sourceNode.getIdFromPos();
if ( ( sourceNodeId == endNodeId1 && currentNodeId == endNodeId2 )
|| ( sourceNodeId == endNodeId2 && currentNodeId == endNodeId1 ) )
{
// track found, compile
logInfo( "found track at cost " + path.cost + " nodesVisited = " + nodesVisited );
return compileTrack( path, verbose );
}
}
// recheck cutoff before doing expensive stuff
int airDistance2 = currentNode.calcDistance( endPos );
if ( path.cost + airDistance2 > maxTotalCost + 10 )
{
continue;
}
if ( !currentNode.wasProcessed )
{
expandHollowLinkTargets( currentNode, true );
nodesMap.removeCompletedNodes();
}
if ( sourceNode != null )
{
sourceNode.unlinkLink ( currentLink );
}
OsmLink counterLink = null;
for( OsmLink link = currentNode.firstlink; link != null; link = link.next )
{
OsmNode nextNode = link.targetNode;
if ( nextNode.isHollow() )
{
continue; // border node?
}
if ( nextNode.firstlink == null )
{
continue; // don't care about dead ends
}
if ( nextNode == sourceNode )
{
counterLink = link;
continue; // border node?
}
if ( guideTrack != null )
{
int gidx = path.treedepth + 1;
if ( gidx >= guideTrack.nodes.size() )
{
continue;
}
OsmPathElement guideNode = guideTrack.nodes.get( gidx );
if ( nextNode.getILat() != guideNode.getILat() || nextNode.getILon() != guideNode.getILon() )
{
continue;
}
}
OsmPath bestPath = null;
boolean isFinalLink = false;
long targetNodeId = link.targetNode.getIdFromPos();
if ( currentNodeId == endNodeId1 || currentNodeId == endNodeId2 )
{
if ( targetNodeId == endNodeId1 || targetNodeId == endNodeId2 )
{
isFinalLink = true;
}
}
for( OsmLinkHolder linkHolder = currentLink.firstlinkholder; linkHolder != null; linkHolder = linkHolder.getNextForLink() )
{
OsmPath otherPath = (OsmPath)linkHolder;
try
{
if ( isFinalLink )
{
endWp.crosspoint.radius = 1e-5;
routingContext.setWaypoint( endWp.crosspoint, true );
}
OsmPath testPath = new OsmPath( currentNode, otherPath, link, refTrack, guideTrack != null, routingContext );
if ( testPath.cost >= 0 && ( bestPath == null || testPath.cost < bestPath.cost ) )
{
bestPath = testPath;
}
}
finally
{
routingContext.unsetWaypoint();
}
if ( otherPath != path )
{
synchronized( openSet )
{
openSet.remove( otherPath );
}
}
}
if ( bestPath != null )
{
int airDistance = isFinalLink ? 0 : nextNode.calcDistance( endPos );
bestPath.setAirDistanceCostAdjustment( (int)( airDistance * airDistanceCostFactor ) );
// check for a match with the cost-cutting-track
if ( costCuttingTrack != null )
{
OsmPathElement pe = costCuttingTrack.getLink( currentNodeId, targetNodeId );
if ( pe != null )
{
int costEstimate = bestPath.cost
+ bestPath.elevationCorrection( routingContext )
+ ( costCuttingTrack.cost - pe.cost );
if ( costEstimate <= maxTotalCost )
{
matchPath = new OsmPathElement( bestPath );
}
if ( costEstimate < maxTotalCost )
{
logInfo( "maxcost " + maxTotalCost + " -> " + costEstimate + " airDistance=" + airDistance );
maxTotalCost = costEstimate;
}
}
}
if ( isFinalLink || bestPath.cost + airDistance <= maxTotalCost + 10 )
{
// add only if this may beat an existing path for that link
OsmLinkHolder dominator = link.firstlinkholder;
while( dominator != null )
{
if ( bestPath.definitlyWorseThan( (OsmPath)dominator, routingContext ) )
{
break;
}
dominator = dominator.getNextForLink();
}
if ( dominator == null )
{
bestPath.treedepth = path.treedepth + 1;
link.addLinkHolder( bestPath );
synchronized( openSet )
{
openSet.add( bestPath );
}
}
}
}
}
// if the counterlink does not yet have a path, remove it
if ( counterLink != null && counterLink.firstlinkholder == null )
{
currentNode.unlinkLink(counterLink);
}
}
return null;
}
private void preloadPosition( OsmNode n, int minRingWidth, int minCount )
{
int c = 0;
int ring = 0;
while( ring <= minRingWidth || ( c < minCount && ring <= 5 ) )
{
c += preloadRing( n, ring++ );
}
}
private int preloadRing( OsmNode n, int ring )
{
int d = 12500;
int c = 0;
for( int idxLat=-ring; idxLat<=ring; idxLat++ )
for( int idxLon=-ring; idxLon<=ring; idxLon++ )
{
int absLat = idxLat < 0 ? -idxLat : idxLat;
int absLon = idxLon < 0 ? -idxLon : idxLon;
int max = absLat > absLon ? absLat : absLon;
if ( max < ring ) continue;
c += nodesCache.loadSegmentFor( n.ilon + d*idxLon , n.ilat +d*idxLat );
}
return c;
}
private OsmTrack compileTrack( OsmPath path, boolean verbose )
{
OsmPathElement element = new OsmPathElement( path );
// for final track, cut endnode
if ( guideTrack != null ) element = element.origin;
OsmTrack track = new OsmTrack();
track.cost = path.cost;
int distance = 0;
double ascend = 0;
double ehb = 0.;
short ele_start = Short.MIN_VALUE;
short ele_end = Short.MIN_VALUE;
while ( element != null )
{
track.addNode( element );
OsmPathElement nextElement = element.origin;
short ele = element.getSElev();
if ( ele != Short.MIN_VALUE ) ele_start = ele;
if ( ele_end == Short.MIN_VALUE ) ele_end = ele;
if ( nextElement != null )
{
distance += element.calcDistance( nextElement );
short ele_next = nextElement.getSElev();
if ( ele_next != Short.MIN_VALUE )
{
ehb = ehb + (ele - ele_next)/4.;
}
if ( ehb > 10. )
{
ascend += ehb-10.;
ehb = 10.;
}
else if ( ehb < 0. )
{
ehb = 0.;
}
}
element = nextElement ;
}
ascend += ehb;
track.distance = distance;
track.ascend = (int)ascend;
track.plainAscend = ( ele_end - ele_start ) / 4;
logInfo( "track-length = " + track.distance );
logInfo( "filtered ascend = " + track.ascend );
track.buildMap();
return track;
}
private OsmTrack mergeTrack( OsmPathElement match, OsmTrack oldTrack )
{
OsmPathElement element = match;
OsmTrack track = new OsmTrack();
while ( element != null )
{
track.addNode( element );
element = element.origin ;
}
long lastId = 0;
long id1 = match.getIdFromPos();
long id0 = match.origin == null ? 0 : match.origin.getIdFromPos();
boolean appending = false;
for( OsmPathElement n : oldTrack.nodes )
{
if ( appending )
{
track.nodes.add( n );
}
long id = n.getIdFromPos();
if ( id == id1 && lastId == id0 )
{
appending = true;
}
lastId = id;
}
track.buildMap();
return track;
}
public int[] getOpenSet()
{
synchronized( openSet )
{
return openSet.getExtract();
}
}
public boolean isFinished()
{
return finished;
}
public int getLinksProcessed()
{
return linksProcessed;
}
public int getDistance()
{
return foundTrack.distance;
}
public int getAscend()
{
return foundTrack.ascend;
}
public int getPlainAscend()
{
return foundTrack.plainAscend;
}
public OsmTrack getFoundTrack()
{
return foundTrack;
}
public int getAlternativeIndex()
{
return alternativeIndex;
}
public OsmTrack getFoundRawTrack()
{
return foundRawTrack;
}
public String getErrorMessage()
{
return errorMessage;
}
public void terminate()
{
terminated = true;
}
}

View file

@ -0,0 +1,28 @@
/**
* Container for routig configs
*
* @author ab
*/
package btools.router;
import btools.expressions.BExpressionReceiver;
final class RoutingMessageHandler implements BExpressionReceiver
{
private int ilon;
private int ilat;
public void setCurrentPos( int lon, int lat)
{
ilon = lon;
ilat = lat;
}
@Override
public void expressionWarning( String context, String message )
{
System.out.println( "message (lon=" + (ilon-180000000) + " lat=" + (ilat-90000000)
+ " context " + context + "): " + message );
}
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>0.98</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-expressions</artifactId>
<packaging>jar</packaging>
</project>

View file

@ -0,0 +1,173 @@
package btools.expressions;
final class BExpression
{
private static final int OR_EXP = 10;
private static final int AND_EXP = 11;
private static final int NOT_EXP = 12;
private static final int ADD_EXP = 20;
private static final int MULTIPLY_EXP = 21;
private static final int MAX_EXP = 22;
private static final int SWITCH_EXP = 30;
private static final int ASSIGN_EXP = 31;
private static final int LOOKUP_EXP = 32;
private static final int NUMBER_EXP = 33;
private static final int VARIABLE_EXP = 34;
private static final int DUMPPOS_EXP = 40;
private int typ;
private BExpression op1;
private BExpression op2;
private BExpression op3;
private float numberValue;
private int variableIdx;
private int lookupNameIdx;
private int lookupValueIdx;
// Parse the expression and all subexpression
public static BExpression parse( BExpressionContext ctx, int level ) throws Exception
{
String operator = ctx.parseToken();
if ( operator == null )
{
if ( level == 0 ) return null;
else throw new IllegalArgumentException( "unexpected end of file" );
}
if ( level == 0 )
{
if ( !"assign".equals( operator ) )
{
throw new IllegalArgumentException( "operator " + operator + " is invalid on toplevel (only 'assign' allowed)" );
}
}
BExpression exp = new BExpression();
int nops = 3;
if ( "switch".equals( operator ) )
{
exp.typ = SWITCH_EXP;
}
else
{
nops = 2; // check binary expressions
if ( "or".equals( operator ) )
{
exp.typ = OR_EXP;
}
else if ( "and".equals( operator ) )
{
exp.typ = AND_EXP;
}
else if ( "multiply".equals( operator ) )
{
exp.typ = MULTIPLY_EXP;
}
else if ( "add".equals( operator ) )
{
exp.typ = ADD_EXP;
}
else if ( "max".equals( operator ) )
{
exp.typ = MAX_EXP;
}
else
{
nops = 1; // check unary expressions
if ( "assign".equals( operator ) )
{
if ( level > 0 ) throw new IllegalArgumentException( "assign operator within expression" );
exp.typ = ASSIGN_EXP;
String variable = ctx.parseToken();
if ( variable == null ) throw new IllegalArgumentException( "unexpected end of file" );
exp.variableIdx = ctx.getVariableIdx( variable, true );
if ( exp.variableIdx < ctx.getMinWriteIdx() ) throw new IllegalArgumentException( "cannot assign to readonly variable " + variable );
}
else if ( "not".equals( operator ) )
{
exp.typ = NOT_EXP;
}
else if ( "dumppos".equals( operator ) )
{
exp.typ = DUMPPOS_EXP;
}
else
{
nops = 0; // check elemantary expressions
int idx = operator.indexOf( '=' );
if ( idx >= 0 )
{
exp.typ = LOOKUP_EXP;
String name = operator.substring( 0, idx );
String value = operator.substring( idx+1 );
exp.lookupNameIdx = ctx.getLookupNameIdx( name );
if ( exp.lookupNameIdx < 0 )
{
throw new IllegalArgumentException( "unknown lookup name: " + name );
}
exp.lookupValueIdx = ctx.getLookupValueIdx( exp.lookupNameIdx, value );
if ( exp.lookupValueIdx < 0 )
{
throw new IllegalArgumentException( "unknown lookup value: " + value );
}
}
else if ( (idx = ctx.getVariableIdx( operator, false )) >= 0 )
{
exp.typ = VARIABLE_EXP;
exp.variableIdx = idx;
}
else
{
try
{
exp.numberValue = Float.parseFloat( operator );
exp.typ = NUMBER_EXP;
}
catch( NumberFormatException nfe )
{
throw new IllegalArgumentException( "unknown expression: " + operator );
}
}
}
}
}
// parse operands
if ( nops > 0 ) exp.op1 = BExpression.parse( ctx, level+1 );
if ( nops > 1 ) exp.op2 = BExpression.parse( ctx, level+1 );
if ( nops > 2 ) exp.op3 = BExpression.parse( ctx, level+1 );
return exp;
}
// Evaluate the expression
public float evaluate( BExpressionContext ctx )
{
switch( typ )
{
case OR_EXP: return op1.evaluate(ctx) != 0.f ? 1.f : ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f );
case AND_EXP: return op1.evaluate(ctx) != 0.f ? ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f ) : 0.f;
case ADD_EXP: return op1.evaluate(ctx) + op2.evaluate(ctx);
case MULTIPLY_EXP: return op1.evaluate(ctx) * op2.evaluate(ctx);
case MAX_EXP: return max( op1.evaluate(ctx), op2.evaluate(ctx) );
case SWITCH_EXP: return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx);
case ASSIGN_EXP: return ctx.assign( variableIdx, op1.evaluate(ctx) );
case LOOKUP_EXP: return ctx.getLookupMatch( lookupNameIdx, lookupValueIdx );
case NUMBER_EXP: return numberValue;
case VARIABLE_EXP: return ctx.getVariableValue( variableIdx );
case NOT_EXP: return op1.evaluate(ctx) == 0.f ? 1.f : 0.f;
case DUMPPOS_EXP: ctx.expressionWarning( "INFO" ); return op1.evaluate(ctx);
default: throw new IllegalArgumentException( "unknown op-code: " + typ );
}
}
private float max( float v1, float v2 )
{
return v1 > v2 ? v1 : v2;
}
}

View file

@ -0,0 +1,620 @@
// context for simple expression
// context means:
// - the local variables
// - the local variable names
// - the lookup-input variables
package btools.expressions;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
public final class BExpressionContext
{
private static final String CONTEXT_TAG = "---context:";
private static final String VERSION_TAG = "---lookupversion:";
private String context;
private boolean _inOurContext = false;
private BufferedReader _br = null;
private boolean _readerDone = false;
private BExpressionReceiver _receiver;
private Map<String,Integer> lookupNumbers = new HashMap<String,Integer>();
private ArrayList<BExpressionLookupValue[]> lookupValues = new ArrayList<BExpressionLookupValue[]>();
private ArrayList<String> lookupNames = new ArrayList<String>();
private ArrayList<int[]> lookupHistograms = new ArrayList<int[]>();
private boolean lookupDataFrozen = false;
private int[] lookupData = new int[0];
private Map<String,Integer> variableNumbers = new HashMap<String,Integer>();
private float[] variableData;
// hash-cache for function results
private long[] _arrayBitmap;
private int currentHashBucket = -1;
private long currentBitmap = 0;
public List<BExpression> expressionList;
private int minWriteIdx;
// build-in variable indexes for fast access
private int costfactorIdx;
private int turncostIdx;
private int initialcostIdx;
private float[] _arrayCostfactor;
private float[] _arrayTurncost;
private float[] _arrayInitialcost;
public float getCostfactor() { return _arrayCostfactor[currentHashBucket]; }
public float getTurncost() { return _arrayTurncost[currentHashBucket]; }
public float getInitialcost() { return _arrayInitialcost[currentHashBucket]; }
private int linenr;
public short lookupVersion = -1;
public BExpressionContext( String context )
{
this( context, 4096 );
}
/**
* Create an Expression-Context for the given node
*
* @param context global, way or node - context of that instance
* @param hashSize size of hashmap for result caching
*/
public BExpressionContext( String context, int hashSize )
{
this.context = context;
_arrayBitmap = new long[hashSize];
_arrayCostfactor = new float[hashSize];
_arrayTurncost = new float[hashSize];
_arrayInitialcost = new float[hashSize];
}
/**
* encode lookup data to a 64-bit word
*/
public long encode( int[] ld )
{
long w = 0;
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{
int n = lookupValues.get(inum).length - 1;
int d = ld[inum];
if ( n == 2 ) { n = 1; d = d == 2 ? 1 : 0; } // 1-bit encoding for booleans
while( n != 0 ) { n >>= 1; w <<= 1; }
w |= (long)d;
}
return w;
}
/**
* decode a 64-bit word into a lookup data array
*/
public void decode( int[] ld, long w )
{
for( int inum = lookupValues.size()-1; inum >= 0; inum-- ) // loop over lookup names
{
int nv = lookupValues.get(inum).length;
int n = nv == 3 ? 1 : nv-1; // 1-bit encoding for booleans
int m = 0;
long ww = w;
while( n != 0 ) { n >>= 1; ww >>= 1; m = m<<1 | 1; }
int d = (int)(w & m);
if ( nv == 3 && d == 1 ) d = 2; // 1-bit encoding for booleans
ld[inum] = d;
w = ww;
}
}
/**
* much like decode, but just for counting bits
*/
private void countBits()
{
int bits = 0;
for( int inum = lookupValues.size()-1; inum >= 0; inum-- ) // loop over lookup names
{
int nv = lookupValues.get(inum).length;
int n = nv == 3 ? 1 : nv-1; // 1-bit encoding for booleans
while( n != 0 ) { n >>= 1; bits++; }
}
// System.out.println( "context=" + context + ",bits=" + bits + " keys=" + lookupValues.size() );
if ( bits > 64 ) throw new IllegalArgumentException( "lookup table for context " + context + " exceeds 64 bits!" );
}
public String getCsvDescription( long bitmap )
{
StringBuilder sb = new StringBuilder( 200 );
decode( lookupData, bitmap );
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{
BExpressionLookupValue[] va = lookupValues.get(inum);
sb.append( '\t' ).append( va[lookupData[inum]].toString() );
}
return sb.toString();
}
public String getCsvHeader()
{
StringBuilder sb = new StringBuilder( 200 );
for( String name: lookupNames )
{
sb.append( '\t' ).append( name );
}
return sb.toString();
}
public void readMetaData( File lookupsFile )
{
try
{
BufferedReader br = new BufferedReader( new FileReader( lookupsFile ) );
int parsedLines = 0;
boolean ourContext = false;
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
line = line.trim();
if ( line.length() == 0 || line.startsWith( "#" ) ) continue;
if ( line.startsWith( CONTEXT_TAG ) )
{
ourContext = line.substring( CONTEXT_TAG.length() ).equals( context );
continue;
}
if ( line.startsWith( VERSION_TAG ) )
{
lookupVersion = Short.parseShort( line.substring( VERSION_TAG.length() ) );
continue;
}
if ( !ourContext ) continue;
parsedLines++;
StringTokenizer tk = new StringTokenizer( line, " " );
String name = tk.nextToken();
String value = tk.nextToken();
int idx = name.indexOf( ';' );
if ( idx >= 0 ) name = name.substring( 0, idx );
BExpressionLookupValue newValue = addLookupValue( name, value, null );
// add aliases
while( newValue != null && tk.hasMoreTokens() ) newValue.addAlias( tk.nextToken() );
}
br.close();
if ( parsedLines == 0 && !"global".equals(context) )
{
throw new IllegalArgumentException( lookupsFile.getAbsolutePath()
+ " does not contain data for context " + context + " (old version?)" );
}
// post-process metadata:
lookupDataFrozen = true;
countBits();
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
private void evaluate( int[] lookupData2 )
{
lookupData = lookupData2;
for( BExpression exp: expressionList)
{
exp.evaluate( this );
}
}
private static int[] crctable = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
public void evaluate( long bitmap, BExpressionReceiver receiver )
{
_receiver = receiver;
if ( currentBitmap != bitmap || currentHashBucket < 0 )
{
// calc hash bucket from crc
int crc = 0xFFFFFFFF;
long bm = bitmap;
for( int j=0; j<8; j++ )
{
crc = (crc >>> 8) ^ crctable[(crc ^ (int)bm) & 0xff];
bm >>= 8;
}
int hashSize = _arrayBitmap.length;
currentHashBucket = (crc & 0xfffffff) % hashSize;
currentBitmap = bitmap;
}
if ( _arrayBitmap[currentHashBucket] == bitmap )
{
return;
}
_arrayBitmap[currentHashBucket] = bitmap;
decode( lookupData, bitmap );
evaluate( lookupData );
_arrayCostfactor[currentHashBucket] = variableData[costfactorIdx];
_arrayTurncost[currentHashBucket] = variableData[turncostIdx];
_arrayInitialcost[currentHashBucket] = variableData[initialcostIdx];
_receiver = null;
}
public void dumpStatistics()
{
TreeMap<String,String> counts = new TreeMap<String,String>();
// first count
for( String name: lookupNumbers.keySet() )
{
int cnt = 0;
int inum = lookupNumbers.get(name).intValue();
int[] histo = lookupHistograms.get(inum);
// if ( histo.length == 500 ) continue;
for( int i=2; i<histo.length; i++ )
{
cnt += histo[i];
}
counts.put( "" + ( 1000000000 + cnt) + "_" + name, name );
}
while( counts.size() > 0 )
{
String key = counts.lastEntry().getKey();
String name = counts.get(key);
counts.remove( key );
int inum = lookupNumbers.get(name).intValue();
BExpressionLookupValue[] values = lookupValues.get(inum);
int[] histo = lookupHistograms.get(inum);
if ( values.length == 1000 ) continue;
String[] svalues = new String[values.length];
for( int i=0; i<values.length; i++ )
{
String scnt = "0000000000" + histo[i];
scnt = scnt.substring( scnt.length() - 10 );
svalues[i] = scnt + " " + values[i].toString();
}
Arrays.sort( svalues );
for( int i=svalues.length-1; i>=0; i-- )
{
System.out.println( name + ";" + svalues[i] );
}
}
}
/**
* @return a new lookupData array, or null if no metadata defined
*/
public int[] createNewLookupData()
{
if ( lookupDataFrozen )
{
return new int[lookupValues.size()];
}
return null;
}
/**
* add a new lookup-value for the given name to the given lookupData array.
* If no array is given (null value passed), the value is added to
* the context-binded array. In that case, unknown names and values are
* created dynamically.
*
* @return a newly created value element, if any, to optionally add aliases
*/
public BExpressionLookupValue addLookupValue( String name, String value, int[] lookupData2 )
{
BExpressionLookupValue newValue = null;
Integer num = lookupNumbers.get( name );
if ( num == null )
{
if ( lookupData2 != null )
{
// do not create unknown name for external data array
return newValue;
}
// unknown name, create
num = new Integer( lookupValues.size() );
lookupNumbers.put( name, num );
lookupNames.add( name );
lookupValues.add( new BExpressionLookupValue[]{ new BExpressionLookupValue( "" )
, new BExpressionLookupValue( "unknown" ) } );
lookupHistograms.add( new int[2] );
int[] ndata = new int[lookupData.length+1];
System.arraycopy( lookupData, 0, ndata, 0, lookupData.length );
lookupData = ndata;
}
// look for that value
int inum = num.intValue();
BExpressionLookupValue[] values = lookupValues.get( inum );
int[] histo = lookupHistograms.get( inum );
int i=0;
for( ; i<values.length; i++ )
{
BExpressionLookupValue v = values[i];
if ( v.matches( value ) ) break;
}
if ( i == values.length )
{
if ( lookupData2 != null )
{
// do not create unknown value for external data array,
// record as 'other' instead
lookupData2[inum] = 1;
return newValue;
}
if ( i == 499 )
{
// System.out.println( "value limit reached for: " + name );
}
if ( i == 500 )
{
return newValue;
}
// unknown value, create
BExpressionLookupValue[] nvalues = new BExpressionLookupValue[values.length+1];
int[] nhisto = new int[values.length+1];
System.arraycopy( values, 0, nvalues, 0, values.length );
System.arraycopy( histo, 0, nhisto, 0, histo.length );
values = nvalues;
histo = nhisto;
newValue = new BExpressionLookupValue( value );
values[i] = newValue;
lookupHistograms.set(inum, histo);
lookupValues.set(inum, values);
}
histo[i]++;
// finally remember the actual data
if ( lookupData2 != null ) lookupData2[inum] = i;
else lookupData[inum] = i;
return newValue;
}
public void parseFile( File file, String readOnlyContext )
{
try
{
if ( readOnlyContext != null )
{
linenr = 1;
String realContext = context;
context = readOnlyContext;
expressionList = _parseFile( file );
variableData = new float[variableNumbers.size()];
evaluate( 1L, null );
context = realContext;
}
linenr = 1;
minWriteIdx = variableData == null ? 0 : variableData.length;
costfactorIdx = getVariableIdx( "costfactor", true );
turncostIdx = getVariableIdx( "turncost", true );
initialcostIdx = getVariableIdx( "initialcost", true );
expressionList = _parseFile( file );
float[] readOnlyData = variableData;
variableData = new float[variableNumbers.size()];
for( int i=0; i<minWriteIdx; i++ )
{
variableData[i] = readOnlyData[i];
}
}
catch( Exception e )
{
if ( e instanceof IllegalArgumentException )
{
throw new IllegalArgumentException( "ParseException at line " + linenr + ": " + e.getMessage() );
}
throw new RuntimeException( e );
}
if ( expressionList.size() == 0 )
{
throw new IllegalArgumentException( file.getAbsolutePath()
+ " does not contain expressions for context " + context + " (old version?)" );
}
}
private List<BExpression> _parseFile( File file ) throws Exception
{
_br = new BufferedReader( new FileReader( file ) );
_readerDone = false;
List<BExpression> result = new ArrayList<BExpression>();
for(;;)
{
BExpression exp = BExpression.parse( this, 0 );
if ( exp == null ) break;
result.add( exp );
}
_br.close();
_br = null;
return result;
}
public float getVariableValue( String name, float defaultValue )
{
Integer num = variableNumbers.get( name );
return num == null ? defaultValue : getVariableValue( num.intValue() );
}
public float getVariableValue( String name )
{
Integer num = variableNumbers.get( name );
return num == null ? 0.f : getVariableValue( num.intValue() );
}
public float getVariableValue( int variableIdx )
{
return variableData[variableIdx];
}
public int getVariableIdx( String name, boolean create )
{
Integer num = variableNumbers.get( name );
if ( num == null )
{
if ( create )
{
num = new Integer( variableNumbers.size() );
variableNumbers.put( name, num );
}
else
{
return -1;
}
}
return num.intValue();
}
public int getMinWriteIdx()
{
return minWriteIdx;
}
public float getLookupMatch( int nameIdx, int valueIdx )
{
return lookupData[nameIdx] == valueIdx ? 1.0f : 0.0f;
}
public int getLookupNameIdx( String name )
{
Integer num = lookupNumbers.get( name );
return num == null ? -1 : num.intValue();
}
public int getLookupValueIdx( int nameIdx, String value )
{
BExpressionLookupValue[] values = lookupValues.get( nameIdx );
for( int i=0; i< values.length; i++ )
{
if ( values[i].equals( value ) ) return i;
}
return -1;
}
public String parseToken() throws Exception
{
for(;;)
{
String token = _parseToken();
if ( token == null ) return null;
if ( token.startsWith( CONTEXT_TAG ) )
{
_inOurContext = token.substring( CONTEXT_TAG.length() ).equals( context );
}
else if ( _inOurContext )
{
return token;
}
}
}
private String _parseToken() throws Exception
{
StringBuilder sb = new StringBuilder(32);
boolean inComment = false;
for(;;)
{
int ic = _readerDone ? -1 : _br.read();
if ( ic < 0 )
{
if ( sb.length() == 0 ) return null;
_readerDone = true;
return sb.toString();
}
char c = (char)ic;
if ( c == '\n' ) linenr++;
if ( inComment )
{
if ( c == '\r' || c == '\n' ) inComment = false;
continue;
}
if ( Character.isWhitespace( c ) )
{
if ( sb.length() > 0 ) return sb.toString();
else continue;
}
if ( c == '#' && sb.length() == 0 ) inComment = true;
else sb.append( c );
}
}
public float assign( int variableIdx, float value )
{
variableData[variableIdx] = value;
return value;
}
public void expressionWarning( String message )
{
_arrayBitmap[currentHashBucket] = 0L; // no caching if warnings
if ( _receiver != null ) _receiver.expressionWarning( context, message );
}
}

View file

@ -0,0 +1,66 @@
/**
* A lookup value with optional aliases
*
* toString just gives the primary value,
* equals just compares against primary value
* matches() also compares aliases
*
* @author ab
*/
package btools.expressions;
import java.util.ArrayList;
final class BExpressionLookupValue
{
String value;
ArrayList<String> aliases;
@Override
public String toString()
{
return value;
}
public BExpressionLookupValue( String value )
{
this.value = value;
}
public void addAlias( String alias )
{
if ( aliases == null ) aliases = new ArrayList<String>();
aliases.add( alias );
}
@Override
public boolean equals( Object o )
{
if ( o instanceof String )
{
String v = (String)o;
return value.equals( v );
}
if ( o instanceof BExpressionLookupValue )
{
BExpressionLookupValue v = (BExpressionLookupValue)o;
return value.equals( v.value );
}
return false;
}
public boolean matches( String s )
{
if ( value.equals( s ) ) return true;
if ( aliases != null )
{
for( String alias : aliases )
{
if ( alias.equals( s ) ) return true;
}
}
return false;
}
}

View file

@ -0,0 +1,7 @@
package btools.expressions;
public interface BExpressionReceiver
{
public void expressionWarning( String context, String message );
}

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>0.98</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-map-creator</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-expressions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-mapaccess</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,166 @@
/**
* common base class for the map-filters
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener
{
private DataOutputStream[] tileOutStreams;
protected File outTileDir;
protected HashMap<String,String> tags;
public void putTag( String key, String value )
{
if ( tags == null ) tags = new HashMap<String,String>();
tags.put( key, value );
}
public String getTag( String key )
{
return tags == null ? null : tags.get( key );
}
public HashMap<String,String> getTagsOrNull()
{
return tags;
}
public void setTags( HashMap<String,String> tags )
{
this.tags = tags;
}
protected static long readId( DataInputStream is) throws IOException
{
int offset = is.readByte();
if ( offset == 32 ) return -1;
long i = is.readInt();
i = i << 5;
return i | offset;
}
protected static void writeId( DataOutputStream o, long id ) throws IOException
{
if ( id == -1 )
{
o.writeByte( 32 );
return;
}
int offset = (int)( id & 0x1f );
int i = (int)( id >> 5 );
o.writeByte( offset );
o.writeInt( i );
}
protected static File[] sortBySizeAsc( File[] files )
{
int n = files.length;
long[] sizes = new long[n];
File[] sorted = new File[n];
for( int i=0; i<n; i++ ) sizes[i] = files[i].length();
for(int nf=0; nf<n; nf++)
{
int idx = -1;
long min = -1;
for( int i=0; i<n; i++ )
{
if ( sizes[i] != -1 && ( idx == -1 || sizes[i] < min ) )
{
min = sizes[i];
idx = i;
}
}
sizes[idx] = -1;
sorted[nf] = files[idx];
}
return sorted;
}
protected File fileFromTemplate( File template, File dir, String suffix )
{
String filename = template.getName();
filename = filename.substring( 0, filename.length() - 3 ) + suffix;
return new File( dir, filename );
}
protected DataInputStream createInStream( File inFile ) throws IOException
{
return new DataInputStream( new BufferedInputStream ( new FileInputStream( inFile ) ) );
}
protected DataOutputStream createOutStream( File outFile ) throws IOException
{
return new DataOutputStream( new BufferedOutputStream( new FileOutputStream( outFile ) ) );
}
protected DataOutputStream getOutStreamForTile( int tileIndex ) throws Exception
{
if ( tileOutStreams == null )
{
tileOutStreams = new DataOutputStream[64];
}
if ( tileOutStreams[tileIndex] == null )
{
tileOutStreams[tileIndex] = createOutStream( new File( outTileDir, getNameForTile( tileIndex ) ) );
}
return tileOutStreams[tileIndex];
}
protected String getNameForTile( int tileIndex )
{
throw new IllegalArgumentException( "getNameForTile not implemented" );
}
protected void closeTileOutStreams() throws Exception
{
if ( tileOutStreams == null )
{
return;
}
for( int tileIndex=0; tileIndex<tileOutStreams.length; tileIndex++ )
{
if ( tileOutStreams[tileIndex] != null ) tileOutStreams[tileIndex].close();
tileOutStreams[tileIndex] = null;
}
}
// interface dummys
@Override
public void nodeFileStart( File nodefile ) throws Exception {}
@Override
public void nextNode( NodeData n ) throws Exception {}
@Override
public void nodeFileEnd( File nodefile ) throws Exception {}
@Override
public void wayFileStart( File wayfile ) throws Exception {}
@Override
public void nextWay( WayData data ) throws Exception {}
@Override
public void wayFileEnd( File wayfile ) throws Exception {}
@Override
public void nextRelation( RelationData data ) throws Exception {}
}

View file

@ -0,0 +1,87 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
/**
* NodeCutter does 1 step in map-processing:
*
* - cuts the 45*30 node tiles into 5*5 pieces
*
* @author ab
*/
public class NodeCutter extends MapCreatorBase
{
private int lonoffset;
private int latoffset;
public static void main(String[] args) throws Exception
{
System.out.println("*** NodeCutter: Cut big node-tiles into 5x5 tiles");
if (args.length != 2)
{
System.out.println("usage: java NodeCutter <node-tiles-in> <node-tiles-out>" );
return;
}
new NodeCutter().process( new File( args[0] ), new File( args[1] ) );
}
public void process( File nodeTilesIn, File nodeTilesOut ) throws Exception
{
this.outTileDir = nodeTilesOut;
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tlf" );
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
lonoffset = -1;
latoffset = -1;
}
@Override
public void nextNode( NodeData n ) throws Exception
{
n.writeTo( getOutStreamForTile( getTileIndex( n.ilon, n.ilat ) ) );
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
closeTileOutStreams();
}
private int getTileIndex( int ilon, int ilat )
{
int lonoff = (ilon / 45000000 ) * 45;
int latoff = (ilat / 30000000 ) * 30;
if ( lonoffset == -1 ) lonoffset = lonoff;
if ( latoffset == -1 ) latoffset = latoff;
if ( lonoff != lonoffset || latoff != latoffset )
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
int lon = (ilon / 5000000) % 9;
int lat = (ilat / 5000000) % 6;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat );
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 5 + lonoffset - 180;
int lat = (tileIndex % 6 ) * 5 + latoffset - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".n5d";
}
}

View file

@ -0,0 +1,55 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Container for node data on the preprocessor level
*
* @author ab
*/
public class NodeData extends MapCreatorBase
{
public long nid;
public int ilon;
public int ilat;
public long description;
public short selev = Short.MIN_VALUE;
public NodeData( long id, double lon, double lat )
{
nid = id;
ilat = (int)( ( lat + 90. )*1000000. + 0.5);
ilon = (int)( ( lon + 180. )*1000000. + 0.5);
}
public NodeData( DataInputStream dis ) throws Exception
{
nid = readId( dis );
ilon = dis.readInt();
ilat = dis.readInt();
int mode = dis.readByte();
if ( ( mode & 1 ) != 0 ) description = dis.readLong();
if ( ( mode & 2 ) != 0 ) selev = dis.readShort();
}
public void writeTo( DataOutputStream dos ) throws Exception
{
writeId( dos, nid );
dos.writeInt( ilon );
dos.writeInt( ilat );
int mode = ( description == 0L ? 0 : 1 ) | ( selev == Short.MIN_VALUE ? 0 : 2 );
dos.writeByte( (byte)mode );
if ( ( mode & 1 ) != 0 ) dos.writeLong( description );
if ( ( mode & 2 ) != 0 ) dos.writeShort( selev );
}
}

View file

@ -0,0 +1,86 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* NodeFilter does 1 step in map-processing:
*
* - filters out unused nodes according to the way file
*
* @author ab
*/
public class NodeFilter extends MapCreatorBase
{
private DataOutputStream nodesOutStream;
private File nodeTilesOut;
protected DenseLongMap nodebitmap;
public static void main(String[] args) throws Exception
{
System.out.println("*** NodeFilter: Filter way related nodes");
if (args.length != 3)
{
System.out.println("usage: java NodeFilter <node-tiles-in> <way-file-in> <node-tiles-out>" );
return;
}
new NodeFilter().process( new File( args[0] ), new File( args[1] ), new File( args[2] ) );
}
public void process( File nodeTilesIn, File wayFileIn, File nodeTilesOut ) throws Exception
{
this.nodeTilesOut = nodeTilesOut;
// read the wayfile into a bitmap of used nodes
nodebitmap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 1 ) : new TinyDenseLongMap();
new WayIterator( this, false ).processFile( wayFileIn );
// finally filter all node files
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tls" );
}
@Override
public void nextWay( WayData data ) throws Exception
{
int nnodes = data.nodes.size();
for (int i=0; i<nnodes; i++ )
{
nodebitmap.put( data.nodes.get(i), 0 );
}
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
String filename = nodefile.getName();
filename = filename.substring( 0, filename.length() - 3 ) + "tlf";
File outfile = new File( nodeTilesOut, filename );
nodesOutStream = new DataOutputStream( new BufferedOutputStream ( new FileOutputStream( outfile ) ) );
}
@Override
public void nextNode( NodeData n ) throws Exception
{
// check if node passes bitmap
if ( nodebitmap.getInt( n.nid ) == 0 ) // 0 -> bit set, -1 -> unset
{
n.writeTo( nodesOutStream );
}
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
nodesOutStream.close();
}
}

View file

@ -0,0 +1,76 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Iterate over a singe nodefile or a directory
* of nodetiles and feed the nodes to the callback listener
*
* @author ab
*/
public class NodeIterator extends MapCreatorBase
{
private NodeListener listener;
private boolean delete;
public NodeIterator( NodeListener nodeListener, boolean deleteAfterReading )
{
listener = nodeListener;
delete = deleteAfterReading;
}
public void processDir( File indir, String inSuffix ) throws Exception
{
if ( !indir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + indir );
}
File[] af = sortBySizeAsc( indir.listFiles() );
for( int i=0; i<af.length; i++ )
{
File nodefile = af[i];
if ( nodefile.getName().endsWith( inSuffix ) )
{
processFile( nodefile );
}
}
}
public void processFile(File nodefile) throws Exception
{
System.out.println( "*** NodeIterator reading: " + nodefile );
listener.nodeFileStart( nodefile );
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( nodefile ) ) );
try
{
for(;;)
{
NodeData n = new NodeData( di );
listener.nextNode( n );
}
}
catch( EOFException eof )
{
di.close();
}
listener.nodeFileEnd( nodefile );
if ( delete && "true".equals( System.getProperty( "deletetmpfiles" ) ))
{
nodefile.delete();
}
}
}

View file

@ -0,0 +1,17 @@
package btools.mapcreator;
import java.io.File;
/**
* Callbacklistener for NodeIterator
*
* @author ab
*/
public interface NodeListener
{
void nodeFileStart( File nodefile ) throws Exception;
void nextNode( NodeData data ) throws Exception;
void nodeFileEnd( File nodefile ) throws Exception;
}

View file

@ -0,0 +1,205 @@
/**
* This program
* - reads an *.osm from stdin
* - writes 45*30 degree node tiles + a way file + a rel file
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
import btools.expressions.BExpressionContext;
public class OsmCutter extends MapCreatorBase
{
private long recordCnt;
private long nodesParsed;
private long waysParsed;
private long relsParsed;
private long changesetsParsed;
private DataOutputStream wayDos;
private DataOutputStream cyclewayDos;
public static void main(String[] args) throws Exception
{
System.out.println("*** OsmCutter: cut an osm map in node-tiles + a way file");
if (args.length != 4 && args.length != 5)
{
System.out.println("usage: bzip2 -dc <map> | java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file>");
System.out.println("or : java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <inputfile>");
return;
}
new OsmCutter().process(
new File( args[0] )
, new File( args[1] )
, new File( args[2] )
, new File( args[3] )
, args.length > 4 ? new File( args[4] ) : null );
}
private BExpressionContext _expctxWay;
private BExpressionContext _expctxNode;
public void process (File lookupFile, File outTileDir, File wayFile, File relFile, File mapFile) throws Exception
{
if ( !lookupFile.exists() )
{
throw new IllegalArgumentException( "lookup-file: " + lookupFile + " does not exist" );
}
_expctxWay = new BExpressionContext("way");
_expctxWay.readMetaData( lookupFile );
_expctxNode = new BExpressionContext("node");
_expctxNode.readMetaData( lookupFile );
this.outTileDir = outTileDir;
if ( !outTileDir.isDirectory() ) throw new RuntimeException( "out tile directory " + outTileDir + " does not exist" );
wayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( wayFile ) ) );
cyclewayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( relFile ) ) );
// read the osm map into memory
long t0 = System.currentTimeMillis();
new OsmParser().readMap( mapFile, this, this, this );
long t1 = System.currentTimeMillis();
System.out.println( "parsing time (ms) =" + (t1-t0) );
// close all files
closeTileOutStreams();
wayDos.close();
cyclewayDos.close();
/* System.out.println( "-------- way-statistics -------- " );
_expctxWay.dumpStatistics();
System.out.println( "-------- node-statistics -------- " );
_expctxNode.dumpStatistics();
*/
System.out.println( statsLine() );
}
private void checkStats()
{
if ( (++recordCnt % 100000) == 0 ) System.out.println( statsLine() );
}
private String statsLine()
{
return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed;
}
@Override
public void nextNode( NodeData n ) throws Exception
{
nodesParsed++;
checkStats();
if ( n.getTagsOrNull() != null )
{
int[] lookupData = _expctxNode.createNewLookupData();
for( String key : n.getTagsOrNull().keySet() )
{
String value = n.getTag( key );
_expctxNode.addLookupValue( key, value, lookupData );
}
n.description = _expctxNode.encode(lookupData);
}
// write node to file
int tileIndex = getTileIndex( n.ilon, n.ilat );
if ( tileIndex >= 0 )
{
DataOutputStream dos = getOutStreamForTile( tileIndex );
n.writeTo( dos );
}
}
@Override
public void nextWay( WayData w ) throws Exception
{
waysParsed++;
checkStats();
// filter out non-highway ways
if ( w.getTag( "highway" ) == null )
{
// ... but eventually fake a ferry tag
if ( "ferry".equals( w.getTag( "route" ) ) )
{
w.putTag( "highway", "ferry" );
}
else
{
return;
}
}
// encode tags
if ( w.getTagsOrNull() != null )
{
int[] lookupData = _expctxWay.createNewLookupData();
for( String key : w.getTagsOrNull().keySet() )
{
String value = w.getTag( key );
_expctxWay.addLookupValue( key, value, lookupData );
}
w.description = _expctxWay.encode(lookupData);
}
w.writeTo( wayDos );
}
@Override
public void nextRelation( RelationData r ) throws Exception
{
relsParsed++;
checkStats();
// filter out non-cycle relations
if ( ! "bicycle".equals( r.getTag( "route" ) ) )
{
return;
}
for ( int i=0; i<r.ways.size();i++ )
{
long wid = r.ways.get(i);
writeId( cyclewayDos, wid );
}
}
private int getTileIndex( int ilon, int ilat )
{
int lon = ilon / 45000000;
int lat = ilat / 30000000;
if ( lon < 0 || lon > 7 || lat < 0 || lat > 5 )
{
System.out.println( "warning: ignoring illegal pos: " + ilon + "," + ilat );
return -1;
}
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 45 - 180;
int lat = (tileIndex % 6 ) * 30 - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".tls";
}
}

View file

@ -0,0 +1,29 @@
/**
* Container for link between two Osm nodes (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
public final class OsmLinkP
{
/**
* The description bitmap is mainly the way description
* used to calculate the costfactor
*/
public long descriptionBitmap;
/**
* The target is either the next link or the target node
*/
public OsmNodeP targetNode;
public OsmLinkP next;
public boolean counterLinkWritten( )
{
return descriptionBitmap == 0L;
}
}

View file

@ -0,0 +1,243 @@
/**
* Container for an osm node (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class OsmNodeP implements Comparable<OsmNodeP>
{
public static final int EXTERNAL_BITMASK = 0x80;
public static final int FIRSTFORWAY_BITMASK = 0x40;
public static final int TRANSFERNODE_BITMASK = 0x20;
public static final int WRITEDESC_BITMASK = 0x10;
public static final int SKIPDETAILS_BITMASK = 0x08;
public static final int NODEDESC_BITMASK = 0x04;
/**
* The latitude
*/
public int ilat;
/**
* The longitude
*/
public int ilon;
/**
* The links to other nodes
*/
public OsmLinkP firstlink = null;
/**
* The elevation
*/
public short selev;
public boolean isBorder = false;
public byte wayAndBits = -1; // use for bridge/tunnel logic
// interface OsmPos
public int getILat()
{
return ilat;
}
public int getILon()
{
return ilon;
}
public short getSElev()
{
// if all bridge or all tunnel, elevation=no-data
return (wayAndBits & 24) == 0 ? selev : Short.MIN_VALUE;
}
public double getElev()
{
return selev / 4.;
}
public void addLink( OsmLinkP link )
{
if ( firstlink != null ) link.next = firstlink;
firstlink = link;
}
public long getNodeDecsription()
{
return 0L;
}
public void writeNodeData( DataOutputStream os ) throws IOException
{
int lonIdx = ilon/62500;
int latIdx = ilat/62500;
// buffer the body to first calc size
ByteArrayOutputStream bos = new ByteArrayOutputStream( );
DataOutputStream os2 = new DataOutputStream( bos );
os2.writeShort( getSElev() );
int nlinks = 0;
// hack: write node-desc as link tag (copy cycleway-bits)
long nodeDescription = getNodeDecsription();
for( OsmLinkP link0 = firstlink; link0 != null; link0 = link0.next )
{
nlinks++;
OsmLinkP link = link0;
OsmNodeP origin = this;
int skipDetailBit = link0.counterLinkWritten() ? SKIPDETAILS_BITMASK : 0;
// first pass just to see if that link is consistent
while( link != null )
{
OsmNodeP target = link.targetNode;
if ( !target.isTransferNode() )
{
break;
}
// next link is the one (of two), does does'nt point back
for( link = target.firstlink; link != null; link = link.next )
{
if ( link.targetNode != origin ) break;
}
origin = target;
}
if ( link == null ) continue; // dead end
if ( skipDetailBit == 0)
{
link = link0;
}
origin = this;
long lastDescription = 0;
while( link != null )
{
OsmNodeP target = link.targetNode;
int tranferbit = target.isTransferNode() ? TRANSFERNODE_BITMASK : 0;
int writedescbit = link.descriptionBitmap != lastDescription ? WRITEDESC_BITMASK : 0;
int nodedescbit = nodeDescription != 0L ? NODEDESC_BITMASK : 0;
if ( skipDetailBit != 0 )
{
writedescbit = 0;
}
int targetLonIdx = target.ilon/62500;
int targetLatIdx = target.ilat/62500;
if ( targetLonIdx == lonIdx && targetLatIdx == latIdx )
{
// reduced position for internal target
os2.writeByte( tranferbit | writedescbit | nodedescbit | skipDetailBit );
os2.writeShort( (short)(target.ilon - lonIdx*62500 - 31250) );
os2.writeShort( (short)(target.ilat - latIdx*62500 - 31250) );
}
else
{
// full position for external target
os2.writeByte( tranferbit | writedescbit | nodedescbit | skipDetailBit | EXTERNAL_BITMASK );
os2.writeInt( target.ilon );
os2.writeInt( target.ilat );
}
if ( writedescbit != 0 )
{
os2.writeLong( link.descriptionBitmap );
}
if ( nodedescbit != 0 )
{
os2.writeLong( nodeDescription );
nodeDescription = 0L;
}
lastDescription = link.descriptionBitmap;
if ( tranferbit == 0)
{
target.markLinkWritten( origin );
break;
}
os2.writeShort( target.getSElev() );
// next link is the one (of two), does does'nt point back
for( link = target.firstlink; link != null; link = link.next )
{
if ( link.targetNode != origin ) break;
}
if ( link == null ) throw new RuntimeException( "follow-up link not found for transfer-node!" );
origin = target;
}
}
// calculate the body size
int bodySize = bos.size();
os.writeShort( (short)(ilon - lonIdx*62500 - 31250) );
os.writeShort( (short)(ilat - latIdx*62500 - 31250) );
os.writeInt( bodySize );
bos.writeTo( os );
}
public String toString2()
{
return (ilon-180000000) + "_" + (ilat-90000000) + "_" + (selev/4);
}
public long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
}
public boolean isTransferNode()
{
return (!isBorder) && _linkCnt() == 2;
}
private int _linkCnt()
{
int cnt = 0;
for( OsmLinkP link = firstlink; link != null; link = link.next )
{
cnt++;
}
return cnt;
}
// mark the link to the given node as written,
// don't want to write the counter-direction
// in full details
public void markLinkWritten( OsmNodeP t )
{
for( OsmLinkP link = firstlink; link != null; link = link.next )
{
if ( link.targetNode == t) link.descriptionBitmap = 0L;
}
}
/**
* Compares two OsmNodes for position ordering.
*
* @return -1,0,1 depending an comparson result
*/
public int compareTo( OsmNodeP n )
{
long id1 = getIdFromPos();
long id2 = n.getIdFromPos();
if ( id1 < id2 ) return -1;
if ( id1 > id2 ) return 1;
return 0;
}
}

View file

@ -0,0 +1,39 @@
/**
* Container for an osm node with tags (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class OsmNodePT extends OsmNodeP
{
public long descriptionBits;
public byte wayOrBits = 0; // used to propagate bike networks to nodes
public OsmNodePT()
{
}
public OsmNodePT( long descriptionBits )
{
this.descriptionBits = descriptionBits;
}
@Override
public long getNodeDecsription()
{
return descriptionBits | (long)( (wayOrBits & 6) >> 1 );
}
@Override
public boolean isTransferNode()
{
return false; // always have descriptionBits so never transfernode
}
}

View file

@ -0,0 +1,240 @@
package btools.mapcreator;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
/**
* Parser for OSM data
*
* @author ab
*/
public class OsmParser extends MapCreatorBase
{
private BufferedReader _br;
private NodeListener nListener;
private WayListener wListener;
private RelationListener rListener;
public void readMap( File mapFile,
NodeListener nListener,
WayListener wListener,
RelationListener rListener ) throws Exception
{
this.nListener = nListener;
this.wListener = wListener;
this.rListener = rListener;
if ( mapFile == null )
{
_br = new BufferedReader(new InputStreamReader(System.in));
}
else
{
if ( mapFile.getName().endsWith( ".gz" ) )
{
_br = new BufferedReader(new InputStreamReader( new GZIPInputStream( new FileInputStream( mapFile ) ) ) );
}
else
{
_br = new BufferedReader(new InputStreamReader( new FileInputStream( mapFile ) ) );
}
}
for(;;)
{
String line = _br.readLine();
if ( line == null ) break;
if ( checkNode( line ) ) continue;
if ( checkWay( line ) ) continue;
if ( checkRelation( line ) ) continue;
if ( checkChangeset( line ) ) continue;
}
if ( mapFile != null )
{
_br.close();
}
}
private boolean checkNode( String line ) throws Exception
{
int idx0 = line.indexOf( "<node id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 10;
int idx1 = line.indexOf( '"', idx0 );
long nodeId = Long.parseLong( line.substring( idx0, idx1 ) );
int idx2 = line.indexOf( " lat=\"" );
if ( idx2 < 0 ) return false;
idx2 += 6;
int idx3 = line.indexOf( '"', idx2 );
double lat = Double.parseDouble( line.substring( idx2, idx3 ) );
int idx4 = line.indexOf( " lon=\"" );
if ( idx4 < 0 ) return false;
idx4 += 6;
int idx5 = line.indexOf( '"', idx4 );
double lon = Double.parseDouble( line.substring( idx4, idx5 ) );
NodeData n = new NodeData( nodeId, lon, lat );
if ( !line.endsWith( "/>" ) )
{
// read additional tags
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
n.putTag( key, value );
}
}
else if ( l2.indexOf( "</node>" ) >= 0 )
{ // end-tag
break;
}
}
}
nListener.nextNode( n );
return true;
}
private boolean checkWay( String line ) throws Exception
{
int idx0 = line.indexOf( "<way id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 9;
int idx1 = line.indexOf( '"', idx0 );
long id = Long.parseLong( line.substring( idx0, idx1 ) );
WayData w = new WayData( id );
// read the nodes
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<nd ref=\"" )) >= 0 )
{ // node reference
i2 += 9;
int ri2 = l2.indexOf( '"', i2 );
long nid = Long.parseLong( l2.substring( i2, ri2 ) );
w.nodes.add( nid );
}
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
w.putTag( key, value );
}
}
else if ( l2.indexOf( "</way>" ) >= 0 )
{ // end-tag
break;
}
}
wListener.nextWay( w );
return true;
}
private boolean checkChangeset( String line ) throws Exception
{
int idx0 = line.indexOf( "<changeset id=\"" );
if ( idx0 < 0 ) return false;
if ( !line.endsWith( "/>" ) )
{
int loopcheck = 0;
for(;;)
{
String l2 = _br.readLine();
if ( l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000 ) break;
}
}
return true;
}
private boolean checkRelation( String line ) throws Exception
{
int idx0 = line.indexOf( "<relation id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 14;
int idx1 = line.indexOf( '"', idx0 );
long rid = Long.parseLong( line.substring( idx0, idx1 ) );
RelationData r = new RelationData( rid );
// read the nodes
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<member type=\"way\" ref=\"" )) >= 0 )
{ // node reference
i2 += 24;
int ri2 = l2.indexOf( '"', i2 );
long wid = Long.parseLong( l2.substring( i2, ri2 ) );
r.ways.add( wid );
}
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
r.putTag( key, value );
}
}
else if ( l2.indexOf( "</relation>" ) >= 0 )
{ // end-tag
break;
}
}
rListener.nextRelation( r );
return true;
}
}

View file

@ -0,0 +1,203 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.CompactLongSet;
import btools.util.CompactLongMap;
import btools.util.FrozenLongSet;
import btools.util.FrozenLongMap;
/**
* PosUnifier does 3 steps in map-processing:
*
* - unify positions
* - add srtm elevation data
* - make a bordernodes file containing net data
* from the bordernids-file just containing ids
*
* @author ab
*/
public class PosUnifier extends MapCreatorBase
{
private DataOutputStream nodesOutStream;
private DataOutputStream borderNodesOut;
private File nodeTilesOut;
private CompactLongSet positionSet;
private HashMap<String,SrtmData> srtmmap ;
private int lastStrmLonIdx;
private int lastStrmLatIdx;
private SrtmData lastSrtmData;
private String srtmdir;
private int totalLatSteps = 0;
private int totalLonSteps = 0;
private CompactLongSet borderNids;
public static void main(String[] args) throws Exception
{
System.out.println("*** PosUnifier: Unify position values and enhance elevation");
if (args.length != 5)
{
System.out.println("usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <strm-data-dir>" );
return;
}
new PosUnifier().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), args[4] );
}
public void process( File nodeTilesIn, File nodeTilesOut, File bordernidsinfile, File bordernodesoutfile, String srtmdir ) throws Exception
{
this.nodeTilesOut = nodeTilesOut;
this.srtmdir = srtmdir;
// read border nids set
DataInputStream dis = createInStream( bordernidsinfile );
borderNids = new CompactLongSet();
try
{
for(;;)
{
long nid = readId( dis );
if ( !borderNids.contains( nid ) ) borderNids.fastAdd( nid );
}
}
catch( EOFException eof )
{
dis.close();
}
borderNids = new FrozenLongSet( borderNids );
// process all files
borderNodesOut = createOutStream( bordernodesoutfile );
new NodeIterator( this, true ).processDir( nodeTilesIn, ".n5d" );
borderNodesOut.close();
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
resetSrtm();
nodesOutStream = createOutStream( fileFromTemplate( nodefile, nodeTilesOut, "u5d" ) );
positionSet = new CompactLongSet();
}
@Override
public void nextNode( NodeData n ) throws Exception
{
SrtmData srtm = srtmForNode( n.ilon, n.ilat );
n.selev = srtm == null ? Short.MIN_VALUE : srtm.getElevation( n.ilon, n.ilat);
findUniquePos( n );
n.writeTo( nodesOutStream );
if ( borderNids.contains( n.nid ) )
{
n.writeTo( borderNodesOut );
}
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
nodesOutStream.close();
}
private void findUniquePos( NodeData n )
{
// fix the position for uniqueness
int lonmod = n.ilon % 1000000;
int londelta = lonmod < 500000 ? 1 : -1;
int latmod = n.ilat % 1000000;
int latdelta = latmod < 500000 ? 1 : -1;
for(int latsteps = 0; latsteps < 100; latsteps++)
{
for(int lonsteps = 0; lonsteps <= latsteps; lonsteps++)
{
int lon = n.ilon + lonsteps*londelta;
int lat = n.ilat + latsteps*latdelta;
long pid = ((long)lon)<<32 | lat; // id from position
if ( !positionSet.contains( pid ) )
{
totalLonSteps += lonsteps;
totalLatSteps += latsteps;
positionSet.fastAdd( pid );
n.ilon = lon;
n.ilat = lat;
return;
}
}
}
System.out.println( "*** WARNING: cannot unify position for: " + n.ilon + " " + n.ilat );
}
/**
* get the srtm data set for a position
* srtm coords are srtm_<srtmLon>_<srtmLat>
* where srtmLon = 180 + lon, srtmLat = 60 - lat
*/
private SrtmData srtmForNode( int ilon, int ilat ) throws Exception
{
int srtmLonIdx = (ilon+5000000)/5000000;
int srtmLatIdx = (154999999-ilat)/5000000;
if ( srtmLatIdx < 1 || srtmLatIdx > 24 || srtmLonIdx < 1 || srtmLonIdx > 72 )
{
return null;
}
if ( srtmLonIdx == lastStrmLonIdx && srtmLatIdx == lastStrmLatIdx )
{
return lastSrtmData;
}
lastStrmLonIdx = srtmLonIdx;
lastStrmLatIdx = srtmLatIdx;
StringBuilder sb = new StringBuilder( 16 );
sb.append( "srtm_" );
sb.append( (char)('0' + srtmLonIdx/10 ) ).append( (char)('0' + srtmLonIdx%10 ) ).append( '_' );
sb.append( (char)('0' + srtmLatIdx/10 ) ).append( (char)('0' + srtmLatIdx%10 ) ).append( ".zip" );
String filename = sb.toString();
lastSrtmData = srtmmap.get( filename );
if ( lastSrtmData == null && !srtmmap.containsKey( filename ) )
{
File f = new File( new File( srtmdir ), filename );
System.out.println( "reading: " + f + " ilon=" + ilon + " ilat=" + ilat );
if ( f.exists() )
{
try
{
lastSrtmData = new SrtmData( f );
}
catch( Exception e )
{
System.out.println( "**** ERROR reading " + f + " ****" );
}
}
srtmmap.put( filename, lastSrtmData );
}
return lastSrtmData;
}
private void resetSrtm()
{
srtmmap = new HashMap<String,SrtmData>();
lastStrmLonIdx = -1;
lastStrmLatIdx = -1;
lastSrtmData = null;
}
}

View file

@ -0,0 +1,37 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Container for relation data on the preprocessor level
*
* @author ab
*/
public class RelationData extends MapCreatorBase
{
public long rid;
public long description;
public LongList ways;
public RelationData( long id )
{
rid = id;
ways = new LongList( 16 );
}
public RelationData( long id, LongList ways )
{
rid = id;
this.ways = ways;
}
}

View file

@ -0,0 +1,13 @@
package btools.mapcreator;
import java.io.File;
/**
* Callbacklistener for Relations
*
* @author ab
*/
public interface RelationListener
{
void nextRelation( RelationData data ) throws Exception;
}

View file

@ -0,0 +1,174 @@
/**
* This is a wrapper for a 5*5 degree srtm file in ascii/zip-format
*
* - filter out unused nodes according to the way file
* - enhance with SRTM elevation data
* - split further in smaller (5*5 degree) tiles
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class SrtmData
{
public int ncols;
public int nrows;
public double xllcorner;
public double yllcorner;
public double cellsize;
public int nodata_value;
public short[] eval_array;
private double minlon;
private double maxlon;
private double minlat;
private double maxlat;
public void init()
{
minlon = xllcorner;
maxlon = minlon + cellsize*ncols;
minlat = yllcorner;
maxlat = minlat + cellsize*nrows;
}
private boolean missingData = false;
public short getElevation( int ilon, int ilat )
{
double lon = ilon / 1000000. - 180.;
double lat = ilat / 1000000. - 90.;
double dcol = (lon - minlon)/cellsize -0.5;
double drow = (lat - minlat)/cellsize -0.5;
int row = (int)drow;
int col = (int)dcol;
if ( col < 0 ) col = 0;
if ( col >= ncols-1 ) col = ncols - 2;
if ( row < 0 ) row = 0;
if ( row >= nrows-1 ) row = nrows - 2;
double wrow = drow-row;
double wcol = dcol-col;
missingData = false;
double eval = (1.-wrow)*(1.-wcol)*get(row ,col )
+ ( wrow)*(1.-wcol)*get(row+1,col )
+ (1.-wrow)*( wcol)*get(row ,col+1)
+ ( wrow)*( wcol)*get(row+1,col+1);
return missingData ? Short.MIN_VALUE : (short)(eval);
}
private short get( int r, int c )
{
short e = eval_array[r*ncols + c ];
if ( e == Short.MIN_VALUE ) missingData = true;
return e;
}
public SrtmData( File file ) throws Exception
{
ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) );
try
{
for(;;)
{
ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".asc" ) )
{
readFromStream( zis );
/* // test
int[] ca = new int[]{ 50477121, 8051915, // 181
50477742, 8047408, // 154
50477189, 8047308, // 159
};
for( int i=0; i<ca.length; i+=2 )
{
int lat=ca[i] + 90000000;
int lon=ca[i+1] + 180000000;
System.err.println( "lat=" + lat + " lon=" + lon + " elev=" + getElevation( lon, lat )/4. );
}
// end test
*/
return;
}
}
}
finally
{
zis.close();
}
}
public void readFromStream( InputStream is ) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(is));
int linenr = 0;
for(;;)
{
linenr++;
if ( linenr <= 6 )
{
String line = br.readLine();
if ( linenr == 1 ) ncols = Integer.parseInt( line.substring(14) );
else if ( linenr == 2 ) nrows = Integer.parseInt( line.substring(14) );
else if ( linenr == 3 ) xllcorner = Double.parseDouble( line.substring(14) );
else if ( linenr == 4 ) yllcorner = Double.parseDouble( line.substring(14) );
else if ( linenr == 5 ) cellsize = Double.parseDouble( line.substring(14) );
else if ( linenr == 6 )
{
nodata_value = Integer.parseInt( line.substring(14) );
eval_array = new short[ncols * nrows];
}
}
else
{
int row = 0;
int col = 0;
int n = 0;
boolean negative = false;
for(;;)
{
int c = br.read();
if ( c < 0 ) break;
if ( c == ' ' )
{
if ( negative ) n = -n;
short val = n == nodata_value ? Short.MIN_VALUE : (short)(n*4);
if ( val < -1000 ) val = Short.MIN_VALUE;
eval_array[ (nrows-1-row)*ncols + col ] = val;
if (++col == ncols )
{
col = 0;
++row;
}
n = 0;
negative = false;
}
else if ( c >= '0' && c <= '9' )
{
n = 10*n + (c-'0');
}
else if ( c == '-' )
{
negative = true;
}
}
break;
}
}
init();
br.close();
}
}

View file

@ -0,0 +1,127 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* WayCutter does 2 step in map-processing:
*
* - cut the way file into 45*30 - pieces
* - enrich ways with relation information
*
* @author ab
*/
public class WayCutter extends MapCreatorBase
{
private CompactLongSet cyclewayset;
private DenseLongMap tileIndexMap;
public static void main(String[] args) throws Exception
{
System.out.println("*** WayCutter: Soft-Cut way-data into tiles");
if (args.length != 4)
{
System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out> <relation-file>" );
return;
}
new WayCutter().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ) );
}
public void process( File nodeTilesIn, File wayFileIn, File wayTilesOut, File relationFileIn ) throws Exception
{
this.outTileDir = wayTilesOut;
// *** read the relation file into a set (currently cycleway processing only)
cyclewayset = new CompactLongSet();
DataInputStream dis = createInStream( relationFileIn );
try
{
for(;;)
{
long wid = readId( dis );
if ( !cyclewayset.contains( wid ) ) cyclewayset.add( wid );
}
}
catch( EOFException eof )
{
dis.close();
}
System.out.println( "marked cycleways: " + cyclewayset.size() );
// *** read all nodes into tileIndexMap
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 6 ) : new TinyDenseLongMap();
new NodeIterator( this, false ).processDir( nodeTilesIn, ".tlf" );
// *** finally process the way-file, cutting into pieces
new WayIterator( this, true ).processFile( wayFileIn );
closeTileOutStreams();
}
@Override
public void nextNode( NodeData n ) throws Exception
{
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) );
}
@Override
public void nextWay( WayData data ) throws Exception
{
// propagate the cycleway-bit
if ( cyclewayset.contains( data.wid ) )
{
data.description |= 2;
}
long waytileset = 0;
int nnodes = data.nodes.size();
// determine the tile-index for each node
for (int i=0; i<nnodes; i++ )
{
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) );
if ( tileIndex != -1 )
{
waytileset |= ( 1L << tileIndex );
}
}
// now write way to all tiles hit
for( int tileIndex=0; tileIndex<54; tileIndex++ )
{
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{
continue;
}
data.writeTo( getOutStreamForTile( tileIndex ) );
}
}
private int getTileIndex( int ilon, int ilat )
{
int lon = ilon / 45000000;
int lat = ilat / 30000000;
if ( lon < 0 || lon > 7 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat );
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 45 - 180;
int lat = (tileIndex % 6 ) * 30 - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".wtl";
}
}

View file

@ -0,0 +1,146 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* WayCutter5 does 2 step in map-processing:
*
* - cut the 45*30 way files into 5*5 pieces
* - create a file containing all border node ids
*
* @author ab
*/
public class WayCutter5 extends MapCreatorBase
{
private DataOutputStream borderNidsOutStream;
private DenseLongMap tileIndexMap;
private File nodeTilesIn;
private int lonoffset;
private int latoffset;
public static void main(String[] args) throws Exception
{
System.out.println("*** WayCutter5: Soft-Cut way-data into tiles");
if (args.length != 4)
{
System.out.println("usage: java WayCutter5 <node-tiles-in> <way-tiles-in> <way-tiles-out> <border-nids-out>" );
return;
}
new WayCutter5().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ) );
}
public void process( File nodeTilesIn, File wayTilesIn, File wayTilesOut, File borderNidsOut ) throws Exception
{
this.nodeTilesIn = nodeTilesIn;
this.outTileDir = wayTilesOut;
borderNidsOutStream = createOutStream( borderNidsOut );
new WayIterator( this, true ).processDir( wayTilesIn, ".wtl" );
borderNidsOutStream.close();
}
@Override
public void wayFileStart( File wayfile ) throws Exception
{
// read corresponding node-file into tileIndexMap
String name = wayfile.getName();
String nodefilename = name.substring( 0, name.length()-3 ) + "tlf";
File nodefile = new File( nodeTilesIn, nodefilename );
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 6 ) : new TinyDenseLongMap();
lonoffset = -1;
latoffset = -1;
new NodeIterator( this, false ).processFile( nodefile );
}
@Override
public void nextNode( NodeData n ) throws Exception
{
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) );
}
@Override
public void nextWay( WayData data ) throws Exception
{
long waytileset = 0;
int nnodes = data.nodes.size();
int[] tiForNode = new int[nnodes];
// determine the tile-index for each node
for (int i=0; i<nnodes; i++ )
{
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) );
if ( tileIndex != -1 )
{
waytileset |= ( 1L << tileIndex );
}
tiForNode[i] = tileIndex;
}
// now write way to all tiles hit
for( int tileIndex=0; tileIndex<54; tileIndex++ )
{
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{
continue;
}
data.writeTo( getOutStreamForTile( tileIndex ) );
}
// and write edge nodes to the border-nid file
for( int i=0; i < nnodes; i++ )
{
int ti = tiForNode[i];
if ( ti != -1 )
{
if ( ( i > 0 && tiForNode[i-1] != ti ) || (i+1 < nnodes && tiForNode[i+1] != ti ) )
{
writeId( borderNidsOutStream, data.nodes.get(i) );
}
}
}
}
@Override
public void wayFileEnd( File wayFile ) throws Exception
{
closeTileOutStreams();
}
private int getTileIndex( int ilon, int ilat )
{
int lonoff = (ilon / 45000000 ) * 45;
int latoff = (ilat / 30000000 ) * 30;
if ( lonoffset == -1 ) lonoffset = lonoff;
if ( latoffset == -1 ) latoffset = latoff;
if ( lonoff != lonoffset || latoff != latoffset )
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
int lon = (ilon / 5000000) % 9;
int lat = (ilat / 5000000) % 6;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat );
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 5 + lonoffset - 180;
int lat = (tileIndex % 6 ) * 5 + latoffset - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".wt5";
}
}

View file

@ -0,0 +1,62 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Container for waydata on the preprocessor level
*
* @author ab
*/
public class WayData extends MapCreatorBase
{
public long wid;
public long description;
public LongList nodes;
public WayData( long id )
{
wid = id;
nodes = new LongList( 16 );
}
public WayData( long id, LongList nodes )
{
wid = id;
this.nodes = nodes;
}
public WayData( DataInputStream di ) throws Exception
{
nodes = new LongList( 16 );
wid = readId( di) ;
description = di.readLong();
for (;;)
{
long nid = readId( di );
if ( nid == -1 ) break;
nodes.add( nid );
}
}
public void writeTo( DataOutputStream dos ) throws Exception
{
writeId( dos, wid );
dos.writeLong( description );
int size = nodes.size();
for( int i=0; i < size; i++ )
{
writeId( dos, nodes.get( i ) );
}
writeId( dos, -1 ); // stopbyte
}
}

View file

@ -0,0 +1,76 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Iterate over a singe wayfile or a directory
* of waytiles and feed the ways to the callback listener
*
* @author ab
*/
public class WayIterator extends MapCreatorBase
{
private WayListener listener;
private boolean delete;
public WayIterator( WayListener wayListener, boolean deleteAfterReading )
{
listener = wayListener;
delete = deleteAfterReading;
}
public void processDir( File indir, String inSuffix ) throws Exception
{
if ( !indir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + indir );
}
File[] af = sortBySizeAsc( indir.listFiles() );
for( int i=0; i<af.length; i++ )
{
File wayfile = af[i];
if ( wayfile.getName().endsWith( inSuffix ) )
{
processFile( wayfile );
}
}
}
public void processFile(File wayfile) throws Exception
{
System.out.println( "*** WayIterator reading: " + wayfile );
listener.wayFileStart( wayfile );
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( wayfile ) ) );
try
{
for(;;)
{
WayData w = new WayData( di );
listener.nextWay( w );
}
}
catch( EOFException eof )
{
di.close();
}
listener.wayFileEnd( wayfile );
if ( delete && "true".equals( System.getProperty( "deletetmpfiles" ) ))
{
wayfile.delete();
}
}
}

View file

@ -0,0 +1,289 @@
package btools.mapcreator;
import java.io.*;
import java.util.*;
import btools.util.*;
import btools.expressions.BExpressionContext;
/**
* WayLinker finally puts the pieces together
* to create the rd5 files. For each 5*5 tile,
* the corresponding nodefile and wayfile is read,
* plus the (global) bordernodes file, and an rd5
* is written
*
* @author ab
*/
public class WayLinker extends MapCreatorBase
{
private File nodeTilesIn;
private File dataTilesOut;
private File borderFileIn;
private String dataTilesSuffix;
private boolean readingBorder;
private CompactLongMap<OsmNodeP> nodesMap;
private List<OsmNodeP> nodesList;
private CompactLongSet borderSet;
private short lookupVersion;
private BExpressionContext expctxWay;
private int minLon;
private int minLat;
private void reset()
{
minLon = -1;
minLat = -1;
nodesMap = new CompactLongMap<OsmNodeP>();
borderSet = new CompactLongSet();
}
public static void main(String[] args) throws Exception
{
System.out.println("*** WayLinker: Format a regionof an OSM map for routing");
if (args.length != 7)
{
System.out.println("usage: java WayLinker <node-tiles-in> <way-tiles-in> <bordernodes> <lookup-file> <profile-file> <data-tiles-out> <data-tiles-suffix> ");
return;
}
new WayLinker().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), new File( args[4] ), new File( args[5] ), args[6] );
}
public void process( File nodeTilesIn, File wayTilesIn, File borderFileIn, File lookupFile, File profileFile, File dataTilesOut, String dataTilesSuffix ) throws Exception
{
this.nodeTilesIn = nodeTilesIn;
this.dataTilesOut = dataTilesOut;
this.borderFileIn = borderFileIn;
this.dataTilesSuffix = dataTilesSuffix;
// read lookup file to get the lookup-version
expctxWay = new BExpressionContext("way");
expctxWay.readMetaData( lookupFile );
lookupVersion = expctxWay.lookupVersion;
expctxWay.parseFile( profileFile, "global" );
// then process all segments
new WayIterator( this, true ).processDir( wayTilesIn, ".wt5" );
}
@Override
public void wayFileStart( File wayfile ) throws Exception
{
// process corresponding node-file, if any
File nodeFile = fileFromTemplate( wayfile, nodeTilesIn, "u5d" );
if ( nodeFile.exists() )
{
reset();
// read the border file
readingBorder = true;
new NodeIterator( this, false ).processFile( borderFileIn );
borderSet = new FrozenLongSet( borderSet );
// read this tile's nodes
readingBorder = false;
new NodeIterator( this, false ).processFile( nodeFile );
// freeze the nodes-map
FrozenLongMap<OsmNodeP> nodesMapFrozen = new FrozenLongMap<OsmNodeP>( nodesMap );
nodesMap = nodesMapFrozen;
nodesList = nodesMapFrozen.getValueList();
}
}
@Override
public void nextNode( NodeData data ) throws Exception
{
OsmNodeP n = data.description == 0L ? new OsmNodeP() : new OsmNodePT(data.description);
n.ilon = data.ilon;
n.ilat = data.ilat;
n.selev = data.selev;
n.isBorder = readingBorder;
if ( readingBorder || (!borderSet.contains( data.nid )) )
{
nodesMap.fastPut( data.nid, n );
}
if ( readingBorder )
{
borderSet.fastAdd( data.nid );
return;
}
// remember the segment coords
int min_lon = (n.ilon / 5000000 ) * 5000000;
int min_lat = (n.ilat / 5000000 ) * 5000000;
if ( minLon == -1 ) minLon = min_lon;
if ( minLat == -1 ) minLat = min_lat;
if ( minLat != min_lat || minLon != min_lon )
throw new IllegalArgumentException( "inconsistent node: " + n.ilon + " " + n.ilat );
}
@Override
public void nextWay( WayData way ) throws Exception
{
long description = way.description;
long reverseDescription = description | 1L; // (add reverse bit)
// filter according to profile
expctxWay.evaluate( description, null );
boolean ok = expctxWay.getCostfactor() < 10000.;
expctxWay.evaluate( reverseDescription, null );
ok |= expctxWay.getCostfactor() < 10000.;
if ( !ok ) return;
byte lowbyte = (byte)description;
OsmNodeP n1 = null;
OsmNodeP n2 = null;
for (int i=0; i<way.nodes.size(); i++)
{
long nid = way.nodes.get(i);
n1 = n2;
n2 = nodesMap.get( nid );
if ( n1 != null && n2 != null )
{
OsmLinkP l1 = new OsmLinkP();
l1.targetNode = n2;
l1.descriptionBitmap = description;
n1.addLink( l1 );
OsmLinkP l2 = new OsmLinkP();
l2.targetNode = n1;
l2.descriptionBitmap = reverseDescription;
n2.addLink( l2 );
}
if ( n2 != null )
{
n2.wayAndBits &= lowbyte;
if ( n2 instanceof OsmNodePT ) ((OsmNodePT)n2).wayOrBits |= lowbyte;
}
}
}
@Override
public void wayFileEnd( File wayfile ) throws Exception
{
nodesMap = null;
borderSet = null;
int maxLon = minLon + 5000000;
int maxLat = minLat + 5000000;
// write segment data to individual files
{
int nLonSegs = (maxLon - minLon)/1000000;
int nLatSegs = (maxLat - minLat)/1000000;
// sort the nodes into segments
LazyArrayOfLists<OsmNodeP> seglists = new LazyArrayOfLists<OsmNodeP>(nLonSegs*nLatSegs);
for( OsmNodeP n : nodesList )
{
if ( n == null || n.firstlink == null || n.isTransferNode() ) continue;
if ( n.ilon < minLon || n.ilon >= maxLon
|| n.ilat < minLat || n.ilat >= maxLat ) continue;
int lonIdx = (n.ilon-minLon)/1000000;
int latIdx = (n.ilat-minLat)/1000000;
int tileIndex = lonIdx * nLatSegs + latIdx;
seglists.getList(tileIndex).add( n );
}
nodesList = null;
seglists.trimAll();
// open the output file
File outfile = fileFromTemplate( wayfile, dataTilesOut, dataTilesSuffix );
DataOutputStream os = createOutStream( outfile );
// write 5*5 index dummy
long[] fileIndex = new long[25];
for( int i55=0; i55<25; i55++)
{
os.writeLong( 0 );
}
long filepos = 200L;
// sort further in 1/80-degree squares
for( int lonIdx = 0; lonIdx < nLonSegs; lonIdx++ )
{
for( int latIdx = 0; latIdx < nLatSegs; latIdx++ )
{
int tileIndex = lonIdx * nLatSegs + latIdx;
if ( seglists.getSize(tileIndex) > 0 )
{
List<OsmNodeP> nlist = seglists.getList(tileIndex);
LazyArrayOfLists<OsmNodeP> subs = new LazyArrayOfLists<OsmNodeP>(6400);
byte[][] subByteArrays = new byte[6400][];
for( int ni=0; ni<nlist.size(); ni++ )
{
OsmNodeP n = nlist.get(ni);
int subLonIdx = (n.ilon - minLon) / 12500 - 80*lonIdx;
int subLatIdx = (n.ilat - minLat) / 12500 - 80*latIdx;
int si = subLatIdx*80 + subLonIdx;
subs.getList(si).add( n );
}
subs.trimAll();
int[] posIdx = new int[6400];
int pos = 25600;
for( int si=0; si<6400; si++)
{
List<OsmNodeP> subList = subs.getList(si);
if ( subList.size() > 0 )
{
Collections.sort( subList );
ByteArrayOutputStream bos = new ByteArrayOutputStream( );
DataOutputStream dos = new DataOutputStream( bos );
dos.writeInt( subList.size() );
for( int ni=0; ni<subList.size(); ni++ )
{
OsmNodeP n = subList.get(ni);
n.writeNodeData( dos );
}
dos.close();
byte[] subBytes = bos.toByteArray();
pos += subBytes.length;
subByteArrays[si] = subBytes;
}
posIdx[si] = pos;
}
for( int si=0; si<6400; si++)
{
os.writeInt( posIdx[si] );
}
for( int si=0; si<6400; si++)
{
if ( subByteArrays[si] != null )
{
os.write( subByteArrays[si] );
}
}
filepos += pos;
}
fileIndex[ tileIndex ] = filepos;
}
}
os.close();
// re-open random-access to write file-index
RandomAccessFile ra = new RandomAccessFile( outfile, "rw" );
long versionPrefix = lookupVersion;
versionPrefix <<= 48;
for( int i55=0; i55<25; i55++)
{
ra.writeLong( fileIndex[i55] | versionPrefix );
}
ra.close();
}
}
}

View file

@ -0,0 +1,17 @@
package btools.mapcreator;
import java.io.File;
/**
* Callbacklistener for WayIterator
*
* @author ab
*/
public interface WayListener
{
void wayFileStart( File wayfile ) throws Exception;
void nextWay( WayData data ) throws Exception;
void wayFileEnd( File wayfile ) throws Exception;
}

View file

@ -0,0 +1,70 @@
package btools.mapcreator;
import java.util.Random;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import java.net.URL;
import java.io.File;
public class MapcreatorTest
{
@Test
public void mapcreatorTest() throws Exception
{
URL mapurl = this.getClass().getResource( "/dreieich.osm.gz" );
Assert.assertTrue( "test-osm-map dreieich.osm not found", mapurl != null );
File mapfile = new File(mapurl.getFile());
File workingDir = mapfile.getParentFile();
File tmpdir = new File( workingDir, "tmp" );
tmpdir.mkdir();
// run OsmCutter
File nodetiles = new File( tmpdir, "nodetiles" );
nodetiles.mkdir();
File lookupFile = new File( workingDir, "lookups.dat" );
File wayFile = new File( tmpdir, "ways.dat" );
File relFile = new File( tmpdir, "cycleways.dat" );
new OsmCutter().process( lookupFile, nodetiles, wayFile, relFile, mapfile );
// run NodeFilter
File ftiles = new File( tmpdir, "ftiles" );
ftiles.mkdir();
new NodeFilter().process( nodetiles, wayFile, ftiles );
// run WayCutter
File waytiles = new File( tmpdir, "waytiles" );
waytiles.mkdir();
new WayCutter().process( ftiles, wayFile, waytiles, relFile );
// run WayCutter5
File waytiles55 = new File( tmpdir, "waytiles55" );
File bordernids = new File( tmpdir, "bordernids.dat" );
waytiles55.mkdir();
new WayCutter5().process( ftiles, waytiles, waytiles55, bordernids );
// run NodeCutter
File nodes55 = new File( tmpdir, "nodes55" );
nodes55.mkdir();
new NodeCutter().process( ftiles, nodes55 );
// run PosUnifier
File unodes55 = new File( tmpdir, "unodes55" );
File bordernodes = new File( tmpdir, "bordernodes.dat" );
unodes55.mkdir();
new PosUnifier().process( nodes55, unodes55, bordernids, bordernodes, "/private-backup/srtm" );
// run WayLinker
File segments = new File( tmpdir, "segments" );
segments.mkdir();
File profileAllFile = new File( workingDir, "all.brf" );
new WayLinker().process( unodes55, waytiles55, bordernodes, lookupFile, profileAllFile, segments, "rd5" );
// run WayLinker, car subset
File carsubset = new File( segments, "carsubset" );
carsubset.mkdir();
File profileCarFile = new File( workingDir, "car-test.brf" );
new WayLinker().process( unodes55, waytiles55, bordernodes, lookupFile, profileCarFile, carsubset, "cd5" );
}
}

View file

@ -0,0 +1,70 @@
package btools.mapcreator;
import java.util.Random;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import java.net.URL;
import java.io.File;
public class MapcreatorTest
{
@Test
public void mapcreatorTest() throws Exception
{
URL mapurl = this.getClass().getResource( "/dreieich.osm.gz" );
Assert.assertTrue( "test-osm-map dreieich.osm not found", mapurl != null );
File mapfile = new File(mapurl.getFile());
File workingDir = mapfile.getParentFile();
File tmpdir = new File( workingDir, "tmp" );
tmpdir.mkdir();
// run OsmCutter
File nodetiles = new File( tmpdir, "nodetiles" );
nodetiles.mkdir();
File lookupFile = new File( workingDir, "lookups.dat" );
File wayFile = new File( tmpdir, "ways.dat" );
File relFile = new File( tmpdir, "cycleways.dat" );
new OsmCutter().process( lookupFile, nodetiles, wayFile, relFile, mapfile );
// run NodeFilter
File ftiles = new File( tmpdir, "ftiles" );
ftiles.mkdir();
new NodeFilter().process( nodetiles, wayFile, ftiles );
// run WayCutter
File waytiles = new File( tmpdir, "waytiles" );
waytiles.mkdir();
new WayCutter().process( ftiles, wayFile, waytiles, relFile );
// run WayCutter5
File waytiles55 = new File( tmpdir, "waytiles55" );
File bordernids = new File( tmpdir, "bordernids.dat" );
waytiles55.mkdir();
new WayCutter5().process( ftiles, waytiles, waytiles55, bordernids );
// run NodeCutter
File nodes55 = new File( tmpdir, "nodes55" );
nodes55.mkdir();
new NodeCutter().process( ftiles, nodes55 );
// run PosUnifier
File unodes55 = new File( tmpdir, "unodes55" );
File bordernodes = new File( tmpdir, "bordernodes.dat" );
unodes55.mkdir();
new PosUnifier().process( nodes55, unodes55, bordernids, bordernodes, "/private-backup/srtm" );
// run WayLinker
File segments = new File( tmpdir, "segments" );
segments.mkdir();
File profileAllFile = new File( workingDir, "all.brf" );
new WayLinker().process( unodes55, waytiles55, bordernodes, lookupFile, segments, "rd5" );
// run WayLinker, car subset
File carsubset = new File( segments, "carsubset" );
carsubset.mkdir();
File profileCarFile = new File( workingDir, "car-test.brf" );
new WayLinker().process( unodes55, waytiles55, bordernodes, lookupFile, carsubset, "cd5" );
}
}

View file

@ -0,0 +1,18 @@
---context:global # following code refers to global config
# the elevation parameters
assign downhillcost 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
assign turncost 0
assign initialcost 0
assign costfactor 1
---context:node # following code refers to node tags
assign initialcost 0

View file

@ -0,0 +1,11 @@
---context:global # following code refers to global config
---context:way # following code refers to way-tags
assign turncost 0
assign initialcost 0
assign costfactor 1
---context:node # following code refers to node tags
assign initialcost 0

View file

@ -0,0 +1,107 @@
#
# Car-Routing is experimantal !!!
#
# DO NOT USE FOR ACTUAL NAVIGATION
#
# Turn restrictions are missing, leading to wrong routes
#
---context:global
assign downhillcost 0
assign downhillcutoff 0
assign uphillcost 0
assign uphillcutoff 0
assign validForCars 1
---context:way # following code refers to way-tags
assign turncost 200
assign initialcost switch highway=ferry 20000 0
#
# calculate logical car access
#
assign caraccess
switch motorcar=
switch motor_vehicle=
switch vehicle=
switch access=
switch or highway=motorway highway=motorway_link 1
switch or highway=trunk highway=trunk_link 1
switch or highway=primary highway=primary_link 1
switch or highway=secondary highway=secondary_link 1
switch or highway=tertiary highway=tertiary_link 1
switch highway=unclassified 1
switch highway=ferry 1
switch or highway=residential highway=living_street 1
switch highway=service 1
0
or access=yes or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=designated motor_vehicle=destination
or motorcar=yes or motorcar=designated motorcar=destination
assign accesspenalty
switch caraccess
0
10000
assign onewaypenalty
switch switch reversedirection=yes
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
oneway=-1
10000
0.0
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign costfactor
add max onewaypenalty accesspenalty
switch or highway=motorway highway=motorway_link 1
switch or highway=trunk highway=trunk_link 1
switch or highway=primary highway=primary_link switch maxspeed=30 2.0 switch maxspeed=50 1.5 1.2
switch or highway=secondary highway=secondary_link 1.3
switch or highway=tertiary highway=tertiary_link 1.4
switch highway=unclassified 1.5
switch highway=ferry 5.67
switch highway=bridleway 5
switch or highway=residential highway=living_street 2
switch highway=service 2
switch or highway=track or highway=road highway=path
switch tracktype=grade1 5
switch ispaved 5
30
10000
---context:node # following code refers to node tags
#
# calculate logical car access to nodes
#
assign caraccess
switch motorcar=
switch motor_vehicle=
switch vehicle=
switch access=
switch barrier=gate 0
switch barrier=bollard 0
switch barrier=lift_gate 0
switch barrier=cycle_barrier 0
1
or access=yes or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=designated motor_vehicle=destination
or motorcar=yes or motorcar=designated motorcar=destination
assign initialcost
switch caraccess
0
1000000

Binary file not shown.

View file

@ -0,0 +1,317 @@
---lookupversion:2
---context:way
highway;0001731794 track
highway;0001457935 residential
highway;0000968516 service
highway;0000756237 footway
highway;0000521566 path
highway;0000261772 unclassified
highway;0000220315 secondary
highway;0000207585 tertiary
highway;0000103445 steps
highway;0000102114 primary
highway;0000094484 cycleway
highway;0000090388 living_street
highway;0000035041 motorway
highway;0000029965 pedestrian
highway;0000026875 motorway_link
highway;0000015054 trunk
highway;0000014604 primary_link
highway;0000012211 road
highway;0000011822 trunk_link
highway;0000005882 construction
highway;0000005425 bridleway
highway;0000005180 secondary_link
highway;0000003360 platform
highway;0000002616 proposed abandoned
highway;0000001374 tertiary_link
highway;0000000760 ferry
highway;0000000541 raceway
highway;0000000346 rest_area
highway;0000000300 bus_stop
highway;0000000184 services
tracktype;0000356503 grade2
tracktype;0000353482 grade3
tracktype;0000281625 grade1
tracktype;0000245193 grade4
tracktype;0000179135 grade5
surface;0000363915 asphalt
surface;0000303589 paved
surface;0000196783 gravel
surface;0000137371 ground
surface;0000128215 grass
surface;0000092748 unpaved
surface;0000086579 paving_stones
surface;0000066111 cobblestone
surface;0000042061 dirt
surface;0000026551 concrete
surface;0000025631 compacted
surface;0000019861 sand
surface;0000009400 pebblestone
surface;0000003197 fine_gravel
maxspeed;0000402224 30
maxspeed;0000224685 50
maxspeed;0000045177 100
maxspeed;0000037529 70
maxspeed;0000014237 none
maxspeed;0000014022 60
maxspeed;0000011530 80
maxspeed;0000009951 10
maxspeed;0000008056 20
maxspeed;0000005772 120
maxspeed;0000003165 40
maxspeed;0000002987 7
maxspeed;0000002826 signals
maxspeed;0000001933 130
service;0000221481 parking_aisle
service;0000157110 driveway
lit;0000132495 yes
lanes;0000098207 2
lanes;0000042192 1
lanes;0000018533 3
lanes;0000004577 4
lanes;0000000448 5
lanes;0000000318 1.5
access;0000044859 yes permissive
access;0000008452 designated official
access;0000028727 destination customers
access;0000076985 agricultural forestry
access;0000116270 private
access;0000028044 no
foot;0000339384 yes allowed Yes
foot;0000125339 designated official
foot;0000018945 no
foot;0000001562 private
foot;0000000279 destination
foot;0000008172 permissive
bicycle;0000302789 yes allowed permissive
bicycle;0000108056 designated official
bicycle;0000000265 destination
bicycle;0000003593 dismount
bicycle;0000001426 private
bicycle;0000070179 no
motorcar;0000010111 yes permissive
motorcar;0000001537 designated official
motorcar;0000007102 destination
motorcar;0000016706 agricultural forestry agriculture
motorcar;0000002178 private
motorcar;0000077771 no
motor_vehicle;0000013813 yes permissive
motor_vehicle;0000002098 designated official
motor_vehicle;0000009792 destination
motor_vehicle;0000019301 agricultural forestry
motor_vehicle;0000006563 private
motor_vehicle;0000025491 no
motorcycle;0000005750 yes permissive
motorcycle;0000001158 designated official
motorcycle;0000005805 destination
motorcycle;0000012401 agricultural forestry
motorcycle;0000001180 private
motorcycle;0000053955 no
vehicle;0000000505 yes permissive
vehicle;0000000027 designated
vehicle;0000007582 destination
vehicle;0000004357 agricultural forestry
vehicle;0000001155 private
vehicle;0000006487 no
cycleway;0000033575 track
cycleway;0000012829 no
cycleway;0000011604 lane
cycleway;0000008938 opposite
cycleway;0000001503 none
cycleway;0000001146 right
cycleway;0000001031 opposite_track
cycleway;0000001029 yes
cycleway;0000000856 opposite_lane
cycleway;0000000675 both
cycleway;0000000665 left
cycleway;0000000521 shared
cycleway;0000000383 street
cycleway;0000000176 segregated
mtb:scale;0000043968 0
mtb:scale;0000019705 1
mtb:scale;0000006436 2
mtb:scale;0000002702 3
mtb:scale;0000001083 4
mtb:scale;0000000329 5
sac_scale;0000049626 hiking
sac_scale;0000007933 mountain_hiking
sac_scale;0000001160 demanding_mountain_hiking
sac_scale;0000000523 yes
sac_scale;0000000364 alpine_hiking
sac_scale;0000000117 demanding_alpine_hiking
noexit;0000058492 yes
motorroad;0000019250 yes
oneway;0000330245 yes
oneway;0000075148 no
oneway;0000003679 -1
oneway;0000000001 true
oneway;0000000001 1
junction;0000015929 roundabout
bridge;0000182649 yes viaduct true suspension
tunnel;0000031626 yes
lcn;0000018999 yes
longdistancecycleway;0000000001 yes
reversedirection;0000000001 yes
---context:node
highway;0000100947 turning_circle
highway;0000067645 traffic_signals
highway;0000047209 crossing
highway;0000037164 bus_stop
highway;0000006577 motorway_junction
highway;0000003811 stop
highway;0000002331 mini_roundabout
highway;0000001789 milestone
highway;0000001692 passing_place
highway;0000001289 give_way
highway;0000001092 emergency_access_point
highway;0000000683 speed_camera
highway;0000000672 steps
highway;0000000658 incline_steep
highway;0000000620 elevator
highway;0000000506 street_lamp
highway;0000000490 ford
highway;0000000458 incline
highway;0000000135 rest_area
highway;0000000105 path
highway;0000000098 emergency_bay
highway;0000000096 road
highway;0000000087 platform
highway;0000000074 services
highway;0000000058 track
highway;0000000055 service
highway;0000000054 footway
highway;0000000053 traffic_calming
highway;0000000046 toll_bridge
highway;0000000037 city_entry
barrier;0000076979 gate
barrier;0000069308 bollard
barrier;0000028131 lift_gate
barrier;0000017332 cycle_barrier
barrier;0000005693 entrance
barrier;0000002885 block
barrier;0000001065 kissing_gate
barrier;0000000828 cattle_grid
barrier;0000000602 stile
barrier;0000000561 turnstile
barrier;0000000512 no
barrier;0000000463 fence
barrier;0000000417 bump_gate
barrier;0000000324 sally_port
barrier;0000000283 yes
barrier;0000000283 hampshire_gate
barrier;0000000236 swing_gate
barrier;0000000203 chain
barrier;0000000181 toll_booth
barrier;0000000180 door
barrier;0000000104 chicane
barrier;0000000096 tree
barrier;0000000087 border_control
barrier;0000000077 log
barrier;0000000076 traffic_crossing_pole
barrier;0000000063 wall
barrier;0000000060 fallen_tree
barrier;0000000052 stone
barrier;0000000048 ditch
barrier;0000000031 spikes
access;0000001309 yes permissive
access;0000000118 designated official
access;0000000405 destination customers
access;0000000276 agricultural forestry
access;0000008574 private
access;0000002145 no
foot;0000080681 yes permissive
foot;0000000326 designated official
foot;0000000023 destination
foot;0000000156 private
foot;0000009170 no
bicycle;0000076717 yes permissive
bicycle;0000000406 designated official
bicycle;0000000018 destination
bicycle;0000000081 dismount
bicycle;0000000051 private
bicycle;0000016121 no
motorcar;0000005785 yes permissive
motorcar;0000000026 designated official
motorcar;0000000080 destination
motorcar;0000000112 agricultural forestry
motorcar;0000000171 private
motorcar;0000001817 no
motor_vehicle;0000000066 yes permissive
motor_vehicle;0000000000 designated official
motor_vehicle;0000000030 destination
motor_vehicle;0000000073 agricultural forestry
motor_vehicle;0000000136 private
motor_vehicle;0000000469 no
motorcycle;0000004515 yes permissive
motorcycle;0000000007 designated official
motorcycle;0000000054 destination
motorcycle;0000000027 agricultural forestry
motorcycle;0000000063 private
motorcycle;0000001637 no
vehicle;0000000058 yes permissive
vehicle;0000000000 designated
vehicle;0000000081 destination
vehicle;0000000038 agricultural forestry
vehicle;0000000041 private
vehicle;0000000271 no
crossing;0000032485 traffic_signals
crossing;0000014300 uncontrolled
crossing;0000005086 island
crossing;0000001565 unmarked
crossing;0000001066 no
crossing;0000000333 zebra
railway;0000034039 level_crossing
railway;0000010175 crossing
noexit;0000043010 yes
entrance;0000015094 yes
entrance;0000007079 main
entrance;0000000554 service
entrance;0000000169 emergency
entrance;0000000063 exit
entrance;0000000008 private
lcn;0000018999 yes
longdistancecycleway;0000000001 yes

13
brouter-mapaccess/pom.xml Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>0.98</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-mapaccess</artifactId>
<packaging>jar</packaging>
</project>

View file

@ -0,0 +1,59 @@
/**
* fast data-reading from a byte-array
*
* @author ab
*/
package btools.mapaccess;
final class ByteDataReader
{
private byte[] ab;
private int aboffset;
public ByteDataReader( byte[] byteArray )
{
ab = byteArray;
}
public int readInt()
{
int i3 = ab[aboffset++]& 0xff;
int i2 = ab[aboffset++]& 0xff;
int i1 = ab[aboffset++]& 0xff;
int i0 = ab[aboffset++]& 0xff;
return (i3 << 24) + (i2 << 16) + (i1 << 8) + i0;
}
public long readLong()
{
long i7 = ab[aboffset++]& 0xff;
long i6 = ab[aboffset++]& 0xff;
long i5 = ab[aboffset++]& 0xff;
long i4 = ab[aboffset++]& 0xff;
long i3 = ab[aboffset++]& 0xff;
long i2 = ab[aboffset++]& 0xff;
long i1 = ab[aboffset++]& 0xff;
long i0 = ab[aboffset++]& 0xff;
return (i7 << 56) + (i6 << 48) + (i5 << 40) + (i4 << 32) + (i3 << 24) + (i2 << 16) + (i1 << 8) + i0;
}
public boolean readBoolean()
{
int i0 = ab[aboffset++]& 0xff;
return i0 != 0;
}
public byte readByte()
{
int i0 = ab[aboffset++] & 0xff;
return (byte)(i0);
}
public short readShort()
{
int i1 = ab[aboffset++] & 0xff;
int i0 = ab[aboffset++] & 0xff;
return (short)( (i1 << 8) | i0);
}
}

View file

@ -0,0 +1,54 @@
/**
* fast data-reading from a byte-array
*
* @author ab
*/
package btools.mapaccess;
final class ByteDataWriter
{
private byte[] ab;
private int aboffset;
public ByteDataWriter( byte[] byteArray )
{
ab = byteArray;
}
public void writeInt( int v )
{
ab[aboffset++] = (byte)( (v >> 24) & 0xff );
ab[aboffset++] = (byte)( (v >> 16) & 0xff );
ab[aboffset++] = (byte)( (v >> 8) & 0xff );
ab[aboffset++] = (byte)( (v ) & 0xff );
}
public void writeLong( long v )
{
ab[aboffset++] = (byte)( (v >> 56) & 0xff );
ab[aboffset++] = (byte)( (v >> 48) & 0xff );
ab[aboffset++] = (byte)( (v >> 40) & 0xff );
ab[aboffset++] = (byte)( (v >> 32) & 0xff );
ab[aboffset++] = (byte)( (v >> 24) & 0xff );
ab[aboffset++] = (byte)( (v >> 16) & 0xff );
ab[aboffset++] = (byte)( (v >> 8) & 0xff );
ab[aboffset++] = (byte)( (v ) & 0xff );
}
public void writeBoolean( boolean v)
{
ab[aboffset++] = (byte)( v ? 1 : 0 );
}
public void writeByte( int v )
{
ab[aboffset++] = (byte)( (v ) & 0xff );
}
public void writeShort( int v )
{
ab[aboffset++] = (byte)( (v >> 8) & 0xff );
ab[aboffset++] = (byte)( (v ) & 0xff );
}
}

View file

@ -0,0 +1,16 @@
/**
* Container for routig configs
*
* @author ab
*/
package btools.mapaccess;
public interface DistanceChecker
{
/**
* Checks whether the given path is within a maximum distance
* known to the distance checker
* @return true if close enough
*/
boolean isWithinRadius( int ilon0, int ilat0, OsmTransferNode firstTransfer, int ilon1, int ilat1 );
}

View file

@ -0,0 +1,232 @@
/**
* cache for a single square
*
* @author ab
*/
package btools.mapaccess;
import java.util.*;
import java.io.*;
final class MicroCache
{
private long[] faid;
private int[] fapos;
private int size = 0;
private int delcount = 0;
private int delbytes = 0;
private int p2size; // next power of 2 of size
// the object parsing position and length
private byte[] ab;
private int aboffset;
private int ablength;
public MicroCache( OsmFile segfile, int lonIdx80, int latIdx80, byte[] iobuffer ) throws Exception
{
int lonDegree = lonIdx80/80;
int latDegree = latIdx80/80;
int lonIdxBase = (lonIdx80/5)*62500 + 31250;
int latIdxBase = (latIdx80/5)*62500 + 31250;
int subIdx = (latIdx80-80*latDegree)*80 + (lonIdx80-80*lonDegree);
try
{
ab = iobuffer;
int asize = segfile.getDataInputForSubIdx(subIdx, ab);
if ( asize == 0 )
{
return;
}
if ( asize > iobuffer.length )
{
ab = new byte[asize];
asize = segfile.getDataInputForSubIdx(subIdx, ab);
}
aboffset = 0;
size = readInt();
// new array with only net data
byte[] nab = new byte[asize - 4 - size*8];
int noffset = 0;
faid = new long[size];
fapos = new int[size];
p2size = 0x40000000;
while( p2size > size ) p2size >>= 1;
for(int i = 0; i<size; i++)
{
int ilon = readShort();
int ilat = readShort();
ilon += lonIdxBase;
ilat += latIdxBase;
long nodeId = ((long)ilon)<<32 | ilat;
faid[i] = nodeId;
int bodySize = readInt();
fapos[i] = noffset;
System.arraycopy( ab, aboffset, nab, noffset, bodySize );
aboffset += bodySize;
noffset += bodySize;
}
ab = nab;
}
catch( EOFException eof )
{
}
}
public int getSize()
{
return size;
}
/**
* @return the value for "id",
* Throw an exception if not contained in the map.
*/
private boolean getAndClear( long id )
{
if ( size == 0 )
{
return false;
}
long[] a = faid;
int offset = p2size;
int n = 0;
while ( offset> 0 )
{
int nn = n + offset;
if ( nn < size && a[nn] <= id )
{
n = nn;
}
offset >>= 1;
}
if ( a[n] == id )
{
if ( ( fapos[n] & 0x80000000 ) == 0 )
{
aboffset = fapos[n];
ablength = ( n+1 < size ? fapos[n+1] & 0x7fffffff : ab.length ) - aboffset;
fapos[n] |= 0x80000000; // mark deleted
delbytes+= ablength;
delcount++;
return true;
}
else
{
throw new RuntimeException( "MicroCache: node already consumed: id=" + id );
}
}
return false;
}
public void fillNode( OsmNode node, OsmNodesMap nodesMap, DistanceChecker dc )
{
long id = node.getIdFromPos();
if ( getAndClear( id ) )
{
node.parseNodeBody( this, ablength, nodesMap, dc );
}
if ( delcount > size / 2 ) // garbage collection
{
int nsize = size - delcount;
if ( nsize == 0 )
{
faid = null;
fapos = null;
}
else
{
long[] nfaid = new long[nsize];
int[] nfapos = new int[nsize];
int idx = 0;
byte[] nab = new byte[ab.length - delbytes];
int nab_off = 0;
for( int i=0; i<size; i++ )
{
int pos = fapos[i];
if ( ( pos & 0x80000000 ) == 0 )
{
ablength = ( i+1 < size ? fapos[i+1] & 0x7fffffff : ab.length ) - pos;
System.arraycopy( ab, pos, nab, nab_off, ablength );
nfaid[idx] = faid[i];
nfapos[idx] = nab_off;
nab_off += ablength;
idx++;
}
}
faid = nfaid;
fapos = nfapos;
ab = nab;
}
size = nsize;
delcount = 0;
delbytes = 0;
p2size = 0x40000000;
while( p2size > size ) p2size >>= 1;
}
}
public List<OsmNode> getPositions( OsmNodesMap nodesMap )
{
ArrayList<OsmNode> positions = new ArrayList<OsmNode>();
for( int i=0; i<size; i++ )
{
OsmNode n = new OsmNode( faid[i] );
n.setHollow();
nodesMap.put( faid[i], n );
positions.add( n );
}
return positions;
}
public int readInt()
{
int i3 = ab[aboffset++]& 0xff;
int i2 = ab[aboffset++]& 0xff;
int i1 = ab[aboffset++]& 0xff;
int i0 = ab[aboffset++]& 0xff;
return (i3 << 24) + (i2 << 16) + (i1 << 8) + i0;
}
public long readLong()
{
long i7 = ab[aboffset++]& 0xff;
long i6 = ab[aboffset++]& 0xff;
long i5 = ab[aboffset++]& 0xff;
long i4 = ab[aboffset++]& 0xff;
long i3 = ab[aboffset++]& 0xff;
long i2 = ab[aboffset++]& 0xff;
long i1 = ab[aboffset++]& 0xff;
long i0 = ab[aboffset++]& 0xff;
return (i7 << 56) + (i6 << 48) + (i5 << 40) + (i4 << 32) + (i3 << 24) + (i2 << 16) + (i1 << 8) + i0;
}
public boolean readBoolean()
{
int i0 = ab[aboffset++]& 0xff;
return i0 != 0;
}
public byte readByte()
{
int i0 = ab[aboffset++] & 0xff;
return (byte)(i0);
}
public short readShort()
{
int i1 = ab[aboffset++] & 0xff;
int i0 = ab[aboffset++] & 0xff;
return (short)( (i1 << 8) | i0);
}
}

View file

@ -0,0 +1,223 @@
/**
* Efficient cache or osmnodes
*
* @author ab
*/
package btools.mapaccess;
import java.util.*;
import java.io.*;
public final class NodesCache
{
private String segmentDir;
private OsmNodesMap nodesMap;
private int lookupVersion;
private boolean carMode;
private String currentFileName;
private HashMap<String,RandomAccessFile> fileCache;
private HashMap<String,long[]> indexCache;
private byte[] iobuffer;
private OsmFile[][] fileRows = new OsmFile[180][];
private ArrayList<MicroCache> segmentList = new ArrayList<MicroCache>();
public DistanceChecker distanceChecker;
public boolean oom_carsubset_hint = false;
public NodesCache( String segmentDir, OsmNodesMap nodesMap, int lookupVersion, boolean carMode, NodesCache oldCache )
{
this.segmentDir = segmentDir;
this.nodesMap = nodesMap;
this.lookupVersion = lookupVersion;
this.carMode = carMode;
if ( oldCache != null )
{
fileCache = oldCache.fileCache;
indexCache = oldCache.indexCache;
iobuffer = oldCache.iobuffer;
oom_carsubset_hint = oldCache.oom_carsubset_hint;
}
else
{
fileCache = new HashMap<String,RandomAccessFile>(4);
indexCache = new HashMap<String,long[]>(4);
iobuffer = new byte[65636];
}
}
public int loadSegmentFor( int ilon, int ilat )
{
MicroCache mc = getSegmentFor( ilon, ilat );
return mc == null ? 0 : mc.getSize();
}
public MicroCache getSegmentFor( int ilon, int ilat )
{
try
{
int lonIdx80 = ilon/12500;
int latIdx80 = ilat/12500;
int lonDegree = lonIdx80/80;
int latDegree = latIdx80/80;
OsmFile osmf = null;
OsmFile[] fileRow = fileRows[latDegree];
int ndegrees = fileRow == null ? 0 : fileRow.length;
for( int i=0; i<ndegrees; i++ )
{
if ( fileRow[i].lonDegree == lonDegree )
{
osmf = fileRow[i];
break;
}
}
if ( osmf == null )
{
osmf = fileForSegment( lonDegree, latDegree );
OsmFile[] newFileRow = new OsmFile[ndegrees+1];
for( int i=0; i<ndegrees; i++ )
{
newFileRow[i] = fileRow[i];
}
newFileRow[ndegrees] = osmf;
fileRows[latDegree] = newFileRow;
}
currentFileName = osmf.filename;
if ( osmf.microCaches == null )
{
return null;
}
int subIdx = (latIdx80-80*latDegree)*80 + (lonIdx80-80*lonDegree);
MicroCache segment = osmf.microCaches[subIdx];
if ( segment == null )
{
// nodesMap.removeCompleteNodes();
segment = new MicroCache( osmf, lonIdx80, latIdx80, iobuffer );
osmf.microCaches[subIdx] = segment;
segmentList.add( segment );
}
return segment;
}
catch( RuntimeException re )
{
throw re;
}
catch( Exception e )
{
throw new RuntimeException( "error reading datafile " + currentFileName + ": " + e );
}
}
public boolean obtainNonHollowNode( OsmNode node )
{
if ( !node.isHollow() ) return true;
MicroCache segment = getSegmentFor( node.ilon, node.ilat );
if ( segment == null )
{
return false;
}
segment.fillNode( node, nodesMap, distanceChecker );
return !node.isHollow();
}
private OsmFile fileForSegment( int lonDegree, int latDegree ) throws Exception
{
File base = new File( segmentDir );
if ( !base.isDirectory() ) throw new RuntimeException( "segment directory " + segmentDir + " does not exist" );
int lonMod5 = lonDegree % 5;
int latMod5 = latDegree % 5;
int tileIndex = lonMod5 * 5 + latMod5;
int lon = lonDegree - 180 - lonMod5;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
int lat = latDegree - 90 - latMod5;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
String filenameBase = slon + "_" + slat;
currentFileName = filenameBase + ".rd5/cd5";
if ( !fileCache.containsKey( filenameBase ) )
{
File f = null;
if ( carMode )
{
File carFile = new File( new File( base, "carsubset" ), filenameBase + ".cd5" );
if ( carFile.exists() ) f = carFile;
}
if ( f == null )
{
File fullFile = new File( base, filenameBase + ".rd5" );
if ( fullFile.exists() ) f = fullFile;
if ( carMode && f != null ) oom_carsubset_hint = true;
}
RandomAccessFile ra = f != null ? new RandomAccessFile( f, "r" ) : null;
fileCache.put( filenameBase, ra );
if ( ra != null )
{
long[] fileIndex = new long[25];
ra.readFully( iobuffer, 0, 200 );
ByteDataReader dis = new ByteDataReader( iobuffer );
for( int i=0; i<25; i++ )
{
long lv = dis.readLong();
short readVersion = (short)(lv >> 48);
if ( readVersion != lookupVersion )
{
throw new IllegalArgumentException( "lookup version mismatch (old rd5?) lookups.dat="
+ lookupVersion + " " + f. getAbsolutePath() + "=" + readVersion );
}
fileIndex[i] = lv & 0xffffffffffffL;
}
indexCache.put( filenameBase, fileIndex );
}
}
RandomAccessFile ra = fileCache.get( filenameBase );
long startPos = 0L;
if ( ra != null )
{
long[] index = indexCache.get( filenameBase );
startPos = tileIndex > 0 ? index[ tileIndex-1 ] : 200L;
if ( startPos == index[ tileIndex] ) ra = null;
}
OsmFile osmf = new OsmFile( ra, startPos, iobuffer );
osmf.lonDegree = lonDegree;
osmf.latDegree = latDegree;
osmf.filename = currentFileName;
return osmf;
}
public List<OsmNode> getAllNodes()
{
List<OsmNode> all = new ArrayList<OsmNode>();
for( MicroCache segment : segmentList )
{
List<OsmNode> positions = segment.getPositions( nodesMap );
all.addAll( positions );
}
return all;
}
public void close()
{
for( RandomAccessFile f: fileCache.values() )
{
try
{
f.close();
}
catch( IOException ioe )
{
// ignore
}
}
}
}

View file

@ -0,0 +1,14 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
import java.util.*;
final class NodesList
{
public OsmNode node;
public NodesList next;
}

View file

@ -0,0 +1,67 @@
/**
* cache for a single square
*
* @author ab
*/
package btools.mapaccess;
import java.io.IOException;
import java.io.RandomAccessFile;
final class OsmFile
{
private RandomAccessFile is = null;
private long fileOffset;
private int[] posIdx;
public MicroCache[] microCaches;
public int lonDegree;
public int latDegree;
public String filename;
public OsmFile( RandomAccessFile rafile, long startPos, byte[] iobuffer ) throws Exception
{
fileOffset = startPos;
if ( rafile != null )
{
is = rafile;
posIdx = new int[6400];
microCaches = new MicroCache[6400];
is.seek( fileOffset );
is.readFully( iobuffer, 0, 25600 );
ByteDataReader dis = new ByteDataReader( iobuffer );
for( int i=0; i<6400; i++ )
{
posIdx[i] = dis.readInt();
}
}
}
private int getPosIdx( int idx )
{
return idx == -1 ? 25600 : posIdx[idx];
}
public int getDataInputForSubIdx( int subIdx, byte[] iobuffer ) throws Exception
{
int startPos = getPosIdx(subIdx-1);
int endPos = getPosIdx(subIdx);
int size = endPos-startPos;
if ( size > 0 )
{
is.seek( fileOffset + startPos );
if ( size <= iobuffer.length )
{
is.readFully( iobuffer );
}
}
return size;
}
public void close()
{
try { is.close(); } catch( IOException e ) { throw new RuntimeException( e ); }
}
}

View file

@ -0,0 +1,53 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
import java.util.*;
public final class OsmLink
{
/**
* The description bitmap is mainly the way description
* used to calculate the costfactor
*/
public long descriptionBitmap;
/**
* The target is either the next link or the target node
*/
public OsmNode targetNode;
/**
* The origin position
*/
public int ilatOrigin;
public int ilonOrigin;
public OsmLink next;
public byte[] firsttransferBytes;
public OsmTransferNode decodeFirsttransfer()
{
return firsttransferBytes == null ? null : OsmTransferNode.decode( firsttransferBytes );
}
public void encodeFirsttransfer( OsmTransferNode firsttransfer )
{
if ( firsttransfer == null ) firsttransferBytes = null;
else firsttransferBytes = OsmTransferNode.encode( firsttransfer );
}
public boolean counterLinkWritten;
public OsmLinkHolder firstlinkholder = null;
public void addLinkHolder( OsmLinkHolder holder )
{
if ( firstlinkholder != null ) { holder.setNextForLink( firstlinkholder ); }
firstlinkholder = holder;
}
}

View file

@ -0,0 +1,13 @@
/**
* Container for routig configs
*
* @author ab
*/
package btools.mapaccess;
public interface OsmLinkHolder
{
void setNextForLink( OsmLinkHolder holder );
OsmLinkHolder getNextForLink();
}

View file

@ -0,0 +1,397 @@
/**
* Container for an osm node
*
* @author ab
*/
package btools.mapaccess;
public class OsmNode implements OsmPos, Comparable
{
private static final long serialVersionUID = -4166565134085275556L;
public static final int EXTERNAL_BITMASK = 0x80;
public static final int FIRSTFORWAY_BITMASK = 0x40;
public static final int TRANSFERNODE_BITMASK = 0x20;
public static final int WRITEDESC_BITMASK = 0x10;
public static final int SKIPDETAILS_BITMASK = 0x08;
public static final int NODEDESC_BITMASK = 0x04;
public OsmNode()
{
}
public OsmNode( int ilon, int ilat )
{
this.ilon = ilon;
this.ilat = ilat;
}
public OsmNode( long id )
{
ilon = (int)(id >> 32);
ilat = (int)(id & 0xffffffff);
}
/**
* The latitude
*/
public int ilat;
/**
* The longitude
*/
public int ilon;
/**
* The elevation
*/
public short selev;
public long nodeDescription;
// interface OsmPos
public int getILat()
{
return ilat;
}
public int getILon()
{
return ilon;
}
public short getSElev()
{
return selev;
}
public double getElev()
{
return selev / 4.;
}
/**
* Whether there's a traffic signal
*/
/**
* The links to other nodes
*/
public OsmLink firstlink = null;
public OsmLink firstreverse = null;
// whether this node is completed and registerd for map-removal
public boolean completed;
public boolean wasProcessed;
public int maxcost; // maximum cost to consider for that node
public void addLink( OsmLink link )
{
if ( firstlink != null ) link.next = firstlink;
firstlink = link;
}
public int calcDistance( OsmPos p )
{
double l = (ilat-90000000) * 0.00000001234134;
double l2 = l*l;
double l4 = l2*l2;
double coslat = 1.- l2 + l4 / 6.;
double dlat = (ilat - p.getILat() )/1000000.;
double dlon = (ilon - p.getILon() )/1000000. * coslat;
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * (6378000. / 57.3);
return (int)(d + 1.0 );
}
public void parseNodeBody( MicroCache is, int bodySize, OsmNodesMap hollowNodes, DistanceChecker dc )
{
selev = is.readShort();
bodySize -= 2;
OsmLink lastlink = null;
int lonIdx = ilon/62500;
int latIdx = ilat/62500;
while( bodySize > 0 )
{
OsmLink link = new OsmLink();
OsmTransferNode firstTransferNode = null;
OsmTransferNode lastTransferNode = null;
int linklon;
int linklat;
long description = 0L;
for(;;)
{
int bitField = is.readByte();
bodySize -= 1;
if ( (bitField & EXTERNAL_BITMASK) != 0 )
{
// full position for external target
bodySize -= 8;
linklon = is.readInt();
linklat = is.readInt();
}
else
{
// reduced position for internal target
bodySize -= 4;
linklon = is.readShort();
linklat = is.readShort();
linklon += lonIdx*62500 + 31250;
linklat += latIdx*62500 + 31250;
}
if ( (bitField & WRITEDESC_BITMASK ) != 0 )
{
description = is.readLong();
bodySize -= 8;
}
if ( (bitField & NODEDESC_BITMASK ) != 0 )
{
nodeDescription = is.readLong();
bodySize -= 8;
}
if ( (bitField & SKIPDETAILS_BITMASK ) != 0 )
{
link.counterLinkWritten = true;
}
boolean isTransfer = (bitField & TRANSFERNODE_BITMASK ) != 0;
if ( isTransfer )
{
OsmTransferNode trans = new OsmTransferNode();
trans.ilon = linklon;
trans.ilat = linklat;
trans.descriptionBitmap = description;
bodySize -= 2;
trans.selev = is.readShort();
if ( lastTransferNode == null )
{
firstTransferNode = trans;
}
else
{
lastTransferNode.next = trans;
}
lastTransferNode = trans;
}
else
{
link.descriptionBitmap = description;
break;
}
}
// performance shortcut: ignore link if out of reach
if ( dc != null && !link.counterLinkWritten )
{
if ( !dc.isWithinRadius( ilon, ilat, firstTransferNode, linklon, linklat ) )
{
continue;
}
}
if ( linklon == ilon && linklat == ilat )
{
continue; // skip self-ref
}
if ( lastlink == null )
{
firstlink = link;
}
else
{
lastlink.next = link;
}
lastlink = link;
long targetNodeId = ((long)linklon)<<32 | linklat;
OsmNode tn = hollowNodes.get( targetNodeId ); // target node
if ( tn == null )
{
// node not yet known, create a hollow proxy
tn = new OsmNode(linklon, linklat);
tn.setHollow();
hollowNodes.put( targetNodeId, tn );
}
else
{
if ( !( tn.isHollow() || tn.hasHollowLinks() ) )
{
hollowNodes.registerCompletedNode( tn );
}
}
link.targetNode = tn;
link.encodeFirsttransfer(firstTransferNode);
// compute the reverse link
if ( !link.counterLinkWritten )
{
OsmLink rlink = new OsmLink();
long rerverseLinkBitmap = link.descriptionBitmap ^ 1L;
rlink.ilonOrigin = tn.ilon;
rlink.ilatOrigin = tn.ilat;
rlink.targetNode = this;
rlink.descriptionBitmap = rerverseLinkBitmap; // default for no transfer-nodes
OsmTransferNode previous = null;
OsmTransferNode rtrans = null;
for( OsmTransferNode trans = firstTransferNode; trans != null; trans = trans.next )
{
long rerverseTransBitmap = trans.descriptionBitmap ^ 1L;
if ( previous == null )
{
rlink.descriptionBitmap = rerverseTransBitmap;
}
else
{
previous.descriptionBitmap = rerverseTransBitmap;
}
rtrans = new OsmTransferNode();
rtrans.ilon = trans.ilon;
rtrans.ilat = trans.ilat;
rtrans.selev = trans.selev;
rtrans.next = previous;
rtrans.descriptionBitmap = rerverseLinkBitmap;
previous = rtrans;
}
rlink.encodeFirsttransfer(rtrans);
rlink.next = firstreverse;
firstreverse = rlink;
}
}
if ( !hasHollowLinks() )
{
hollowNodes.registerCompletedNode( this );
}
}
public boolean isHollow()
{
return selev == -12345;
}
public void setHollow()
{
selev = -12345;
}
public long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
}
public boolean hasHollowLinks()
{
for( OsmLink link = firstlink; link != null; link = link.next )
{
if ( link.targetNode.isHollow() ) return true;
}
return false;
}
public int linkCnt()
{
int cnt = 0;
for( OsmLink link = firstlink; link != null; link = link.next )
{
cnt++;
}
return cnt;
}
public void unlinkLink( OsmLink link )
{
if ( link == firstlink )
{
firstlink = link.next;
return;
}
for( OsmLink l = firstlink; l != null; l = l.next )
{
if ( l.next == link )
{
l.next = link.next;
return;
}
}
}
/**
* Compares two OsmNodes for position ordering.
*
* @return -1,0,1 depending an comparson result
*/
public int compareTo( Object o )
{
OsmNode n = (OsmNode)o;
long id1 = getIdFromPos();
long id2 = n.getIdFromPos();
if ( id1 < id2 ) return -1;
if ( id1 > id2 ) return 1;
return 0;
}
/**
* @return if equals in the sense of compareTo == 0
*/
public boolean equals( Object o )
{
return compareTo( o ) == 0;
}
// mark the link to the given node as written,
// don't want to write the counter-direction
// in full details
public void markLinkWritten( OsmNode t )
{
for( OsmLink link = firstlink; link != null; link = link.next )
{
if ( link.targetNode == t) link.counterLinkWritten = true;
}
}
public OsmLink getReverseLink( int lon, int lat )
{
for( OsmLink rlink = firstreverse; rlink != null; rlink = rlink.next )
{
if ( rlink.ilonOrigin == lon && rlink.ilatOrigin == lat )
{
unlinkRLink( rlink );
return rlink;
}
}
return null;
}
public void unlinkRLink( OsmLink rlink )
{
if ( rlink == firstreverse )
{
firstreverse = rlink.next;
return;
}
for( OsmLink l = firstreverse; l != null; l = l.next )
{
if ( l.next == rlink )
{
l.next = rlink.next;
return;
}
}
}
}

View file

@ -0,0 +1,109 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
import java.util.*;
public final class OsmNodesMap
{
private HashMap<Long,OsmNode> hmap = new HashMap<Long,OsmNode>();
private NodesList completedNodes = null;
/**
* Get a node from the map
* @return the node for the given id if exist, else null
*/
public OsmNode get( long id )
{
return hmap.get( new Long( id ) );
}
public void remove( long id )
{
hmap.remove( new Long( id ) );
}
public void removeCompletedNodes()
{
for( NodesList le = completedNodes; le != null; le = le.next )
{
remove( le.node.getIdFromPos() );
}
completedNodes = null;
}
public void registerCompletedNode( OsmNode n )
{
if ( n.completed ) return;
n.completed = true;
NodesList le = new NodesList();
le.node = n;
if ( completedNodes != null ) le.next = completedNodes;
completedNodes = le;
}
/**
* Put a node into the map
* @return the previous node if that id existed, else null
*/
public OsmNode put( long id, OsmNode node )
{
return hmap.put( new Long( id ), node );
}
/**
* Return the internal list.
* A reference is returned, not a copy-
* @return the nodes list
*/
public Collection<OsmNode> nodes()
{
return hmap.values();
}
/**
* @return the number of nodes in that map
*/
public int size()
{
return hmap.size();
}
/**
* cleanup the map by removing the nodes
* with no hollow issues
*/
private int dontCareCount = 0;
public void removeCompleteNodes()
{
if ( ++dontCareCount < 5 ) return;
dontCareCount = 0;
ArrayList<OsmNode> delNodes = new ArrayList<OsmNode>();
for( OsmNode n : hmap.values() )
{
if ( n.isHollow() || n.hasHollowLinks() )
{
continue;
}
delNodes.add( n );
}
if ( delNodes.size() > 0 )
{
// System.out.println( "removing " + delNodes.size() + " nodes" );
for( OsmNode n : delNodes )
{
hmap.remove( new Long( n.getIdFromPos() ) );
}
}
}
}

View file

@ -0,0 +1,23 @@
/**
* Interface for a position (OsmNode or OsmPath)
*
* @author ab
*/
package btools.mapaccess;
public interface OsmPos
{
public int getILat();
public int getILon();
public short getSElev();
public double getElev();
public int calcDistance( OsmPos p );
public long getIdFromPos();
}

View file

@ -0,0 +1,144 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public final class OsmTransferNode
{
/**
* The description bitmap is mainly the way description
* used to calculate the costfactor
*/
public long descriptionBitmap;
public OsmTransferNode next;
public int ilon;
public int ilat;
public short selev;
private static final int BIT_DESC = 1;
private static final int BIT_ILONHIGH = 2;
private static final int BIT_ILATHIGH = 4;
private static final int BIT_STOP = 8;
// encode this transfer-node into a byte array
public static byte[] encode( OsmTransferNode tn )
{
long currentDesc = 0;
int currentILonHigh = 0;
int currentILatHigh = 0;
OsmTransferNode n = tn;
// first loop to calc size
int size = 1; // stop-bit
while( n != null )
{
if( n.descriptionBitmap != currentDesc )
{
size += 8;
currentDesc = n.descriptionBitmap;
}
if( ( n.ilon >> 16 ) != currentILonHigh )
{
size += 2;
currentILonHigh = n.ilon >> 16;
}
if( (n.ilat >> 16) != currentILatHigh )
{
size += 2;
currentILatHigh = n.ilat >> 16;
}
size += 7;
n = n.next;
}
byte[] ab = new byte[size];
ByteDataWriter os = new ByteDataWriter( ab );
currentDesc = 0;
currentILonHigh = 0;
currentILatHigh = 0;
n = tn;
while( n != null )
{
int mode = 0;
if( n.descriptionBitmap != currentDesc )
{
mode |= BIT_DESC;
currentDesc = n.descriptionBitmap;
}
if( ( n.ilon >> 16 ) != currentILonHigh )
{
mode |= BIT_ILONHIGH;
currentILonHigh = n.ilon >> 16;
}
if( (n.ilat >> 16) != currentILatHigh )
{
mode |= BIT_ILATHIGH;
currentILatHigh = n.ilat >> 16;
}
os.writeByte( mode);
if ( (mode & BIT_DESC) != 0 ) os.writeLong( currentDesc );
if ( (mode & BIT_ILONHIGH) != 0 ) os.writeShort( currentILonHigh );
if ( (mode & BIT_ILATHIGH) != 0 ) os.writeShort( currentILatHigh );
os.writeShort( n.ilon );
os.writeShort( n.ilat );
os.writeShort( n.selev );
n = n.next;
}
os.writeByte( BIT_STOP );
return ab;
}
// decode a transfer-node from a byte array
public static OsmTransferNode decode( byte[] ab )
{
ByteDataReader is = new ByteDataReader( ab );
OsmTransferNode firstNode = null;
OsmTransferNode lastNode = null;
long currentDesc = 0;
int currentILonHigh = 0;
int currentILatHigh = 0;
for(;;)
{
byte mode = is.readByte();
if ( (mode & BIT_STOP ) != 0 ) break;
OsmTransferNode n = new OsmTransferNode();
if ( (mode & BIT_DESC) != 0 ) currentDesc = is.readLong();
if ( (mode & BIT_ILONHIGH) != 0 ) currentILonHigh = is.readShort();
if ( (mode & BIT_ILATHIGH) != 0 ) currentILatHigh = is.readShort();
n.descriptionBitmap = currentDesc;
int ilon = is.readShort() & 0xffff; ilon |= currentILonHigh << 16;
int ilat = is.readShort() & 0xffff; ilat |= currentILatHigh << 16;
n.ilon = ilon;
n.ilat = ilat;
n.selev = is.readShort();
if ( ilon != n.ilon ) System.out.println( "ilon=" + ilon + " n.ilon=" + n.ilon );
if ( ilat != n.ilat ) System.out.println( "ilat=" + ilat + " n.ilat=" + n.ilat );
if ( lastNode != null )
{
lastNode.next = n;
}
else
{
firstNode = n;
}
lastNode = n;
}
return firstNode;
}
}

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" package="btools.routingapp">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BRouterActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:exported="true"
android:name=".BRouterService"
android:enabled="true"
android:process=":brouter_service">
</service>
</application>
<uses-sdk android:minSdkVersion="5"></uses-sdk>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
</manifest>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View file

@ -0,0 +1,5 @@
package btools.routingapp;
public final class BuildConfig {
public static final boolean DEBUG = true;
}

View file

@ -0,0 +1,136 @@
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\brouter\\brouter-routing-app\\src\\main\\java\\btools\\routingapp\\IBRouterService.aidl
*/
package btools.routingapp;
public interface IBRouterService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements btools.routingapp.IBRouterService
{
private static final java.lang.String DESCRIPTOR = "btools.routingapp.IBRouterService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an btools.routingapp.IBRouterService interface,
* generating a proxy if needed.
*/
public static btools.routingapp.IBRouterService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof btools.routingapp.IBRouterService))) {
return ((btools.routingapp.IBRouterService)iin);
}
return new btools.routingapp.IBRouterService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getTrackFromParams:
{
data.enforceInterface(DESCRIPTOR);
android.os.Bundle _arg0;
if ((0!=data.readInt())) {
_arg0 = android.os.Bundle.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.lang.String _result = this.getTrackFromParams(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements btools.routingapp.IBRouterService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
//param params--> Map of params:
// "pathToFileResult"-->String with the path to where the result must be saved, including file name and extension
// -->if null, the track is passed via the return argument
// "maxRunningTime"-->String with a number of seconds for the routing timeout, default = 60
// "trackFormat"-->[kml|gpx] default = gpx
// "lats"-->double[] array of latitudes; 2 values at least.
// "lons"-->double[] array of longitudes; 2 values at least.
// "nogoLats"-->double[] array of nogo latitudes; may be null.
// "nogoLons"-->double[] array of nogo longitudes; may be null.
// "nogoRadi"-->double[] array of nogo radius in meters; may be null.
// "fast"-->[0|1]
// "v"-->[motorcar|bicycle|foot]
//return null if all ok and no path given, the track if ok and path given, an error message if it was wrong
//call in a background thread, heavy task!
@Override public java.lang.String getTrackFromParams(android.os.Bundle params) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((params!=null)) {
_data.writeInt(1);
params.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_getTrackFromParams, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getTrackFromParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
//param params--> Map of params:
// "pathToFileResult"-->String with the path to where the result must be saved, including file name and extension
// -->if null, the track is passed via the return argument
// "maxRunningTime"-->String with a number of seconds for the routing timeout, default = 60
// "trackFormat"-->[kml|gpx] default = gpx
// "lats"-->double[] array of latitudes; 2 values at least.
// "lons"-->double[] array of longitudes; 2 values at least.
// "nogoLats"-->double[] array of nogo latitudes; may be null.
// "nogoLons"-->double[] array of nogo longitudes; may be null.
// "nogoRadi"-->double[] array of nogo radius in meters; may be null.
// "fast"-->[0|1]
// "v"-->[motorcar|bicycle|foot]
//return null if all ok and no path given, the track if ok and path given, an error message if it was wrong
//call in a background thread, heavy task!
public java.lang.String getTrackFromParams(android.os.Bundle params) throws android.os.RemoteException;
}

View file

@ -0,0 +1,22 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package btools.routingapp;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040000;
}
}

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>0.98</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-routing-app</artifactId>
<packaging>apk</packaging>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>AccelerometerPlay</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-10

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</LinearLayout>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name">BRouter</string>
</resources>

View file

@ -0,0 +1,375 @@
package btools.routingapp;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.view.Display;
import android.view.WindowManager;
import android.widget.EditText;
import btools.router.OsmNodeNamed;
public class BRouterActivity extends Activity implements OnInitListener {
private static final int DIALOG_SELECTPROFILE_ID = 1;
private static final int DIALOG_EXCEPTION_ID = 2;
private static final int DIALOG_WARNEXPIRY_ID = 3;
private static final int DIALOG_TEXTENTRY_ID = 4;
private static final int DIALOG_VIASELECT_ID = 5;
private static final int DIALOG_NOGOSELECT_ID = 6;
private static final int DIALOG_SHOWRESULT_ID = 7;
private static final int DIALOG_ROUTINGMODES_ID = 8;
private static final int DIALOG_MODECONFIGOVERVIEW_ID = 9;
private static final int DIALOG_PICKWAYPOINT_ID = 10;
private BRouterView mBRouterView;
private PowerManager mPowerManager;
private WindowManager mWindowManager;
private Display mDisplay;
private WakeLock mWakeLock;
/** Called when the activity is first created. */
@Override
@SuppressWarnings("deprecation")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get an instance of the PowerManager
mPowerManager = (PowerManager) getSystemService(POWER_SERVICE);
// Get an instance of the WindowManager
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
// Create a bright wake lock
mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass()
.getName());
// instantiate our simulation view and set it as the activity's content
mBRouterView = new BRouterView(this);
setContentView(mBRouterView);
}
@Override
@SuppressWarnings("deprecation")
protected Dialog onCreateDialog(int id)
{
AlertDialog.Builder builder;
switch(id)
{
case DIALOG_SELECTPROFILE_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle("Select a routing profile");
builder.setItems(availableProfiles, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
selectedProfile = availableProfiles[item];
mBRouterView.startProcessing(selectedProfile);
}
});
return builder.create();
case DIALOG_ROUTINGMODES_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle( message );
builder.setMultiChoiceItems(routingModes, routingModesChecked, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which,
boolean isChecked) {
routingModesChecked[which] = isChecked;
}
});
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mBRouterView.configureService(routingModes,routingModesChecked);
}
});
return builder.create();
case DIALOG_EXCEPTION_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle( "An Error occured" )
.setMessage( errorMessage )
.setPositiveButton( "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mBRouterView.continueProcessing();
}
});
return builder.create();
case DIALOG_WARNEXPIRY_ID:
builder = new AlertDialog.Builder(this);
builder.setMessage( errorMessage )
.setPositiveButton( "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mBRouterView.startProcessing(selectedProfile);
}
});
return builder.create();
case DIALOG_TEXTENTRY_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle("Enter SDCARD base dir:");
builder.setMessage(message);
final EditText input = new EditText(this);
input.setText( defaultbasedir );
builder.setView(input);
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String basedir = input.getText().toString();
mBRouterView.startSetup(basedir, true );
}
});
return builder.create();
case DIALOG_VIASELECT_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle("Check VIA Selection:");
builder.setMultiChoiceItems(availableVias, getCheckedBooleanArray( availableVias.length ),
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which,
boolean isChecked) {
if (isChecked)
{
selectedVias.add(availableVias[which]);
}
else
{
selectedVias.remove(availableVias[which]);
}
}
});
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mBRouterView.updateViaList( selectedVias );
mBRouterView.startProcessing(selectedProfile);
}
});
return builder.create();
case DIALOG_NOGOSELECT_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle("Check NoGo Selection:");
String[] nogoNames = new String[nogoList.size()];
for( int i=0; i<nogoList.size(); i++ ) nogoNames[i] = nogoList.get(i).name;
final boolean[] nogoEnabled = getCheckedBooleanArray(nogoList.size());
builder.setMultiChoiceItems(nogoNames, getCheckedBooleanArray( nogoNames.length ),
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
nogoEnabled[which] = isChecked;
}
});
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mBRouterView.updateNogoList( nogoEnabled );
mBRouterView.startProcessing(selectedProfile);
}
});
return builder.create();
case DIALOG_SHOWRESULT_ID:
String leftLabel = wpCount < 0 ? "Exit" : ( wpCount == 0 ? "Select from" : "Select to/via" );
String rightLabel = wpCount < 2 ? "Server-Mode" : "Calc Route";
builder = new AlertDialog.Builder(this);
builder.setTitle( title )
.setMessage( errorMessage )
.setPositiveButton( leftLabel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if ( wpCount < 0 ) finish();
else mBRouterView.pickWaypoints();
}
})
.setNegativeButton( rightLabel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if ( wpCount < 2 ) mBRouterView.startConfigureService();
else
{
mBRouterView.finishWaypointSelection();
mBRouterView.startProcessing(selectedProfile);
}
}
});
return builder.create();
case DIALOG_MODECONFIGOVERVIEW_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle( "Success" )
.setMessage( message )
.setPositiveButton( "Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
});
return builder.create();
case DIALOG_PICKWAYPOINT_ID:
builder = new AlertDialog.Builder(this);
builder.setTitle( wpCount > 0 ? "Select to/via" : "Select from" );
builder.setItems(availableWaypoints, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
mBRouterView.updateWaypointList( availableWaypoints[item] );
mBRouterView.startProcessing(selectedProfile);
}
});
return builder.create();
default:
return null;
}
}
private boolean[] getCheckedBooleanArray( int size )
{
boolean[] checked = new boolean[size];
for( int i=0; i<checked.length; i++ ) checked[i] = true;
return checked;
}
private String[] availableProfiles;
private String selectedProfile = null;
private String[] availableWaypoints;
private String selectedWaypoint = null;
private String[] routingModes;
private boolean[] routingModesChecked;
private String defaultbasedir = null;
private String message = null;
private String[] availableVias;
private Set<String> selectedVias;
private List<OsmNodeNamed> nogoList;
@SuppressWarnings("deprecation")
public void selectProfile( String[] items )
{
availableProfiles = items;
showDialog( DIALOG_SELECTPROFILE_ID );
}
@SuppressWarnings("deprecation")
public void selectRoutingModes( String[] modes, boolean[] modesChecked, String message )
{
routingModes = modes;
routingModesChecked = modesChecked;
this.message = message;
showDialog( DIALOG_ROUTINGMODES_ID );
}
@SuppressWarnings("deprecation")
public void showModeConfigOverview( String message )
{
this.message = message;
showDialog( DIALOG_MODECONFIGOVERVIEW_ID );
}
@SuppressWarnings("deprecation")
public void selectBasedir( String defaultBasedir, String message )
{
this.defaultbasedir = defaultBasedir;
this.message = message;
showDialog( DIALOG_TEXTENTRY_ID );
}
@SuppressWarnings("deprecation")
public void selectVias( String[] items )
{
availableVias = items;
selectedVias = new HashSet<String>(availableVias.length);
for( String via : items ) selectedVias.add( via );
showDialog( DIALOG_VIASELECT_ID );
}
@SuppressWarnings("deprecation")
public void selectWaypoint( String[] items )
{
availableWaypoints = items;
showNewDialog( DIALOG_PICKWAYPOINT_ID );
}
@SuppressWarnings("deprecation")
public void selectNogos( List<OsmNodeNamed> nogoList )
{
this.nogoList = nogoList;
showDialog( DIALOG_NOGOSELECT_ID );
}
private Set<Integer> dialogIds = new HashSet<Integer>();
private void showNewDialog( int id )
{
if ( dialogIds.contains( new Integer( id ) ) )
{
removeDialog( id );
}
dialogIds.add( new Integer( id ) );
showDialog( id );
}
private String errorMessage;
private String title;
private int wpCount;
@SuppressWarnings("deprecation")
public void showErrorMessage( String msg )
{
errorMessage = msg;
showNewDialog( DIALOG_EXCEPTION_ID );
}
@SuppressWarnings("deprecation")
public void showResultMessage( String title, String msg, int wpCount )
{
errorMessage = msg;
this.title = title;
this.wpCount = wpCount;
showNewDialog( DIALOG_SHOWRESULT_ID );
}
@Override
protected void onResume() {
super.onResume();
/*
* when the activity is resumed, we acquire a wake-lock so that the
* screen stays on, since the user will likely not be fiddling with the
* screen or buttons.
*/
mWakeLock.acquire();
// Start the simulation
mBRouterView.startSimulation();
}
@Override
protected void onPause() {
super.onPause();
/*
* When the activity is paused, we make sure to stop the simulation,
* release our sensor resources and wake locks
*/
// Stop the simulation
mBRouterView.stopSimulation();
// and release our wake-lock
mWakeLock.release();
}
@Override
public void onInit(int i)
{
}
}

View file

@ -0,0 +1,146 @@
package btools.routingapp;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.StringTokenizer;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import btools.router.OsmNodeNamed;
public class BRouterService extends Service
{
@Override
public IBinder onBind(Intent arg0) {
Log.d(getClass().getSimpleName(), "onBind()");
return myBRouterServiceStub;
}
private IBRouterService.Stub myBRouterServiceStub = new IBRouterService.Stub()
{
@Override
public String getTrackFromParams(Bundle params) throws RemoteException
{
BRouterWorker worker = new BRouterWorker();
// get base dir from private file
String baseDir = null;
InputStream configInput = null;
try
{
configInput = openFileInput( "config.dat" );
BufferedReader br = new BufferedReader( new InputStreamReader (configInput ) );
baseDir = br.readLine();
}
catch( Exception e ) {}
finally
{
if ( configInput != null ) try { configInput.close(); } catch( Exception ee ) {}
}
String fast = params.getString( "fast" );
boolean isFast = "1".equals( fast ) || "true".equals( fast ) || "yes".equals( fast );
String mode_key = params.getString( "v" ) + "_" + (isFast ? "fast" : "short");
boolean configFound = false;
BufferedReader br = null;
try
{
String modesFile = baseDir + "/brouter/modes/serviceconfig.dat";
br = new BufferedReader( new FileReader (modesFile ) );
worker.segmentDir = baseDir + "/brouter/segments2";
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
ServiceModeConfig smc = new ServiceModeConfig( line );
if ( !smc.mode.equals( mode_key ) ) continue;
worker.profilePath = baseDir + "/brouter/profiles2/" + smc.profile + ".brf";
worker.rawTrackPath = baseDir + "/brouter/modes/" + mode_key + "_rawtrack.dat";
CoordinateReader cor = CoordinateReader.obtainValidReader( baseDir );
worker.nogoList = new ArrayList<OsmNodeNamed>();
// veto nogos by profiles veto list
for(OsmNodeNamed nogo : cor.nogopoints )
{
if ( !smc.nogoVetos.contains( nogo.ilon + "," + nogo.ilat ) )
{
worker.nogoList.add( nogo );
}
}
configFound = true;
}
}
catch( Exception e )
{
return "no brouter service config found, mode " + mode_key;
}
finally
{
if ( br != null ) try { br.close(); } catch( Exception ee ) {}
}
if ( !configFound )
{
return "no brouter service config found for mode " + mode_key;
}
try
{
return worker.getTrackFromParams(params);
}
catch( IllegalArgumentException iae )
{
return iae.getMessage();
}
}
};
@Override
public void onCreate()
{
super.onCreate();
Log.d(getClass().getSimpleName(),"onCreate()");
}
@Override
public void onDestroy()
{
super.onDestroy();
Log.d(getClass().getSimpleName(),"onDestroy()");
}
// This is the old onStart method that will be called on the pre-2.0
// platform. On 2.0 or later we override onStartCommand() so this
// method will not be called.
@Override
@SuppressWarnings("deprecation")
public void onStart(Intent intent, int startId)
{
Log.d(getClass().getSimpleName(), "onStart()");
handleStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
handleStart(intent, startId);
return START_STICKY;
}
void handleStart(Intent intent, int startId)
{
}
}

View file

@ -0,0 +1,760 @@
package btools.routingapp;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Toast;
import btools.expressions.BExpressionContext;
import btools.mapaccess.OsmNode;
import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
public class BRouterView extends View
{
RoutingEngine cr;
private int imgw;
private int imgh;
private int centerLon;
private int centerLat;
private double scaleLon;
private double scaleLat;
private List<OsmNodeNamed> wpList;
private List<OsmNodeNamed> nogoList;
private List<OsmNodeNamed> nogoVetoList;
private OsmTrack rawTrack;
private String modesDir;
private String tracksDir;
private String segmentDir;
private String profileDir;
private String profilePath;
private String profileName;
private String sourceHint;
private boolean waitingForSelection = false;
private boolean needsViaSelection;
private boolean needsNogoSelection;
private boolean needsWaypointSelection;
private long lastDataTime = System.currentTimeMillis();
private CoordinateReader cor;
private int[] imgPixels;
public void startSimulation() {
}
public void stopSimulation() {
if ( cr != null ) cr.terminate();
}
public BRouterView(Context context) {
super(context);
DisplayMetrics metrics = new DisplayMetrics();
((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
imgw = metrics.widthPixels;
imgh = metrics.heightPixels;
// get base dir from private file
String baseDir = null;
InputStream configInput = null;
try
{
configInput = getContext().openFileInput( "config.dat" );
BufferedReader br = new BufferedReader( new InputStreamReader (configInput ) );
baseDir = br.readLine();
}
catch( Exception e ) {}
finally
{
if ( configInput != null ) try { configInput.close(); } catch( Exception ee ) {}
}
// check if valid
boolean bdValid = false;
if ( baseDir != null )
{
File bd = new File( baseDir );
bdValid = bd.isDirectory();
File brd = new File( bd, "brouter" );
if ( brd.isDirectory() )
{
startSetup( baseDir, false );
return;
}
}
String message = baseDir == null ?
"(no basedir configured previously)" :
"(previous basedir " + baseDir +
( bdValid ? " does not contain 'brouter' subfolder)"
: " is not valid)" );
((BRouterActivity)getContext()).selectBasedir( guessBaseDir(), message );
waitingForSelection = true;
}
public void startSetup( String baseDir, boolean storeBasedir )
{
File fbd = new File( baseDir );
if ( !fbd.isDirectory() )
{
throw new IllegalArgumentException( "Base-directory " + baseDir + " is not a directory " );
}
String basedir = fbd.getAbsolutePath();
if ( storeBasedir )
{
BufferedWriter bw = null;
try
{
OutputStream configOutput = getContext().openFileOutput( "config.dat", Context.MODE_PRIVATE );
bw = new BufferedWriter( new OutputStreamWriter (configOutput ) );
bw.write( baseDir );
bw.write( '\n' );
}
catch( Exception e ) {}
finally
{
if ( bw != null ) try { bw.close(); } catch( Exception ee ) {}
}
}
cor = null;
try
{
// create missing directories
assertDirectoryExists( "project directory", basedir + "/brouter" );
segmentDir = basedir + "/brouter/segments2";
assertDirectoryExists( "map directory", segmentDir );
profileDir = basedir + "/brouter/profiles2";
assertDirectoryExists( "profile directory", profileDir );
modesDir = basedir + "/brouter/modes";
assertDirectoryExists( "modes directory", modesDir );
cor = CoordinateReader.obtainValidReader( basedir );
wpList = cor.waypoints;
nogoList = cor.nogopoints;
nogoVetoList = new ArrayList<OsmNodeNamed>();
sourceHint = "(coordinate-source: " + cor.basedir + cor.rootdir + ")";
needsViaSelection = wpList.size() > 2;
needsNogoSelection = nogoList.size() > 0;
needsWaypointSelection = wpList.size() == 0;
if ( cor.tracksdir != null )
{
tracksDir = cor.basedir + cor.tracksdir;
assertDirectoryExists( "track directory", tracksDir );
// output redirect: look for a pointerfile in tracksdir
File tracksDirPointer = new File( tracksDir + "/brouter.redirect" );
if ( tracksDirPointer.isFile() )
{
tracksDir = readSingleLineFile( tracksDirPointer );
if ( tracksDir == null ) throw new IllegalArgumentException( "redirect pointer file is empty: " + tracksDirPointer );
if ( !(new File( tracksDir ).isDirectory()) ) throw new IllegalArgumentException(
"redirect pointer file " + tracksDirPointer + " does not point to a directory: " + tracksDir );
}
}
boolean segmentFound = false;
String[] fileNames = new File( segmentDir ).list();
for( String fileName : fileNames )
{
if ( fileName.endsWith( ".rd5" ) ) segmentFound = true;
}
File carSubset = new File( segmentDir, "carsubset" );
if ( carSubset.isDirectory() )
{
fileNames = carSubset.list();
for( String fileName : fileNames )
{
if ( fileName.endsWith( ".cd5" ) ) segmentFound = true;
}
}
if ( !segmentFound )
{
throw new IllegalArgumentException( "The segments-directory " + segmentDir
+ " contains no routing data files (*.rd5)."
+ " see www.dr-brenschede.de/brouter for setup instructions." );
}
fileNames = new File( profileDir ).list();
ArrayList<String> profiles = new ArrayList<String>();
boolean lookupsFound = false;
for( String fileName : fileNames )
{
if ( fileName.endsWith( ".brf" ) )
{
profiles.add( fileName.substring( 0, fileName.length()-4 ) );
}
if ( fileName.equals( "lookups.dat" ) ) lookupsFound = true;
}
if ( !lookupsFound )
{
throw new IllegalArgumentException( "The profile-directory " + profileDir
+ " does not contain the lookups.dat file."
+ " see www.dr-brenschede.de/brouter for setup instructions." );
}
if ( profiles.size() == 0 )
{
throw new IllegalArgumentException( "The profile-directory " + profileDir
+ " contains no routing profiles (*.brf)."
+ " see www.dr-brenschede.de/brouter for setup instructions." );
}
((BRouterActivity)getContext()).selectProfile( profiles.toArray( new String[0]) );
}
catch( Exception e )
{
String msg = e instanceof IllegalArgumentException
? e.getMessage() + ( cor == null ? "" : " (coordinate-source: " + cor.basedir + cor.rootdir + ")" )
: e.toString();
((BRouterActivity)getContext()).showErrorMessage( msg );
}
waitingForSelection = true;
}
public void continueProcessing()
{
waitingForSelection = false;
invalidate();
}
public void updateViaList( Set<String> selectedVias )
{
ArrayList<OsmNodeNamed> filtered = new ArrayList<OsmNodeNamed>(wpList.size());
for( OsmNodeNamed n : wpList )
{
String name = n.name;
if ( "from".equals( name ) || "to".equals(name) || selectedVias.contains( name ) )
filtered.add( n );
}
wpList = filtered;
}
public void updateNogoList( boolean[] enabled )
{
for( int i=nogoList.size()-1; i >= 0; i-- )
{
if ( !enabled[i] )
{
nogoVetoList.add( nogoList.get(i) );
nogoList.remove( i );
}
}
}
public void pickWaypoints()
{
String msg = null;
Map<String,OsmNodeNamed> allpoints = cor.allpoints;
if ( allpoints == null )
{
allpoints = new TreeMap<String,OsmNodeNamed>();
cor.allpoints = allpoints;
try { cor.readFromTo(); } catch ( Exception e ) { msg = "Error reading waypoints: " + e.toString(); }
if ( allpoints.size() < 2 ) msg = "coordinate source does not contain enough waypoints: " + allpoints.size();
if ( allpoints.size() > 100 ) msg = "coordinate source contains too much waypoints: " + allpoints.size() + "(please use from/to/via names)";
}
if ( allpoints.size() < 1 ) msg = "no more wayoints available!";
if ( msg != null )
{
((BRouterActivity)getContext()).showErrorMessage( msg );
}
else
{
String[] wpts = new String[allpoints.size()];
int i = 0;
for( OsmNodeNamed wp : allpoints.values() ) wpts[i++] = wp.name;
System.out.println( "calling selectWaypoint..." );
((BRouterActivity)getContext()).selectWaypoint( wpts );
}
}
public void updateWaypointList( String waypoint )
{
wpList.add( cor.allpoints.get( waypoint ) );
cor.allpoints.remove( waypoint );
System.out.println( "updateWaypointList: " + waypoint + " wpList.size()=" + wpList.size() );
}
public void finishWaypointSelection()
{
needsWaypointSelection = false;
}
public void startProcessing( String profile )
{
profilePath = profileDir + "/" + profile + ".brf";
profileName = profile;
if ( needsViaSelection )
{
needsViaSelection = false;
String[] availableVias = new String[wpList.size()-2];
for( int viaidx=0; viaidx<wpList.size()-2; viaidx++ )
availableVias[viaidx] = wpList.get( viaidx+1 ).name;
((BRouterActivity)getContext()).selectVias( availableVias );
return;
}
if ( needsNogoSelection )
{
needsNogoSelection = false;
((BRouterActivity)getContext()).selectNogos( nogoList );
return;
}
if ( needsWaypointSelection )
{
String msg;
if ( wpList.size() == 0 )
{
msg = "no from/to found\n" + sourceHint;
}
else
{
msg = "current waypoint selection:\n";
for ( int i=0; i< wpList.size(); i++ ) msg += (i>0?"->" : "") + wpList.get(i).name;
}
((BRouterActivity)getContext()).showResultMessage( "Select Action", msg, wpList.size() );
return;
}
try
{
waitingForSelection = false;
RoutingContext rc = new RoutingContext();
// TODO: TEST!
// rc.rawTrackPath = "/mnt/sdcard/brouter/modes/bicycle_fast_rawtrack.dat";
rc.localFunction = profilePath;
int plain_distance = 0;
int maxlon = Integer.MIN_VALUE;
int minlon = Integer.MAX_VALUE;
int maxlat = Integer.MIN_VALUE;
int minlat = Integer.MAX_VALUE;
OsmNode prev = null;
for( OsmNode n : wpList )
{
maxlon = n.ilon > maxlon ? n.ilon : maxlon;
minlon = n.ilon < minlon ? n.ilon : minlon;
maxlat = n.ilat > maxlat ? n.ilat : maxlat;
minlat = n.ilat < minlat ? n.ilat : minlat;
if ( prev != null )
{
plain_distance += n.calcDistance( prev );
}
prev = n;
}
toast( "Plain distance = " + plain_distance/1000. + " km" );
centerLon = (maxlon + minlon)/2;
centerLat = (maxlat + minlat)/2;
double coslat = Math.cos( ((centerLat / 1000000.) - 90.) / 57.3 ) ;
double difflon = maxlon - minlon;
double difflat = maxlat - minlat;
scaleLon = imgw / (difflon*1.5);
scaleLat = imgh / (difflat*1.5);
if ( scaleLon < scaleLat*coslat ) scaleLat = scaleLon/coslat;
else scaleLon = scaleLat*coslat;
startTime = System.currentTimeMillis();
rc.prepareNogoPoints( nogoList );
rc.nogopoints = nogoList;
cr = new RoutingEngine( tracksDir + "/brouter", null, segmentDir, wpList, rc );
cr.start();
invalidate();
}
catch( Exception e )
{
String msg = e instanceof IllegalArgumentException ? e.getMessage() : e.toString();
toast( msg );
}
}
private void assertDirectoryExists( String message, String path )
{
File f = new File( path );
f.mkdirs();
if ( !f.exists() || !f.isDirectory() ) throw new IllegalArgumentException( message + ": " + path + " cannot be created" );
}
private void paintPosition( int ilon, int ilat, int color, int with )
{
int lon = ilon - centerLon;
int lat = ilat - centerLat;
int x = imgw/2 + (int)(scaleLon*lon);
int y = imgh/2 - (int)(scaleLat*lat);
for( int nx=x-with; nx<=x+with; nx++)
for( int ny=y-with; ny<=y+with; ny++)
{
if ( nx >= 0 && nx < imgw && ny >= 0 && ny < imgh )
{
imgPixels[ nx+imgw*ny] = color;
}
}
}
private void paintCircle( Canvas canvas, OsmNodeNamed n, int color, int minradius )
{
int lon = n.ilon - centerLon;
int lat = n.ilat - centerLat;
int x = imgw/2 + (int)(scaleLon*lon);
int y = imgh/2 - (int)(scaleLat*lat);
int ir = (int)(n.radius * 1000000. * scaleLat);
if ( ir > minradius )
{
Paint paint = new Paint();
paint.setColor( Color.RED );
paint.setStyle( Paint.Style.STROKE );
canvas.drawCircle( (float)x, (float)y, (float)ir, paint );
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
}
private void toast( String msg )
{
Toast.makeText(getContext(), msg, Toast.LENGTH_LONG ).show();
lastDataTime += 4000; // give time for the toast before exiting
}
private long lastTs = System.currentTimeMillis();
private long startTime = 0L;
@Override
protected void onDraw(Canvas canvas) {
try
{
_onDraw( canvas );
}
catch( Throwable t )
{
// on out of mem, try to stop the show
String hint = "";
if ( cr != null ) hint = cr.cleanOnOOM();
cr = null;
try { Thread.sleep( 2000 ); } catch( InterruptedException ie ) {}
((BRouterActivity)getContext()).showErrorMessage( t.toString() + hint );
waitingForSelection = true;
}
}
private void _onDraw(Canvas canvas) {
if ( waitingForSelection ) return;
long currentTs = System.currentTimeMillis();
long diffTs = currentTs - lastTs;
long sleeptime = 500 - diffTs;
while ( sleeptime < 200 ) sleeptime += 500;
try { Thread.sleep( sleeptime ); } catch ( InterruptedException ie ) {}
lastTs = System.currentTimeMillis();
if ( cr == null || cr.isFinished() )
{
if ( cr != null )
{
if ( cr.getErrorMessage() != null )
{
((BRouterActivity)getContext()).showErrorMessage( cr.getErrorMessage() );
cr = null;
waitingForSelection = true;
return;
}
else
{
String result = "version = BRouter-0.98\n"
+ "distance = " + cr.getDistance()/1000. + " km\n"
+ "filtered ascend = " + cr.getAscend() + " m\n"
+ "plain ascend = " + cr.getPlainAscend();
rawTrack = cr.getFoundRawTrack();
String title = "Success";
if ( cr.getAlternativeIndex() > 0 ) title += " / " + cr.getAlternativeIndex() + ". Alternative";
((BRouterActivity)getContext()).showResultMessage( title, result, -1 );
cr = null;
waitingForSelection = true;
return;
}
}
else if ( System.currentTimeMillis() > lastDataTime )
{
System.exit(0);
}
}
else
{
lastDataTime = System.currentTimeMillis();
imgPixels = new int[imgw*imgh];
int[] openSet = cr.getOpenSet();
for( int si = 0; si < openSet.length; si += 2 )
{
paintPosition( openSet[si], openSet[si+1], 0xffffff, 1 );
}
// paint nogos on top (red)
for( int ngi=0; ngi<nogoList.size(); ngi++ )
{
OsmNodeNamed n = nogoList.get(ngi);
int color = 0xff0000;
paintPosition( n.ilon, n.ilat, color, 4 );
}
// paint start/end/vias on top (yellow/green/blue)
for( int wpi=0; wpi<wpList.size(); wpi++ )
{
OsmNodeNamed n = wpList.get(wpi);
int color = wpi == 0 ? 0xffff00 : wpi < wpList.size()-1 ? 0xff : 0xff00;
paintPosition( n.ilon, n.ilat, color, 4 );
}
canvas.drawBitmap(imgPixels, 0, imgw, (float)0., (float)0., imgw, imgh, false, null);
// nogo circles if any
for( int ngi=0; ngi<nogoList.size(); ngi++ )
{
OsmNodeNamed n = nogoList.get(ngi);
int color = 0xff0000;
paintCircle( canvas, n, color, 4 );
}
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
long mseconds = System.currentTimeMillis() - startTime;
long links = cr.getLinksProcessed();
long perS = (1000*links)/mseconds;
String msg = "Links: " + cr.getLinksProcessed() + " in " + (mseconds/1000) + "s (" + perS + " l/s)";
canvas.drawText( msg, 10, 25, paint);
}
// and make sure to redraw asap
invalidate();
}
private String guessBaseDir()
{
File basedir = Environment.getExternalStorageDirectory();
try
{
File bd2 = new File( basedir, "external_sd" );
ArrayList<String> basedirGuesses = new ArrayList<String>();
basedirGuesses.add( basedir.getAbsolutePath() );
if ( bd2.exists() )
{
basedir = bd2;
basedirGuesses.add( basedir.getAbsolutePath() );
}
ArrayList<CoordinateReader> rl = new ArrayList<CoordinateReader>();
for( String bdg : basedirGuesses )
{
rl.add( new CoordinateReaderOsmAnd(bdg) );
rl.add( new CoordinateReaderLocus(bdg) );
rl.add( new CoordinateReaderOrux(bdg) );
}
long tmax = 0;
CoordinateReader cor = null;
for( CoordinateReader r : rl )
{
long t = r.getTimeStamp();
if ( t > tmax )
{
tmax = t;
cor = r;
}
}
if ( cor != null )
{
return cor.basedir;
}
}
catch( Exception e )
{
System.out.println( "guessBaseDir:" + e );
}
return basedir.getAbsolutePath();
}
public void writeRawTrackToMode( String mode )
{
// plus eventually the raw track for re-use
String rawTrackPath = modesDir + "/" + mode + "_rawtrack.dat";
if ( rawTrack != null )
{
try
{
rawTrack.writeBinary( rawTrackPath );
}
catch( Exception e ) {}
}
else
{
new File( rawTrackPath ).delete();
}
}
public void startConfigureService()
{
String[] modes = new String[] {
"foot_short", "foot_fast",
"bicycle_short", "bicycle_fast",
"motorcar_short", "motorcar_fast"
};
boolean[] modesChecked = new boolean[6];
// parse global section of profile for mode preselection
BExpressionContext expctxGlobal = new BExpressionContext( "global" );
expctxGlobal.readMetaData( new File( profileDir, "lookups.dat" ) );
expctxGlobal.parseFile( new File( profilePath ), null );
expctxGlobal.evaluate( 1L, null );
boolean isFoot = 0.f != expctxGlobal.getVariableValue( "validForFoot" );
boolean isBike = 0.f != expctxGlobal.getVariableValue( "validForBikes" );
boolean isCar = 0.f != expctxGlobal.getVariableValue( "validForCars" );
if ( isFoot || isBike || isCar )
{
modesChecked[ 0 ] = isFoot;
modesChecked[ 1 ] = isFoot;
modesChecked[ 2 ] = isBike;
modesChecked[ 3 ] = isBike;
modesChecked[ 4 ] = isCar;
modesChecked[ 5 ] = isCar;
}
else
{
for( int i=0; i<6; i++)
{
modesChecked[i] = true;
}
}
String msg = "Choose service-modes to configure (" + profileName + " [" + nogoVetoList.size() + "])";
((BRouterActivity)getContext()).selectRoutingModes( modes, modesChecked, msg );
}
public void configureService(String[] routingModes, boolean[] checkedModes)
{
// read in current config
TreeMap<String,ServiceModeConfig> map = new TreeMap<String,ServiceModeConfig>();
BufferedReader br = null;
String modesFile = modesDir + "/serviceconfig.dat";
try
{
br = new BufferedReader( new FileReader (modesFile ) );
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
ServiceModeConfig smc = new ServiceModeConfig( line );
map.put( smc.mode, smc );
}
}
catch( Exception e ) {}
finally
{
if ( br != null ) try { br.close(); } catch( Exception ee ) {}
}
// replace selected modes
for( int i=0; i<6; i++)
{
if ( checkedModes[i] )
{
writeRawTrackToMode( routingModes[i] );
ServiceModeConfig smc = new ServiceModeConfig( routingModes[i], profileName);
for( OsmNodeNamed nogo : nogoVetoList)
{
smc.nogoVetos.add( nogo.ilon + "," + nogo.ilat );
}
map.put( smc.mode, smc );
}
}
// no write new config
BufferedWriter bw = null;
StringBuilder msg = new StringBuilder( "Mode mapping is now:\n" );
msg.append( "( [..] counts nogo-vetos)\n" );
try
{
bw = new BufferedWriter( new FileWriter ( modesFile ) );
for( ServiceModeConfig smc : map.values() )
{
bw.write( smc.toLine() );
bw.write( '\n' );
msg.append( smc.toString() ).append( '\n' );
}
}
catch( Exception e ) {}
finally
{
if ( bw != null ) try { bw.close(); } catch( Exception ee ) {}
}
((BRouterActivity)getContext()).showModeConfigOverview( msg.toString() );
}
private String readSingleLineFile( File f )
{
BufferedReader br = null;
try
{
br = new BufferedReader( new InputStreamReader ( new FileInputStream( f ) ) );
return br.readLine();
}
catch( Exception e ) { return null; }
finally
{
if ( br != null ) try { br.close(); } catch( Exception ee ) {}
}
}
}

View file

@ -0,0 +1,139 @@
package btools.routingapp;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import btools.router.RoutingEngine;
import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
public class BRouterWorker
{
public String segmentDir;
public String profilePath;
public String rawTrackPath;
public List<OsmNodeNamed> nogoList;
public String getTrackFromParams(Bundle params)
{
String pathToFileResult = params.getString("pathToFileResult");
if (pathToFileResult != null)
{
File f = new File (pathToFileResult);
File dir = f.getParentFile();
if (!dir.exists() || !dir.canWrite()){
return "file folder does not exists or can not be written!";
}
}
long maxRunningTime = 60000;
String sMaxRunningTime = params.getString( "maxRunningTime" );
if ( sMaxRunningTime != null )
{
maxRunningTime = Integer.parseInt( sMaxRunningTime ) * 1000;
}
RoutingContext rc = new RoutingContext();
rc.rawTrackPath = rawTrackPath;
rc.localFunction = profilePath;
if ( nogoList != null )
{
rc.prepareNogoPoints( nogoList );
rc.nogopoints = nogoList;
}
readNogos( params ); // add interface provides nogos
RoutingEngine cr = new RoutingEngine( null, null, segmentDir, readPositions(params), rc );
cr.quite = true;
cr.doRun( maxRunningTime );
if ( cr.getErrorMessage() != null )
{
return cr.getErrorMessage();
}
// store new reference track if any
if ( cr.getFoundRawTrack() != null )
{
try
{
cr.getFoundRawTrack().writeBinary( rawTrackPath );
}
catch( Exception e ) {}
}
String format = params.getString("trackFormat");
boolean writeKml = format != null && "kml".equals( format );
OsmTrack track = cr.getFoundTrack();
if ( track != null )
{
if ( pathToFileResult == null )
{
if ( writeKml ) return track.formatAsKml();
return track.formatAsGpx();
}
try
{
if ( writeKml ) track.writeKml(pathToFileResult);
else track.writeGpx(pathToFileResult);
}
catch( Exception e )
{
return "error writing file: " + e;
}
}
return null;
}
private List<OsmNodeNamed> readPositions( Bundle params )
{
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
double[] lats = params.getDoubleArray("lats");
double[] lons = params.getDoubleArray("lons");
if (lats == null || lats.length < 2 || lons == null || lons.length < 2)
{
throw new IllegalArgumentException( "we need two lat/lon points at least!" );
}
for( int i=0; i<lats.length && i<lons.length; i++ )
{
OsmNodeNamed n = new OsmNodeNamed();
n.name = "via" + i;
n.ilon = (int)( ( lons[i] + 180. ) *1000000. + 0.5);
n.ilat = (int)( ( lats[i] + 90. ) *1000000. + 0.5);
wplist.add( n );
}
wplist.get(0).name = "from";
wplist.get(wplist.size()-1).name = "to";
return wplist;
}
private void readNogos( Bundle params )
{
double[] lats = params.getDoubleArray("nogoLats");
double[] lons = params.getDoubleArray("nogoLons");
double[] radi = params.getDoubleArray("nogoRadi");
if ( lats == null || lons == null || radi == null ) return;
for( int i=0; i<lats.length && i<lons.length && i<radi.length; i++ )
{
OsmNodeNamed n = new OsmNodeNamed();
n.name = "nogo" + (int)radi[i];
n.ilon = (int)( ( lons[i] + 180. ) *1000000. + 0.5);
n.ilat = (int)( ( lats[i] + 90. ) *1000000. + 0.5);
n.isNogo = true;
nogoList.add( n );
}
}
}

View file

@ -0,0 +1,137 @@
package btools.routingapp;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Environment;
import btools.router.OsmNodeNamed;
/**
* Read coordinates from a gpx-file
*/
public abstract class CoordinateReader
{
public List<OsmNodeNamed> waypoints;
public List<OsmNodeNamed> nogopoints;
public String basedir;
public String rootdir;
public String tracksdir;
public Map<String,OsmNodeNamed> allpoints;
private HashMap<String,OsmNodeNamed> pointmap;
protected static String[] posnames
= new String[]{ "from", "via1", "via2", "via3", "via4", "via5", "via6", "via7", "via8", "via9", "to" };
public CoordinateReader( String basedir )
{
this.basedir = basedir;
}
public abstract long getTimeStamp() throws Exception;
/*
* read the from, to and via-positions from a gpx-file
*/
public void readFromTo() throws Exception
{
pointmap = new HashMap<String,OsmNodeNamed>();
waypoints = new ArrayList<OsmNodeNamed>();
nogopoints = new ArrayList<OsmNodeNamed>();
readPointmap();
boolean fromToMissing = false;
for( int i=0; i<posnames.length; i++ )
{
String name = posnames[i];
OsmNodeNamed n = pointmap.get(name);
if ( n != null )
{
waypoints.add( n );
}
else
{
if ( "from".equals( name ) ) fromToMissing = true;
if ( "to".equals( name ) ) fromToMissing = true;
}
}
if ( fromToMissing ) waypoints.clear();
}
protected void checkAddPoint( OsmNodeNamed n )
{
if ( allpoints != null )
{
allpoints.put( n.name, n );
return;
}
boolean isKnown = false;
for( int i=0; i<posnames.length; i++ )
{
if ( posnames[i].equals( n.name ) )
{
isKnown = true;
break;
}
}
if ( isKnown )
{
if ( pointmap.put( n.name, n ) != null )
{
throw new IllegalArgumentException( "multiple " + n.name + "-positions!" );
}
}
else if ( n.name != null && n.name.startsWith( "nogo" ) )
{
n.isNogo = true;
nogopoints.add( n );
}
}
protected abstract void readPointmap() throws Exception;
public static CoordinateReader obtainValidReader( String basedir ) throws Exception
{
CoordinateReader cor = null;
ArrayList<CoordinateReader> rl = new ArrayList<CoordinateReader>();
rl.add( new CoordinateReaderOsmAnd(basedir) );
rl.add( new CoordinateReaderLocus(basedir) );
rl.add( new CoordinateReaderOrux(basedir) );
// eventually add standard-sd
File standardbase = Environment.getExternalStorageDirectory();
if ( standardbase != null )
{
String base2 = standardbase.getAbsolutePath();
if ( !base2.equals( basedir ) )
{
rl.add( new CoordinateReaderOsmAnd(base2) );
rl.add( new CoordinateReaderLocus(base2) );
rl.add( new CoordinateReaderOrux(base2) );
}
}
long tmax = 0;
for( CoordinateReader r : rl )
{
long t = r.getTimeStamp();
if ( t > tmax )
{
tmax = t;
cor = r;
}
}
if ( cor == null )
{
cor = new CoordinateReaderNone();
}
cor.readFromTo();
return cor;
}
}

View file

@ -0,0 +1,53 @@
package btools.routingapp;
import java.io.File;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import btools.router.OsmNodeNamed;
/**
* Read coordinates from a gpx-file
*/
public class CoordinateReaderLocus extends CoordinateReader
{
public CoordinateReaderLocus( String basedir )
{
super( basedir );
tracksdir = "/Locus/mapItems";
rootdir = "/Locus";
}
@Override
public long getTimeStamp() throws Exception
{
long t1 = new File( basedir + "/Locus/data/database/waypoints.db" ).lastModified();
return t1;
}
/*
* read the from and to position from a ggx-file
* (with hardcoded name for now)
*/
@Override
public void readPointmap() throws Exception
{
_readPointmap( basedir + "/Locus/data/database/waypoints.db" );
}
private void _readPointmap( String filename ) throws Exception
{
SQLiteDatabase myDataBase = SQLiteDatabase.openDatabase( filename, null, SQLiteDatabase.OPEN_READONLY);
Cursor c = myDataBase.rawQuery("SELECT name, longitude, latitude FROM waypoints", null);
while (c.moveToNext())
{
OsmNodeNamed n = new OsmNodeNamed();
n.name = c.getString(0);
n.ilon = (int)( ( Double.parseDouble( c.getString(1) ) + 180. )*1000000. + 0.5);
n.ilat = (int)( ( Double.parseDouble( c.getString(2) ) + 90. )*1000000. + 0.5);
checkAddPoint( n );
}
myDataBase.close();
}
}

View file

@ -0,0 +1,26 @@
package btools.routingapp;
/**
* Dummy coordinate reader if none found
*/
public class CoordinateReaderNone extends CoordinateReader
{
public CoordinateReaderNone()
{
super( "" );
rootdir = "none";
}
@Override
public long getTimeStamp() throws Exception
{
return 0L;
}
@Override
public void readPointmap() throws Exception
{
}
}

View file

@ -0,0 +1,52 @@
package btools.routingapp;
import java.io.File;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import btools.router.OsmNodeNamed;
/**
* Read coordinates from a gpx-file
*/
public class CoordinateReaderOrux extends CoordinateReader
{
public CoordinateReaderOrux( String basedir )
{
super( basedir );
tracksdir = "/oruxmaps/tracklogs";
rootdir = "/oruxmaps";
}
@Override
public long getTimeStamp() throws Exception
{
long t1 = new File( basedir + "/oruxmaps/tracklogs/oruxmapstracks.db" ).lastModified();
return t1;
}
/*
* read the from and to position from a ggx-file
* (with hardcoded name for now)
*/
@Override
public void readPointmap() throws Exception
{
_readPointmap( basedir + "/oruxmaps/tracklogs/oruxmapstracks.db" );
}
private void _readPointmap( String filename ) throws Exception
{
SQLiteDatabase myDataBase = SQLiteDatabase.openDatabase( filename, null, SQLiteDatabase.OPEN_READONLY);
Cursor c = myDataBase.rawQuery("SELECT poiname, poilon, poilat FROM pois", null);
while (c.moveToNext())
{
OsmNodeNamed n = new OsmNodeNamed();
n.name = c.getString(0);
n.ilon = (int)( ( Double.parseDouble( c.getString(1) ) + 180. )*1000000. + 0.5);
n.ilat = (int)( ( Double.parseDouble( c.getString(2) ) + 90. )*1000000. + 0.5);
checkAddPoint( n );
}
myDataBase.close();
}
}

View file

@ -0,0 +1,87 @@
package btools.routingapp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import btools.router.OsmNodeNamed;
/**
* Read coordinates from a gpx-file
*/
public class CoordinateReaderOsmAnd extends CoordinateReader
{
public CoordinateReaderOsmAnd( String basedir )
{
super( basedir );
tracksdir = "/osmand/tracks";
rootdir = "/osmand";
}
@Override
public long getTimeStamp() throws Exception
{
long t1 = new File( basedir + "/osmand/favourites_bak.gpx" ).lastModified();
long t2 = new File( basedir + "/osmand/favourites.gpx" ).lastModified();
return t1 > t2 ? t1 : t2;
}
/*
* read the from and to position from a gpx-file
* (with hardcoded name for now)
*/
@Override
public void readPointmap() throws Exception
{
try
{
_readPointmap( basedir + "/osmand/favourites_bak.gpx" );
}
catch( Exception e )
{
_readPointmap( basedir + "/osmand/favourites.gpx" );
}
}
private void _readPointmap( String filename ) throws Exception
{
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream( filename ) ) );
OsmNodeNamed n = null;
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
int idx0 = line.indexOf( "<wpt lat=\"" );
int idx10 = line.indexOf( "<name>" );
if ( idx0 >= 0 )
{
n = new OsmNodeNamed();
idx0 += 10;
int idx1 = line.indexOf( '"', idx0 );
n.ilat = (int)( (Double.parseDouble( line.substring( idx0, idx1 ) ) + 90. )*1000000. + 0.5);
int idx2 = line.indexOf( " lon=\"" );
if ( idx2 < 0 ) continue;
idx2 += 6;
int idx3 = line.indexOf( '"', idx2 );
n.ilon = (int)( ( Double.parseDouble( line.substring( idx2, idx3 ) ) + 180. )*1000000. + 0.5);
continue;
}
if ( n != null && idx10 >= 0 )
{
idx10 += 6;
int idx11 = line.indexOf( "</name>", idx10 );
if ( idx11 >= 0 )
{
n.name = line.substring( idx10, idx11 ).trim();
checkAddPoint( n );
}
}
}
br.close();
}
}

View file

@ -0,0 +1,23 @@
package btools.routingapp;
interface IBRouterService {
//param params--> Map of params:
// "pathToFileResult"-->String with the path to where the result must be saved, including file name and extension
// -->if null, the track is passed via the return argument
// "maxRunningTime"-->String with a number of seconds for the routing timeout, default = 60
// "trackFormat"-->[kml|gpx] default = gpx
// "lats"-->double[] array of latitudes; 2 values at least.
// "lons"-->double[] array of longitudes; 2 values at least.
// "nogoLats"-->double[] array of nogo latitudes; may be null.
// "nogoLons"-->double[] array of nogo longitudes; may be null.
// "nogoRadi"-->double[] array of nogo radius in meters; may be null.
// "fast"-->[0|1]
// "v"-->[motorcar|bicycle|foot]
//return null if all ok and no path given, the track if ok and path given, an error message if it was wrong
//call in a background thread, heavy task!
String getTrackFromParams(in Bundle params);
}

View file

@ -0,0 +1,50 @@
package btools.routingapp;
import java.util.StringTokenizer;
import java.util.TreeSet;
/**
* Decsription of a service config
*/
public class ServiceModeConfig
{
public String mode;
public String profile;
public TreeSet<String> nogoVetos;
public ServiceModeConfig( String line )
{
StringTokenizer tk = new StringTokenizer( line );
mode = tk.nextToken();
profile = tk.nextToken();
nogoVetos = new TreeSet<String>();
while( tk.hasMoreTokens() )
{
nogoVetos.add( tk.nextToken() );
}
}
public ServiceModeConfig( String mode, String profile )
{
this.mode = mode;
this.profile = profile;
nogoVetos = new TreeSet<String>();
}
public String toLine()
{
StringBuilder sb = new StringBuilder( 100 );
sb.append( mode ).append( ' ' ).append( profile );
for( String veto: nogoVetos ) sb.append( ' ' ).append( veto );
return sb.toString();
}
public String toString()
{
StringBuilder sb = new StringBuilder( 100 );
sb.append( mode ).append( "->" ).append( profile );
sb.append ( " [" + nogoVetos.size() + "]" );
return sb.toString();
}
}

View file

@ -0,0 +1,105 @@
#
# Car-Routing is experimantal !!!
#
# DO NOT USE FOR ACTUAL NAVIGATION
#
# Turn restrictions are missing, leading to wrong routes
#
---context:global
assign downhillcost 0
assign downhillcutoff 0
assign uphillcost 0
assign uphillcutoff 0
---context:way # following code refers to way-tags
assign turncost 200
assign initialcost switch highway=ferry 20000 0
#
# calculate logical car access
#
assign caraccess
switch motorcar=
switch motor_vehicle=
switch vehicle=
switch access=
switch or highway=motorway highway=motorway_link 1
switch or highway=trunk highway=trunk_link 1
switch or highway=primary highway=primary_link 1
switch or highway=secondary highway=secondary_link 1
switch or highway=tertiary highway=tertiary_link 1
switch highway=unclassified 1
switch highway=ferry 1
switch or highway=residential highway=living_street 1
switch highway=service 1
0
or access=yes or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=designated motor_vehicle=destination
or motorcar=yes or motorcar=designated motorcar=destination
assign accesspenalty
switch caraccess
0
10000
assign onewaypenalty
switch switch reversedirection=yes
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
oneway=-1
10000
0.0
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign costfactor
add max onewaypenalty accesspenalty
switch or highway=motorway highway=motorway_link 1
switch or highway=trunk highway=trunk_link 1
switch or highway=primary highway=primary_link switch maxspeed=30 2.0 switch maxspeed=50 1.5 1.2
switch or highway=secondary highway=secondary_link 1.3
switch or highway=tertiary highway=tertiary_link 1.4
switch highway=unclassified 1.5
switch highway=ferry 5.67
switch highway=bridleway 5
switch or highway=residential highway=living_street 2
switch highway=service 2
switch or highway=track or highway=road highway=path
switch tracktype=grade1 5
switch ispaved 5
30
10000
---context:node # following code refers to node tags
#
# calculate logical car access to nodes
#
assign caraccess
switch motorcar=
switch motor_vehicle=
switch vehicle=
switch access=
switch barrier=gate 0
switch barrier=bollard 0
switch barrier=lift_gate 0
switch barrier=cycle_barrier 0
1
or access=yes or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=designated motor_vehicle=destination
or motorcar=yes or motorcar=designated motorcar=destination
assign initialcost
switch caraccess
0
1000000

View file

@ -0,0 +1,164 @@
#
# A fastbike could be a racing bike or a speed pedelec.
# But also at night or in rainy whether you might want
# to fallback to this one.
#
# Structure is similar to trekking.brf, see this for documenation.
#
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign turncost 90
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
6
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
6.0
0.0
assign costfactor
add max onewaypenalty accesspenalty
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
switch or highway=trunk highway=trunk_link 10
switch or highway=primary highway=primary_link 1.2
switch or highway=secondary highway=secondary_link 1.1
switch or highway=tertiary highway=tertiary_link 1.0
switch highway=unclassified 1.1
switch highway=pedestrian 10
switch highway=steps 1000
switch highway=ferry 5.67
switch highway=bridleway 5
switch highway=cycleway 1.3
switch or highway=residential highway=living_street switch isunpaved 10 1.2
switch highway=service switch isunpaved 10 1.2
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch isunpaved 3 1.2
switch tracktype=grade2 switch isunpaved 10 3
switch tracktype=grade3 10.0
switch tracktype=grade4 20.0
switch tracktype=grade5 30.0
switch ispaved 2.0 100.0
10.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
300
1000000

View file

@ -0,0 +1,317 @@
---lookupversion:2
---context:way
highway;0001731794 track
highway;0001457935 residential
highway;0000968516 service
highway;0000756237 footway
highway;0000521566 path
highway;0000261772 unclassified
highway;0000220315 secondary
highway;0000207585 tertiary
highway;0000103445 steps
highway;0000102114 primary
highway;0000094484 cycleway
highway;0000090388 living_street
highway;0000035041 motorway
highway;0000029965 pedestrian
highway;0000026875 motorway_link
highway;0000015054 trunk
highway;0000014604 primary_link
highway;0000012211 road
highway;0000011822 trunk_link
highway;0000005882 construction
highway;0000005425 bridleway
highway;0000005180 secondary_link
highway;0000003360 platform
highway;0000002616 proposed abandoned
highway;0000001374 tertiary_link
highway;0000000760 ferry
highway;0000000541 raceway
highway;0000000346 rest_area
highway;0000000300 bus_stop
highway;0000000184 services
tracktype;0000356503 grade2
tracktype;0000353482 grade3
tracktype;0000281625 grade1
tracktype;0000245193 grade4
tracktype;0000179135 grade5
surface;0000363915 asphalt
surface;0000303589 paved
surface;0000196783 gravel
surface;0000137371 ground
surface;0000128215 grass
surface;0000092748 unpaved
surface;0000086579 paving_stones
surface;0000066111 cobblestone
surface;0000042061 dirt
surface;0000026551 concrete
surface;0000025631 compacted
surface;0000019861 sand
surface;0000009400 pebblestone
surface;0000003197 fine_gravel
maxspeed;0000402224 30
maxspeed;0000224685 50
maxspeed;0000045177 100
maxspeed;0000037529 70
maxspeed;0000014237 none
maxspeed;0000014022 60
maxspeed;0000011530 80
maxspeed;0000009951 10
maxspeed;0000008056 20
maxspeed;0000005772 120
maxspeed;0000003165 40
maxspeed;0000002987 7
maxspeed;0000002826 signals
maxspeed;0000001933 130
service;0000221481 parking_aisle
service;0000157110 driveway
lit;0000132495 yes
lanes;0000098207 2
lanes;0000042192 1
lanes;0000018533 3
lanes;0000004577 4
lanes;0000000448 5
lanes;0000000318 1.5
access;0000044859 yes permissive
access;0000008452 designated official
access;0000028727 destination customers
access;0000076985 agricultural forestry
access;0000116270 private
access;0000028044 no
foot;0000339384 yes allowed Yes
foot;0000125339 designated official
foot;0000018945 no
foot;0000001562 private
foot;0000000279 destination
foot;0000008172 permissive
bicycle;0000302789 yes allowed permissive
bicycle;0000108056 designated official
bicycle;0000000265 destination
bicycle;0000003593 dismount
bicycle;0000001426 private
bicycle;0000070179 no
motorcar;0000010111 yes permissive
motorcar;0000001537 designated official
motorcar;0000007102 destination
motorcar;0000016706 agricultural forestry agriculture
motorcar;0000002178 private
motorcar;0000077771 no
motor_vehicle;0000013813 yes permissive
motor_vehicle;0000002098 designated official
motor_vehicle;0000009792 destination
motor_vehicle;0000019301 agricultural forestry
motor_vehicle;0000006563 private
motor_vehicle;0000025491 no
motorcycle;0000005750 yes permissive
motorcycle;0000001158 designated official
motorcycle;0000005805 destination
motorcycle;0000012401 agricultural forestry
motorcycle;0000001180 private
motorcycle;0000053955 no
vehicle;0000000505 yes permissive
vehicle;0000000027 designated
vehicle;0000007582 destination
vehicle;0000004357 agricultural forestry
vehicle;0000001155 private
vehicle;0000006487 no
cycleway;0000033575 track
cycleway;0000012829 no
cycleway;0000011604 lane
cycleway;0000008938 opposite
cycleway;0000001503 none
cycleway;0000001146 right
cycleway;0000001031 opposite_track
cycleway;0000001029 yes
cycleway;0000000856 opposite_lane
cycleway;0000000675 both
cycleway;0000000665 left
cycleway;0000000521 shared
cycleway;0000000383 street
cycleway;0000000176 segregated
mtb:scale;0000043968 0
mtb:scale;0000019705 1
mtb:scale;0000006436 2
mtb:scale;0000002702 3
mtb:scale;0000001083 4
mtb:scale;0000000329 5
sac_scale;0000049626 hiking
sac_scale;0000007933 mountain_hiking
sac_scale;0000001160 demanding_mountain_hiking
sac_scale;0000000523 yes
sac_scale;0000000364 alpine_hiking
sac_scale;0000000117 demanding_alpine_hiking
noexit;0000058492 yes
motorroad;0000019250 yes
oneway;0000330245 yes
oneway;0000075148 no
oneway;0000003679 -1
oneway;0000000001 true
oneway;0000000001 1
junction;0000015929 roundabout
bridge;0000182649 yes viaduct true suspension
tunnel;0000031626 yes
lcn;0000018999 yes
longdistancecycleway;0000000001 yes
reversedirection;0000000001 yes
---context:node
highway;0000100947 turning_circle
highway;0000067645 traffic_signals
highway;0000047209 crossing
highway;0000037164 bus_stop
highway;0000006577 motorway_junction
highway;0000003811 stop
highway;0000002331 mini_roundabout
highway;0000001789 milestone
highway;0000001692 passing_place
highway;0000001289 give_way
highway;0000001092 emergency_access_point
highway;0000000683 speed_camera
highway;0000000672 steps
highway;0000000658 incline_steep
highway;0000000620 elevator
highway;0000000506 street_lamp
highway;0000000490 ford
highway;0000000458 incline
highway;0000000135 rest_area
highway;0000000105 path
highway;0000000098 emergency_bay
highway;0000000096 road
highway;0000000087 platform
highway;0000000074 services
highway;0000000058 track
highway;0000000055 service
highway;0000000054 footway
highway;0000000053 traffic_calming
highway;0000000046 toll_bridge
highway;0000000037 city_entry
barrier;0000076979 gate
barrier;0000069308 bollard
barrier;0000028131 lift_gate
barrier;0000017332 cycle_barrier
barrier;0000005693 entrance
barrier;0000002885 block
barrier;0000001065 kissing_gate
barrier;0000000828 cattle_grid
barrier;0000000602 stile
barrier;0000000561 turnstile
barrier;0000000512 no
barrier;0000000463 fence
barrier;0000000417 bump_gate
barrier;0000000324 sally_port
barrier;0000000283 yes
barrier;0000000283 hampshire_gate
barrier;0000000236 swing_gate
barrier;0000000203 chain
barrier;0000000181 toll_booth
barrier;0000000180 door
barrier;0000000104 chicane
barrier;0000000096 tree
barrier;0000000087 border_control
barrier;0000000077 log
barrier;0000000076 traffic_crossing_pole
barrier;0000000063 wall
barrier;0000000060 fallen_tree
barrier;0000000052 stone
barrier;0000000048 ditch
barrier;0000000031 spikes
access;0000001309 yes permissive
access;0000000118 designated official
access;0000000405 destination customers
access;0000000276 agricultural forestry
access;0000008574 private
access;0000002145 no
foot;0000080681 yes permissive
foot;0000000326 designated official
foot;0000000023 destination
foot;0000000156 private
foot;0000009170 no
bicycle;0000076717 yes permissive
bicycle;0000000406 designated official
bicycle;0000000018 destination
bicycle;0000000081 dismount
bicycle;0000000051 private
bicycle;0000016121 no
motorcar;0000005785 yes permissive
motorcar;0000000026 designated official
motorcar;0000000080 destination
motorcar;0000000112 agricultural forestry
motorcar;0000000171 private
motorcar;0000001817 no
motor_vehicle;0000000066 yes permissive
motor_vehicle;0000000000 designated official
motor_vehicle;0000000030 destination
motor_vehicle;0000000073 agricultural forestry
motor_vehicle;0000000136 private
motor_vehicle;0000000469 no
motorcycle;0000004515 yes permissive
motorcycle;0000000007 designated official
motorcycle;0000000054 destination
motorcycle;0000000027 agricultural forestry
motorcycle;0000000063 private
motorcycle;0000001637 no
vehicle;0000000058 yes permissive
vehicle;0000000000 designated
vehicle;0000000081 destination
vehicle;0000000038 agricultural forestry
vehicle;0000000041 private
vehicle;0000000271 no
crossing;0000032485 traffic_signals
crossing;0000014300 uncontrolled
crossing;0000005086 island
crossing;0000001565 unmarked
crossing;0000001066 no
crossing;0000000333 zebra
railway;0000034039 level_crossing
railway;0000010175 crossing
noexit;0000043010 yes
entrance;0000015094 yes
entrance;0000007079 main
entrance;0000000554 service
entrance;0000000169 emergency
entrance;0000000063 exit
entrance;0000000008 private
lcn;0000018999 yes
longdistancecycleway;0000000001 yes

View file

@ -0,0 +1,119 @@
#
# Moped-Routing is experimantal !!!
#
# DO NOT USE FOR ACTUAL NAVIGATION
#
# Turn restrictions are missing, leading to wrong routes
#
---context:global
assign downhillcost 0
assign downhillcutoff 0
assign uphillcost 0
assign uphillcutoff 0
---context:way # following code refers to way-tags
assign turncost 90
assign initialcost switch highway=ferry 20000 0
#
# calculate logical car access
#
assign motorverhicleaccess
switch motor_vehicle=
switch vehicle=
switch access=
switch or highway=trunk highway=trunk_link 1
switch or highway=primary highway=primary_link 1
switch or highway=secondary highway=secondary_link 1
switch or highway=tertiary highway=tertiary_link 1
switch highway=unclassified 1
switch highway=ferry 1
switch or highway=residential highway=living_street 1
switch highway=service 1
0
or access=yes or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=designated motor_vehicle=destination
assign caraccess
switch motorcar=
motorverhicleaccess
or motorcar=yes or motorcar=designated motorcar=destination
assign motorcycleaccess
switch motorcycle=
motorverhicleaccess
or motorcycle=yes or motorcycle=designated motorcycle=destination
assign accesspenalty
switch or caraccess motorcycleaccess
switch motorroad=yes 10000 0
10000
assign onewaypenalty
switch switch reversedirection=yes
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
oneway=-1
10000
0.0
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign costfactor
add max onewaypenalty accesspenalty
switch or highway=trunk highway=trunk_link 1.5
switch or highway=primary highway=primary_link switch maxspeed=30 2.0 switch maxspeed=50 1.5 1.2
switch or highway=secondary highway=secondary_link 1.4
switch or highway=tertiary highway=tertiary_link 1.3
switch highway=unclassified 1.2
switch highway=ferry 5.67
switch highway=bridleway 5
switch or highway=residential highway=living_street 2
switch highway=service 2
switch or highway=track or highway=road highway=path
switch tracktype=grade1 5
switch ispaved 5
30
10000
---context:node # following code refers to node tags
#
# calculate logical car access to nodes
#
assign motorvehicleaccess
switch motor_vehicle=
switch vehicle=
switch access=
switch barrier=gate 0
switch barrier=bollard 0
switch barrier=lift_gate 0
switch barrier=cycle_barrier 0
1
or access=yes or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=designated motor_vehicle=destination
assign caraccess
switch motorcar=
motorvehicleaccess
or motorcar=yes or motorcar=designated motorcar=destination
assign motorcycleaccess
switch motorcycle=
motorvehicleaccess
or motorcycle=yes or motorcycle=designated motorcycle=destination
assign initialcost
switch or caraccess motorcycleaccess
0
1000000

View file

@ -0,0 +1,223 @@
# *** The trekking profile is for slow travel
# *** and avoiding car traffic, but still with
# *** a focus on approaching your destination
# *** efficiently.
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 1 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
#
# pre-calculate some logical expressions
#
assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes
assign isbike or bicycle=yes or bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
#
# this is the cost (in Meter) for a 90-degree turn
# The actual cost is calculated as turncost*cos(angle)
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
# to calculate the cost of that segment. The costfactor
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
add max onewaypenalty accesspenalty
#
# steps and ferries are special. Note this is handled
# before the longdistancecycleway-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch highway=ferry switch allow_ferries 5.67 100000
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
#
# default for any other highway type not handled above
#
2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000

View file

@ -0,0 +1,89 @@
---context:global # following code refers to global config
# the elevation parameters
assign downhillcost 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
assign turncost 0
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
assign accesspenalty switch or bikeaccess footaccess 0 100000
assign costfactor
add accesspenalty
switch highway=ferry 5.67
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
1
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost switch or bikeaccess footaccess 0 1000000

View file

@ -0,0 +1,223 @@
# *** The trekking profile is for slow travel
# *** and avoiding car traffic, but still with
# *** a focus on approaching your destination
# *** efficiently.
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 1 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
#
# pre-calculate some logical expressions
#
assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes
assign isbike or bicycle=yes or bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
#
# this is the cost (in Meter) for a 90-degree turn
# The actual cost is calculated as turncost*cos(angle)
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
# to calculate the cost of that segment. The costfactor
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
add max onewaypenalty accesspenalty
#
# steps and ferries are special. Note this is handled
# before the longdistancecycleway-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch highway=ferry switch allow_ferries 5.67 100000
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
#
# default for any other highway type not handled above
#
2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000

View file

@ -0,0 +1,223 @@
# *** The trekking profile is for slow travel
# *** and avoiding car traffic, but still with
# *** a focus on approaching your destination
# *** efficiently.
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 0 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
#
# pre-calculate some logical expressions
#
assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes
assign isbike or bicycle=yes or bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
#
# this is the cost (in Meter) for a 90-degree turn
# The actual cost is calculated as turncost*cos(angle)
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
# to calculate the cost of that segment. The costfactor
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
add max onewaypenalty accesspenalty
#
# steps and ferries are special. Note this is handled
# before the longdistancecycleway-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch highway=ferry switch allow_ferries 5.67 100000
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
#
# default for any other highway type not handled above
#
2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000

View file

@ -0,0 +1,223 @@
# *** The trekking profile is for slow travel
# *** and avoiding car traffic, but still with
# *** a focus on approaching your destination
# *** efficiently.
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 0 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
#
# pre-calculate some logical expressions
#
assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes
assign isbike or bicycle=yes or bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
#
# this is the cost (in Meter) for a 90-degree turn
# The actual cost is calculated as turncost*cos(angle)
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
# to calculate the cost of that segment. The costfactor
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
add max onewaypenalty accesspenalty
#
# steps and ferries are special. Note this is handled
# before the longdistancecycleway-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch highway=ferry switch allow_ferries 5.67 100000
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
#
# default for any other highway type not handled above
#
2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000

View file

@ -0,0 +1,223 @@
# *** The trekking profile is for slow travel
# *** and avoiding car traffic, but still with
# *** a focus on approaching your destination
# *** efficiently.
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 0 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
#
# pre-calculate some logical expressions
#
assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes
assign isbike or bicycle=yes or bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
#
# this is the cost (in Meter) for a 90-degree turn
# The actual cost is calculated as turncost*cos(angle)
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
# to calculate the cost of that segment. The costfactor
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
add max onewaypenalty accesspenalty
#
# steps and ferries are special. Note this is handled
# before the longdistancecycleway-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch highway=ferry switch allow_ferries 5.67 100000
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
#
# default for any other highway type not handled above
#
2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000

View file

@ -0,0 +1,223 @@
# *** The trekking profile is for slow travel
# *** and avoiding car traffic, but still with
# *** a focus on approaching your destination
# *** efficiently.
---context:global # following code refers to global config
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
---context:way # following code refers to way-tags
#
# pre-calculate some logical expressions
#
assign is_ldcr and longdistancecycleway=yes not ignore_cycleroutes
assign isbike or bicycle=yes or bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
#
# this is the cost (in Meter) for a 90-degree turn
# The actual cost is calculated as turncost*cos(angle)
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch highway=ferry 10000 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
#
# calculate logical bike access
#
assign bikeaccess
or longdistancecycleway=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
#
# handle one-ways. On primary roads, wrong-oneways should
# be close to forbidden, while on other ways we just add
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane cycleway=opposite_track 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
# by which the distance of a way-segment is multiplied
# to calculate the cost of that segment. The costfactor
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
add max onewaypenalty accesspenalty
#
# steps and ferries are special. Note this is handled
# before the longdistancecycleway-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch highway=ferry switch allow_ferries 5.67 100000
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch highway=proposed 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
#
# default for any other highway type not handled above
#
2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign bikeaccess
or or longdistancecycleway=yes lcn=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000

55
brouter-server/pom.xml Normal file
View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>0.98</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-server</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>btools.server.BRouter</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-map-creator</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,132 @@
package btools.server;
import java.io.File;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import btools.router.OsmNodeNamed;
import btools.router.RoutingEngine;
import btools.router.RoutingContext;
import btools.router.OsmTrack;
public class BRouter
{
public static void main(String[] args) throws Exception
{
if ( args.length == 2) // cgi-input-mode
{
try
{
String queryString = args[1];
int sepIdx = queryString.indexOf( '=' );
if ( sepIdx >= 0 ) queryString = queryString.substring( sepIdx + 1 );
queryString = URLDecoder.decode( queryString, "ISO-8859-1" );
int ntokens = 1;
for( int ic = 0; ic<queryString.length(); ic++ )
{
if ( queryString.charAt(ic) == '_' ) ntokens++;
}
String[] a2 = new String[ntokens + 1];
int idx = 1;
int pos = 0;
for(;;)
{
int p = queryString.indexOf( '_', pos );
if ( p < 0 )
{
a2[idx++] = queryString.substring( pos );
break;
}
a2[idx++] = queryString.substring( pos, p );
pos = p+1;
}
// cgi-header
System.out.println( "Content-type: text/plain" );
System.out.println();
OsmNodeNamed from = readPosition( a2, 1, "from" );
OsmNodeNamed to = readPosition( a2, 3, "to" );
int airDistance = from.calcDistance( to );
String airDistanceLimit = System.getProperty( "airDistanceLimit" );
if ( airDistanceLimit != null )
{
int maxKm = Integer.parseInt( airDistanceLimit );
if ( airDistance > maxKm * 1000 )
{
System.out.println( "airDistance " + (airDistance/1000) + "km exceeds limit for online router (" + maxKm + "km)" );
return;
}
}
long maxRunningTime = 60000; // the cgi gets a 1 Minute timeout
String sMaxRunningTime = System.getProperty( "maxRunningTime" );
if ( sMaxRunningTime != null )
{
maxRunningTime = Integer.parseInt( sMaxRunningTime ) * 1000;
}
long startTime = System.currentTimeMillis();
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
wplist.add( from );
wplist.add( to );
RoutingEngine re = new RoutingEngine( null, null, args[0], wplist, readRoutingContext(a2) );
re.doRun( maxRunningTime );
if ( re.getErrorMessage() != null )
{
System.out.println( re.getErrorMessage() );
}
}
catch( Throwable e )
{
System.out.println( "unexpected exception: " + e );
}
System.exit(0);
}
System.out.println("BRouter 0.98 / 12012014 / abrensch");
if ( args.length < 6 )
{
System.out.println("Find routes in an OSM map");
System.out.println("usage: java -jar brouter.jar <segmentdir> <lon-from> <lat-from> <lon-to> <lat-to> <profile>");
return;
}
List<OsmNodeNamed> wplist = new ArrayList<OsmNodeNamed>();
wplist.add( readPosition( args, 1, "from" ) );
wplist.add( readPosition( args, 3, "to" ) );
RoutingEngine re = new RoutingEngine( "mytrack", "mylog", args[0], wplist, readRoutingContext(args) );
re.doRun( 0 );
if ( re.getErrorMessage() != null )
{
System.out.println( re.getErrorMessage() );
}
}
private static OsmNodeNamed readPosition( String[] args, int idx, String name )
{
OsmNodeNamed n = new OsmNodeNamed();
n.name = name;
n.ilon = (int)( ( Double.parseDouble( args[idx ] ) + 180. ) *1000000. + 0.5);
n.ilat = (int)( ( Double.parseDouble( args[idx+1] ) + 90. ) *1000000. + 0.5);
return n;
}
private static RoutingContext readRoutingContext( String[] args )
{
RoutingContext c = new RoutingContext();
if ( args.length > 5 )
{
c.localFunction = args[5];
if ( args.length > 6 )
{
c.setAlternativeIdx( Integer.parseInt( args[6] ) );
}
}
return c;
}
}

View file

@ -0,0 +1,111 @@
package btools.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URLDecoder;
public class CgiUpload
{
public static void main(String[] args)
{
try
{
_main(args);
}
catch( Exception e )
{
System.out.println( "unexpected exception: " + e );
}
}
private static void _main(String[] args) throws Exception
{
String htmlTemplate = args[0];
String customeProfileDir = args[1];
String id = "" + System.currentTimeMillis();
// cgi-header
System.out.println( "Content-type: text/html" );
System.out.println();
// write the post message to a file
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream( customeProfileDir + "/" + id + ".brf" ) ) );
BufferedReader ir = new BufferedReader( new InputStreamReader( System.in ) );
String postData = ir.readLine();
String[] coordValues = new String[4];
if( postData != null )
{
int coordsIdx = postData.indexOf( "coords=" );
if ( coordsIdx >= 0)
{
int coordsEnd = postData.indexOf( '&' );
if ( coordsEnd >= 0)
{
String coordsString = postData.substring( coordsIdx + 7, coordsEnd );
postData = postData.substring( coordsEnd+1 );
int pos = 0;
for(int idx=0; idx<4; idx++)
{
int p = coordsString.indexOf( '_', pos );
coordValues[idx] = coordsString.substring( pos, p );
pos = p+1;
}
}
}
int sepIdx = postData.indexOf( '=' );
if ( sepIdx >= 0 ) postData = postData.substring( sepIdx + 1 );
postData = URLDecoder.decode( postData, "ISO-8859-1" );
bw.write( postData );
}
bw.close();
// echo the template with a custom select item
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream( htmlTemplate ) ) );
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
if ( line.indexOf( "<!-- sample profiles -->" ) >= 0 )
{
line = " <option value=\"../customprofiles/" + id + "\">custom</option>";
}
else if ( line.indexOf( "paste your profile here" ) >= 0 )
{
System.out.println( "<textarea type=\"text\" name=\"profile\" rows=30 cols=100>" );
System.out.println( postData );
line = "</textarea>";
}
else
{
line = replaceCoord( line, "lonfrom", coordValues[0] );
line = replaceCoord( line, "latfrom", coordValues[1] );
line = replaceCoord( line, "lonto", coordValues[2] );
line = replaceCoord( line, "latto", coordValues[3] );
}
System.out.println( line );
}
br.close();
}
private static String replaceCoord( String line, String name, String value )
{
String inputTag = "<td><input type=\"text\" name=\"" + name + "\"";
if ( line.indexOf( inputTag ) >= 0 )
{
return inputTag + " value=\"" + value + "\"></td>";
}
return line;
}
}

View file

@ -0,0 +1,267 @@
package btools.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
import btools.server.request.RequestHandler;
import btools.server.request.ServerHandler;
import btools.server.request.YoursHandler;
public class RouteServer extends Thread
{
public ServiceContext serviceContext;
public short port = 17777;
private boolean serverStopped = false;
private ServerSocket serverSocket = null;
public void close()
{
serverStopped = true;
try
{
ServerSocket ss = serverSocket;
serverSocket = null;
ss.close();
}
catch( Throwable t ) {}
}
private void killOtherServer() throws Exception
{
Socket socket = new Socket( "localhost", port );
BufferedWriter bw = null;
try
{
bw = new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) );
bw.write( "EXIT\n" );
}
finally
{
bw.close();
socket.close();
}
}
public void run()
{
// first go an kill any other server on that port
for(;;)
{
try
{
killOtherServer();
System.out.println( "killed, waiting" );
try { Thread.sleep( 3000 ); } catch( InterruptedException ie ) {}
}
catch( Throwable t ) {
System.out.println( "not killed: " + t );
break;
}
}
try
{
serverSocket = new ServerSocket(port);
for(;;)
{
System.out.println("RouteServer accepting connections..");
Socket clientSocket = serverSocket.accept();
if ( !serveRequest( clientSocket ) ) break;
}
}
catch( Throwable e )
{
System.out.println("RouteServer main loop got exception (exiting): "+e);
if ( serverSocket != null )
{
try { serverSocket.close(); } catch( Throwable t ) {}
}
System.exit(0);
}
}
public boolean serveRequest( Socket clientSocket )
{
BufferedReader br = null;
BufferedWriter bw = null;
try
{
br = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) );
bw = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream() ) );
// we just read the first line
String getline = br.readLine();
if ( getline == null || getline.startsWith( "EXIT") )
{
throw new RuntimeException( "socketExitRequest" );
}
if ( getline.startsWith("GET /favicon.ico") )
{
return true;
}
String url = getline.split(" ")[1];
HashMap<String,String> params = getUrlParams(url);
long maxRunningTime = getMaxRunningTime();
long startTime = System.currentTimeMillis();
RequestHandler handler;
if ( params.containsKey( "lonlats" ) && params.containsKey( "profile" ) )
{
handler = new ServerHandler( serviceContext, params );
}
else
{
handler = new YoursHandler( serviceContext, params );
}
RoutingContext rc = handler.readRoutingContext();
List<OsmNodeNamed> wplist = handler.readWayPointList();
RoutingEngine cr = new RoutingEngine( null, null, serviceContext.segmentDir, wplist, rc );
cr.quite = true;
cr.doRun( maxRunningTime );
// http-header
bw.write( "HTTP/1.1 200 OK\n" );
bw.write( "Connection: close\n" );
bw.write( "Content-Type: text/xml; charset=utf-8\n" );
bw.write( "Access-Control-Allow-Origin: *\n" );
bw.write( "\n" );
if ( cr.getErrorMessage() != null )
{
bw.write( cr.getErrorMessage() );
bw.write( "\n" );
}
else
{
OsmTrack track = cr.getFoundTrack();
if ( track != null )
{
bw.write( handler.formatTrack(track) );
}
}
bw.flush();
}
catch (Throwable e)
{
if ( "socketExitRequest".equals( e.getMessage() ) )
{
return false;
}
System.out.println("RouteServer got exception (will continue): "+e);
e.printStackTrace();
}
finally
{
if ( br != null ) try { br.close(); } catch( Exception e ) {}
if ( bw != null ) try { bw.close(); } catch( Exception e ) {}
}
return true;
}
public static void main(String[] args) throws Exception
{
System.out.println("BRouter 0.98 / 12012014 / abrensch");
if ( args.length != 3 )
{
System.out.println("serve YOURS protocol for BRouter");
System.out.println("usage: java RouteServer <segmentdir> <profile-list> <port>");
System.out.println("");
System.out.println("serve BRouter protocol");
System.out.println("usage: java RouteServer <segmentdir> <profiledir> <port>");
return;
}
ServiceContext serviceContext = new ServiceContext();
serviceContext.segmentDir = args[0];
File profileMapOrDir = new File( args[1] );
if ( profileMapOrDir.isDirectory() )
{
System.setProperty( "profileBaseDir", args[1] );
}
else
{
serviceContext.profileMap = loadProfileMap( profileMapOrDir );
}
ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[2]));
for (;;)
{
Socket clientSocket = serverSocket.accept();
RouteServer server = new RouteServer();
server.serviceContext = serviceContext;
server.serveRequest( clientSocket );
}
}
private static Map<String,String> loadProfileMap( File file ) throws IOException
{
Map<String,String> profileMap = new HashMap<String,String>();
BufferedReader pr = new BufferedReader( new InputStreamReader( new FileInputStream( file ) ) );
for(;;)
{
String key = pr.readLine();
if ( key == null ) break;
key = key.trim();
if ( key.length() == 0 ) continue;
String value = pr.readLine();
value = value.trim();
profileMap.put( key, value );
}
return profileMap;
}
private static HashMap<String,String> getUrlParams( String url )
{
HashMap<String,String> params = new HashMap<String,String>();
StringTokenizer tk = new StringTokenizer( url, "?&" );
while( tk.hasMoreTokens() )
{
String t = tk.nextToken();
StringTokenizer tk2 = new StringTokenizer( t, "=" );
if ( tk2.hasMoreTokens() )
{
String key = tk2.nextToken();
if ( tk2.hasMoreTokens() )
{
String value = tk2.nextToken();
params.put( key, value );
}
}
}
return params;
}
private static long getMaxRunningTime() {
long maxRunningTime = 60000;
String sMaxRunningTime = System.getProperty( "maxRunningTime" );
if ( sMaxRunningTime != null )
{
maxRunningTime = Integer.parseInt( sMaxRunningTime ) * 1000;
}
return maxRunningTime;
}
}

View file

@ -0,0 +1,16 @@
package btools.server;
import java.util.List;
import java.util.Map;
import btools.router.OsmNodeNamed;
/**
* Environment configuration that is initialized at server/service startup
*/
public class ServiceContext
{
public String segmentDir;
public Map<String,String> profileMap = null;
public List<OsmNodeNamed> nogoList;
}

View file

@ -0,0 +1,28 @@
package btools.server.request;
import java.util.HashMap;
import java.util.List;
import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.server.ServiceContext;
public abstract class RequestHandler
{
protected ServiceContext serviceContext;
protected HashMap<String,String> params;
public RequestHandler( ServiceContext serviceContext, HashMap<String,String> params )
{
this.serviceContext = serviceContext;
this.params = params;
}
public abstract RoutingContext readRoutingContext();
public abstract List<OsmNodeNamed> readWayPointList();
public abstract String formatTrack(OsmTrack track);
}

Some files were not shown because too many files have changed in this diff Show more