diff --git a/brouter-codec/pom.xml b/brouter-codec/pom.xml
index b14d8e2..8275910 100644
--- a/brouter-codec/pom.xml
+++ b/brouter-codec/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-codec
diff --git a/brouter-core/pom.xml b/brouter-core/pom.xml
index dd97bac..86be86c 100644
--- a/brouter-core/pom.xml
+++ b/brouter-core/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-core
diff --git a/brouter-core/src/main/java/btools/router/KinematicModel.java b/brouter-core/src/main/java/btools/router/KinematicModel.java
new file mode 100644
index 0000000..db35a30
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/KinematicModel.java
@@ -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;
+ }
+}
diff --git a/brouter-core/src/main/java/btools/router/KinematicModelDummy.java b/brouter-core/src/main/java/btools/router/KinematicModelDummy.java
new file mode 100644
index 0000000..b215f6c
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/KinematicModelDummy.java
@@ -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;
+ }
+}
diff --git a/brouter-core/src/main/java/btools/router/KinematicPath.java b/brouter-core/src/main/java/btools/router/KinematicPath.java
new file mode 100644
index 0000000..24884cd
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/KinematicPath.java
@@ -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;
+ }
+}
diff --git a/brouter-core/src/main/java/btools/router/KinematicPrePath.java b/brouter-core/src/main/java/btools/router/KinematicPrePath.java
new file mode 100644
index 0000000..13013ef
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/KinematicPrePath.java
@@ -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();
+ }
+}
diff --git a/brouter-core/src/main/java/btools/router/MessageData.java b/brouter-core/src/main/java/btools/router/MessageData.java
index abe93fb..873b96d 100644
--- a/brouter-core/src/main/java/btools/router/MessageData.java
+++ b/brouter-core/src/main/java/btools/router/MessageData.java
@@ -26,6 +26,9 @@ final class MessageData implements Cloneable
int lat;
short ele;
+ float time;
+ float energy;
+
String toMessage()
{
if ( wayKeyValues == null )
diff --git a/brouter-core/src/main/java/btools/router/OsmPath.java b/brouter-core/src/main/java/btools/router/OsmPath.java
index d413936..1454662 100644
--- a/brouter-core/src/main/java/btools/router/OsmPath.java
+++ b/brouter-core/src/main/java/btools/router/OsmPath.java
@@ -13,33 +13,27 @@ import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
import btools.mapaccess.TurnRestriction;
-final class OsmPath implements OsmLinkHolder
+abstract class OsmPath implements OsmLinkHolder
{
/**
* The cost of that path (a modified distance)
*/
public int cost = 0;
- /**
- * The elevation-hysteresis-buffer (0-10 m)
- */
- private int ehbd; // in micrometer
- private int ehbu; // in micrometer
-
// the elevation assumed for that path can have a value
// if the corresponding node has not
public short selev;
public int airdistance = 0; // distance to endpos
- private OsmNode sourceNode;
- private OsmNode targetNode;
+ protected OsmNode sourceNode;
+ protected OsmNode targetNode;
- private OsmLink link;
+ protected OsmLink link;
public OsmPathElement originElement;
public OsmPathElement myElement;
- private float traffic;
+ protected float traffic;
private OsmLinkHolder nextForLink = null;
@@ -51,7 +45,9 @@ final class OsmPath implements OsmLinkHolder
public int originLat;
// the classifier of the segment just before this paths position
- public float lastClassifier;
+ protected float lastClassifier;
+
+ protected int priorityclassifier;
public MessageData message;
@@ -81,13 +77,8 @@ final class OsmPath implements OsmLinkHolder
}
}
- OsmPath()
+ public void init( OsmLink link )
{
- }
-
- OsmPath( OsmLink link )
- {
- this();
this.link = link;
targetNode = link.getTarget( null );
selev = targetNode.getSElev();
@@ -96,9 +87,8 @@ final class OsmPath implements OsmLinkHolder
originLat = -1;
}
- OsmPath( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
+ public void init( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
{
- this();
if ( origin.myElement == null )
{
origin.myElement = OsmPathElement.create( origin, rc.countTraffic );
@@ -108,19 +98,22 @@ final class OsmPath implements OsmLinkHolder
this.sourceNode = origin.targetNode;
this.targetNode = link.getTarget( sourceNode );
this.cost = origin.cost;
- this.ehbd = origin.ehbd;
- this.ehbu = origin.ehbu;
this.lastClassifier = origin.lastClassifier;
+ init( origin );
addAddionalPenalty(refTrack, detailMode, origin, link, rc );
}
+
+ protected abstract void init( OsmPath orig );
- private void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
+ protected abstract void resetState();
+
+
+ protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
{
byte[] description = link.descriptionBitmap;
- if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
+ if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
boolean recordTransferNodes = detailMode || rc.countTraffic;
- boolean recordMessageData = detailMode;
rc.nogomatch = false;
@@ -128,55 +121,48 @@ final class OsmPath implements OsmLinkHolder
int lon0 = origin.originLon;
int lat0 = origin.originLat;
- OsmNode p1 = sourceNode;
- int lon1 = p1.getILon();
- int lat1 = p1.getILat();
+ int lon1 = sourceNode.getILon();
+ int lat1 = sourceNode.getILat();
short ele1 = origin.selev;
int linkdisttotal = 0;
- MessageData msgData = recordMessageData ? new MessageData() : null;
+ message = detailMode ? new MessageData() : null;
boolean isReverse = link.isReverse( sourceNode );
// evaluate the way tags
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
+
// calculate the costfactor inputs
+ float costfactor = rc.expctxWay.getCostfactor();
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
- float turncostbase = rc.expctxWay.getTurncost();
- float cfup = rc.expctxWay.getUphillCostfactor();
- float cfdown = rc.expctxWay.getDownhillCostfactor();
- float cf = rc.expctxWay.getCostfactor();
- cfup = cfup == 0.f ? cf : cfup;
- cfdown = cfdown == 0.f ? cf : cfdown;
+ int lastpriorityclassifier = priorityclassifier;
+ priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
+ int classifiermask = (int)rc.expctxWay.getClassifierMask();
// *** add initial cost if the classifier changed
float newClassifier = rc.expctxWay.getInitialClassifier();
- if ( newClassifier == 0. )
- {
- newClassifier = (cfup + cfdown + cf)/3;
- }
float classifierDiff = newClassifier - lastClassifier;
if ( classifierDiff > 0.0005 || classifierDiff < -0.0005 )
{
lastClassifier = newClassifier;
float initialcost = rc.expctxWay.getInitialcost();
int iicost = (int)initialcost;
- if ( recordMessageData )
+ if ( message != null )
{
- msgData.linkinitcost += iicost;
+ message.linkinitcost += iicost;
}
cost += iicost;
}
OsmTransferNode transferNode = link.geometry == null ? null
- : rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
+ : rc.geometryDecoder.decodeGeometry( link.geometry, sourceNode, targetNode, isReverse );
- boolean isFirstSection = true;
-
- for(;;)
+ for(int nsection=0; ;nsection++)
{
+
originLon = lon1;
originLat = lat1;
@@ -197,19 +183,8 @@ final class OsmPath implements OsmLinkHolder
ele2 = transferNode.selev;
}
- // check turn restrictions: do we have one with that origin?
- boolean checkTRs = false;
- if ( isFirstSection )
- {
- isFirstSection = false;
-
- // TODO: TRs for inverse routing would need inverse TR logic,
- // inverse routing for now just for target island check, so don't care (?)
- // in detail mode (=final pass) no TR to not mess up voice hints
- checkTRs = rc.considerTurnRestrictions && !rc.inverseDirection && !detailMode;
- }
-
- if ( checkTRs )
+ // check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
+ if ( nsection == 0 && rc.considerTurnRestrictions && !detailMode )
{
boolean hasAnyPositive = false;
boolean hasPositive = false;
@@ -217,14 +192,22 @@ final class OsmPath implements OsmLinkHolder
TurnRestriction tr = sourceNode.firstRestriction;
while( tr != null )
{
- boolean trValid = ! (tr.exceptBikes() && rc.bikeMode);
- if ( trValid && tr.fromLon == lon0 && tr.fromLat == lat0 )
+ if ( tr.exceptBikes() && rc.bikeMode )
+ {
+ tr = tr.next;
+ continue;
+ }
+ int fromLon = rc.inverseDirection ? lon2 : lon0;
+ int fromLat = rc.inverseDirection ? lat2 : lat0;
+ int toLon = rc.inverseDirection ? lon0 : lon2;
+ int toLat = rc.inverseDirection ? lat0 : lat2;
+ if ( tr.fromLon == fromLon && tr.fromLat == fromLat )
{
if ( tr.isPositive )
{
hasAnyPositive = true;
}
- if ( tr.toLon == lon2 && tr.toLat == lat2 )
+ if ( tr.toLon == toLon && tr.toLat == toLat )
{
if ( tr.isPositive )
{
@@ -246,13 +229,14 @@ final class OsmPath implements OsmLinkHolder
}
// if recording, new MessageData for each section (needed for turn-instructions)
- if ( recordMessageData && msgData.wayKeyValues != null )
+ if ( message != null && message.wayKeyValues != null )
{
- originElement.message = msgData;
- msgData = new MessageData();
+ originElement.message = message;
+ message = new MessageData();
}
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
+
boolean stopAtEndpoint = false;
if ( rc.shortestmatch )
{
@@ -263,10 +247,9 @@ final class OsmPath implements OsmLinkHolder
}
else
{
- // we just start here, reset cost
+ // we just start here, reset everything
cost = 0;
- ehbd = 0;
- ehbu = 0;
+ resetState();
lon0 = -1; // reset turncost-pipe
lat0 = -1;
@@ -285,131 +268,57 @@ final class OsmPath implements OsmLinkHolder
}
}
- if ( recordMessageData )
+ if ( message != null )
{
- msgData.linkdist += dist;
+ message.linkdist += dist;
}
linkdisttotal += dist;
// apply a start-direction if appropriate (by faking the origin position)
- if ( lon0 == -1 && lat0 == -1 )
+ boolean isStartpoint = lon0 == -1 && lat0 == -1;
+ if ( isStartpoint )
{
- double coslat = Math.cos( ( lat1 - 90000000 ) * 0.00000001234134 );
- if ( rc.startDirectionValid && coslat > 0. )
+ if ( rc.startDirectionValid )
{
double dir = rc.startDirection.intValue() / 57.29578;
- lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / coslat );
+ lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / rc.getCosLat() );
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) );
}
- }
-
- // *** penalty for turning angles
- if ( !isTrafficBackbone && lon0 != -1 && lat0 != -1 )
- {
- // penalty proportional to direction change
- double cos = rc.calcCosAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
- int actualturncost = (int)(cos * turncostbase + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
- cost += actualturncost;
- if ( recordMessageData )
+ else
{
- msgData.linkturncost += actualturncost;
- msgData.turnangle = (float)rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
+ lon0 = lon1 - (lon2-lon1);
+ lat0 = lat1 - (lat2-lat1);
}
}
+ double angle = rc.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
+ double cosangle = rc.getCosAngle();
- // *** penalty for elevation (penalty is for descend! in a way that slow descends give no penalty)
- // only the part of the descend that does not fit into the elevation-hysteresis-buffer
- // leads to an immediate penalty
-
- int elefactor = 250000;
+ // *** elevation stuff
+ double delta_h = 0.;
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1;
if ( ele1 != Short.MIN_VALUE )
{
- ehbd += (ele1 - ele2)*elefactor - dist * rc.downhillcutoff;
- ehbu += (ele2 - ele1)*elefactor - dist * rc.uphillcutoff;
- }
-
- float downweight = 0.f;
- if ( ehbd > rc.elevationpenaltybuffer )
- {
- downweight = 1.f;
-
- int excess = ehbd - rc.elevationpenaltybuffer;
- int reduce = dist * rc.elevationbufferreduce;
- if ( reduce > excess )
- {
- downweight = ((float)excess)/reduce;
- reduce = excess;
- }
- excess = ehbd - rc.elevationmaxbuffer;
- if ( reduce < excess )
- {
- reduce = excess;
- }
- ehbd -= reduce;
- if ( rc.downhillcostdiv > 0 )
- {
- int elevationCost = reduce/rc.downhillcostdiv;
- cost += elevationCost;
- if ( recordMessageData )
- {
- msgData.linkelevationcost += elevationCost;
- }
- }
- }
- else if ( ehbd < 0 )
- {
- ehbd = 0;
- }
-
- float upweight = 0.f;
- if ( ehbu > rc.elevationpenaltybuffer )
- {
- upweight = 1.f;
-
- int excess = ehbu - rc.elevationpenaltybuffer;
- int reduce = dist * rc.elevationbufferreduce;
- if ( reduce > excess )
+ delta_h = (ele2 - ele1)/4.;
+ if ( rc.inverseDirection )
{
- upweight = ((float)excess)/reduce;
- reduce = excess;
- }
- excess = ehbu - rc.elevationmaxbuffer;
- if ( reduce < excess )
- {
- reduce = excess;
- }
- ehbu -= reduce;
- if ( rc.uphillcostdiv > 0 )
- {
- int elevationCost = reduce/rc.uphillcostdiv;
- cost += elevationCost;
- if ( recordMessageData )
- {
- msgData.linkelevationcost += elevationCost;
- }
+ delta_h = -delta_h;
}
}
- else if ( ehbu < 0 )
- {
- ehbu = 0;
- }
- // get the effective costfactor (slope dependent)
- float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
- if ( isTrafficBackbone )
- {
- costfactor = 0.f;
- }
- float fcost = dist * costfactor + 0.5f;
- if ( ( costfactor > 9998. && !detailMode ) || fcost + cost >= 2000000000. )
+ double sectionCost = processWaySection( rc, dist, delta_h, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier );
+ if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. )
{
cost = -1;
return;
}
- int waycost = (int)(fcost);
- cost += waycost;
+
+ if ( isTrafficBackbone )
+ {
+ sectionCost = 0.;
+ }
+
+ cost += (int)sectionCost;
// calculate traffic
if ( rc.countTraffic )
@@ -419,15 +328,17 @@ final class OsmPath implements OsmLinkHolder
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent);
}
- if ( recordMessageData )
+ if ( message != null )
{
- msgData.costfactor = costfactor;
- msgData.priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
- msgData.classifiermask = (int)rc.expctxWay.getClassifierMask();
- msgData.lon = lon2;
- msgData.lat = lat2;
- msgData.ele = ele2;
- msgData.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
+ message.turnangle = (float)angle;
+ message.time = (float)getTotalTime();
+ message.energy = (float)getTotalEnergy();
+ message.priorityclassifier = priorityclassifier;
+ message.classifiermask = classifiermask;
+ message.lon = lon2;
+ message.lat = lat2;
+ message.ele = ele2;
+ message.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
}
if ( stopAtEndpoint )
@@ -436,9 +347,9 @@ final class OsmPath implements OsmLinkHolder
{
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
originElement.cost = cost;
- if ( recordMessageData )
+ if ( message != null )
{
- originElement.message = msgData;
+ originElement.message = message;
}
}
if ( rc.nogomatch )
@@ -473,44 +384,26 @@ final class OsmPath implements OsmLinkHolder
lon1 = lon2;
lat1 = lat2;
ele1 = ele2;
-
}
// check for nogo-matches (after the *actual* start of segment)
if ( rc.nogomatch )
{
- cost = -1;
- return;
+ cost = -1;
+ return;
}
- // finally add node-costs for target node
- if ( targetNode.nodeDescription != null )
+ // add target-node costs
+ double targetCost = processTargetNode( rc );
+ if ( targetCost < 0. || targetCost + cost >= 2000000000. )
{
- boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
- rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
- float initialcost = rc.expctxNode.getInitialcost();
- if ( initialcost >= 1000000. )
- {
- cost = -1;
- return;
- }
- int iicost = (int)initialcost;
-
- cost += iicost;
-
- if ( recordMessageData )
- {
- msgData.linknodecost += iicost;
- msgData.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
- }
+ cost = -1;
+ return;
}
- if ( recordMessageData )
- {
- message = msgData;
- }
-
+ cost += (int)targetCost;
}
+
public short interpolateEle( short e1, short e2, double fraction )
{
if ( e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE )
@@ -520,29 +413,13 @@ final class OsmPath implements OsmLinkHolder
return (short)( e1*(1.-fraction) + e2*fraction );
}
- public int elevationCorrection( RoutingContext rc )
- {
- return ( rc.downhillcostdiv > 0 ? ehbd/rc.downhillcostdiv : 0 )
- + ( rc.uphillcostdiv > 0 ? ehbu/rc.uphillcostdiv : 0 );
- }
+ protected abstract double processWaySection( RoutingContext rc, double dist, double delta_h, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier );
- public boolean definitlyWorseThan( OsmPath p, RoutingContext rc )
- {
- int c = p.cost;
- if ( rc.downhillcostdiv > 0 )
- {
- int delta = p.ehbd - ehbd;
- if ( delta > 0 ) c += delta/rc.downhillcostdiv;
- }
- if ( rc.uphillcostdiv > 0 )
- {
- int delta = p.ehbu - ehbu;
- if ( delta > 0 ) c += delta/rc.uphillcostdiv;
- }
-
- return cost > c;
- }
-
+ protected abstract double processTargetNode( RoutingContext rc );
+
+ public abstract int elevationCorrection( RoutingContext rc );
+
+ public abstract boolean definitlyWorseThan( OsmPath p, RoutingContext rc );
public OsmNode getSourceNode()
{
@@ -569,4 +446,14 @@ final class OsmPath implements OsmLinkHolder
{
return nextForLink;
}
+
+ public double getTotalTime()
+ {
+ return 0.;
+ }
+
+ public double getTotalEnergy()
+ {
+ return 0.;
+ }
}
diff --git a/brouter-core/src/main/java/btools/router/OsmPathElement.java b/brouter-core/src/main/java/btools/router/OsmPathElement.java
index d061ca7..34807d8 100644
--- a/brouter-core/src/main/java/btools/router/OsmPathElement.java
+++ b/brouter-core/src/main/java/btools/router/OsmPathElement.java
@@ -18,7 +18,7 @@ public class OsmPathElement implements OsmPos
private int ilat; // latitude
private int ilon; // longitude
private short selev; // longitude
-
+
public MessageData message = null; // description
public int cost;
@@ -44,6 +44,19 @@ public class OsmPathElement implements OsmPos
return selev / 4.;
}
+ public final float getTime()
+ {
+ return message == null ? 0.f : message.time;
+ }
+
+ public final void setTime( float t )
+ {
+ if ( message != null )
+ {
+ message.time = t;
+ }
+ }
+
public final long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
@@ -58,7 +71,7 @@ public class OsmPathElement implements OsmPos
double dlat = (ilat - p.getILat() )/1000000.;
double dlon = (ilon - p.getILon() )/1000000. * coslat;
- double d = Math.sqrt( dlat*dlat + dlon*dlon ) * (6378000. / 57.);
+ double d = Math.sqrt( dlat*dlat + dlon*dlon ) * 110984.; // 6378000. / 57.3;
return (int)(d + 1.0 );
}
diff --git a/brouter-core/src/main/java/btools/router/OsmPathModel.java b/brouter-core/src/main/java/btools/router/OsmPathModel.java
new file mode 100644
index 0000000..17a7bda
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/OsmPathModel.java
@@ -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 );
+}
diff --git a/brouter-core/src/main/java/btools/router/OsmPrePath.java b/brouter-core/src/main/java/btools/router/OsmPrePath.java
new file mode 100644
index 0000000..266cf58
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/OsmPrePath.java
@@ -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 );
+}
diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java
index 1ca24af..217b03e 100644
--- a/brouter-core/src/main/java/btools/router/OsmTrack.java
+++ b/brouter-core/src/main/java/btools/router/OsmTrack.java
@@ -37,6 +37,8 @@ public final class OsmTrack
public long profileTimestamp;
public boolean isDirty;
+ public boolean showspeed;
+
private static class OsmPathElementHolder
{
public OsmPathElement node;
@@ -120,7 +122,7 @@ public final class OsmTrack
MessageData current = null;
for ( OsmPathElement n : nodes )
{
- if ( n.message != null )
+ if ( n.message != null && n.message.wayKeyValues != null )
{
MessageData md = n.message.copy();
if ( current != null )
@@ -289,11 +291,15 @@ public final class OsmTrack
public void appendTrack( OsmTrack t )
{
+ int ourSize = nodes.size();
+ float t0 = ourSize > 0 ? nodes.get(ourSize - 1 ).getTime() : 0;
for ( int i = 0; i < t.nodes.size(); i++ )
{
- if ( i > 0 || nodes.size() == 0 )
+ if ( i > 0 || ourSize == 0 )
{
- nodes.add( t.nodes.get( i ) );
+ OsmPathElement e = t.nodes.get( i );
+ e.setTime( e.getTime() + t0 );
+ nodes.add( e );
}
}
@@ -313,12 +319,16 @@ public final class OsmTrack
ascend += t.ascend;
plainAscend += t.plainAscend;
cost += t.cost;
+ energy += t.energy;
+
+ showspeed |= t.showspeed;
}
public int distance;
public int ascend;
public int plainAscend;
public int cost;
+ public int energy;
/**
* writes the track in gpx-format to a file
@@ -390,7 +400,7 @@ public final class OsmTrack
}
else
{
- sb.append( " creator=\"BRouter-1.4.8\" version=\"1.1\">\n" );
+ sb.append( " creator=\"BRouter-1.4.9\" version=\"1.1\">\n" );
}
if ( turnInstructionMode == 3) // osmand style
@@ -537,6 +547,8 @@ public final class OsmTrack
sb.append( " \"track-length\": \"" ).append( distance ).append( "\",\n" );
sb.append( " \"filtered ascend\": \"" ).append( ascend ).append( "\",\n" );
sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" );
+ sb.append( " \"total-time\": \"" ).append( getTotalSeconds() ).append( "\",\n" );
+ sb.append( " \"total-energy\": \"" ).append( energy ).append( "\",\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\",\n" );
sb.append( " \"messages\": [\n" );
sb.append( " [\"" ).append( MESSAGES_HEADER.replaceAll( "\t", "\", \"" ) ).append( "\"],\n" );
@@ -563,11 +575,27 @@ public final class OsmTrack
sb.append( " \"type\": \"LineString\",\n" );
sb.append( " \"coordinates\": [\n" );
+ OsmPathElement nn = null;
for ( OsmPathElement n : nodes )
{
String sele = n.getSElev() == Short.MIN_VALUE ? "" : ", " + n.getElev();
+ if ( showspeed ) // hack: show speed instead of elevation
+ {
+ int speed = 0;
+ if ( nn != null )
+ {
+ int dist = n.calcDistance( nn );
+ float dt = n.getTime()-nn.getTime();
+ if ( dt != 0.f )
+ {
+ speed = (int)((3.6f*dist)/dt + 0.5);
+ }
+ }
+ sele = ", " + speed;
+ }
sb.append( " [" ).append( formatILon( n.getILon() ) ).append( ", " ).append( formatILat( n.getILat() ) )
.append( sele ).append( "],\n" );
+ nn = n;
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
@@ -580,6 +608,22 @@ public final class OsmTrack
return sb.toString();
}
+ private int getTotalSeconds()
+ {
+ float s = nodes.size() < 2 ? 0 : nodes.get( nodes.size()-1 ).getTime() - nodes.get( 0 ).getTime();
+ return (int)(s + 0.5);
+ }
+
+ public String getFormattedTime()
+ {
+ return format1( getTotalSeconds()/60. ) + "m";
+ }
+
+ public String getFormattedEnergy()
+ {
+ return format1( energy/3600000. ) + "kwh";
+ }
+
private static String formatILon( int ilon )
{
return formatPos( ilon - 180000000 );
@@ -608,6 +652,13 @@ public final class OsmTrack
ac[i--] = '-';
return new String( ac, i + 1, 11 - i );
}
+
+ private String format1( double n )
+ {
+ String s = "" + (long)(n*10 + 0.5);
+ int len = s.length();
+ return s.substring( 0, len-1 ) + "." + s.charAt( len-1 );
+ }
public void dumpMessages( String filename, RoutingContext rc ) throws Exception
{
diff --git a/brouter-core/src/main/java/btools/router/ProfileCache.java b/brouter-core/src/main/java/btools/router/ProfileCache.java
index f03e6ae..b6b4c8f 100644
--- a/brouter-core/src/main/java/btools/router/ProfileCache.java
+++ b/brouter-core/src/main/java/btools/router/ProfileCache.java
@@ -7,7 +7,6 @@ package btools.router;
import java.io.File;
-import btools.expressions.BExpressionContextGlobal;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
@@ -54,7 +53,7 @@ public final class ProfileCache
rc.expctxWay = expctxWay;
rc.expctxNode = expctxNode;
profilesBusy = true;
- rc.readGlobalConfig(expctxWay);
+ rc.readGlobalConfig();
return true;
}
}
@@ -62,19 +61,16 @@ public final class ProfileCache
BExpressionMetaData meta = new BExpressionMetaData();
- BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta );
rc.expctxWay = new BExpressionContextWay( rc.memoryclass * 512, meta );
rc.expctxNode = new BExpressionContextNode( 0, meta );
rc.expctxNode.setForeignContext( rc.expctxWay );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
- expctxGlobal.parseFile( profileFile, null );
- expctxGlobal.evaluate( new int[0] );
- rc.readGlobalConfig(expctxGlobal);
-
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode.parseFile( profileFile, "global" );
+
+ rc.readGlobalConfig();
if ( rc.processUnusedTags )
{
diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java
index 815afe0..0ae2641 100644
--- a/brouter-core/src/main/java/btools/router/RoutingContext.java
+++ b/brouter-core/src/main/java/btools/router/RoutingContext.java
@@ -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;
+ }
+
}
diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java
index 8491eab..56632fe 100644
--- a/brouter-core/src/main/java/btools/router/RoutingEngine.java
+++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java
@@ -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 0 )
+ if ( routingContext.inverseRouting )
{
- throw new IllegalArgumentException( "target island detected for section " + i );
+ OsmTrack seg = findTrack( "start-island-check", matchedWaypoints.get(i), matchedWaypoints.get(i+1), null, null, false );
+ if ( seg == null && nodeLimit > 0 )
+ {
+ throw new IllegalArgumentException( "start island detected for section " + i );
+ }
+ }
+ else
+ {
+ OsmTrack seg = findTrack( "target-island-check", matchedWaypoints.get(i+1), matchedWaypoints.get(i), null, null, false );
+ if ( seg == null && nodeLimit > 0 )
+ {
+ throw new IllegalArgumentException( "target island detected for section " + i );
+ }
}
}
routingContext.inverseDirection = false;
@@ -397,7 +412,18 @@ public class RoutingEngine extends Thread
refTracks[i].addNodes( lastTracks[i] );
}
- OsmTrack seg = searchTrack( matchedWaypoints.get(i), matchedWaypoints.get(i+1), i == matchedWaypoints.size()-2 ? nearbyTrack : null, refTracks[i] );
+ OsmTrack seg;
+ if ( routingContext.inverseRouting )
+ {
+ routingContext.inverseDirection = true;
+ seg = searchTrack( matchedWaypoints.get(i+1), matchedWaypoints.get(i), null, refTracks[i] );
+ routingContext.inverseDirection = false;
+ }
+ else
+ {
+ seg = searchTrack( matchedWaypoints.get(i), matchedWaypoints.get(i+1), i == matchedWaypoints.size()-2 ? nearbyTrack : null, refTracks[i] );
+ }
+
if ( seg == null ) return null;
totaltrack.appendTrack( seg );
lastTracks[i] = seg;
@@ -651,7 +677,7 @@ public class RoutingEngine extends Thread
OsmPath bestPath = null;
OsmLink bestLink = null;
OsmLink startLink = new OsmLink( null, n1 );
- OsmPath startPath = new OsmPath( startLink );
+ OsmPath startPath = routingContext.createPath( startLink );
startLink.addLinkHolder( startPath, null );
double minradius = 1e10;
for( OsmLink link = n1.firstlink; link != null; link = link.getNext( n1 ) )
@@ -663,7 +689,7 @@ public class RoutingEngine extends Thread
if ( nextNode != n2 ) continue; // just that link
wp.radius = 1e9;
- OsmPath testPath = new OsmPath( startPath, link, null, guideTrack != null, routingContext );
+ OsmPath testPath = routingContext.createPath( startPath, link, null, guideTrack != null );
testPath.airdistance = endPos == null ? 0 : nextNode.calcDistance( endPos );
if ( wp.radius < minradius )
{
@@ -692,12 +718,12 @@ public class RoutingEngine extends Thread
{
if ( wp != null ) routingContext.setWaypoint( wp, true );
OsmLink startLink = new OsmLink( null, n1 );
- OsmPath startPath = new OsmPath( startLink );
+ OsmPath startPath = routingContext.createPath( startLink );
startLink.addLinkHolder( startPath, null );
if ( wp != null ) wp.radius = 1e-5;
- return new OsmPath( startPath, link, null, guideTrack != null, routingContext );
+ return routingContext.createPath( startPath, link, null, guideTrack != null );
}
finally
{
@@ -761,7 +787,7 @@ public class RoutingEngine extends Thread
if ( start1 == null || start2 == null ) return null;
- if ( routingContext.startDirectionValid = ( fastPartialRecalc && routingContext.startDirection != null ) )
+ if ( routingContext.startDirectionValid = ( fastPartialRecalc && routingContext.startDirection != null && !routingContext.inverseDirection ) )
{
logInfo( "using start direction " + routingContext.startDirection );
}
@@ -865,7 +891,9 @@ public class RoutingEngine extends Thread
{
// track found, compile
logInfo( "found track at cost " + path.cost + " nodesVisited = " + nodesVisited );
- return compileTrack( path, verbose );
+ OsmTrack t = compileTrack( path, verbose );
+ t.showspeed = routingContext.showspeed;
+ return t;
}
// check for a match with the cost-cutting-track
@@ -916,11 +944,38 @@ public class RoutingEngine extends Thread
}
// recheck cutoff before doing expensive stuff
- if ( path.cost + path.airdistance > maxTotalCost + 10 )
+ if ( path.cost + path.airdistance > maxTotalCost + 100 )
{
path.unregisterUpTree( routingContext );
continue;
}
+
+ routingContext.firstPrePath = null;
+
+ for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
+ {
+ OsmNode nextNode = link.getTarget( currentNode );
+
+ if ( ! nodesCache.obtainNonHollowNode( nextNode ) )
+ {
+ continue; // border node?
+ }
+ if ( nextNode.firstlink == null )
+ {
+ continue; // don't care about dead ends
+ }
+ if ( nextNode == sourceNode )
+ {
+ continue; // border node?
+ }
+
+ OsmPrePath prePath = routingContext.createPrePath( path, link );
+ if ( prePath != null )
+ {
+ prePath.next = routingContext.firstPrePath;
+ routingContext.firstPrePath = prePath;
+ }
+ }
for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
{
@@ -946,14 +1001,14 @@ public class RoutingEngine extends Thread
{
continue;
}
- OsmPathElement guideNode = guideTrack.nodes.get( gidx );
+ OsmPathElement guideNode = guideTrack.nodes.get( routingContext.inverseRouting ? guideTrack.nodes.size() - 1 - gidx : gidx );
long nextId = nextNode.getIdFromPos();
if ( nextId != guideNode.getIdFromPos() )
{
// not along the guide-track, discard, but register for voice-hint processing
if ( routingContext.turnInstructionMode > 0 )
{
- OsmPath detour = new OsmPath( path, link, refTrack, true, routingContext );
+ OsmPath detour = routingContext.createPath( path, link, refTrack, true );
if ( detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2 )
{
guideTrack.registerDetourForId( currentNode.getIdFromPos(), OsmPathElement.create( detour, false ) );
@@ -985,7 +1040,7 @@ public class RoutingEngine extends Thread
endPos.radius = 1e-5;
routingContext.setWaypoint( endPos, true );
}
- OsmPath testPath = new OsmPath( otherPath, link, refTrack, guideTrack != null, routingContext );
+ OsmPath testPath = routingContext.createPath( otherPath, link, refTrack, guideTrack != null );
if ( testPath.cost >= 0 && ( bestPath == null || testPath.cost < bestPath.cost ) )
{
bestPath = testPath;
@@ -1004,7 +1059,7 @@ public class RoutingEngine extends Thread
boolean inRadius = boundary == null || boundary.isInBoundary( nextNode, bestPath.cost );
- if ( inRadius && ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 10 ) )
+ if ( inRadius && ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 100 ) )
{
// add only if this may beat an existing path for that link
OsmLinkHolder dominator = link.getFirstLinkHolder( currentNode );
@@ -1052,12 +1107,18 @@ public class RoutingEngine extends Thread
private OsmTrack compileTrack( OsmPath path, boolean verbose )
{
OsmPathElement element = OsmPathElement.create( path, false );
-
+
// for final track, cut endnode
- if ( guideTrack != null ) element = element.origin;
+ if ( guideTrack != null )
+ {
+ element = element.origin;
+ }
+
+ float totalTime = element.getTime();
OsmTrack track = new OsmTrack();
track.cost = path.cost;
+ track.energy = (int)path.getTotalEnergy();
int distance = 0;
double ascend = 0;
@@ -1066,9 +1127,24 @@ public class RoutingEngine extends Thread
short ele_start = Short.MIN_VALUE;
short ele_end = Short.MIN_VALUE;
+ double eleFactor = routingContext.inverseRouting ? -0.25 : 0.25;
while ( element != null )
{
- track.addNode( element );
+ if ( guideTrack != null && element.message == null )
+ {
+ element.message = new MessageData();
+ }
+
+ if ( routingContext.inverseRouting )
+ {
+ element.setTime( totalTime - element.getTime() );
+ track.nodes.add( element );
+ }
+ else
+ {
+ track.nodes.add( 0, element );
+ }
+
OsmPathElement nextElement = element.origin;
short ele = element.getSElev();
@@ -1081,7 +1157,7 @@ public class RoutingEngine extends Thread
short ele_next = nextElement.getSElev();
if ( ele_next != Short.MIN_VALUE )
{
- ehb = ehb + (ele - ele_next)/4.;
+ ehb = ehb + (ele - ele_next)*eleFactor;
}
if ( ehb > 10. )
{
@@ -1098,7 +1174,7 @@ public class RoutingEngine extends Thread
ascend += ehb;
track.distance = distance;
track.ascend = (int)ascend;
- track.plainAscend = ( ele_end - ele_start ) / 4;
+ track.plainAscend = (int)(( ele_end - ele_start )*eleFactor+0.5);
logInfo( "track-length = " + track.distance );
logInfo( "filtered ascend = " + track.ascend );
track.buildMap();
diff --git a/brouter-core/src/main/java/btools/router/StdModel.java b/brouter-core/src/main/java/btools/router/StdModel.java
new file mode 100644
index 0000000..11f4701
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/StdModel.java
@@ -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...
+
+ }
+}
diff --git a/brouter-core/src/main/java/btools/router/StdPath.java b/brouter-core/src/main/java/btools/router/StdPath.java
new file mode 100644
index 0000000..6f73f92
--- /dev/null
+++ b/brouter-core/src/main/java/btools/router/StdPath.java
@@ -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;
+ }
+
+}
diff --git a/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java b/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java
index 83456d0..4266dd3 100644
--- a/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java
+++ b/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java
@@ -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;
}
}
diff --git a/brouter-expressions/pom.xml b/brouter-expressions/pom.xml
index c4bbf38..daa4fd3 100644
--- a/brouter-expressions/pom.xml
+++ b/brouter-expressions/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-expressions
diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java
index 3d265d5..74d874d 100644
--- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java
+++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java
@@ -27,11 +27,14 @@ import btools.util.LruMap;
public abstract class BExpressionContext implements IByteArrayUnifier
{
private static final String CONTEXT_TAG = "---context:";
+ private static final String MODEL_TAG = "---model:";
private String context;
private boolean _inOurContext = false;
private BufferedReader _br = null;
private boolean _readerDone = false;
+
+ public String _modelClass;
private Map lookupNumbers = new HashMap();
private ArrayList lookupValues = new ArrayList();
@@ -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;
diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContextGlobal.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContextGlobal.java
deleted file mode 100644
index b0764f6..0000000
--- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContextGlobal.java
+++ /dev/null
@@ -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 );
- }
-}
diff --git a/brouter-map-creator/pom.xml b/brouter-map-creator/pom.xml
index cb1e6c3..0ebf90a 100644
--- a/brouter-map-creator/pom.xml
+++ b/brouter-map-creator/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-map-creator
diff --git a/brouter-mapaccess/pom.xml b/brouter-mapaccess/pom.xml
index db24139..268b6a7 100644
--- a/brouter-mapaccess/pom.xml
+++ b/brouter-mapaccess/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-mapaccess
diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/GeometryDecoder.java b/brouter-mapaccess/src/main/java/btools/mapaccess/GeometryDecoder.java
index 6533d5a..f297547 100644
--- a/brouter-mapaccess/src/main/java/btools/mapaccess/GeometryDecoder.java
+++ b/brouter-mapaccess/src/main/java/btools/mapaccess/GeometryDecoder.java
@@ -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;
}
}
diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
index 3dc6e57..2e2ccd9 100644
--- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
+++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
@@ -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 );
}
diff --git a/brouter-mem-router/pom.xml b/brouter-mem-router/pom.xml
index 3e07766..34840f0 100644
--- a/brouter-mem-router/pom.xml
+++ b/brouter-mem-router/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-mem-router
diff --git a/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java b/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java
index 18ed30e..5c7c2f8 100644
--- a/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java
+++ b/brouter-mem-router/src/main/java/btools/memrouter/OsmNodeP.java
@@ -109,7 +109,7 @@ public class OsmNodeP extends OsmLinkP implements Comparable, 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 );
}
diff --git a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java
index 3059f60..b7e0cb3 100644
--- a/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java
+++ b/brouter-mem-router/src/main/java/btools/memrouter/ScheduledRouter.java
@@ -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;
}
diff --git a/brouter-routing-app/AndroidManifest.xml b/brouter-routing-app/AndroidManifest.xml
index 242705c..0de810b 100644
--- a/brouter-routing-app/AndroidManifest.xml
+++ b/brouter-routing-app/AndroidManifest.xml
@@ -1,8 +1,8 @@
+ android:versionCode="21"
+ android:versionName="1.4.9" package="btools.routingapp">
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-routing-app
diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
index 43f9de3..d611000 100644
--- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
+++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
@@ -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 )
{
diff --git a/brouter-server/pom.xml b/brouter-server/pom.xml
index d96f3a7..03b798c 100644
--- a/brouter-server/pom.xml
+++ b/brouter-server/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-server
diff --git a/brouter-server/src/main/java/btools/server/BRouter.java b/brouter-server/src/main/java/btools/server/BRouter.java
index 199c10f..6a72c3d 100644
--- a/brouter-server/src/main/java/btools/server/BRouter.java
+++ b/brouter-server/src/main/java/btools/server/BRouter.java
@@ -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");
diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java
index 53344b2..4a9cd56 100644
--- a/brouter-server/src/main/java/btools/server/RouteServer.java
+++ b/brouter-server/src/main/java/btools/server/RouteServer.java
@@ -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");
diff --git a/brouter-util/pom.xml b/brouter-util/pom.xml
index a3f4a78..c71dd03 100644
--- a/brouter-util/pom.xml
+++ b/brouter-util/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.8
+ 1.4.9
../pom.xml
brouter-util
diff --git a/misc/pbfparser/compile_parser.bat b/misc/pbfparser/compile_parser.bat
index 7a5452b..a95926a 100644
--- a/misc/pbfparser/compile_parser.bat
+++ b/misc/pbfparser/compile_parser.bat
@@ -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
diff --git a/misc/profiles2/car-eco.brf b/misc/profiles2/car-eco.brf
new file mode 100644
index 0000000..0cbec3e
--- /dev/null
+++ b/misc/profiles2/car-eco.brf
@@ -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
diff --git a/misc/profiles2/car-fast.brf b/misc/profiles2/car-fast.brf
new file mode 100644
index 0000000..3c9959a
--- /dev/null
+++ b/misc/profiles2/car-fast.brf
@@ -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
diff --git a/misc/profiles2/car-test.brf b/misc/profiles2/car-test.brf
deleted file mode 100644
index 7d446f2..0000000
--- a/misc/profiles2/car-test.brf
+++ /dev/null
@@ -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
diff --git a/misc/profiles2/lookups.dat b/misc/profiles2/lookups.dat
index a1cc7fe..3826d05 100644
--- a/misc/profiles2/lookups.dat
+++ b/misc/profiles2/lookups.dat
@@ -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
highway;0000000046 toll_bridge
highway;0000000037 city_entry
+highway;0000002967 traffic_mirror
+highway;0000001724 priority
barrier;0000606512 gate
barrier;0000164120 bollard
diff --git a/pom.xml b/pom.xml
index 168f359..a8999e9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
org.btools
brouter
- 1.4.8
+ 1.4.9
pom
http://brouter.de/brouter/
brouter