version 1.4.9
This commit is contained in:
parent
0171ba39a0
commit
c517ccc2df
43 changed files with 2002 additions and 508 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
98
brouter-core/src/main/java/btools/router/KinematicModel.java
Normal file
98
brouter-core/src/main/java/btools/router/KinematicModel.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
271
brouter-core/src/main/java/btools/router/KinematicPath.java
Normal file
271
brouter-core/src/main/java/btools/router/KinematicPath.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -26,6 +26,9 @@ final class MessageData implements Cloneable
|
|||
int lat;
|
||||
short ele;
|
||||
|
||||
float time;
|
||||
float energy;
|
||||
|
||||
String toMessage()
|
||||
{
|
||||
if ( wayKeyValues == null )
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
private void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
|
||||
protected abstract void init( OsmPath orig );
|
||||
|
||||
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;
|
||||
}
|
||||
protected abstract double processTargetNode( RoutingContext rc );
|
||||
|
||||
return cost > c;
|
||||
}
|
||||
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.;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
20
brouter-core/src/main/java/btools/router/OsmPathModel.java
Normal file
20
brouter-core/src/main/java/btools/router/OsmPathModel.java
Normal 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 );
|
||||
}
|
29
brouter-core/src/main/java/btools/router/OsmPrePath.java
Normal file
29
brouter-core/src/main/java/btools/router/OsmPrePath.java
Normal 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 );
|
||||
}
|
|
@ -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 );
|
||||
|
@ -609,6 +653,13 @@ public final class OsmTrack
|
|||
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
|
||||
{
|
||||
BufferedWriter bw = filename == null ? null : new BufferedWriter( new FileWriter( filename ) );
|
||||
|
|
|
@ -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,20 +61,17 @@ 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 )
|
||||
{
|
||||
rc.expctxWay.setAllTagsUsed();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,12 +944,39 @@ 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) )
|
||||
{
|
||||
OsmNode nextNode = link.getTarget( 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 );
|
||||
|
@ -1054,10 +1109,16 @@ public class RoutingEngine extends Thread
|
|||
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();
|
||||
|
|
38
brouter-core/src/main/java/btools/router/StdModel.java
Normal file
38
brouter-core/src/main/java/btools/router/StdModel.java
Normal 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...
|
||||
|
||||
}
|
||||
}
|
596
brouter-core/src/main/java/btools/router/StdPath.java
Normal file
596
brouter-core/src/main/java/btools/router/StdPath.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -27,12 +27,15 @@ 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[]>();
|
||||
private ArrayList<String> lookupNames = new ArrayList<String>();
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
Binary file not shown.
|
@ -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>
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
181
misc/profiles2/car-eco.brf
Normal 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
181
misc/profiles2/car-fast.brf
Normal 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
|
|
@ -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
|
|
@ -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
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue