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
|
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