version 1.4.9

This commit is contained in:
Arndt Brenschede 2017-09-24 17:11:04 +02:00
parent 0171ba39a0
commit c517ccc2df
43 changed files with 2002 additions and 508 deletions

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-codec</artifactId>

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-core</artifactId>

View file

@ -0,0 +1,98 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import btools.expressions.BExpressionContext;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
class KinematicModel extends OsmPathModel
{
public OsmPrePath createPrePath()
{
return new KinematicPrePath();
}
public OsmPath createPath()
{
return new KinematicPath();
}
public double turnAngleDecayLength;
public double f_roll;
public double f_air;
public double f_recup;
public double p_standby;
public double recup_efficiency;
public double totalweight;
public double vmax;
public double leftWaySpeed;
public double rightWaySpeed;
// derived values
public double xweight; // the weight-factor between time and energy for cost calculation
public double timecost0; // minimum possible "energy-adjusted-time" per meter
private int wayIdxMaxspeed;
private int wayIdxMinspeed;
private int nodeIdxMaxspeed;
protected BExpressionContextWay ctxWay;
protected BExpressionContextNode ctxNode;
@Override
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode )
{
ctxWay = expctxWay;
ctxNode = expctxNode;
BExpressionContext expctxGlobal = expctxWay; // just one of them...
turnAngleDecayLength = expctxGlobal.getVariableValue( "turnAngleDecayLength", 50.f );
f_roll = expctxGlobal.getVariableValue( "f_roll", 232.f );
f_air = expctxGlobal.getVariableValue( "f_air", 0.4f );
f_recup = expctxGlobal.getVariableValue( "f_recup", 400.f );
p_standby = expctxGlobal.getVariableValue( "p_standby", 250.f );
recup_efficiency = expctxGlobal.getVariableValue( "recup_efficiency", 0.7f );
totalweight = expctxGlobal.getVariableValue( "totalweight", 1640.f );
vmax = expctxGlobal.getVariableValue( "vmax", 80.f ) / 3.6;
leftWaySpeed = expctxGlobal.getVariableValue( "leftWaySpeed", 12.f ) / 3.6;
rightWaySpeed = expctxGlobal.getVariableValue( "rightWaySpeed", 12.f ) / 3.6;
xweight = 1./( 2. * f_air * vmax * vmax * vmax - p_standby );
timecost0 = 1./vmax + xweight*(f_roll + f_air*vmax*vmax + p_standby/vmax );
wayIdxMaxspeed = ctxWay.getOutputVariableIndex( "maxspeed", false );
wayIdxMinspeed = ctxWay.getOutputVariableIndex( "minspeed", false );
nodeIdxMaxspeed = ctxNode.getOutputVariableIndex( "maxspeed", false );
}
public float getWayMaxspeed()
{
return ctxWay.getBuildInVariable( wayIdxMaxspeed ) / 3.6f;
}
public float getWayMinspeed()
{
return ctxWay.getBuildInVariable( wayIdxMinspeed ) / 3.6f;
}
public float getNodeMaxspeed()
{
return ctxNode.getBuildInVariable( nodeIdxMaxspeed ) / 3.6f;
}
public double getMaxKineticEnergy()
{
// determine maximum possible speed and kinetic energy
double mspeed = Math.min( getWayMaxspeed(), Math.max( getWayMinspeed(), vmax ) );
return 0.5*totalweight*mspeed*mspeed;
}
}

View file

@ -0,0 +1,62 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
final class KinematicModelDummy extends KinematicModel
{
public OsmPrePath createPrePath()
{
return null;
}
public OsmPath createPath()
{
return null;
}
public KinematicModelDummy()
{
turnAngleDecayLength = 50.;
f_roll = 232.;
f_air = 0.4;
f_recup = 600.;
p_standby = 250.;
recup_efficiency = 0.7;
totalweight = 1640.;
vmax = 60./ 3.6;
leftWaySpeed = 12.f / 3.6;
rightWaySpeed = 12.f / 3.6;
}
public boolean useNewtonApprox;
// derived values
public double xweight = 1./( 2. * f_air * vmax * vmax * vmax - p_standby );
public double timecost0 = 1./vmax + xweight*(f_roll + f_air*vmax*vmax + p_standby/vmax );
@Override
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode )
{
}
public float getWayMaxspeed()
{
return 100.f;
}
public float getWayMinspeed()
{
return 0.f;
}
public float getNodeMaxspeed()
{
return 999.f;
}
}

View file

@ -0,0 +1,271 @@
/**
* The path-instance of the kinematic model
*
* @author ab
*/
package btools.router;
final class KinematicPath extends OsmPath
{
private double ekin; // kinetic energy (Joule)
private double totalTime; // travel time (seconds)
private double totalEnergy; // total route energy (Joule)
private float floatingAngleLeft; // sliding average left bend (degree)
private float floatingAngleRight; // sliding average right bend (degree)
@Override
protected void init( OsmPath orig )
{
KinematicPath origin = (KinematicPath)orig;
ekin = origin.ekin;
totalTime = origin.totalTime;
totalEnergy = origin.totalEnergy;
floatingAngleLeft = origin.floatingAngleLeft;
floatingAngleRight = origin.floatingAngleRight;
priorityclassifier = origin.priorityclassifier;
}
@Override
protected void resetState()
{
ekin = 0.;
totalTime = 0.;
totalEnergy = 0.;
floatingAngleLeft = 0.f;
floatingAngleRight = 0.f;
}
@Override
protected double processWaySection( RoutingContext rc, double dist, double delta_h, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier )
{
KinematicModel km = (KinematicModel)rc.pm;
double cost = 0.;
if ( isStartpoint )
{
// for forward direction, we start with target speed
if ( !rc.inverseDirection )
{
cost = 0.5 * (1. - cosangle ) * 40. / km.timecost0; // 40 seconds turn penalty
}
}
else
{
double turnspeed = 999.; // just high
if ( km.turnAngleDecayLength != 0. ) // process turn-angle slowdown
{
double decayFactor = exp( - dist / km.turnAngleDecayLength );
floatingAngleLeft = (float)( floatingAngleLeft * decayFactor );
floatingAngleRight = (float)( floatingAngleRight * decayFactor );
if ( angle < 0 ) floatingAngleLeft -= (float)angle;
else floatingAngleRight += (float)angle;
float aa = Math.max( floatingAngleLeft, floatingAngleRight );
if ( aa > 130. ) turnspeed = 0.;
else if ( aa > 100. ) turnspeed = 1.;
else if ( aa > 70. ) turnspeed = 2.;
else if ( aa > 50. ) turnspeed = 4.;
else if ( aa > 30. ) turnspeed = 8.;
else if ( aa > 20. ) turnspeed = 14.;
else if ( aa > 10. ) turnspeed = 20.;
}
if ( nsection == 0 ) // process slowdown by crossing geometry
{
int classifiermask = (int)rc.expctxWay.getClassifierMask();
// penalty for equal priority crossing
boolean hasLeftWay = false;
boolean hasRightWay = false;
boolean hasResidential = false;
for( OsmPrePath prePath = rc.firstPrePath; prePath != null; prePath = prePath.next )
{
KinematicPrePath pp = (KinematicPrePath)prePath;
if ( ( (pp.classifiermask ^ classifiermask) & 8 ) != 0 ) // exactly one is linktype
{
continue;
}
if ( ( pp.classifiermask & 32 ) != 0 ) // touching a residential?
{
hasResidential = true;
}
if ( pp.priorityclassifier > priorityclassifier || pp.priorityclassifier == priorityclassifier && priorityclassifier < 20 )
{
double diff = pp.angle - angle;
if ( diff < -40. && diff > -140.) hasLeftWay = true;
if ( diff > 40. && diff < 140. ) hasRightWay = true;
}
}
double residentialSpeed = 13.;
if ( hasLeftWay && turnspeed > km.leftWaySpeed ) turnspeed = km.leftWaySpeed;
if ( hasRightWay && turnspeed > km.rightWaySpeed ) turnspeed = km.rightWaySpeed;
if ( hasResidential && turnspeed > residentialSpeed ) turnspeed = residentialSpeed;
if ( (lastpriorityclassifier < 20) ^ (priorityclassifier < 20) ) turnspeed = 0; // full stop for entering or leaving road network
}
cutEkin( km.totalweight, turnspeed ); // apply turnspeed
}
double distanceCost = evolveDistance( km, dist, delta_h );
if ( message != null )
{
message.costfactor = (float)(distanceCost/dist);
}
return cost + distanceCost;
}
protected double evolveDistance( KinematicModel km, double dist, double delta_h )
{
// elevation force
double fh = delta_h * km.totalweight * 9.81 / dist;
double emax = km.getMaxKineticEnergy();
if ( emax <= 0. )
{
return -1.;
}
double elow = 0.5*emax; // recup phase below half energy (=70% vmax)
double elapsedTime = 0.;
double dissipatedEnergy = 0.;
double v = Math.sqrt( 2. * ekin / km.totalweight );
double d = dist;
while( d > 0. )
{
boolean slow = ekin < elow;
boolean fast = ekin >= emax;
double etarget = slow ? elow : emax;
double f = km.f_roll + km.f_air*v*v + fh;
double f_recup = Math.max( 0., fast ? -f : (slow ? km.f_recup :0 ) -fh ); // additional recup for slow part
f += f_recup;
double delta_ekin;
double x;
if ( fast )
{
x = d;
delta_ekin = x*f;
elapsedTime += x/v;
ekin = etarget;
}
else
{
delta_ekin = etarget-ekin;
double b = 2.*km.f_air / km.totalweight;
double x0 = delta_ekin/f;
double x0b = x0*b;
x = x0*(1. - x0b*(0.5 + x0b*(0.333333333-x0b*0.25 ) ) ); // = ln( delta_ekin*b/f + 1.) / b;
double maxstep = Math.min( 50., d );
if ( x >= maxstep )
{
x = maxstep;
double xb = x*b;
delta_ekin = x*f*(1.+xb*(0.5+xb*(0.166666667+xb*0.0416666667 ) ) ); // = f/b* exp(xb-1)
ekin += delta_ekin;
}
else
{
ekin = etarget;
}
double v2 = Math.sqrt( 2. * ekin / km.totalweight );
double a = f / km.totalweight; // TODO: average force?
elapsedTime += (v2-v)/a;
v = v2;
}
d -= x;
// dissipated energy does not contain elevation and efficient recup
dissipatedEnergy += delta_ekin - x*(fh + f_recup*km.recup_efficiency);
}
dissipatedEnergy += elapsedTime * km.p_standby;
totalTime += elapsedTime;
totalEnergy += dissipatedEnergy + dist*fh;
return (elapsedTime + km.xweight * dissipatedEnergy)/km.timecost0; // =cost
}
@Override
protected double processTargetNode( RoutingContext rc )
{
KinematicModel km = (KinematicModel)rc.pm;
// finally add node-costs for target node
if ( targetNode.nodeDescription != null )
{
rc.expctxNode.evaluate( false , targetNode.nodeDescription );
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
return -1.;
}
cutEkin( km.totalweight, km.getNodeMaxspeed() ); // apply node maxspeed
if ( message != null )
{
message.linknodecost += (int)initialcost;
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription( false, targetNode.nodeDescription );
}
return initialcost;
}
return 0.;
}
private void cutEkin( double weight, double speed )
{
double e = 0.5*weight*speed*speed;
if ( ekin > e ) ekin = e;
}
private static double exp( double e )
{
double x = e;
double f = 1.;
while( e < -1. )
{
e += 1.;
f *= 0.367879;
}
return f*( 1. + x*( 1. + x * ( 0.5 + x * ( 0.166667 + 0.0416667 * x) ) ) );
}
@Override
public int elevationCorrection( RoutingContext rc )
{
return 0;
}
@Override
public boolean definitlyWorseThan( OsmPath path, RoutingContext rc )
{
KinematicPath p = (KinematicPath)path;
int c = p.cost;
return cost > c + 100;
}
public double getTotalTime()
{
return totalTime;
}
public double getTotalEnergy()
{
return totalEnergy;
}
}

View file

@ -0,0 +1,58 @@
/**
* Simple version of OsmPath just to get angle and priority of first segment
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
final class KinematicPrePath extends OsmPrePath
{
public double angle;
public int priorityclassifier;
public int classifiermask;
protected void initPrePath(OsmPath origin, RoutingContext rc )
{
byte[] description = link.descriptionBitmap;
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
// extract the 3 positions of the first section
int lon0 = origin.originLon;
int lat0 = origin.originLat;
OsmNode p1 = sourceNode;
int lon1 = p1.getILon();
int lat1 = p1.getILat();
boolean isReverse = link.isReverse( sourceNode );
// evaluate the way tags
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
int lon2;
int lat2;
if ( transferNode == null )
{
lon2 = targetNode.ilon;
lat2 = targetNode.ilat;
}
else
{
lon2 = transferNode.ilon;
lat2 = transferNode.ilat;
}
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
angle = rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
classifiermask = (int)rc.expctxWay.getClassifierMask();
}
}

View file

@ -26,6 +26,9 @@ final class MessageData implements Cloneable
int lat;
short ele;
float time;
float energy;
String toMessage()
{
if ( wayKeyValues == null )

View file

@ -13,33 +13,27 @@ import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
import btools.mapaccess.TurnRestriction;
final class OsmPath implements OsmLinkHolder
abstract class OsmPath implements OsmLinkHolder
{
/**
* 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;
public int airdistance = 0; // distance to endpos
private OsmNode sourceNode;
private OsmNode targetNode;
protected OsmNode sourceNode;
protected OsmNode targetNode;
private OsmLink link;
protected OsmLink link;
public OsmPathElement originElement;
public OsmPathElement myElement;
private float traffic;
protected float traffic;
private OsmLinkHolder nextForLink = null;
@ -51,7 +45,9 @@ final class OsmPath implements OsmLinkHolder
public int originLat;
// the classifier of the segment just before this paths position
public float lastClassifier;
protected float lastClassifier;
protected int priorityclassifier;
public MessageData message;
@ -81,13 +77,8 @@ final class OsmPath implements OsmLinkHolder
}
}
OsmPath()
public void init( OsmLink link )
{
}
OsmPath( OsmLink link )
{
this();
this.link = link;
targetNode = link.getTarget( null );
selev = targetNode.getSElev();
@ -96,9 +87,8 @@ final class OsmPath implements OsmLinkHolder
originLat = -1;
}
OsmPath( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
public void init( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
{
this();
if ( origin.myElement == null )
{
origin.myElement = OsmPathElement.create( origin, rc.countTraffic );
@ -108,19 +98,22 @@ final class OsmPath implements OsmLinkHolder
this.sourceNode = origin.targetNode;
this.targetNode = link.getTarget( sourceNode );
this.cost = origin.cost;
this.ehbd = origin.ehbd;
this.ehbu = origin.ehbu;
this.lastClassifier = origin.lastClassifier;
init( origin );
addAddionalPenalty(refTrack, detailMode, origin, link, rc );
}
protected abstract void init( OsmPath orig );
private void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
protected abstract void resetState();
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
{
byte[] description = link.descriptionBitmap;
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
boolean recordTransferNodes = detailMode || rc.countTraffic;
boolean recordMessageData = detailMode;
rc.nogomatch = false;
@ -128,55 +121,48 @@ final class OsmPath implements OsmLinkHolder
int lon0 = origin.originLon;
int lat0 = origin.originLat;
OsmNode p1 = sourceNode;
int lon1 = p1.getILon();
int lat1 = p1.getILat();
int lon1 = sourceNode.getILon();
int lat1 = sourceNode.getILat();
short ele1 = origin.selev;
int linkdisttotal = 0;
MessageData msgData = recordMessageData ? new MessageData() : null;
message = detailMode ? new MessageData() : null;
boolean isReverse = link.isReverse( sourceNode );
// evaluate the way tags
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
// calculate the costfactor inputs
float costfactor = rc.expctxWay.getCostfactor();
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
float turncostbase = rc.expctxWay.getTurncost();
float cfup = rc.expctxWay.getUphillCostfactor();
float cfdown = rc.expctxWay.getDownhillCostfactor();
float cf = rc.expctxWay.getCostfactor();
cfup = cfup == 0.f ? cf : cfup;
cfdown = cfdown == 0.f ? cf : cfdown;
int lastpriorityclassifier = priorityclassifier;
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
int classifiermask = (int)rc.expctxWay.getClassifierMask();
// *** add initial cost if the classifier changed
float newClassifier = rc.expctxWay.getInitialClassifier();
if ( newClassifier == 0. )
{
newClassifier = (cfup + cfdown + cf)/3;
}
float classifierDiff = newClassifier - lastClassifier;
if ( classifierDiff > 0.0005 || classifierDiff < -0.0005 )
{
lastClassifier = newClassifier;
float initialcost = rc.expctxWay.getInitialcost();
int iicost = (int)initialcost;
if ( recordMessageData )
if ( message != null )
{
msgData.linkinitcost += iicost;
message.linkinitcost += iicost;
}
cost += iicost;
}
OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
: rc.geometryDecoder.decodeGeometry( link.geometry, sourceNode, targetNode, isReverse );
boolean isFirstSection = true;
for(;;)
for(int nsection=0; ;nsection++)
{
originLon = lon1;
originLat = lat1;
@ -197,19 +183,8 @@ final class OsmPath implements OsmLinkHolder
ele2 = transferNode.selev;
}
// check turn restrictions: do we have one with that origin?
boolean checkTRs = false;
if ( isFirstSection )
{
isFirstSection = false;
// TODO: TRs for inverse routing would need inverse TR logic,
// inverse routing for now just for target island check, so don't care (?)
// in detail mode (=final pass) no TR to not mess up voice hints
checkTRs = rc.considerTurnRestrictions && !rc.inverseDirection && !detailMode;
}
if ( checkTRs )
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
if ( nsection == 0 && rc.considerTurnRestrictions && !detailMode )
{
boolean hasAnyPositive = false;
boolean hasPositive = false;
@ -217,14 +192,22 @@ final class OsmPath implements OsmLinkHolder
TurnRestriction tr = sourceNode.firstRestriction;
while( tr != null )
{
boolean trValid = ! (tr.exceptBikes() && rc.bikeMode);
if ( trValid && tr.fromLon == lon0 && tr.fromLat == lat0 )
if ( tr.exceptBikes() && rc.bikeMode )
{
tr = tr.next;
continue;
}
int fromLon = rc.inverseDirection ? lon2 : lon0;
int fromLat = rc.inverseDirection ? lat2 : lat0;
int toLon = rc.inverseDirection ? lon0 : lon2;
int toLat = rc.inverseDirection ? lat0 : lat2;
if ( tr.fromLon == fromLon && tr.fromLat == fromLat )
{
if ( tr.isPositive )
{
hasAnyPositive = true;
}
if ( tr.toLon == lon2 && tr.toLat == lat2 )
if ( tr.toLon == toLon && tr.toLat == toLat )
{
if ( tr.isPositive )
{
@ -246,13 +229,14 @@ final class OsmPath implements OsmLinkHolder
}
// if recording, new MessageData for each section (needed for turn-instructions)
if ( recordMessageData && msgData.wayKeyValues != null )
if ( message != null && message.wayKeyValues != null )
{
originElement.message = msgData;
msgData = new MessageData();
originElement.message = message;
message = new MessageData();
}
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
boolean stopAtEndpoint = false;
if ( rc.shortestmatch )
{
@ -263,10 +247,9 @@ final class OsmPath implements OsmLinkHolder
}
else
{
// we just start here, reset cost
// we just start here, reset everything
cost = 0;
ehbd = 0;
ehbu = 0;
resetState();
lon0 = -1; // reset turncost-pipe
lat0 = -1;
@ -285,131 +268,57 @@ final class OsmPath implements OsmLinkHolder
}
}
if ( recordMessageData )
if ( message != null )
{
msgData.linkdist += dist;
message.linkdist += dist;
}
linkdisttotal += dist;
// apply a start-direction if appropriate (by faking the origin position)
if ( lon0 == -1 && lat0 == -1 )
boolean isStartpoint = lon0 == -1 && lat0 == -1;
if ( isStartpoint )
{
double coslat = Math.cos( ( lat1 - 90000000 ) * 0.00000001234134 );
if ( rc.startDirectionValid && coslat > 0. )
if ( rc.startDirectionValid )
{
double dir = rc.startDirection.intValue() / 57.29578;
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / coslat );
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / rc.getCosLat() );
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) );
}
}
// *** penalty for turning angles
if ( !isTrafficBackbone && lon0 != -1 && lat0 != -1 )
{
// penalty proportional to direction change
double cos = rc.calcCosAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
int actualturncost = (int)(cos * turncostbase + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
cost += actualturncost;
if ( recordMessageData )
else
{
msgData.linkturncost += actualturncost;
msgData.turnangle = (float)rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
lon0 = lon1 - (lon2-lon1);
lat0 = lat1 - (lat2-lat1);
}
}
double angle = rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
double cosangle = rc.getCosAngle();
// *** 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
int elefactor = 250000;
// *** elevation stuff
double delta_h = 0.;
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;
}
float downweight = 0.f;
if ( ehbd > rc.elevationpenaltybuffer )
{
downweight = 1.f;
int excess = ehbd - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
downweight = ((float)excess)/reduce;
reduce = excess;
}
excess = ehbd - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
ehbd -= reduce;
if ( rc.downhillcostdiv > 0 )
{
int elevationCost = reduce/rc.downhillcostdiv;
cost += elevationCost;
if ( recordMessageData )
{
msgData.linkelevationcost += elevationCost;
}
}
}
else if ( ehbd < 0 )
{
ehbd = 0;
}
float upweight = 0.f;
if ( ehbu > rc.elevationpenaltybuffer )
{
upweight = 1.f;
int excess = ehbu - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
delta_h = (ele2 - ele1)/4.;
if ( rc.inverseDirection )
{
upweight = ((float)excess)/reduce;
reduce = excess;
}
excess = ehbu - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
ehbu -= reduce;
if ( rc.uphillcostdiv > 0 )
{
int elevationCost = reduce/rc.uphillcostdiv;
cost += elevationCost;
if ( recordMessageData )
{
msgData.linkelevationcost += elevationCost;
}
delta_h = -delta_h;
}
}
else if ( ehbu < 0 )
{
ehbu = 0;
}
// get the effective costfactor (slope dependent)
float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
if ( isTrafficBackbone )
{
costfactor = 0.f;
}
float fcost = dist * costfactor + 0.5f;
if ( ( costfactor > 9998. && !detailMode ) || fcost + cost >= 2000000000. )
double sectionCost = processWaySection( rc, dist, delta_h, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier );
if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. )
{
cost = -1;
return;
}
int waycost = (int)(fcost);
cost += waycost;
if ( isTrafficBackbone )
{
sectionCost = 0.;
}
cost += (int)sectionCost;
// calculate traffic
if ( rc.countTraffic )
@ -419,15 +328,17 @@ final class OsmPath implements OsmLinkHolder
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent);
}
if ( recordMessageData )
if ( message != null )
{
msgData.costfactor = costfactor;
msgData.priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
msgData.classifiermask = (int)rc.expctxWay.getClassifierMask();
msgData.lon = lon2;
msgData.lat = lat2;
msgData.ele = ele2;
msgData.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
message.turnangle = (float)angle;
message.time = (float)getTotalTime();
message.energy = (float)getTotalEnergy();
message.priorityclassifier = priorityclassifier;
message.classifiermask = classifiermask;
message.lon = lon2;
message.lat = lat2;
message.ele = ele2;
message.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
}
if ( stopAtEndpoint )
@ -436,9 +347,9 @@ final class OsmPath implements OsmLinkHolder
{
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
originElement.cost = cost;
if ( recordMessageData )
if ( message != null )
{
originElement.message = msgData;
originElement.message = message;
}
}
if ( rc.nogomatch )
@ -473,44 +384,26 @@ final class OsmPath implements OsmLinkHolder
lon1 = lon2;
lat1 = lat2;
ele1 = ele2;
}
// check for nogo-matches (after the *actual* start of segment)
if ( rc.nogomatch )
{
cost = -1;
return;
cost = -1;
return;
}
// finally add node-costs for target node
if ( targetNode.nodeDescription != null )
// add target-node costs
double targetCost = processTargetNode( rc );
if ( targetCost < 0. || targetCost + cost >= 2000000000. )
{
boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
cost = -1;
return;
}
int iicost = (int)initialcost;
cost += iicost;
if ( recordMessageData )
{
msgData.linknodecost += iicost;
msgData.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
}
cost = -1;
return;
}
if ( recordMessageData )
{
message = msgData;
}
cost += (int)targetCost;
}
public short interpolateEle( short e1, short e2, double fraction )
{
if ( e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE )
@ -520,29 +413,13 @@ final class OsmPath implements OsmLinkHolder
return (short)( e1*(1.-fraction) + e2*fraction );
}
public int elevationCorrection( RoutingContext rc )
{
return ( rc.downhillcostdiv > 0 ? ehbd/rc.downhillcostdiv : 0 )
+ ( rc.uphillcostdiv > 0 ? ehbu/rc.uphillcostdiv : 0 );
}
protected abstract double processWaySection( RoutingContext rc, double dist, double delta_h, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier );
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;
}
protected abstract double processTargetNode( RoutingContext rc );
public abstract int elevationCorrection( RoutingContext rc );
public abstract boolean definitlyWorseThan( OsmPath p, RoutingContext rc );
public OsmNode getSourceNode()
{
@ -569,4 +446,14 @@ final class OsmPath implements OsmLinkHolder
{
return nextForLink;
}
public double getTotalTime()
{
return 0.;
}
public double getTotalEnergy()
{
return 0.;
}
}

View file

@ -18,7 +18,7 @@ public class OsmPathElement implements OsmPos
private int ilat; // latitude
private int ilon; // longitude
private short selev; // longitude
public MessageData message = null; // description
public int cost;
@ -44,6 +44,19 @@ public class OsmPathElement implements OsmPos
return selev / 4.;
}
public final float getTime()
{
return message == null ? 0.f : message.time;
}
public final void setTime( float t )
{
if ( message != null )
{
message.time = t;
}
}
public final long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
@ -58,7 +71,7 @@ public class OsmPathElement implements OsmPos
double dlat = (ilat - p.getILat() )/1000000.;
double dlon = (ilon - p.getILon() )/1000000. * coslat;
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * (6378000. / 57.);
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * 110984.; // 6378000. / 57.3;
return (int)(d + 1.0 );
}

View file

@ -0,0 +1,20 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import btools.expressions.BExpressionContext;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
abstract class OsmPathModel
{
public abstract OsmPrePath createPrePath();
public abstract OsmPath createPath();
public abstract void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode );
}

View file

@ -0,0 +1,29 @@
/**
* Simple version of OsmPath just to get angle and priority of first segment
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
public abstract class OsmPrePath
{
protected OsmNode sourceNode;
protected OsmNode targetNode;
protected OsmLink link;
public OsmPrePath next;
public void init( OsmPath origin, OsmLink link, RoutingContext rc )
{
this.link = link;
this.sourceNode = origin.getTargetNode();
this.targetNode = link.getTarget( sourceNode );
initPrePath(origin, rc );
}
protected abstract void initPrePath(OsmPath origin, RoutingContext rc );
}

View file

@ -37,6 +37,8 @@ public final class OsmTrack
public long profileTimestamp;
public boolean isDirty;
public boolean showspeed;
private static class OsmPathElementHolder
{
public OsmPathElement node;
@ -120,7 +122,7 @@ public final class OsmTrack
MessageData current = null;
for ( OsmPathElement n : nodes )
{
if ( n.message != null )
if ( n.message != null && n.message.wayKeyValues != null )
{
MessageData md = n.message.copy();
if ( current != null )
@ -289,11 +291,15 @@ public final class OsmTrack
public void appendTrack( OsmTrack t )
{
int ourSize = nodes.size();
float t0 = ourSize > 0 ? nodes.get(ourSize - 1 ).getTime() : 0;
for ( int i = 0; i < t.nodes.size(); i++ )
{
if ( i > 0 || nodes.size() == 0 )
if ( i > 0 || ourSize == 0 )
{
nodes.add( t.nodes.get( i ) );
OsmPathElement e = t.nodes.get( i );
e.setTime( e.getTime() + t0 );
nodes.add( e );
}
}
@ -313,12 +319,16 @@ public final class OsmTrack
ascend += t.ascend;
plainAscend += t.plainAscend;
cost += t.cost;
energy += t.energy;
showspeed |= t.showspeed;
}
public int distance;
public int ascend;
public int plainAscend;
public int cost;
public int energy;
/**
* writes the track in gpx-format to a file
@ -390,7 +400,7 @@ public final class OsmTrack
}
else
{
sb.append( " creator=\"BRouter-1.4.8\" version=\"1.1\">\n" );
sb.append( " creator=\"BRouter-1.4.9\" version=\"1.1\">\n" );
}
if ( turnInstructionMode == 3) // osmand style
@ -537,6 +547,8 @@ public final class OsmTrack
sb.append( " \"track-length\": \"" ).append( distance ).append( "\",\n" );
sb.append( " \"filtered ascend\": \"" ).append( ascend ).append( "\",\n" );
sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" );
sb.append( " \"total-time\": \"" ).append( getTotalSeconds() ).append( "\",\n" );
sb.append( " \"total-energy\": \"" ).append( energy ).append( "\",\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\",\n" );
sb.append( " \"messages\": [\n" );
sb.append( " [\"" ).append( MESSAGES_HEADER.replaceAll( "\t", "\", \"" ) ).append( "\"],\n" );
@ -563,11 +575,27 @@ public final class OsmTrack
sb.append( " \"type\": \"LineString\",\n" );
sb.append( " \"coordinates\": [\n" );
OsmPathElement nn = null;
for ( OsmPathElement n : nodes )
{
String sele = n.getSElev() == Short.MIN_VALUE ? "" : ", " + n.getElev();
if ( showspeed ) // hack: show speed instead of elevation
{
int speed = 0;
if ( nn != null )
{
int dist = n.calcDistance( nn );
float dt = n.getTime()-nn.getTime();
if ( dt != 0.f )
{
speed = (int)((3.6f*dist)/dt + 0.5);
}
}
sele = ", " + speed;
}
sb.append( " [" ).append( formatILon( n.getILon() ) ).append( ", " ).append( formatILat( n.getILat() ) )
.append( sele ).append( "],\n" );
nn = n;
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
@ -580,6 +608,22 @@ public final class OsmTrack
return sb.toString();
}
private int getTotalSeconds()
{
float s = nodes.size() < 2 ? 0 : nodes.get( nodes.size()-1 ).getTime() - nodes.get( 0 ).getTime();
return (int)(s + 0.5);
}
public String getFormattedTime()
{
return format1( getTotalSeconds()/60. ) + "m";
}
public String getFormattedEnergy()
{
return format1( energy/3600000. ) + "kwh";
}
private static String formatILon( int ilon )
{
return formatPos( ilon - 180000000 );
@ -608,6 +652,13 @@ public final class OsmTrack
ac[i--] = '-';
return new String( ac, i + 1, 11 - i );
}
private String format1( double n )
{
String s = "" + (long)(n*10 + 0.5);
int len = s.length();
return s.substring( 0, len-1 ) + "." + s.charAt( len-1 );
}
public void dumpMessages( String filename, RoutingContext rc ) throws Exception
{

View file

@ -7,7 +7,6 @@ package btools.router;
import java.io.File;
import btools.expressions.BExpressionContextGlobal;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
@ -54,7 +53,7 @@ public final class ProfileCache
rc.expctxWay = expctxWay;
rc.expctxNode = expctxNode;
profilesBusy = true;
rc.readGlobalConfig(expctxWay);
rc.readGlobalConfig();
return true;
}
}
@ -62,19 +61,16 @@ public final class ProfileCache
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta );
rc.expctxWay = new BExpressionContextWay( rc.memoryclass * 512, meta );
rc.expctxNode = new BExpressionContextNode( 0, meta );
rc.expctxNode.setForeignContext( rc.expctxWay );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
expctxGlobal.parseFile( profileFile, null );
expctxGlobal.evaluate( new int[0] );
rc.readGlobalConfig(expctxGlobal);
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode.parseFile( profileFile, "global" );
rc.readGlobalConfig();
if ( rc.processUnusedTags )
{

View file

@ -14,6 +14,7 @@ import btools.expressions.BExpressionContext;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.mapaccess.GeometryDecoder;
import btools.mapaccess.OsmLink;
public final class RoutingContext
{
@ -71,8 +72,34 @@ public final class RoutingContext
public double starttimeoffset;
public boolean transitonly;
public void readGlobalConfig( BExpressionContext expctxGlobal )
private void setModel( String className )
{
if ( className == null )
{
pm = new StdModel();
}
else
{
try
{
Class clazz = Class.forName( className );
pm = (OsmPathModel) clazz.newInstance();
}
catch( Exception e )
{
throw new RuntimeException( "Cannot create path-model: " + e );
}
}
pm.init( expctxWay, expctxNode );
}
public void readGlobalConfig()
{
BExpressionContext expctxGlobal = expctxWay; // just one of them...
setModel( expctxGlobal._modelClass );
downhillcostdiv = (int)expctxGlobal.getVariableValue( "downhillcost", 0.f );
downhillcutoff = (int)(expctxGlobal.getVariableValue( "downhillcutoff", 0.f )*10000);
uphillcostdiv = (int)expctxGlobal.getVariableValue( "uphillcost", 0.f );
@ -112,6 +139,9 @@ public final class RoutingContext
trafficSourceExponent = expctxGlobal.getVariableValue( "trafficSourceExponent", -0.7f );
trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.f );
showspeed = 0.f != expctxGlobal.getVariableValue( "showspeed", 0.f );
inverseRouting = 0.f != expctxGlobal.getVariableValue( "inverseRouting", 0.f );
int tiMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f );
if ( tiMode != 1 ) // automatic selection from coordinate source
{
@ -128,6 +158,7 @@ public final class RoutingContext
public boolean startDirectionValid;
private double coslat;
private double cosangle;
public boolean nogomatch = false;
public boolean isEndpoint = false;
@ -148,6 +179,11 @@ public final class RoutingContext
public double trafficSourceExponent;
public double trafficSourceMinDist;
public boolean showspeed;
public boolean inverseRouting;
public OsmPrePath firstPrePath;
public int turnInstructionMode; // 0=none, 1=auto, 2=locus, 3=osmand, 4=comment-style, 5=gpsies-style
public double turnInstructionCatchingRange;
public boolean turnInstructionRoundabouts;
@ -165,7 +201,7 @@ public final class RoutingContext
try { ir = Integer.parseInt( s.substring( 4 ) ); }
catch( Exception e ) { /* ignore */ }
}
nogo.radius = ir / 111894.; // 6378000. / 57.;
nogo.radius = ir / 110984.; // 6378000. / 57.3;
}
}
@ -308,22 +344,19 @@ public final class RoutingContext
}
}
}
double dd = d * 111894.7368; // 6378000. / 57.;
double dd = d * 110984.; // 6378000. / 57.3;
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 )
public double getCosAngle()
{
double dlat1 = (lat1 - lat0);
double dlon1 = (lon1 - lon0) * coslat;
double dlat2 = (lat2 - lat1);
double dlon2 = (lon2 - lon1) * coslat;
return cosangle;
}
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..
public double getCosLat()
{
return coslat;
}
public double calcAngle( int lon0, int lat0, int lon1, int lat1, int lon2, int lat2 )
@ -334,14 +367,15 @@ public final class RoutingContext
double dlon2 = (lon2 - lon1) * coslat;
double dd = Math.sqrt( (dlat1*dlat1 + dlon1*dlon1)*(dlat2*dlat2 + dlon2*dlon2) );
if ( dd == 0. ) return 0.;
if ( dd == 0. ) { cosangle = 1.; return 0.; }
double sinp = (dlat1*dlon2 - dlon1*dlat2)/dd;
double cosp = (dlat1*dlat2 + dlon1*dlon2)/dd;
cosangle = cosp;
double p;
if ( sinp > -0.7 && sinp < 0.7 )
if ( sinp > -0.7071 && sinp < 0.7071 )
{
p = Math.asin( sinp )*57.3;
p = asin( sinp );
if ( cosp < 0. )
{
p = 180. - p;
@ -349,7 +383,7 @@ public final class RoutingContext
}
else
{
p = Math.acos( cosp )*57.3;
p = 90. - asin( cosp );
if ( sinp < 0. )
{
p = - p;
@ -362,4 +396,37 @@ public final class RoutingContext
return p;
}
private static double asin( double x )
{
double x2 = x*x;
double x4 = x2*x2;
return x * ( 57.4539 + 9.57565 * x2 + 4.30904 * x4 + 2.56491 * x2*x4 );
}
public OsmPathModel pm;
public OsmPrePath createPrePath( OsmPath origin, OsmLink link )
{
OsmPrePath p = pm.createPrePath();
if ( p != null )
{
p.init( origin, link, this );
}
return p;
}
public OsmPath createPath( OsmLink link )
{
OsmPath p = pm.createPath();
p.init( link );
return p;
}
public OsmPath createPath( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode )
{
OsmPath p = pm.createPath();
p.init( origin, link, refTrack, detailMode, this );
return p;
}
}

View file

@ -163,6 +163,10 @@ public class RoutingEngine extends Thread
track = findTrack( refTracks, lastTracks );
track.message = "track-length = " + track.distance + " filtered ascend = " + track.ascend
+ " plain-ascend = " + track.plainAscend + " cost=" + track.cost;
if ( track.energy != 0 )
{
track.message += " energy=" + track.getFormattedEnergy() + " time=" + track.getFormattedTime();
}
track.name = "brouter_" + routingContext.getProfileName() + "_" + i;
messageList.add( track.message );
@ -369,15 +373,26 @@ public class RoutingEngine extends Thread
matchWaypointsToNodes( matchedWaypoints );
// detect target islands: restricted search in inverse direction
routingContext.inverseDirection = true;
routingContext.inverseDirection = !routingContext.inverseRouting;
airDistanceCostFactor = 0.;
for( int i=0; i<matchedWaypoints.size() -1; i++ )
{
nodeLimit = 200;
OsmTrack seg = findTrack( "target-island-check", matchedWaypoints.get(i+1), matchedWaypoints.get(i), null, null, false );
if ( seg == null && nodeLimit > 0 )
if ( routingContext.inverseRouting )
{
throw new IllegalArgumentException( "target island detected for section " + i );
OsmTrack seg = findTrack( "start-island-check", matchedWaypoints.get(i), matchedWaypoints.get(i+1), null, null, false );
if ( seg == null && nodeLimit > 0 )
{
throw new IllegalArgumentException( "start island detected for section " + i );
}
}
else
{
OsmTrack seg = findTrack( "target-island-check", matchedWaypoints.get(i+1), matchedWaypoints.get(i), null, null, false );
if ( seg == null && nodeLimit > 0 )
{
throw new IllegalArgumentException( "target island detected for section " + i );
}
}
}
routingContext.inverseDirection = false;
@ -397,7 +412,18 @@ public class RoutingEngine extends Thread
refTracks[i].addNodes( lastTracks[i] );
}
OsmTrack seg = searchTrack( matchedWaypoints.get(i), matchedWaypoints.get(i+1), i == matchedWaypoints.size()-2 ? nearbyTrack : null, refTracks[i] );
OsmTrack seg;
if ( routingContext.inverseRouting )
{
routingContext.inverseDirection = true;
seg = searchTrack( matchedWaypoints.get(i+1), matchedWaypoints.get(i), null, refTracks[i] );
routingContext.inverseDirection = false;
}
else
{
seg = searchTrack( matchedWaypoints.get(i), matchedWaypoints.get(i+1), i == matchedWaypoints.size()-2 ? nearbyTrack : null, refTracks[i] );
}
if ( seg == null ) return null;
totaltrack.appendTrack( seg );
lastTracks[i] = seg;
@ -651,7 +677,7 @@ public class RoutingEngine extends Thread
OsmPath bestPath = null;
OsmLink bestLink = null;
OsmLink startLink = new OsmLink( null, n1 );
OsmPath startPath = new OsmPath( startLink );
OsmPath startPath = routingContext.createPath( startLink );
startLink.addLinkHolder( startPath, null );
double minradius = 1e10;
for( OsmLink link = n1.firstlink; link != null; link = link.getNext( n1 ) )
@ -663,7 +689,7 @@ public class RoutingEngine extends Thread
if ( nextNode != n2 ) continue; // just that link
wp.radius = 1e9;
OsmPath testPath = new OsmPath( startPath, link, null, guideTrack != null, routingContext );
OsmPath testPath = routingContext.createPath( startPath, link, null, guideTrack != null );
testPath.airdistance = endPos == null ? 0 : nextNode.calcDistance( endPos );
if ( wp.radius < minradius )
{
@ -692,12 +718,12 @@ public class RoutingEngine extends Thread
{
if ( wp != null ) routingContext.setWaypoint( wp, true );
OsmLink startLink = new OsmLink( null, n1 );
OsmPath startPath = new OsmPath( startLink );
OsmPath startPath = routingContext.createPath( startLink );
startLink.addLinkHolder( startPath, null );
if ( wp != null ) wp.radius = 1e-5;
return new OsmPath( startPath, link, null, guideTrack != null, routingContext );
return routingContext.createPath( startPath, link, null, guideTrack != null );
}
finally
{
@ -761,7 +787,7 @@ public class RoutingEngine extends Thread
if ( start1 == null || start2 == null ) return null;
if ( routingContext.startDirectionValid = ( fastPartialRecalc && routingContext.startDirection != null ) )
if ( routingContext.startDirectionValid = ( fastPartialRecalc && routingContext.startDirection != null && !routingContext.inverseDirection ) )
{
logInfo( "using start direction " + routingContext.startDirection );
}
@ -865,7 +891,9 @@ public class RoutingEngine extends Thread
{
// track found, compile
logInfo( "found track at cost " + path.cost + " nodesVisited = " + nodesVisited );
return compileTrack( path, verbose );
OsmTrack t = compileTrack( path, verbose );
t.showspeed = routingContext.showspeed;
return t;
}
// check for a match with the cost-cutting-track
@ -916,11 +944,38 @@ public class RoutingEngine extends Thread
}
// recheck cutoff before doing expensive stuff
if ( path.cost + path.airdistance > maxTotalCost + 10 )
if ( path.cost + path.airdistance > maxTotalCost + 100 )
{
path.unregisterUpTree( routingContext );
continue;
}
routingContext.firstPrePath = null;
for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
{
OsmNode nextNode = link.getTarget( currentNode );
if ( ! nodesCache.obtainNonHollowNode( nextNode ) )
{
continue; // border node?
}
if ( nextNode.firstlink == null )
{
continue; // don't care about dead ends
}
if ( nextNode == sourceNode )
{
continue; // border node?
}
OsmPrePath prePath = routingContext.createPrePath( path, link );
if ( prePath != null )
{
prePath.next = routingContext.firstPrePath;
routingContext.firstPrePath = prePath;
}
}
for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
{
@ -946,14 +1001,14 @@ public class RoutingEngine extends Thread
{
continue;
}
OsmPathElement guideNode = guideTrack.nodes.get( gidx );
OsmPathElement guideNode = guideTrack.nodes.get( routingContext.inverseRouting ? guideTrack.nodes.size() - 1 - gidx : gidx );
long nextId = nextNode.getIdFromPos();
if ( nextId != guideNode.getIdFromPos() )
{
// not along the guide-track, discard, but register for voice-hint processing
if ( routingContext.turnInstructionMode > 0 )
{
OsmPath detour = new OsmPath( path, link, refTrack, true, routingContext );
OsmPath detour = routingContext.createPath( path, link, refTrack, true );
if ( detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2 )
{
guideTrack.registerDetourForId( currentNode.getIdFromPos(), OsmPathElement.create( detour, false ) );
@ -985,7 +1040,7 @@ public class RoutingEngine extends Thread
endPos.radius = 1e-5;
routingContext.setWaypoint( endPos, true );
}
OsmPath testPath = new OsmPath( otherPath, link, refTrack, guideTrack != null, routingContext );
OsmPath testPath = routingContext.createPath( otherPath, link, refTrack, guideTrack != null );
if ( testPath.cost >= 0 && ( bestPath == null || testPath.cost < bestPath.cost ) )
{
bestPath = testPath;
@ -1004,7 +1059,7 @@ public class RoutingEngine extends Thread
boolean inRadius = boundary == null || boundary.isInBoundary( nextNode, bestPath.cost );
if ( inRadius && ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 10 ) )
if ( inRadius && ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 100 ) )
{
// add only if this may beat an existing path for that link
OsmLinkHolder dominator = link.getFirstLinkHolder( currentNode );
@ -1052,12 +1107,18 @@ public class RoutingEngine extends Thread
private OsmTrack compileTrack( OsmPath path, boolean verbose )
{
OsmPathElement element = OsmPathElement.create( path, false );
// for final track, cut endnode
if ( guideTrack != null ) element = element.origin;
if ( guideTrack != null )
{
element = element.origin;
}
float totalTime = element.getTime();
OsmTrack track = new OsmTrack();
track.cost = path.cost;
track.energy = (int)path.getTotalEnergy();
int distance = 0;
double ascend = 0;
@ -1066,9 +1127,24 @@ public class RoutingEngine extends Thread
short ele_start = Short.MIN_VALUE;
short ele_end = Short.MIN_VALUE;
double eleFactor = routingContext.inverseRouting ? -0.25 : 0.25;
while ( element != null )
{
track.addNode( element );
if ( guideTrack != null && element.message == null )
{
element.message = new MessageData();
}
if ( routingContext.inverseRouting )
{
element.setTime( totalTime - element.getTime() );
track.nodes.add( element );
}
else
{
track.nodes.add( 0, element );
}
OsmPathElement nextElement = element.origin;
short ele = element.getSElev();
@ -1081,7 +1157,7 @@ public class RoutingEngine extends Thread
short ele_next = nextElement.getSElev();
if ( ele_next != Short.MIN_VALUE )
{
ehb = ehb + (ele - ele_next)/4.;
ehb = ehb + (ele - ele_next)*eleFactor;
}
if ( ehb > 10. )
{
@ -1098,7 +1174,7 @@ public class RoutingEngine extends Thread
ascend += ehb;
track.distance = distance;
track.ascend = (int)ascend;
track.plainAscend = ( ele_end - ele_start ) / 4;
track.plainAscend = (int)(( ele_end - ele_start )*eleFactor+0.5);
logInfo( "track-length = " + track.distance );
logInfo( "filtered ascend = " + track.ascend );
track.buildMap();

View file

@ -0,0 +1,38 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import btools.expressions.BExpressionContext;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
final class StdModel extends OsmPathModel
{
public OsmPrePath createPrePath()
{
return null;
}
public OsmPath createPath()
{
return new StdPath();
}
protected BExpressionContextWay ctxWay;
protected BExpressionContextNode ctxNode;
@Override
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode )
{
ctxWay = expctxWay;
ctxNode = expctxNode;
BExpressionContext expctxGlobal = expctxWay; // just one of them...
}
}

View file

@ -0,0 +1,596 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
import btools.mapaccess.TurnRestriction;
final class StdPath extends OsmPath
{
/**
* The elevation-hysteresis-buffer (0-10 m)
*/
private int ehbd; // in micrometer
private int ehbu; // in micrometer
@Override
public void init( OsmPath orig )
{
StdPath origin = (StdPath)orig;
this.ehbd = origin.ehbd;
this.ehbu = origin.ehbu;
}
@Override
protected void resetState()
{
ehbd = 0;
ehbu = 0;
}
@Override
protected double processWaySection( RoutingContext rc, double distance, double delta_h, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier )
{
// calculate the costfactor inputs
float turncostbase = rc.expctxWay.getTurncost();
float cfup = rc.expctxWay.getUphillCostfactor();
float cfdown = rc.expctxWay.getDownhillCostfactor();
float cf = rc.expctxWay.getCostfactor();
cfup = cfup == 0.f ? cf : cfup;
cfdown = cfdown == 0.f ? cf : cfdown;
int dist = (int)distance; // legacy arithmetics needs int
// penalty for turning angle
int turncost = (int)((1.-cosangle) * turncostbase + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
if ( message != null )
{
message.linkturncost += turncost;
message.turnangle = (float)angle;
}
double sectionCost = turncost;
// *** penalty for elevation
// only the part of the descend that does not fit into the elevation-hysteresis-buffers
// leads to an immediate penalty
int delta_h_micros = (int)(1000000. * delta_h);
ehbd += -delta_h_micros - dist * rc.downhillcutoff;
ehbu += delta_h_micros - dist * rc.uphillcutoff;
float downweight = 0.f;
if ( ehbd > rc.elevationpenaltybuffer )
{
downweight = 1.f;
int excess = ehbd - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
downweight = ((float)excess)/reduce;
reduce = excess;
}
excess = ehbd - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
ehbd -= reduce;
if ( rc.downhillcostdiv > 0 )
{
int elevationCost = reduce/rc.downhillcostdiv;
sectionCost += elevationCost;
if ( message != null )
{
message.linkelevationcost += elevationCost;
}
}
}
else if ( ehbd < 0 )
{
ehbd = 0;
}
float upweight = 0.f;
if ( ehbu > rc.elevationpenaltybuffer )
{
upweight = 1.f;
int excess = ehbu - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
upweight = ((float)excess)/reduce;
reduce = excess;
}
excess = ehbu - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
ehbu -= reduce;
if ( rc.uphillcostdiv > 0 )
{
int elevationCost = reduce/rc.uphillcostdiv;
sectionCost += elevationCost;
if ( message != null )
{
message.linkelevationcost += elevationCost;
}
}
}
else if ( ehbu < 0 )
{
ehbu = 0;
}
// get the effective costfactor (slope dependent)
float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
if ( message != null )
{
message.costfactor = costfactor;
}
sectionCost += dist * costfactor + 0.5f;
return sectionCost;
}
@Override
protected double processTargetNode( RoutingContext rc )
{
// finally add node-costs for target node
if ( targetNode.nodeDescription != null )
{
boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
return -1.;
}
if ( message != null )
{
message.linknodecost += (int)initialcost;
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
}
return initialcost;
}
return 0.;
}
// @Override
protected void xxxaddAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
{
byte[] description = link.descriptionBitmap;
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
boolean recordTransferNodes = detailMode || rc.countTraffic;
boolean recordMessageData = detailMode;
rc.nogomatch = false;
// extract the 3 positions of the first section
int lon0 = origin.originLon;
int lat0 = origin.originLat;
OsmNode p1 = sourceNode;
int lon1 = p1.getILon();
int lat1 = p1.getILat();
short ele1 = origin.selev;
int linkdisttotal = 0;
MessageData msgData = recordMessageData ? new MessageData() : null;
boolean isReverse = link.isReverse( sourceNode );
// evaluate the way tags
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
// calculate the costfactor inputs
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
float turncostbase = rc.expctxWay.getTurncost();
float cfup = rc.expctxWay.getUphillCostfactor();
float cfdown = rc.expctxWay.getDownhillCostfactor();
float cf = rc.expctxWay.getCostfactor();
cfup = cfup == 0.f ? cf : cfup;
cfdown = cfdown == 0.f ? cf : cfdown;
// *** add initial cost if the classifier changed
float newClassifier = rc.expctxWay.getInitialClassifier();
if ( newClassifier == 0. )
{
newClassifier = (cfup + cfdown + cf)/3;
}
float classifierDiff = newClassifier - lastClassifier;
if ( classifierDiff > 0.0005 || classifierDiff < -0.0005 )
{
lastClassifier = newClassifier;
float initialcost = rc.expctxWay.getInitialcost();
int iicost = (int)initialcost;
if ( recordMessageData )
{
msgData.linkinitcost += iicost;
}
cost += iicost;
}
OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
boolean isFirstSection = true;
for(;;)
{
originLon = lon1;
originLat = lat1;
int lon2;
int lat2;
short ele2;
if ( transferNode == null )
{
lon2 = targetNode.ilon;
lat2 = targetNode.ilat;
ele2 = targetNode.selev;
}
else
{
lon2 = transferNode.ilon;
lat2 = transferNode.ilat;
ele2 = transferNode.selev;
}
// check turn restrictions: do we have one with that origin?
boolean checkTRs = false;
if ( isFirstSection )
{
isFirstSection = false;
// TODO: TRs for inverse routing would need inverse TR logic,
// inverse routing for now just for target island check, so don't care (?)
// in detail mode (=final pass) no TR to not mess up voice hints
checkTRs = rc.considerTurnRestrictions && !rc.inverseDirection && !detailMode;
}
if ( checkTRs )
{
boolean hasAnyPositive = false;
boolean hasPositive = false;
boolean hasNegative = false;
TurnRestriction tr = sourceNode.firstRestriction;
while( tr != null )
{
boolean trValid = ! (tr.exceptBikes() && rc.bikeMode);
if ( trValid && tr.fromLon == lon0 && tr.fromLat == lat0 )
{
if ( tr.isPositive )
{
hasAnyPositive = true;
}
if ( tr.toLon == lon2 && tr.toLat == lat2 )
{
if ( tr.isPositive )
{
hasPositive = true;
}
else
{
hasNegative = true;
}
}
}
tr = tr.next;
}
if ( !hasPositive && ( hasAnyPositive || hasNegative ) )
{
cost = -1;
return;
}
}
// if recording, new MessageData for each section (needed for turn-instructions)
if ( recordMessageData && msgData.wayKeyValues != null )
{
originElement.message = msgData;
msgData = new MessageData();
}
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
boolean stopAtEndpoint = false;
if ( rc.shortestmatch )
{
if ( rc.isEndpoint )
{
stopAtEndpoint = true;
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
}
else
{
// we just start here, reset cost
cost = 0;
ehbd = 0;
ehbu = 0;
lon0 = -1; // reset turncost-pipe
lat0 = -1;
if ( recordTransferNodes )
{
if ( rc.wayfraction > 0. )
{
ele1 = interpolateEle( ele1, ele2, 1. - rc.wayfraction );
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic );
}
else
{
originElement = null; // prevent duplicate point
}
}
}
}
if ( recordMessageData )
{
msgData.linkdist += dist;
}
linkdisttotal += dist;
// apply a start-direction if appropriate (by faking the origin position)
if ( lon0 == -1 && lat0 == -1 )
{
double coslat = Math.cos( ( lat1 - 90000000 ) * 0.00000001234134 );
if ( rc.startDirectionValid && coslat > 0. )
{
double dir = rc.startDirection.intValue() / 57.29578;
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / coslat );
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) );
}
}
// *** penalty for turning angles
if ( !isTrafficBackbone && lon0 != -1 && lat0 != -1 )
{
// penalty proportional to direction change
double angle = rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
double cos = 1. - rc.getCosAngle();
int actualturncost = (int)(cos * turncostbase + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
cost += actualturncost;
if ( recordMessageData )
{
msgData.linkturncost += actualturncost;
msgData.turnangle = (float)rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
}
}
// *** 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
int elefactor = 250000;
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;
}
float downweight = 0.f;
if ( ehbd > rc.elevationpenaltybuffer )
{
downweight = 1.f;
int excess = ehbd - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
downweight = ((float)excess)/reduce;
reduce = excess;
}
excess = ehbd - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
ehbd -= reduce;
if ( rc.downhillcostdiv > 0 )
{
int elevationCost = reduce/rc.downhillcostdiv;
cost += elevationCost;
if ( recordMessageData )
{
msgData.linkelevationcost += elevationCost;
}
}
}
else if ( ehbd < 0 )
{
ehbd = 0;
}
float upweight = 0.f;
if ( ehbu > rc.elevationpenaltybuffer )
{
upweight = 1.f;
int excess = ehbu - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
upweight = ((float)excess)/reduce;
reduce = excess;
}
excess = ehbu - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
ehbu -= reduce;
if ( rc.uphillcostdiv > 0 )
{
int elevationCost = reduce/rc.uphillcostdiv;
cost += elevationCost;
if ( recordMessageData )
{
msgData.linkelevationcost += elevationCost;
}
}
}
else if ( ehbu < 0 )
{
ehbu = 0;
}
// get the effective costfactor (slope dependent)
float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
if ( isTrafficBackbone )
{
costfactor = 0.f;
}
float fcost = dist * costfactor + 0.5f;
if ( ( costfactor > 9998. && !detailMode ) || fcost + cost >= 2000000000. )
{
cost = -1;
return;
}
int waycost = (int)(fcost);
cost += waycost;
// calculate traffic
if ( rc.countTraffic )
{
int minDist = (int)rc.trafficSourceMinDist;
int cost2 = cost < minDist ? minDist : cost;
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent);
}
if ( recordMessageData )
{
msgData.costfactor = costfactor;
msgData.priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
msgData.classifiermask = (int)rc.expctxWay.getClassifierMask();
msgData.lon = lon2;
msgData.lat = lat2;
msgData.ele = ele2;
msgData.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
}
if ( stopAtEndpoint )
{
if ( recordTransferNodes )
{
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
originElement.cost = cost;
if ( recordMessageData )
{
originElement.message = msgData;
}
}
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( sourceNode ) )
{
int reftrackcost = linkdisttotal;
cost += reftrackcost;
}
selev = ele2;
break;
}
transferNode = transferNode.next;
if ( recordTransferNodes )
{
originElement = OsmPathElement.create( lon2, lat2, ele2, originElement, rc.countTraffic );
originElement.cost = cost;
originElement.addTraffic( traffic );
traffic = 0;
}
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 != null )
{
boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
cost = -1;
return;
}
int iicost = (int)initialcost;
cost += iicost;
if ( recordMessageData )
{
msgData.linknodecost += iicost;
msgData.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
}
}
if ( recordMessageData )
{
message = msgData;
}
}
@Override
public int elevationCorrection( RoutingContext rc )
{
return ( rc.downhillcostdiv > 0 ? ehbd/rc.downhillcostdiv : 0 )
+ ( rc.uphillcostdiv > 0 ? ehbu/rc.uphillcostdiv : 0 );
}
@Override
public boolean definitlyWorseThan( OsmPath path, RoutingContext rc )
{
StdPath p = (StdPath)path;
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;
}
}

View file

@ -27,7 +27,7 @@ public final class WaypointMatcherImpl implements WaypointMatcher
this.waypoints = waypoints;
for ( MatchedWaypoint mwp : waypoints )
{
mwp.radius = maxDistance / 111894.; // 6378000. / 57.;
mwp.radius = maxDistance * 110984.; // 6378000. / 57.3;
}
}

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-expressions</artifactId>

View file

@ -27,11 +27,14 @@ import btools.util.LruMap;
public abstract class BExpressionContext implements IByteArrayUnifier
{
private static final String CONTEXT_TAG = "---context:";
private static final String MODEL_TAG = "---model:";
private String context;
private boolean _inOurContext = false;
private BufferedReader _br = null;
private boolean _readerDone = false;
public String _modelClass;
private Map<String,Integer> lookupNumbers = new HashMap<String,Integer>();
private ArrayList<BExpressionLookupValue[]> lookupValues = new ArrayList<BExpressionLookupValue[]>();
@ -79,7 +82,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier
abstract String[] getBuildInVariableNames();
protected final float getBuildInVariable( int idx )
public final float getBuildInVariable( int idx )
{
return currentVars[idx+currentVarOffset];
}
@ -678,14 +681,17 @@ public abstract class BExpressionContext implements IByteArrayUnifier
return num != null && lookupData[num.intValue()] == 2;
}
public int getOutputVariableIndex( String name )
public int getOutputVariableIndex( String name, boolean mustExist )
{
int idx = getVariableIdx( name, false );
if ( idx < 0 )
{
throw new IllegalArgumentException( "unknown variable: " + name );
if ( mustExist )
{
throw new IllegalArgumentException( "unknown variable: " + name );
}
}
if ( idx < minWriteIdx )
else if ( idx < minWriteIdx )
{
throw new IllegalArgumentException( "bad access to global variable: " + name );
}
@ -719,7 +725,7 @@ public abstract class BExpressionContext implements IByteArrayUnifier
{
throw new IllegalArgumentException( "unknown foreign context: " + context );
}
return foreignContext.getOutputVariableIndex( name );
return foreignContext.getOutputVariableIndex( name, true );
}
public void parseFile( File file, String readOnlyContext )
@ -884,6 +890,10 @@ public abstract class BExpressionContext implements IByteArrayUnifier
{
_inOurContext = token.substring( CONTEXT_TAG.length() ).equals( context );
}
else if ( token.startsWith( MODEL_TAG ) )
{
_modelClass = token.substring( MODEL_TAG.length() ).trim();
}
else if ( _inOurContext )
{
return token;

View file

@ -1,35 +0,0 @@
// context for simple expression
// context means:
// - the local variables
// - the local variable names
// - the lookup-input variables
package btools.expressions;
public final class BExpressionContextGlobal extends BExpressionContext
{
private static String[] buildInVariables =
{};
protected String[] getBuildInVariableNames()
{
return buildInVariables;
}
public BExpressionContextGlobal( BExpressionMetaData meta )
{
super( "global", meta );
}
/**
* Create an Expression-Context for way context
*
* @param hashSize size of hashmap for result caching
*/
public BExpressionContextGlobal( int hashSize, BExpressionMetaData meta )
{
super( "global", hashSize, meta );
}
}

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-map-creator</artifactId>

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-mapaccess</artifactId>

View file

@ -14,6 +14,11 @@ public final class GeometryDecoder
private OsmTransferNode[] cachedNodes;
private int nCachedNodes = 128;
// result-cache
private OsmTransferNode firstTransferNode;
private boolean lastReverse;
private byte[] lastGeometry;
public GeometryDecoder()
{
// create some caches
@ -24,11 +29,14 @@ public final class GeometryDecoder
}
}
public OsmTransferNode decodeGeometry( byte[] geometry, OsmNode sourceNode, OsmNode targetNode, boolean reverseLink )
{
OsmTransferNode firstTransferNode = null;
if ( ( lastGeometry == geometry ) && ( lastReverse == reverseLink ) )
{
return firstTransferNode;
}
firstTransferNode = null;
OsmTransferNode lastTransferNode = null;
OsmNode startnode = reverseLink ? targetNode : sourceNode;
r.reset( geometry );
@ -64,6 +72,10 @@ public final class GeometryDecoder
lastTransferNode = trans;
}
}
lastReverse = reverseLink;
lastGeometry = geometry;
return firstTransferNode;
}
}

View file

@ -109,7 +109,7 @@ public class OsmNode extends OsmLink implements OsmPos
double dlat = ( ilat - p.getILat() ) / 1000000.;
double dlon = ( ilon - p.getILon() ) / 1000000. * coslat;
double d = Math.sqrt( dlat * dlat + dlon * dlon ) * ( 6378000. / 57.3 );
double d = Math.sqrt( dlat * dlat + dlon * dlon ) * 110984.; // 6378000. / 57.3;
return (int) ( d + 1.0 );
}

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-mem-router</artifactId>

View file

@ -109,7 +109,7 @@ public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
double dlat = (ilat - p.getILat() )/1000000.;
double dlon = (ilon - p.getILon() )/1000000. * coslat;
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * (6378000. / 57.3);
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * 110984.; // 6378000. / 57.3;
return (int)(d + 1.0 );
}

View file

@ -379,7 +379,9 @@ System.out.println( "*** finishedOffsets = " + finishedOffsets );
if ( trip.originNode != null )
{
// penalty proportional to direction change
double cos = rc.calcCosAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
double angle = rc.calcAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
double cos = 1. - rc.getCosAngle();
int turncost = (int) ( cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
waycost += turncost;
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="20"
android:versionName="1.4.8" package="btools.routingapp">
android:versionCode="21"
android:versionName="1.4.9" package="btools.routingapp">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BRouterActivity"
android:label="@string/app_name"

Binary file not shown.

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-routing-app</artifactId>

View file

@ -28,10 +28,9 @@ import android.os.Environment;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Toast;
import btools.expressions.BExpressionContextGlobal;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
import btools.mapaccess.OsmNode;
import btools.mapaccess.StorageConfigHelper;
import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
@ -171,7 +170,7 @@ public class BRouterView extends View
String basedir = fbd.getAbsolutePath();
AppLogger.log( "using basedir: " + basedir );
String version = "v1.4.7";
String version = "v1.4.9";
// create missing directories
assertDirectoryExists( "project directory", basedir + "/brouter", null, null );
@ -185,7 +184,7 @@ public class BRouterView extends View
profileDir = basedir + "/brouter/profiles2";
assertDirectoryExists( "profile directory", profileDir, "profiles2.zip", version );
modesDir = basedir + "/brouter/modes";
assertDirectoryExists( "modes directory", modesDir, "modes.zip", null );
assertDirectoryExists( "modes directory", modesDir, "modes.zip", version );
assertDirectoryExists( "readmes directory", basedir + "/brouter/readmes", "readmes.zip", version );
cor = CoordinateReader.obtainValidReader( basedir, segmentDir );
@ -564,7 +563,7 @@ public class BRouterView extends View
{
exists = !vtag.createNewFile();
}
catch( IOException io ) { throw new RuntimeException( "error checking version tag " + vtag ); }
catch( IOException io ) { } // well..
}
if ( !exists )
@ -767,7 +766,7 @@ public class BRouterView extends View
else
{
String memstat = memoryClass + "mb pathPeak " + ((cr.getPathPeak()+500)/1000) + "k";
String result = "version = BRouter-1.4.8\n" + "mem = " + memstat + "\ndistance = " + cr.getDistance() / 1000. + " km\n" + "filtered ascend = " + cr.getAscend()
String result = "version = BRouter-1.4.9\n" + "mem = " + memstat + "\ndistance = " + cr.getDistance() / 1000. + " km\n" + "filtered ascend = " + cr.getAscend()
+ " m\n" + "plain ascend = " + cr.getPlainAscend();
rawTrack = cr.getFoundRawTrack();
@ -920,13 +919,13 @@ public class BRouterView extends View
// parse global section of profile for mode preselection
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta );
BExpressionContextWay expctx = new BExpressionContextWay( meta );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
expctxGlobal.parseFile( new File( profilePath ), null );
expctxGlobal.evaluate( new int[0] );
boolean isFoot = 0.f != expctxGlobal.getVariableValue( "validForFoot", 0.f );
boolean isBike = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f );
boolean isCar = 0.f != expctxGlobal.getVariableValue( "validForCars", 0.f );
expctx.parseFile( new File( profilePath ), "global" );
boolean isFoot = 0.f != expctx.getVariableValue( "validForFoot", 0.f );
boolean isBike = 0.f != expctx.getVariableValue( "validForBikes", 0.f );
boolean isCar = 0.f != expctx.getVariableValue( "validForCars", 0.f );
if ( isFoot || isBike || isCar )
{

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-server</artifactId>

View file

@ -88,7 +88,7 @@ public class BRouter
}
System.exit(0);
}
System.out.println("BRouter 1.4.8 / 10122016 / abrensch");
System.out.println("BRouter 1.4.9 / 24092017 / abrensch");
if ( args.length < 6 )
{
System.out.println("Find routes in an OSM map");

View file

@ -155,7 +155,7 @@ public class RouteServer extends Thread
public static void main(String[] args) throws Exception
{
System.out.println("BRouter 1.4.8 / 10122016");
System.out.println("BRouter 1.4.9 / 24092017");
if ( args.length != 5 )
{
System.out.println("serve BRouter protocol");

View file

@ -5,7 +5,7 @@
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-util</artifactId>

View file

@ -1 +1 @@
javac -d . -cp pbfparser.jar;brouter.jar BPbfFieldDecoder.java BPbfBlobDecoder.java OsmParser.java
javac -d . -cp pbfparser.jar;brouter.jar BPbfFieldDecoder.java BPbfBlobDecoder.java OsmParser.java OsmParser2.java

181
misc/profiles2/car-eco.brf Normal file
View file

@ -0,0 +1,181 @@
#
# Car-Routing based on a kinematic model
#
# Depending on the vmax-parameter (target-speed)
# this can be anything from least-time routing to eco-routing
#
#
---model:btools.router.KinematicModel
---context:global
# kinematic parameters
assign vmax = 90 # kmh
assign recup_efficiency = 0.7 # (ratio)
assign totalweight = 1640 # kg
assign f_roll = 232 # Newton
assign f_air = 0.4 # 0.5*cw*A*rho
assign f_recup = 400 # Newton
assign p_standby = 250 # Watt
# technical parameters
assign validForCars = true
assign pass1coefficient = 1.3
assign turnInstructionMode = 1 # 0=none, 1=auto-choose, 2=locus-style, 3=osmand-style
---context:way # following code refers to way-tags
assign initialcost switch route=ferry 20000 0
#
# calculate logical car access
#
assign caraccess
switch motorcar=
switch motor_vehicle=
switch vehicle=
switch access=
switch highway=motorway|motorway_link 1
switch highway=trunk|trunk_link 1
switch highway=primary|primary_link 1
switch highway=secondary|secondary_link 1
switch highway=tertiary|tertiary_link 1
switch highway=unclassified 1
switch route=ferry 1
switch highway=residential|living_street 1
switch highway=service 1
0
access=yes|permissive|designated|destination
vehicle=yes|designated|destination
motor_vehicle=yes|permissive|designated|destination
motorcar=yes|permissive|designated|destination
assign accessspeedlimit = if caraccess then 999 else 0
assign isbadoneway = if reversedirection=yes then ( if oneway= then junction=roundabout else oneway=yes|true|1 ) else oneway=-1
assign onewayspeedlimit = if isbadoneway then 0 else 999
assign islinktype = highway=motorway_link|trunk_link|primary_link|secondary_link|tertiary_link
assign maxspeed_surface =
switch or surface= surface=paved|asphalt|concrete 999
switch surface=paving_stones|cobblestone 30
2
assign maxspeed_tracktype =
switch tracktype= 999
switch tracktype=grade1 40
switch tracktype=grade2 5
1
assign maxspeed_implicit =
switch highway=motorway 999
switch highway=motorway_link 130
switch highway=trunk 250
switch highway=trunk_link 100
switch highway=primary|primary_link 100
switch highway=secondary|secondary_link 90
switch highway=tertiary|tertiary_link 80
switch highway=unclassified 50
switch route=ferry 10
switch highway=bridleway 10
switch highway=residential|living_street 30
switch highway=service 30
switch highway=track|road|path switch tracktype=grade1 30 5
0
assign maxspeed =
min onewayspeedlimit
min accessspeedlimit
switch maxspeed=50 50
switch maxspeed=30 30
switch maxspeed=10 10
switch maxspeed=20 20
switch maxspeed=40 40
switch maxspeed=60 60
switch maxspeed=70 70
switch maxspeed=80 80
switch maxspeed=90 90
switch maxspeed=100 100
switch maxspeed=110 110
switch maxspeed=120 120
switch maxspeed=130 130
switch maxspeed=urban 50
switch maxspeed=rural 100
min maxspeed_implicit
min maxspeed_surface maxspeed_tracktype
assign costfactor = if equal maxspeed 0 then 10000 else 0
assign minspeed =
switch highway=motorway|trunk 75 0
# way priorities used for voice hint generation
assign priorityclassifier =
if ( highway=motorway ) then 30
else if ( highway=motorway_link ) then 29
else if ( highway=trunk ) then 28
else if ( highway=trunk_link ) then 27
else if ( highway=primary ) then 26
else if ( highway=primary_link ) then 25
else if ( highway=secondary ) then 24
else if ( highway=secondary_link ) then 23
else if ( highway=tertiary ) then 22
else if ( highway=tertiary_link ) then 21
else if ( highway=unclassified ) then 20
else if ( highway=residential|living_street ) then 6
else if ( highway=service ) then 6
else if ( highway=track ) then if tracktype=grade1 then 4 else 2
else if ( highway=bridleway|road ) then 2
else 0
# some more classifying bits used for voice hint generation...
assign isgoodoneway = if reversedirection=yes then oneway=-1
else if oneway= then junction=roundabout else oneway=yes|true|1
assign isroundabout = junction=roundabout
assign isgoodforcars = if greater priorityclassifier 6 then true
else if highway=residential|living_street|service then true
else if ( and highway=track tracktype=grade1 ) then true
else false
# ... encoded into a bitmask
assign classifiermask add isbadoneway
add multiply isgoodoneway 2
add multiply isroundabout 4
add multiply islinktype 8
add multiply isgoodforcars 16
multiply highway=residential|living_street 32
---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=
not barrier=gate|bollard|lift_gate|cycle_barrier
access=yes|permissive|designated|destination
vehicle=yes|permissive|designated|destination
motor_vehicle=yes|permissive|designated|destination
motorcar=yes|permissive|designated|destination
assign initialcost =
switch caraccess
0
1000000
assign maxspeed =
if or crossing=traffic_signals highway=traffic_signals then 0
else 999

181
misc/profiles2/car-fast.brf Normal file
View file

@ -0,0 +1,181 @@
#
# Car-Routing based on a kinematic model
#
# Depending on the vmax-parameter (target-speed)
# this can be anything from least-time routing to eco-routing
#
#
---model:btools.router.KinematicModel
---context:global
# kinematic parameters
assign vmax = 160 # kmh
assign recup_efficiency = 0.7 # (ratio)
assign totalweight = 1640 # kg
assign f_roll = 232 # Newton
assign f_air = 0.4 # 0.5*cw*A*rho
assign f_recup = 400 # Newton
assign p_standby = 250 # Watt
# technical parameters
assign validForCars = true
assign pass1coefficient = 1.3
assign turnInstructionMode = 1 # 0=none, 1=auto-choose, 2=locus-style, 3=osmand-style
---context:way # following code refers to way-tags
assign initialcost switch route=ferry 20000 0
#
# calculate logical car access
#
assign caraccess
switch motorcar=
switch motor_vehicle=
switch vehicle=
switch access=
switch highway=motorway|motorway_link 1
switch highway=trunk|trunk_link 1
switch highway=primary|primary_link 1
switch highway=secondary|secondary_link 1
switch highway=tertiary|tertiary_link 1
switch highway=unclassified 1
switch route=ferry 1
switch highway=residential|living_street 1
switch highway=service 1
0
access=yes|permissive|designated|destination
vehicle=yes|designated|destination
motor_vehicle=yes|permissive|designated|destination
motorcar=yes|permissive|designated|destination
assign accessspeedlimit = if caraccess then 999 else 0
assign isbadoneway = if reversedirection=yes then ( if oneway= then junction=roundabout else oneway=yes|true|1 ) else oneway=-1
assign onewayspeedlimit = if isbadoneway then 0 else 999
assign islinktype = highway=motorway_link|trunk_link|primary_link|secondary_link|tertiary_link
assign maxspeed_surface =
switch or surface= surface=paved|asphalt|concrete 999
switch surface=paving_stones|cobblestone 30
2
assign maxspeed_tracktype =
switch tracktype= 999
switch tracktype=grade1 40
switch tracktype=grade2 5
1
assign maxspeed_implicit =
switch highway=motorway 999
switch highway=motorway_link 130
switch highway=trunk 250
switch highway=trunk_link 100
switch highway=primary|primary_link 100
switch highway=secondary|secondary_link 90
switch highway=tertiary|tertiary_link 80
switch highway=unclassified 50
switch route=ferry 10
switch highway=bridleway 10
switch highway=residential|living_street 30
switch highway=service 30
switch highway=track|road|path switch tracktype=grade1 30 5
0
assign maxspeed =
min onewayspeedlimit
min accessspeedlimit
switch maxspeed=50 50
switch maxspeed=30 30
switch maxspeed=10 10
switch maxspeed=20 20
switch maxspeed=40 40
switch maxspeed=60 60
switch maxspeed=70 70
switch maxspeed=80 80
switch maxspeed=90 90
switch maxspeed=100 100
switch maxspeed=110 110
switch maxspeed=120 120
switch maxspeed=130 130
switch maxspeed=urban 50
switch maxspeed=rural 100
min maxspeed_implicit
min maxspeed_surface maxspeed_tracktype
assign costfactor = if equal maxspeed 0 then 10000 else 0
assign minspeed =
switch highway=motorway|trunk 75 0
# way priorities used for voice hint generation
assign priorityclassifier =
if ( highway=motorway ) then 30
else if ( highway=motorway_link ) then 29
else if ( highway=trunk ) then 28
else if ( highway=trunk_link ) then 27
else if ( highway=primary ) then 26
else if ( highway=primary_link ) then 25
else if ( highway=secondary ) then 24
else if ( highway=secondary_link ) then 23
else if ( highway=tertiary ) then 22
else if ( highway=tertiary_link ) then 21
else if ( highway=unclassified ) then 20
else if ( highway=residential|living_street ) then 6
else if ( highway=service ) then 6
else if ( highway=track ) then if tracktype=grade1 then 4 else 2
else if ( highway=bridleway|road ) then 2
else 0
# some more classifying bits used for voice hint generation...
assign isgoodoneway = if reversedirection=yes then oneway=-1
else if oneway= then junction=roundabout else oneway=yes|true|1
assign isroundabout = junction=roundabout
assign isgoodforcars = if greater priorityclassifier 6 then true
else if highway=residential|living_street|service then true
else if ( and highway=track tracktype=grade1 ) then true
else false
# ... encoded into a bitmask
assign classifiermask add isbadoneway
add multiply isgoodoneway 2
add multiply isroundabout 4
add multiply islinktype 8
add multiply isgoodforcars 16
multiply highway=residential|living_street 32
---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=
not barrier=gate|bollard|lift_gate|cycle_barrier
access=yes|permissive|designated|destination
vehicle=yes|permissive|designated|destination
motor_vehicle=yes|permissive|designated|destination
motorcar=yes|permissive|designated|destination
assign initialcost =
switch caraccess
0
1000000
assign maxspeed =
if or crossing=traffic_signals highway=traffic_signals then 0
else 999

View file

@ -1,158 +0,0 @@
#
# Car-Routing is experimantal !!!
#
# DO NOT USE FOR ACTUAL NAVIGATION
#
# Turn restrictions are not complete, leading to wrong routes
#
---context:global
assign downhillcost 0
assign downhillcutoff 0
assign uphillcost 0
assign uphillcutoff 0
assign validForCars 1
assign pass1coefficient 1.3
assign turnInstructionMode = 1 # 0=none, 1=auto-choose, 2=locus-style, 3=osmand-style
---context:way # following code refers to way-tags
assign turncost if junction=roundabout then 0 else 200
assign initialcost switch route=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 route=ferry 1
switch or highway=residential highway=living_street 1
switch highway=service 1
0
or access=yes or access=permissive or access=designated access=destination
or vehicle=yes or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=permissive or motor_vehicle=designated motor_vehicle=destination
or motorcar=yes or motorcar=permissive 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 islinktype = highway=motorway_link|trunk_link|primary_link|secondary_link|tertiary_link
assign costfactor
add max onewaypenalty accesspenalty
add switch islinktype 0.05 0
switch and highway= not route=ferry 10000
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.3
switch or highway=secondary highway=secondary_link 1.4
switch or highway=tertiary highway=tertiary_link 1.5
switch highway=unclassified 1.6
switch route=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
# way priorities used for voice hint generation
assign priorityclassifier =
if ( highway=motorway ) then 30
else if ( highway=motorway_link ) then 29
else if ( highway=trunk ) then 28
else if ( highway=trunk_link ) then 27
else if ( highway=primary ) then 26
else if ( highway=primary_link ) then 25
else if ( highway=secondary ) then 24
else if ( highway=secondary_link ) then 23
else if ( highway=tertiary ) then 22
else if ( highway=tertiary_link ) then 21
else if ( highway=unclassified ) then 20
else if ( highway=residential|living_street ) then 6
else if ( highway=service ) then 6
else if ( highway=track ) then if tracktype=grade1 then 4 else 2
else if ( highway=bridleway|road ) then 2
else 0
# some more classifying bits used for voice hint generation...
assign isbadoneway = not equal onewaypenalty 0
assign isgoodoneway = if reversedirection=yes then oneway=-1
else if oneway= then junction=roundabout else oneway=yes|true|1
assign isroundabout = junction=roundabout
assign isgoodforcars = if greater priorityclassifier 6 then true
else if highway=residential|living_street|service then true
else if ( and highway=track tracktype=grade1 ) then true
else false
# ... encoded into a bitmask
assign classifiermask add isbadoneway
add multiply isgoodoneway 2
add multiply isroundabout 4
add multiply islinktype 8
multiply isgoodforcars 16
---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=permissive or access=designated access=destination
or vehicle=yes or vehicle=permissive or vehicle=designated vehicle=destination
or motor_vehicle=yes or motor_vehicle=permissive or motor_vehicle=designated motor_vehicle=destination
or motorcar=yes or motorcar=permissive or motorcar=designated motorcar=destination
assign initialcost
switch caraccess
0
1000000

View file

@ -1,5 +1,5 @@
---lookupversion:10
---minorversion:6
---minorversion:7
---context:way
@ -35,6 +35,12 @@ highway;0000002631 services
highway;0000002133 corridor
highway;0000002093 crossing
highway;0000001440 bus_stop
highway;0000001274 yes
highway;0000000679 unsurfaced
highway;0000000108 byway
highway;0000000037 driveway
highway;0000000021 mini_roundabout
highway;0000000020 turning_loop
tracktype;0000887965 grade2
tracktype;0000868414 grade3
@ -512,6 +518,35 @@ mtb:scale:uphill;0000009099 3 3+ 3-
mtb:scale:uphill;0000005825 4 4+ 4-
mtb:scale:uphill;0000004628 5 5+ 5-
crossing;0000101049 zebra
crossing;0000017509 unmarked
crossing;0000013817 traffic_signals
crossing;0000011062 uncontrolled
crossing;0000001722 yes
crossing;0000001678 island
crossing;0000000457 marked
crossing;0000000131 pedestrian_signals
crossing;0000000122 no
informal;0000002424 yes
indoor;0000058418 yes
indoor;0000025038 room
indoor;0000005295 wall
indoor;0000004322 corridor
indoor;0000002410 area
indoor;0000000816 column
indoor;0000000568 no
indoor;0000000129 shop
indoor;0000000099 steps
4wd_only;0000008129 yes Yes
4wd_only;0000000487 recommended
4wd_only;0000000041 no
concrete;0000000043 plates
concrete;0000000013 lanes
---context:node
highway;0001314954 bus_stop
@ -565,6 +600,8 @@ highway;0000000113 culvert
highway;0000000100 <residential>
highway;0000000046 toll_bridge
highway;0000000037 city_entry
highway;0000002967 traffic_mirror
highway;0000001724 priority
barrier;0000606512 gate
barrier;0000164120 bollard

View file

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.8</version>
<version>1.4.9</version>
<packaging>pom</packaging>
<url>http://brouter.de/brouter/</url>
<name>brouter</name>