initial commit of BRouter Version 0.98
This commit is contained in:
parent
e4ae2b37d3
commit
91e62f1164
@ -2,3 +2,9 @@ brouter
|
||||
=======
|
||||
|
||||
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
31
brouter-core/pom.xml
Normal 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>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
172
brouter-core/src/main/java/btools/router/OpenSet.java
Normal file
172
brouter-core/src/main/java/btools/router/OpenSet.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
33
brouter-core/src/main/java/btools/router/OsmNodeNamed.java
Normal file
33
brouter-core/src/main/java/btools/router/OsmNodeNamed.java
Normal 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;
|
||||
}
|
||||
}
|
||||
371
brouter-core/src/main/java/btools/router/OsmPath.java
Normal file
371
brouter-core/src/main/java/btools/router/OsmPath.java
Normal 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;
|
||||
}
|
||||
}
|
||||
113
brouter-core/src/main/java/btools/router/OsmPathElement.java
Normal file
113
brouter-core/src/main/java/btools/router/OsmPathElement.java
Normal 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;
|
||||
}
|
||||
}
|
||||
365
brouter-core/src/main/java/btools/router/OsmTrack.java
Normal file
365
brouter-core/src/main/java/btools/router/OsmTrack.java
Normal 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;
|
||||
}
|
||||
}
|
||||
241
brouter-core/src/main/java/btools/router/RoutingContext.java
Normal file
241
brouter-core/src/main/java/btools/router/RoutingContext.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
968
brouter-core/src/main/java/btools/router/RoutingEngine.java
Normal file
968
brouter-core/src/main/java/btools/router/RoutingEngine.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
13
brouter-expressions/pom.xml
Normal file
13
brouter-expressions/pom.xml
Normal 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>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package btools.expressions;
|
||||
|
||||
|
||||
public interface BExpressionReceiver
|
||||
{
|
||||
public void expressionWarning( String context, String message );
|
||||
}
|
||||
35
brouter-map-creator/pom.xml
Normal file
35
brouter-map-creator/pom.xml
Normal 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>
|
||||
@ -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 {}
|
||||
}
|
||||
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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";
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@ -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";
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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" );
|
||||
}
|
||||
}
|
||||
@ -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" );
|
||||
}
|
||||
}
|
||||
18
brouter-map-creator/src/test/resources/all.brf
Normal file
18
brouter-map-creator/src/test/resources/all.brf
Normal 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
|
||||
11
brouter-map-creator/src/test/resources/all.brf.BAK
Normal file
11
brouter-map-creator/src/test/resources/all.brf.BAK
Normal 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
|
||||
107
brouter-map-creator/src/test/resources/car-test.brf
Normal file
107
brouter-map-creator/src/test/resources/car-test.brf
Normal 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
|
||||
BIN
brouter-map-creator/src/test/resources/dreieich.osm.gz
Normal file
BIN
brouter-map-creator/src/test/resources/dreieich.osm.gz
Normal file
Binary file not shown.
317
brouter-map-creator/src/test/resources/lookups.dat
Normal file
317
brouter-map-creator/src/test/resources/lookups.dat
Normal 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
13
brouter-mapaccess/pom.xml
Normal 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>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
232
brouter-mapaccess/src/main/java/btools/mapaccess/MicroCache.java
Normal file
232
brouter-mapaccess/src/main/java/btools/mapaccess/MicroCache.java
Normal 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);
|
||||
}
|
||||
}
|
||||
223
brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java
Normal file
223
brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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 ); }
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Container for routig configs
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
public interface OsmLinkHolder
|
||||
{
|
||||
void setNextForLink( OsmLinkHolder holder );
|
||||
|
||||
OsmLinkHolder getNextForLink();
|
||||
}
|
||||
397
brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
Normal file
397
brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
brouter-mapaccess/src/main/java/btools/mapaccess/OsmPos.java
Normal file
23
brouter-mapaccess/src/main/java/btools/mapaccess/OsmPos.java
Normal 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();
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
28
brouter-routing-app/AndroidManifest.xml
Normal file
28
brouter-routing-app/AndroidManifest.xml
Normal 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>
|
||||
8
brouter-routing-app/classpath
Normal file
8
brouter-routing-app/classpath
Normal 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>
|
||||
@ -0,0 +1,5 @@
|
||||
package btools.routingapp;
|
||||
|
||||
public final class BuildConfig {
|
||||
public static final boolean DEBUG = true;
|
||||
}
|
||||
136
brouter-routing-app/gen/btools/routingapp/IBRouterService.java
Normal file
136
brouter-routing-app/gen/btools/routingapp/IBRouterService.java
Normal 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;
|
||||
}
|
||||
22
brouter-routing-app/gen/btools/routingapp/R.java
Normal file
22
brouter-routing-app/gen/btools/routingapp/R.java
Normal 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;
|
||||
}
|
||||
}
|
||||
36
brouter-routing-app/pom.xml
Normal file
36
brouter-routing-app/pom.xml
Normal 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>
|
||||
33
brouter-routing-app/project
Normal file
33
brouter-routing-app/project
Normal 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>
|
||||
11
brouter-routing-app/project.properties
Normal file
11
brouter-routing-app/project.properties
Normal 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
|
||||
BIN
brouter-routing-app/res/drawable-hdpi/icon.png
Normal file
BIN
brouter-routing-app/res/drawable-hdpi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
brouter-routing-app/res/drawable-ldpi/icon.png
Normal file
BIN
brouter-routing-app/res/drawable-ldpi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
brouter-routing-app/res/drawable-mdpi/icon.png
Normal file
BIN
brouter-routing-app/res/drawable-mdpi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
22
brouter-routing-app/res/layout/main.xml
Normal file
22
brouter-routing-app/res/layout/main.xml
Normal 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>
|
||||
19
brouter-routing-app/res/values/strings.xml
Normal file
19
brouter-routing-app/res/values/strings.xml
Normal 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>
|
||||
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -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 ) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
55
brouter-server/pom.xml
Normal 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>
|
||||
132
brouter-server/src/main/java/btools/server/BRouter.java
Normal file
132
brouter-server/src/main/java/btools/server/BRouter.java
Normal 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;
|
||||
}
|
||||
}
|
||||
111
brouter-server/src/main/java/btools/server/CgiUpload.java
Normal file
111
brouter-server/src/main/java/btools/server/CgiUpload.java
Normal 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;
|
||||
}
|
||||
}
|
||||
267
brouter-server/src/main/java/btools/server/RouteServer.java
Normal file
267
brouter-server/src/main/java/btools/server/RouteServer.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user