Reformat whole codebase using Android Studio
This commit is contained in:
parent
d5322667d5
commit
c15913c1ab
161 changed files with 15124 additions and 18537 deletions
|
|
@ -11,15 +11,12 @@ import btools.expressions.BExpressionContextNode;
|
|||
import btools.expressions.BExpressionContextWay;
|
||||
|
||||
|
||||
final class KinematicModel extends OsmPathModel
|
||||
{
|
||||
public OsmPrePath createPrePath()
|
||||
{
|
||||
final class KinematicModel extends OsmPathModel {
|
||||
public OsmPrePath createPrePath() {
|
||||
return new KinematicPrePath();
|
||||
}
|
||||
|
||||
public OsmPath createPath()
|
||||
{
|
||||
public OsmPath createPath() {
|
||||
return new KinematicPath();
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +35,7 @@ final class KinematicModel extends OsmPathModel
|
|||
// derived values
|
||||
public double pw; // balance power
|
||||
public double cost0; // minimum possible cost per meter
|
||||
|
||||
|
||||
private int wayIdxMaxspeed;
|
||||
private int wayIdxMaxspeedExplicit;
|
||||
private int wayIdxMinspeed;
|
||||
|
|
@ -47,7 +44,7 @@ final class KinematicModel extends OsmPathModel
|
|||
|
||||
protected BExpressionContextWay ctxWay;
|
||||
protected BExpressionContextNode ctxNode;
|
||||
protected Map<String,String> params;
|
||||
protected Map<String, String> params;
|
||||
|
||||
private boolean initDone = false;
|
||||
|
||||
|
|
@ -55,77 +52,67 @@ final class KinematicModel extends OsmPathModel
|
|||
private double lastBreakingSpeed;
|
||||
|
||||
@Override
|
||||
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> extraParams )
|
||||
{
|
||||
if ( !initDone )
|
||||
{
|
||||
public void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> extraParams) {
|
||||
if (!initDone) {
|
||||
ctxWay = expctxWay;
|
||||
ctxNode = expctxNode;
|
||||
wayIdxMaxspeed = ctxWay.getOutputVariableIndex( "maxspeed", false );
|
||||
wayIdxMaxspeedExplicit = ctxWay.getOutputVariableIndex( "maxspeed_explicit", false );
|
||||
wayIdxMinspeed = ctxWay.getOutputVariableIndex( "minspeed", false );
|
||||
nodeIdxMaxspeed = ctxNode.getOutputVariableIndex( "maxspeed", false );
|
||||
wayIdxMaxspeed = ctxWay.getOutputVariableIndex("maxspeed", false);
|
||||
wayIdxMaxspeedExplicit = ctxWay.getOutputVariableIndex("maxspeed_explicit", false);
|
||||
wayIdxMinspeed = ctxWay.getOutputVariableIndex("minspeed", false);
|
||||
nodeIdxMaxspeed = ctxNode.getOutputVariableIndex("maxspeed", false);
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
params = extraParams;
|
||||
|
||||
turnAngleDecayTime = getParam( "turnAngleDecayTime", 5.f );
|
||||
f_roll = getParam( "f_roll", 232.f );
|
||||
f_air = getParam( "f_air", 0.4f );
|
||||
f_recup = getParam( "f_recup", 400.f );
|
||||
p_standby = getParam( "p_standby", 250.f );
|
||||
outside_temp = getParam( "outside_temp", 20.f );
|
||||
recup_efficiency = getParam( "recup_efficiency", 0.7f );
|
||||
totalweight = getParam( "totalweight", 1640.f );
|
||||
vmax = getParam( "vmax", 80.f ) / 3.6;
|
||||
leftWaySpeed = getParam( "leftWaySpeed", 12.f ) / 3.6;
|
||||
rightWaySpeed = getParam( "rightWaySpeed", 12.f ) / 3.6;
|
||||
|
||||
turnAngleDecayTime = getParam("turnAngleDecayTime", 5.f);
|
||||
f_roll = getParam("f_roll", 232.f);
|
||||
f_air = getParam("f_air", 0.4f);
|
||||
f_recup = getParam("f_recup", 400.f);
|
||||
p_standby = getParam("p_standby", 250.f);
|
||||
outside_temp = getParam("outside_temp", 20.f);
|
||||
recup_efficiency = getParam("recup_efficiency", 0.7f);
|
||||
totalweight = getParam("totalweight", 1640.f);
|
||||
vmax = getParam("vmax", 80.f) / 3.6;
|
||||
leftWaySpeed = getParam("leftWaySpeed", 12.f) / 3.6;
|
||||
rightWaySpeed = getParam("rightWaySpeed", 12.f) / 3.6;
|
||||
|
||||
pw = 2. * f_air * vmax * vmax * vmax - p_standby;
|
||||
cost0 = (pw+p_standby)/vmax + f_roll + f_air*vmax*vmax;
|
||||
cost0 = (pw + p_standby) / vmax + f_roll + f_air * vmax * vmax;
|
||||
}
|
||||
|
||||
protected float getParam( String name, float defaultValue )
|
||||
{
|
||||
String sval = params == null ? null : params.get( name );
|
||||
if ( sval != null )
|
||||
{
|
||||
return Float.parseFloat( sval );
|
||||
protected float getParam(String name, float defaultValue) {
|
||||
String sval = params == null ? null : params.get(name);
|
||||
if (sval != null) {
|
||||
return Float.parseFloat(sval);
|
||||
}
|
||||
float v = ctxWay.getVariableValue( name, defaultValue );
|
||||
if ( params != null )
|
||||
{
|
||||
params.put( name, "" + v );
|
||||
float v = ctxWay.getVariableValue(name, defaultValue);
|
||||
if (params != null) {
|
||||
params.put(name, "" + v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public float getWayMaxspeed()
|
||||
{
|
||||
return ctxWay.getBuildInVariable( wayIdxMaxspeed ) / 3.6f;
|
||||
|
||||
public float getWayMaxspeed() {
|
||||
return ctxWay.getBuildInVariable(wayIdxMaxspeed) / 3.6f;
|
||||
}
|
||||
|
||||
public float getWayMaxspeedExplicit()
|
||||
{
|
||||
return ctxWay.getBuildInVariable( wayIdxMaxspeedExplicit ) / 3.6f;
|
||||
public float getWayMaxspeedExplicit() {
|
||||
return ctxWay.getBuildInVariable(wayIdxMaxspeedExplicit) / 3.6f;
|
||||
}
|
||||
|
||||
public float getWayMinspeed()
|
||||
{
|
||||
return ctxWay.getBuildInVariable( wayIdxMinspeed ) / 3.6f;
|
||||
public float getWayMinspeed() {
|
||||
return ctxWay.getBuildInVariable(wayIdxMinspeed) / 3.6f;
|
||||
}
|
||||
|
||||
public float getNodeMaxspeed()
|
||||
{
|
||||
return ctxNode.getBuildInVariable( nodeIdxMaxspeed ) / 3.6f;
|
||||
public float getNodeMaxspeed() {
|
||||
return ctxNode.getBuildInVariable(nodeIdxMaxspeed) / 3.6f;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the effective speed limit from the way-limit and vmax/vmin
|
||||
*/
|
||||
public double getEffectiveSpeedLimit( )
|
||||
{
|
||||
/**
|
||||
* get the effective speed limit from the way-limit and vmax/vmin
|
||||
*/
|
||||
public double getEffectiveSpeedLimit() {
|
||||
// performance related inline coding
|
||||
double minspeed = getWayMinspeed();
|
||||
double espeed = minspeed > vmax ? minspeed : vmax;
|
||||
|
|
@ -133,30 +120,27 @@ final class KinematicModel extends OsmPathModel
|
|||
return maxspeed < espeed ? maxspeed : espeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the breaking speed for current balance-power (pw) and effective speed limit (vl)
|
||||
*/
|
||||
public double getBreakingSpeed( double vl )
|
||||
{
|
||||
if ( vl == lastEffectiveLimit )
|
||||
{
|
||||
/**
|
||||
* get the breaking speed for current balance-power (pw) and effective speed limit (vl)
|
||||
*/
|
||||
public double getBreakingSpeed(double vl) {
|
||||
if (vl == lastEffectiveLimit) {
|
||||
return lastBreakingSpeed;
|
||||
}
|
||||
|
||||
double v = vl*0.8;
|
||||
double pw2 = pw+p_standby;
|
||||
double v = vl * 0.8;
|
||||
double pw2 = pw + p_standby;
|
||||
double e = recup_efficiency;
|
||||
double x0 = pw2/vl+f_air*e*vl*vl+(1.-e)*f_roll;
|
||||
for(int i=0;i<5;i++)
|
||||
{
|
||||
double v2 = v*v;
|
||||
double x = pw2/v+f_air*e*v2 - x0;
|
||||
double dx = 2.*e*f_air*v - pw2/v2;
|
||||
v -= x/dx;
|
||||
double x0 = pw2 / vl + f_air * e * vl * vl + (1. - e) * f_roll;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
double v2 = v * v;
|
||||
double x = pw2 / v + f_air * e * v2 - x0;
|
||||
double dx = 2. * e * f_air * v - pw2 / v2;
|
||||
v -= x / dx;
|
||||
}
|
||||
lastEffectiveLimit = vl;
|
||||
lastBreakingSpeed = v;
|
||||
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ package btools.router;
|
|||
import btools.util.FastMath;
|
||||
|
||||
|
||||
final class KinematicPath extends OsmPath
|
||||
{
|
||||
final class KinematicPath extends OsmPath {
|
||||
private double ekin; // kinetic energy (Joule)
|
||||
private double totalTime; // travel time (seconds)
|
||||
private double totalEnergy; // total route energy (Joule)
|
||||
|
|
@ -17,9 +16,8 @@ final class KinematicPath extends OsmPath
|
|||
private float floatingAngleRight; // sliding average right bend (degree)
|
||||
|
||||
@Override
|
||||
protected void init( OsmPath orig )
|
||||
{
|
||||
KinematicPath origin = (KinematicPath)orig;
|
||||
protected void init(OsmPath orig) {
|
||||
KinematicPath origin = (KinematicPath) orig;
|
||||
ekin = origin.ekin;
|
||||
totalTime = origin.totalTime;
|
||||
totalEnergy = origin.totalEnergy;
|
||||
|
|
@ -29,8 +27,7 @@ final class KinematicPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void resetState()
|
||||
{
|
||||
protected void resetState() {
|
||||
ekin = 0.;
|
||||
totalTime = 0.;
|
||||
totalEnergy = 0.;
|
||||
|
|
@ -39,267 +36,237 @@ final class KinematicPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double processWaySection( RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier )
|
||||
{
|
||||
KinematicModel km = (KinematicModel)rc.pm;
|
||||
protected double processWaySection(RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier) {
|
||||
KinematicModel km = (KinematicModel) rc.pm;
|
||||
|
||||
double cost = 0.;
|
||||
double extraTime = 0.;
|
||||
|
||||
if ( isStartpoint )
|
||||
{
|
||||
if (isStartpoint) {
|
||||
// for forward direction, we start with target speed
|
||||
if ( !rc.inverseDirection )
|
||||
{
|
||||
extraTime = 0.5 * (1. - cosangle ) * 40.; // 40 seconds turn penalty
|
||||
if (!rc.inverseDirection) {
|
||||
extraTime = 0.5 * (1. - cosangle) * 40.; // 40 seconds turn penalty
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
double turnspeed = 999.; // just high
|
||||
|
||||
if ( km.turnAngleDecayTime != 0. ) // process turn-angle slowdown
|
||||
if (km.turnAngleDecayTime != 0.) // process turn-angle slowdown
|
||||
{
|
||||
if ( angle < 0 ) floatingAngleLeft -= (float)angle;
|
||||
else floatingAngleRight += (float)angle;
|
||||
float aa = Math.max( floatingAngleLeft, floatingAngleRight );
|
||||
if (angle < 0) floatingAngleLeft -= (float) angle;
|
||||
else floatingAngleRight += (float) angle;
|
||||
float aa = Math.max(floatingAngleLeft, floatingAngleRight);
|
||||
|
||||
double curveSpeed = aa > 10. ? 200. / aa : 20.;
|
||||
double curveSpeed = aa > 10. ? 200. / aa : 20.;
|
||||
double distanceTime = dist / curveSpeed;
|
||||
double decayFactor = FastMath.exp( - distanceTime / km.turnAngleDecayTime );
|
||||
floatingAngleLeft = (float)( floatingAngleLeft * decayFactor );
|
||||
floatingAngleRight = (float)( floatingAngleRight * decayFactor );
|
||||
double decayFactor = FastMath.exp(-distanceTime / km.turnAngleDecayTime);
|
||||
floatingAngleLeft = (float) (floatingAngleLeft * decayFactor);
|
||||
floatingAngleRight = (float) (floatingAngleRight * decayFactor);
|
||||
|
||||
if ( curveSpeed < 20. )
|
||||
{
|
||||
if (curveSpeed < 20.) {
|
||||
turnspeed = curveSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nsection == 0 ) // process slowdown by crossing geometry
|
||||
if (nsection == 0) // process slowdown by crossing geometry
|
||||
{
|
||||
double junctionspeed = 999.; // just high
|
||||
|
||||
int classifiermask = (int)rc.expctxWay.getClassifierMask();
|
||||
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;
|
||||
for (OsmPrePath prePath = rc.firstPrePath; prePath != null; prePath = prePath.next) {
|
||||
KinematicPrePath pp = (KinematicPrePath) prePath;
|
||||
|
||||
if ( ( (pp.classifiermask ^ classifiermask) & 8 ) != 0 ) // exactly one is linktype
|
||||
if (((pp.classifiermask ^ classifiermask) & 8) != 0) // exactly one is linktype
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( pp.classifiermask & 32 ) != 0 ) // touching a residential?
|
||||
if ((pp.classifiermask & 32) != 0) // touching a residential?
|
||||
{
|
||||
hasResidential = true;
|
||||
}
|
||||
|
||||
if ( pp.priorityclassifier > priorityclassifier || pp.priorityclassifier == priorityclassifier && priorityclassifier < 20 )
|
||||
{
|
||||
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;
|
||||
if (diff < -40. && diff > -140.) hasLeftWay = true;
|
||||
if (diff > 40. && diff < 140.) hasRightWay = true;
|
||||
}
|
||||
}
|
||||
double residentialSpeed = 13.;
|
||||
|
||||
if ( hasLeftWay && junctionspeed > km.leftWaySpeed ) junctionspeed = km.leftWaySpeed;
|
||||
if ( hasRightWay && junctionspeed > km.rightWaySpeed ) junctionspeed = km.rightWaySpeed;
|
||||
if ( hasResidential && junctionspeed > residentialSpeed ) junctionspeed = residentialSpeed;
|
||||
if (hasLeftWay && junctionspeed > km.leftWaySpeed) junctionspeed = km.leftWaySpeed;
|
||||
if (hasRightWay && junctionspeed > km.rightWaySpeed) junctionspeed = km.rightWaySpeed;
|
||||
if (hasResidential && junctionspeed > residentialSpeed) junctionspeed = residentialSpeed;
|
||||
|
||||
if ( (lastpriorityclassifier < 20) ^ (priorityclassifier < 20) )
|
||||
{
|
||||
if ((lastpriorityclassifier < 20) ^ (priorityclassifier < 20)) {
|
||||
extraTime += 10.;
|
||||
junctionspeed = 0; // full stop for entering or leaving road network
|
||||
}
|
||||
|
||||
if ( lastpriorityclassifier != priorityclassifier && (classifiermask & 8) != 0 )
|
||||
{
|
||||
if (lastpriorityclassifier != priorityclassifier && (classifiermask & 8) != 0) {
|
||||
extraTime += 2.; // two seconds for entering a link-type
|
||||
}
|
||||
turnspeed = turnspeed > junctionspeed ? junctionspeed : turnspeed;
|
||||
|
||||
if ( message != null )
|
||||
{
|
||||
message.vnode0 = (int) ( junctionspeed * 3.6 + 0.5 );
|
||||
if (message != null) {
|
||||
message.vnode0 = (int) (junctionspeed * 3.6 + 0.5);
|
||||
}
|
||||
}
|
||||
cutEkin( km.totalweight, turnspeed ); // apply turnspeed
|
||||
cutEkin(km.totalweight, turnspeed); // apply turnspeed
|
||||
}
|
||||
|
||||
// linear temperature correction
|
||||
double tcorr = (20.-km.outside_temp)*0.0035;
|
||||
double tcorr = (20. - km.outside_temp) * 0.0035;
|
||||
|
||||
// air_pressure down 1mb/8m
|
||||
double ecorr = 0.0001375 * (elevation - 100.);
|
||||
|
||||
double f_air = km.f_air * ( 1. + tcorr - ecorr );
|
||||
double f_air = km.f_air * (1. + tcorr - ecorr);
|
||||
|
||||
double distanceCost = evolveDistance( km, dist, delta_h, f_air );
|
||||
double distanceCost = evolveDistance(km, dist, delta_h, f_air);
|
||||
|
||||
if ( message != null )
|
||||
{
|
||||
message.costfactor = (float)(distanceCost/dist);
|
||||
message.vmax = (int) ( km.getWayMaxspeed() * 3.6 + 0.5 );
|
||||
message.vmaxExplicit = (int) ( km.getWayMaxspeedExplicit() * 3.6 + 0.5 );
|
||||
message.vmin = (int) ( km.getWayMinspeed() * 3.6 + 0.5 );
|
||||
message.extraTime = (int)(extraTime*1000);
|
||||
if (message != null) {
|
||||
message.costfactor = (float) (distanceCost / dist);
|
||||
message.vmax = (int) (km.getWayMaxspeed() * 3.6 + 0.5);
|
||||
message.vmaxExplicit = (int) (km.getWayMaxspeedExplicit() * 3.6 + 0.5);
|
||||
message.vmin = (int) (km.getWayMinspeed() * 3.6 + 0.5);
|
||||
message.extraTime = (int) (extraTime * 1000);
|
||||
}
|
||||
|
||||
cost += extraTime * km.pw / km.cost0;
|
||||
cost += extraTime * km.pw / km.cost0;
|
||||
totalTime += extraTime;
|
||||
|
||||
return cost + distanceCost;
|
||||
}
|
||||
|
||||
|
||||
protected double evolveDistance( KinematicModel km, double dist, double delta_h, double f_air )
|
||||
{
|
||||
protected double evolveDistance(KinematicModel km, double dist, double delta_h, double f_air) {
|
||||
// elevation force
|
||||
double fh = delta_h * km.totalweight * 9.81 / dist;
|
||||
|
||||
double effectiveSpeedLimit = km.getEffectiveSpeedLimit();
|
||||
double emax = 0.5*km.totalweight*effectiveSpeedLimit*effectiveSpeedLimit;
|
||||
if ( emax <= 0. )
|
||||
{
|
||||
double emax = 0.5 * km.totalweight * effectiveSpeedLimit * effectiveSpeedLimit;
|
||||
if (emax <= 0.) {
|
||||
return -1.;
|
||||
}
|
||||
double vb = km.getBreakingSpeed( effectiveSpeedLimit );
|
||||
double elow = 0.5*km.totalweight*vb*vb;
|
||||
double vb = km.getBreakingSpeed(effectiveSpeedLimit);
|
||||
double elow = 0.5 * km.totalweight * vb * vb;
|
||||
|
||||
double elapsedTime = 0.;
|
||||
double dissipatedEnergy = 0.;
|
||||
|
||||
double v = Math.sqrt( 2. * ekin / km.totalweight );
|
||||
double v = Math.sqrt(2. * ekin / km.totalweight);
|
||||
double d = dist;
|
||||
while( d > 0. )
|
||||
{
|
||||
while (d > 0.) {
|
||||
boolean slow = ekin < elow;
|
||||
boolean fast = ekin >= emax;
|
||||
double etarget = slow ? elow : emax;
|
||||
double f = km.f_roll + f_air*v*v + fh;
|
||||
double f_recup = Math.max( 0., fast ? -f : (slow ? km.f_recup :0 ) -fh ); // additional recup for slow part
|
||||
double f = km.f_roll + 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 timeStep;
|
||||
double x;
|
||||
if ( fast )
|
||||
{
|
||||
if (fast) {
|
||||
x = d;
|
||||
delta_ekin = x*f;
|
||||
timeStep = x/v;
|
||||
delta_ekin = x * f;
|
||||
timeStep = x / v;
|
||||
ekin = etarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta_ekin = etarget-ekin;
|
||||
double b = 2.*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 )
|
||||
{
|
||||
} else {
|
||||
delta_ekin = etarget - ekin;
|
||||
double b = 2. * 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)
|
||||
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
|
||||
{
|
||||
} else {
|
||||
ekin = etarget;
|
||||
}
|
||||
double v2 = Math.sqrt( 2. * ekin / km.totalweight );
|
||||
double v2 = Math.sqrt(2. * ekin / km.totalweight);
|
||||
double a = f / km.totalweight; // TODO: average force?
|
||||
timeStep = (v2-v)/a;
|
||||
timeStep = (v2 - v) / a;
|
||||
v = v2;
|
||||
}
|
||||
d -= x;
|
||||
elapsedTime += timeStep;
|
||||
|
||||
// dissipated energy does not contain elevation and efficient recup
|
||||
dissipatedEnergy += delta_ekin - x*(fh + f_recup*km.recup_efficiency);
|
||||
dissipatedEnergy += delta_ekin - x * (fh + f_recup * km.recup_efficiency);
|
||||
|
||||
// correction: inefficient recup going into heating is half efficient
|
||||
double ieRecup = x*f_recup*(1.-km.recup_efficiency);
|
||||
double eaux = timeStep*km.p_standby;
|
||||
dissipatedEnergy -= Math.max( ieRecup, eaux ) * 0.5;
|
||||
double ieRecup = x * f_recup * (1. - km.recup_efficiency);
|
||||
double eaux = timeStep * km.p_standby;
|
||||
dissipatedEnergy -= Math.max(ieRecup, eaux) * 0.5;
|
||||
}
|
||||
|
||||
dissipatedEnergy += elapsedTime * km.p_standby;
|
||||
|
||||
totalTime += elapsedTime;
|
||||
totalEnergy += dissipatedEnergy + dist*fh;
|
||||
totalEnergy += dissipatedEnergy + dist * fh;
|
||||
|
||||
return (km.pw * elapsedTime + dissipatedEnergy)/km.cost0; // =cost
|
||||
return (km.pw * elapsedTime + dissipatedEnergy) / km.cost0; // =cost
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double processTargetNode( RoutingContext rc )
|
||||
{
|
||||
KinematicModel km = (KinematicModel)rc.pm;
|
||||
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 );
|
||||
if (targetNode.nodeDescription != null) {
|
||||
rc.expctxNode.evaluate(false, targetNode.nodeDescription);
|
||||
float initialcost = rc.expctxNode.getInitialcost();
|
||||
if ( initialcost >= 1000000. )
|
||||
{
|
||||
if (initialcost >= 1000000.) {
|
||||
return -1.;
|
||||
}
|
||||
cutEkin( km.totalweight, km.getNodeMaxspeed() ); // apply node maxspeed
|
||||
cutEkin(km.totalweight, km.getNodeMaxspeed()); // apply node maxspeed
|
||||
|
||||
if ( message != null )
|
||||
{
|
||||
message.linknodecost += (int)initialcost;
|
||||
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription( false, targetNode.nodeDescription );
|
||||
if (message != null) {
|
||||
message.linknodecost += (int) initialcost;
|
||||
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription(false, targetNode.nodeDescription);
|
||||
|
||||
message.vnode1 = (int) ( km.getNodeMaxspeed() * 3.6 + 0.5 );
|
||||
message.vnode1 = (int) (km.getNodeMaxspeed() * 3.6 + 0.5);
|
||||
}
|
||||
return initialcost;
|
||||
}
|
||||
return 0.;
|
||||
}
|
||||
|
||||
private void cutEkin( double weight, double speed )
|
||||
{
|
||||
double e = 0.5*weight*speed*speed;
|
||||
if ( ekin > e ) ekin = e;
|
||||
private void cutEkin(double weight, double speed) {
|
||||
double e = 0.5 * weight * speed * speed;
|
||||
if (ekin > e) ekin = e;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int elevationCorrection( RoutingContext rc )
|
||||
{
|
||||
public int elevationCorrection(RoutingContext rc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean definitlyWorseThan( OsmPath path, RoutingContext rc )
|
||||
{
|
||||
KinematicPath p = (KinematicPath)path;
|
||||
public boolean definitlyWorseThan(OsmPath path, RoutingContext rc) {
|
||||
KinematicPath p = (KinematicPath) path;
|
||||
|
||||
int c = p.cost;
|
||||
return cost > c + 100;
|
||||
int c = p.cost;
|
||||
return cost > c + 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTotalTime()
|
||||
{
|
||||
public double getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTotalEnergy()
|
||||
{
|
||||
public double getTotalEnergy() {
|
||||
return totalEnergy;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,16 +8,14 @@ package btools.router;
|
|||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmTransferNode;
|
||||
|
||||
final class KinematicPrePath extends OsmPrePath
|
||||
{
|
||||
final class KinematicPrePath extends OsmPrePath {
|
||||
public double angle;
|
||||
public int priorityclassifier;
|
||||
public int classifiermask;
|
||||
|
||||
protected void initPrePath(OsmPath origin, RoutingContext rc )
|
||||
{
|
||||
protected void initPrePath(OsmPath origin, 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);
|
||||
|
||||
// extract the 3 positions of the first section
|
||||
int lon0 = origin.originLon;
|
||||
|
|
@ -27,32 +25,29 @@ final class KinematicPrePath extends OsmPrePath
|
|||
int lon1 = p1.getILon();
|
||||
int lat1 = p1.getILat();
|
||||
|
||||
boolean isReverse = link.isReverse( sourceNode );
|
||||
boolean isReverse = link.isReverse(sourceNode);
|
||||
|
||||
// evaluate the way tags
|
||||
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
|
||||
rc.expctxWay.evaluate(rc.inverseDirection ^ isReverse, description);
|
||||
|
||||
OsmTransferNode transferNode = link.geometry == null ? null
|
||||
: rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
|
||||
: rc.geometryDecoder.decodeGeometry(link.geometry, p1, targetNode, isReverse);
|
||||
|
||||
int lon2;
|
||||
int lat2;
|
||||
|
||||
if ( transferNode == null )
|
||||
{
|
||||
if (transferNode == null) {
|
||||
lon2 = targetNode.ilon;
|
||||
lat2 = targetNode.ilat;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
lon2 = transferNode.ilon;
|
||||
lat2 = transferNode.ilat;
|
||||
}
|
||||
|
||||
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
|
||||
int dist = rc.calcDistance(lon1, lat1, lon2, lat2);
|
||||
|
||||
angle = rc.anglemeter.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
|
||||
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
|
||||
classifiermask = (int)rc.expctxWay.getClassifierMask();
|
||||
angle = rc.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
|
||||
priorityclassifier = (int) rc.expctxWay.getPriorityClassifier();
|
||||
classifiermask = (int) rc.expctxWay.getClassifierMask();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,13 @@
|
|||
package btools.router;
|
||||
|
||||
|
||||
|
||||
final class MessageData implements Cloneable
|
||||
{
|
||||
final class MessageData implements Cloneable {
|
||||
int linkdist = 0;
|
||||
int linkelevationcost = 0;
|
||||
int linkturncost = 0;
|
||||
int linknodecost = 0;
|
||||
int linkinitcost = 0;
|
||||
|
||||
|
||||
float costfactor;
|
||||
int priorityclassifier;
|
||||
int classifiermask;
|
||||
|
|
@ -25,7 +23,7 @@ final class MessageData implements Cloneable
|
|||
int lon;
|
||||
int lat;
|
||||
short ele;
|
||||
|
||||
|
||||
float time;
|
||||
float energy;
|
||||
|
||||
|
|
@ -37,84 +35,70 @@ final class MessageData implements Cloneable
|
|||
int vnode1 = 999;
|
||||
int extraTime = 0;
|
||||
|
||||
String toMessage()
|
||||
{
|
||||
if ( wayKeyValues == null )
|
||||
{
|
||||
String toMessage() {
|
||||
if (wayKeyValues == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int iCost = (int)(costfactor*1000 + 0.5f);
|
||||
return (lon-180000000) + "\t"
|
||||
+ (lat-90000000) + "\t"
|
||||
+ ele/4 + "\t"
|
||||
+ linkdist + "\t"
|
||||
+ iCost + "\t"
|
||||
+ linkelevationcost
|
||||
+ "\t" + linkturncost
|
||||
+ "\t" + linknodecost
|
||||
+ "\t" + linkinitcost
|
||||
+ "\t" + wayKeyValues
|
||||
+ "\t" + ( nodeKeyValues == null ? "" : nodeKeyValues )
|
||||
+ "\t" + ((int)time)
|
||||
+ "\t" + ((int)energy);
|
||||
|
||||
int iCost = (int) (costfactor * 1000 + 0.5f);
|
||||
return (lon - 180000000) + "\t"
|
||||
+ (lat - 90000000) + "\t"
|
||||
+ ele / 4 + "\t"
|
||||
+ linkdist + "\t"
|
||||
+ iCost + "\t"
|
||||
+ linkelevationcost
|
||||
+ "\t" + linkturncost
|
||||
+ "\t" + linknodecost
|
||||
+ "\t" + linkinitcost
|
||||
+ "\t" + wayKeyValues
|
||||
+ "\t" + (nodeKeyValues == null ? "" : nodeKeyValues)
|
||||
+ "\t" + ((int) time)
|
||||
+ "\t" + ((int) energy);
|
||||
}
|
||||
|
||||
void add( MessageData d )
|
||||
{
|
||||
void add(MessageData d) {
|
||||
linkdist += d.linkdist;
|
||||
linkelevationcost += d.linkelevationcost;
|
||||
linkturncost += d.linkturncost;
|
||||
linknodecost += d.linknodecost;
|
||||
linkinitcost+= d.linkinitcost;
|
||||
linkinitcost += d.linkinitcost;
|
||||
}
|
||||
|
||||
MessageData copy()
|
||||
{
|
||||
try
|
||||
{
|
||||
return (MessageData)clone();
|
||||
}
|
||||
catch( CloneNotSupportedException e )
|
||||
{
|
||||
throw new RuntimeException( e );
|
||||
MessageData copy() {
|
||||
try {
|
||||
return (MessageData) clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
return "dist=" + linkdist + " prio=" + priorityclassifier + " turn=" + turnangle;
|
||||
}
|
||||
|
||||
public int getPrio()
|
||||
{
|
||||
public int getPrio() {
|
||||
return priorityclassifier;
|
||||
}
|
||||
|
||||
public boolean isBadOneway()
|
||||
{
|
||||
return ( classifiermask & 1 ) != 0;
|
||||
public boolean isBadOneway() {
|
||||
return (classifiermask & 1) != 0;
|
||||
}
|
||||
|
||||
public boolean isGoodOneway()
|
||||
{
|
||||
return ( classifiermask & 2 ) != 0;
|
||||
public boolean isGoodOneway() {
|
||||
return (classifiermask & 2) != 0;
|
||||
}
|
||||
|
||||
public boolean isRoundabout()
|
||||
{
|
||||
return ( classifiermask & 4 ) != 0;
|
||||
public boolean isRoundabout() {
|
||||
return (classifiermask & 4) != 0;
|
||||
}
|
||||
|
||||
public boolean isLinktType()
|
||||
{
|
||||
return ( classifiermask & 8 ) != 0;
|
||||
public boolean isLinktType() {
|
||||
return (classifiermask & 8) != 0;
|
||||
}
|
||||
|
||||
public boolean isGoodForCars()
|
||||
{
|
||||
return ( classifiermask & 16 ) != 0;
|
||||
public boolean isGoodForCars() {
|
||||
return (classifiermask & 16) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +1,98 @@
|
|||
/**
|
||||
* Container for an osm node
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.router;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
public class OsmNodeNamed extends OsmNode
|
||||
{
|
||||
public String name;
|
||||
public double radius; // radius of nogopoint (in meters)
|
||||
public double nogoWeight; // weight for nogopoint
|
||||
public boolean isNogo = false;
|
||||
|
||||
public OsmNodeNamed()
|
||||
{
|
||||
}
|
||||
|
||||
public OsmNodeNamed( OsmNode n)
|
||||
{
|
||||
super( n.ilon, n.ilat );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if ( Double.isNaN(nogoWeight ) ) {
|
||||
return ilon + "," + ilat + "," + name;
|
||||
} else {
|
||||
return ilon + "," + ilat + "," + name + "," + nogoWeight;
|
||||
}
|
||||
}
|
||||
|
||||
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lat1 + lat2) >> 1 );
|
||||
|
||||
boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius;
|
||||
boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
|
||||
// First point is within the circle
|
||||
if (isFirstPointWithinCircle) {
|
||||
// Last point is within the circle
|
||||
if (isLastPointWithinCircle) {
|
||||
return totalSegmentLength;
|
||||
}
|
||||
// Last point is not within the circle
|
||||
// Just swap points and go on with first first point not within the
|
||||
// circle now.
|
||||
// Swap longitudes
|
||||
int tmp = lon2;
|
||||
lon2 = lon1;
|
||||
lon1 = tmp;
|
||||
// Swap latitudes
|
||||
tmp = lat2;
|
||||
lat2 = lat1;
|
||||
lat1 = tmp;
|
||||
// Fix boolean values
|
||||
isLastPointWithinCircle = isFirstPointWithinCircle;
|
||||
isFirstPointWithinCircle = false;
|
||||
}
|
||||
// Distance between the initial point and projection of center of
|
||||
// the circle on the current segment.
|
||||
double initialToProject = (
|
||||
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
|
||||
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
|
||||
) / totalSegmentLength;
|
||||
// Distance between the initial point and the center of the circle.
|
||||
double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
|
||||
// Half length of the segment within the circle
|
||||
double halfDistanceWithin = Math.sqrt(
|
||||
radius*radius - (
|
||||
initialToCenter*initialToCenter -
|
||||
initialToProject*initialToProject
|
||||
)
|
||||
);
|
||||
// Last point is within the circle
|
||||
if (isLastPointWithinCircle) {
|
||||
return halfDistanceWithin + (totalSegmentLength - initialToProject);
|
||||
}
|
||||
return 2 * halfDistanceWithin;
|
||||
}
|
||||
|
||||
public static OsmNodeNamed decodeNogo( String s )
|
||||
{
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
int idx1 = s.indexOf( ',' );
|
||||
n.ilon = Integer.parseInt( s.substring( 0, idx1 ) );
|
||||
int idx2 = s.indexOf( ',', idx1+1 );
|
||||
n.ilat = Integer.parseInt( s.substring( idx1+1, idx2 ) );
|
||||
int idx3 = s.indexOf( ',', idx2+1 );
|
||||
if ( idx3 == -1) {
|
||||
n.name = s.substring( idx2 + 1 );
|
||||
n.nogoWeight = Double.NaN;
|
||||
} else {
|
||||
n.name = s.substring( idx2+1, idx3 );
|
||||
n.nogoWeight = Double.parseDouble( s.substring( idx3 + 1 ) );
|
||||
}
|
||||
n.isNogo = true;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Container for an osm node
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.router;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
public class OsmNodeNamed extends OsmNode {
|
||||
public String name;
|
||||
public double radius; // radius of nogopoint (in meters)
|
||||
public double nogoWeight; // weight for nogopoint
|
||||
public boolean isNogo = false;
|
||||
|
||||
public OsmNodeNamed() {
|
||||
}
|
||||
|
||||
public OsmNodeNamed(OsmNode n) {
|
||||
super(n.ilon, n.ilat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (Double.isNaN(nogoWeight)) {
|
||||
return ilon + "," + ilat + "," + name;
|
||||
} else {
|
||||
return ilon + "," + ilat + "," + name + "," + nogoWeight;
|
||||
}
|
||||
}
|
||||
|
||||
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lat1 + lat2) >> 1);
|
||||
|
||||
boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius;
|
||||
boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
|
||||
// First point is within the circle
|
||||
if (isFirstPointWithinCircle) {
|
||||
// Last point is within the circle
|
||||
if (isLastPointWithinCircle) {
|
||||
return totalSegmentLength;
|
||||
}
|
||||
// Last point is not within the circle
|
||||
// Just swap points and go on with first first point not within the
|
||||
// circle now.
|
||||
// Swap longitudes
|
||||
int tmp = lon2;
|
||||
lon2 = lon1;
|
||||
lon1 = tmp;
|
||||
// Swap latitudes
|
||||
tmp = lat2;
|
||||
lat2 = lat1;
|
||||
lat1 = tmp;
|
||||
// Fix boolean values
|
||||
isLastPointWithinCircle = isFirstPointWithinCircle;
|
||||
isFirstPointWithinCircle = false;
|
||||
}
|
||||
// Distance between the initial point and projection of center of
|
||||
// the circle on the current segment.
|
||||
double initialToProject = (
|
||||
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
|
||||
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
|
||||
) / totalSegmentLength;
|
||||
// Distance between the initial point and the center of the circle.
|
||||
double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
|
||||
// Half length of the segment within the circle
|
||||
double halfDistanceWithin = Math.sqrt(
|
||||
radius * radius - (
|
||||
initialToCenter * initialToCenter -
|
||||
initialToProject * initialToProject
|
||||
)
|
||||
);
|
||||
// Last point is within the circle
|
||||
if (isLastPointWithinCircle) {
|
||||
return halfDistanceWithin + (totalSegmentLength - initialToProject);
|
||||
}
|
||||
return 2 * halfDistanceWithin;
|
||||
}
|
||||
|
||||
public static OsmNodeNamed decodeNogo(String s) {
|
||||
OsmNodeNamed n = new OsmNodeNamed();
|
||||
int idx1 = s.indexOf(',');
|
||||
n.ilon = Integer.parseInt(s.substring(0, idx1));
|
||||
int idx2 = s.indexOf(',', idx1 + 1);
|
||||
n.ilat = Integer.parseInt(s.substring(idx1 + 1, idx2));
|
||||
int idx3 = s.indexOf(',', idx2 + 1);
|
||||
if (idx3 == -1) {
|
||||
n.name = s.substring(idx2 + 1);
|
||||
n.nogoWeight = Double.NaN;
|
||||
} else {
|
||||
n.name = s.substring(idx2 + 1, idx3);
|
||||
n.nogoWeight = Double.parseDouble(s.substring(idx3 + 1));
|
||||
}
|
||||
n.isNogo = true;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,524 +1,444 @@
|
|||
/**
|
||||
* Container for link between two Osm nodes
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.router;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.mapaccess.OsmLink;
|
||||
import btools.mapaccess.OsmLinkHolder;
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmTransferNode;
|
||||
import btools.mapaccess.TurnRestriction;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
abstract class OsmPath implements OsmLinkHolder
|
||||
{
|
||||
/**
|
||||
* The cost of that path (a modified distance)
|
||||
*/
|
||||
public int cost = 0;
|
||||
|
||||
// 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
|
||||
|
||||
protected OsmNode sourceNode;
|
||||
protected OsmNode targetNode;
|
||||
|
||||
protected OsmLink link;
|
||||
public OsmPathElement originElement;
|
||||
public OsmPathElement myElement;
|
||||
|
||||
protected float traffic;
|
||||
|
||||
private OsmLinkHolder nextForLink = null;
|
||||
|
||||
public int treedepth = 0;
|
||||
|
||||
// the position of the waypoint just before
|
||||
// this path position (for angle calculation)
|
||||
public int originLon;
|
||||
public int originLat;
|
||||
|
||||
// the classifier of the segment just before this paths position
|
||||
protected float lastClassifier;
|
||||
protected float lastInitialCost;
|
||||
|
||||
protected int priorityclassifier;
|
||||
|
||||
private static final int PATH_START_BIT = 1;
|
||||
private static final int CAN_LEAVE_DESTINATION_BIT = 2;
|
||||
private static final int IS_ON_DESTINATION_BIT = 4;
|
||||
private static final int HAD_DESTINATION_START_BIT = 8;
|
||||
protected int bitfield = PATH_START_BIT;
|
||||
|
||||
private boolean getBit( int mask )
|
||||
{
|
||||
return (bitfield & mask ) != 0;
|
||||
}
|
||||
|
||||
private void setBit( int mask, boolean bit )
|
||||
{
|
||||
if ( getBit( mask ) != bit )
|
||||
{
|
||||
bitfield ^= mask;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean didEnterDestinationArea()
|
||||
{
|
||||
return !getBit( HAD_DESTINATION_START_BIT ) && getBit( IS_ON_DESTINATION_BIT );
|
||||
}
|
||||
|
||||
public MessageData message;
|
||||
|
||||
public void unregisterUpTree( RoutingContext rc )
|
||||
{
|
||||
try
|
||||
{
|
||||
OsmPathElement pe = originElement;
|
||||
while( pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic)pe).unregister(rc) )
|
||||
{
|
||||
pe = pe.origin;
|
||||
}
|
||||
}
|
||||
catch( IOException ioe )
|
||||
{
|
||||
throw new RuntimeException( ioe );
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUpTree()
|
||||
{
|
||||
if ( originElement instanceof OsmPathElementWithTraffic )
|
||||
{
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)originElement;
|
||||
ot.register();
|
||||
ot.addTraffic( traffic );
|
||||
}
|
||||
}
|
||||
|
||||
public void init( OsmLink link )
|
||||
{
|
||||
this.link = link;
|
||||
targetNode = link.getTarget( null );
|
||||
selev = targetNode.getSElev();
|
||||
|
||||
originLon = -1;
|
||||
originLat = -1;
|
||||
}
|
||||
|
||||
public void init( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
|
||||
{
|
||||
if ( origin.myElement == null )
|
||||
{
|
||||
origin.myElement = OsmPathElement.create( origin, rc.countTraffic );
|
||||
}
|
||||
this.originElement = origin.myElement;
|
||||
this.link = link;
|
||||
this.sourceNode = origin.targetNode;
|
||||
this.targetNode = link.getTarget( sourceNode );
|
||||
this.cost = origin.cost;
|
||||
this.lastClassifier = origin.lastClassifier;
|
||||
this.lastInitialCost = origin.lastInitialCost;
|
||||
this.bitfield = origin.bitfield;
|
||||
init( origin );
|
||||
addAddionalPenalty(refTrack, detailMode, origin, link, rc );
|
||||
}
|
||||
|
||||
protected abstract void init( OsmPath orig );
|
||||
|
||||
protected abstract void resetState();
|
||||
|
||||
|
||||
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
|
||||
{
|
||||
byte[] description = link.descriptionBitmap;
|
||||
if ( description == null )
|
||||
{
|
||||
return; // could be a beeline path
|
||||
}
|
||||
|
||||
boolean recordTransferNodes = detailMode || rc.countTraffic;
|
||||
|
||||
rc.nogoCost = 0.;
|
||||
|
||||
// extract the 3 positions of the first section
|
||||
int lon0 = origin.originLon;
|
||||
int lat0 = origin.originLat;
|
||||
|
||||
int lon1 = sourceNode.getILon();
|
||||
int lat1 = sourceNode.getILat();
|
||||
short ele1 = origin.selev;
|
||||
|
||||
int linkdisttotal = 0;
|
||||
|
||||
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;
|
||||
int lastpriorityclassifier = priorityclassifier;
|
||||
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
|
||||
|
||||
// *** add initial cost if the classifier changed
|
||||
float newClassifier = rc.expctxWay.getInitialClassifier();
|
||||
float newInitialCost = rc.expctxWay.getInitialcost();
|
||||
float classifierDiff = newClassifier - lastClassifier;
|
||||
if ( newClassifier != 0. && lastClassifier != 0. && ( classifierDiff > 0.0005 || classifierDiff < -0.0005 ) )
|
||||
{
|
||||
float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost;
|
||||
if ( initialcost >= 1000000. )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int iicost = (int)initialcost;
|
||||
if ( message != null )
|
||||
{
|
||||
message.linkinitcost += iicost;
|
||||
}
|
||||
cost += iicost;
|
||||
}
|
||||
lastClassifier = newClassifier;
|
||||
lastInitialCost = newInitialCost;
|
||||
|
||||
// *** destination logic: no destination access in between
|
||||
int classifiermask = (int)rc.expctxWay.getClassifierMask();
|
||||
boolean newDestination = (classifiermask & 64) != 0;
|
||||
boolean oldDestination = getBit( IS_ON_DESTINATION_BIT );
|
||||
if ( getBit( PATH_START_BIT ) )
|
||||
{
|
||||
setBit( PATH_START_BIT, false );
|
||||
setBit( CAN_LEAVE_DESTINATION_BIT, newDestination );
|
||||
setBit( HAD_DESTINATION_START_BIT, newDestination );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( oldDestination && !newDestination )
|
||||
{
|
||||
if ( getBit( CAN_LEAVE_DESTINATION_BIT ) )
|
||||
{
|
||||
setBit( CAN_LEAVE_DESTINATION_BIT, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
setBit( IS_ON_DESTINATION_BIT, newDestination );
|
||||
|
||||
|
||||
OsmTransferNode transferNode = link.geometry == null ? null
|
||||
: rc.geometryDecoder.decodeGeometry( link.geometry, sourceNode, targetNode, isReverse );
|
||||
|
||||
for(int nsection=0; ;nsection++)
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
boolean isStartpoint = lon0 == -1 && lat0 == -1;
|
||||
|
||||
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
|
||||
if ( nsection == 0 && rc.considerTurnRestrictions && !detailMode&& !isStartpoint )
|
||||
{
|
||||
if ( rc.inverseDirection
|
||||
? TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode )
|
||||
: TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode ) )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if recording, new MessageData for each section (needed for turn-instructions)
|
||||
if ( message != null && message.wayKeyValues != null )
|
||||
{
|
||||
originElement.message = message;
|
||||
message = 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 everything
|
||||
cost = 0;
|
||||
resetState();
|
||||
lon0 = -1; // reset turncost-pipe
|
||||
lat0 = -1;
|
||||
isStartpoint = true;
|
||||
|
||||
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 ( rc.checkPendingEndpoint() )
|
||||
{
|
||||
dist = rc.calcDistance( rc.ilonshortest, rc.ilatshortest, lon2, lat2 );
|
||||
if ( rc.shortestmatch )
|
||||
{
|
||||
stopAtEndpoint = true;
|
||||
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( message != null )
|
||||
{
|
||||
message.linkdist += dist;
|
||||
}
|
||||
linkdisttotal += dist;
|
||||
|
||||
// apply a start-direction if appropriate (by faking the origin position)
|
||||
if ( isStartpoint )
|
||||
{
|
||||
if ( rc.startDirectionValid )
|
||||
{
|
||||
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lon0 + lat1) >> 1 );
|
||||
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / lonlat2m[0] );
|
||||
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) / lonlat2m[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
lon0 = lon1 - (lon2-lon1);
|
||||
lat0 = lat1 - (lat2-lat1);
|
||||
}
|
||||
}
|
||||
double angle = rc.anglemeter.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
|
||||
double cosangle = rc.anglemeter.getCosAngle();
|
||||
|
||||
// *** elevation stuff
|
||||
double delta_h = 0.;
|
||||
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1;
|
||||
if ( ele1 != Short.MIN_VALUE )
|
||||
{
|
||||
delta_h = (ele2 - ele1)/4.;
|
||||
if ( rc.inverseDirection )
|
||||
{
|
||||
delta_h = -delta_h;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.;
|
||||
|
||||
double sectionCost = processWaySection( rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier );
|
||||
if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isTrafficBackbone )
|
||||
{
|
||||
sectionCost = 0.;
|
||||
}
|
||||
|
||||
cost += (int)sectionCost;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// compute kinematic
|
||||
computeKinematic( rc, dist, delta_h, detailMode );
|
||||
|
||||
if ( message != null )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
if ( recordTransferNodes )
|
||||
{
|
||||
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
|
||||
originElement.cost = cost;
|
||||
if ( message != null )
|
||||
{
|
||||
originElement.message = message;
|
||||
}
|
||||
}
|
||||
if ( rc.nogoCost < 0)
|
||||
{
|
||||
cost = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cost += rc.nogoCost;
|
||||
}
|
||||
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.nogoCost < 0)
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cost += rc.nogoCost;
|
||||
}
|
||||
|
||||
// add target-node costs
|
||||
double targetCost = processTargetNode( rc );
|
||||
if ( targetCost < 0. || targetCost + cost >= 2000000000. )
|
||||
{
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
cost += (int)targetCost;
|
||||
}
|
||||
|
||||
|
||||
public short interpolateEle( short e1, short e2, double fraction )
|
||||
{
|
||||
if ( e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE )
|
||||
{
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
return (short)( e1*(1.-fraction) + e2*fraction );
|
||||
}
|
||||
|
||||
protected abstract double processWaySection( RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier );
|
||||
|
||||
protected abstract double processTargetNode( RoutingContext rc );
|
||||
|
||||
protected void computeKinematic( RoutingContext rc, double dist, double delta_h, boolean detailMode )
|
||||
{
|
||||
}
|
||||
|
||||
public abstract int elevationCorrection( RoutingContext rc );
|
||||
|
||||
public abstract boolean definitlyWorseThan( OsmPath p, RoutingContext rc );
|
||||
|
||||
public OsmNode getSourceNode()
|
||||
{
|
||||
return sourceNode;
|
||||
}
|
||||
|
||||
public OsmNode getTargetNode()
|
||||
{
|
||||
return targetNode;
|
||||
}
|
||||
|
||||
public OsmLink getLink()
|
||||
{
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
public void setNextForLink( OsmLinkHolder holder )
|
||||
{
|
||||
nextForLink = holder;
|
||||
}
|
||||
|
||||
public OsmLinkHolder getNextForLink()
|
||||
{
|
||||
return nextForLink;
|
||||
}
|
||||
|
||||
public double getTotalTime()
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
|
||||
public double getTotalEnergy()
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Container for link between two Osm nodes
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.router;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.mapaccess.OsmLink;
|
||||
import btools.mapaccess.OsmLinkHolder;
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmTransferNode;
|
||||
import btools.mapaccess.TurnRestriction;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
abstract class OsmPath implements OsmLinkHolder {
|
||||
/**
|
||||
* The cost of that path (a modified distance)
|
||||
*/
|
||||
public int cost = 0;
|
||||
|
||||
// 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
|
||||
|
||||
protected OsmNode sourceNode;
|
||||
protected OsmNode targetNode;
|
||||
|
||||
protected OsmLink link;
|
||||
public OsmPathElement originElement;
|
||||
public OsmPathElement myElement;
|
||||
|
||||
protected float traffic;
|
||||
|
||||
private OsmLinkHolder nextForLink = null;
|
||||
|
||||
public int treedepth = 0;
|
||||
|
||||
// the position of the waypoint just before
|
||||
// this path position (for angle calculation)
|
||||
public int originLon;
|
||||
public int originLat;
|
||||
|
||||
// the classifier of the segment just before this paths position
|
||||
protected float lastClassifier;
|
||||
protected float lastInitialCost;
|
||||
|
||||
protected int priorityclassifier;
|
||||
|
||||
private static final int PATH_START_BIT = 1;
|
||||
private static final int CAN_LEAVE_DESTINATION_BIT = 2;
|
||||
private static final int IS_ON_DESTINATION_BIT = 4;
|
||||
private static final int HAD_DESTINATION_START_BIT = 8;
|
||||
protected int bitfield = PATH_START_BIT;
|
||||
|
||||
private boolean getBit(int mask) {
|
||||
return (bitfield & mask) != 0;
|
||||
}
|
||||
|
||||
private void setBit(int mask, boolean bit) {
|
||||
if (getBit(mask) != bit) {
|
||||
bitfield ^= mask;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean didEnterDestinationArea() {
|
||||
return !getBit(HAD_DESTINATION_START_BIT) && getBit(IS_ON_DESTINATION_BIT);
|
||||
}
|
||||
|
||||
public MessageData message;
|
||||
|
||||
public void unregisterUpTree(RoutingContext rc) {
|
||||
try {
|
||||
OsmPathElement pe = originElement;
|
||||
while (pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic) pe).unregister(rc)) {
|
||||
pe = pe.origin;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerUpTree() {
|
||||
if (originElement instanceof OsmPathElementWithTraffic) {
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) originElement;
|
||||
ot.register();
|
||||
ot.addTraffic(traffic);
|
||||
}
|
||||
}
|
||||
|
||||
public void init(OsmLink link) {
|
||||
this.link = link;
|
||||
targetNode = link.getTarget(null);
|
||||
selev = targetNode.getSElev();
|
||||
|
||||
originLon = -1;
|
||||
originLat = -1;
|
||||
}
|
||||
|
||||
public void init(OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc) {
|
||||
if (origin.myElement == null) {
|
||||
origin.myElement = OsmPathElement.create(origin, rc.countTraffic);
|
||||
}
|
||||
this.originElement = origin.myElement;
|
||||
this.link = link;
|
||||
this.sourceNode = origin.targetNode;
|
||||
this.targetNode = link.getTarget(sourceNode);
|
||||
this.cost = origin.cost;
|
||||
this.lastClassifier = origin.lastClassifier;
|
||||
this.lastInitialCost = origin.lastInitialCost;
|
||||
this.bitfield = origin.bitfield;
|
||||
init(origin);
|
||||
addAddionalPenalty(refTrack, detailMode, origin, link, rc);
|
||||
}
|
||||
|
||||
protected abstract void init(OsmPath orig);
|
||||
|
||||
protected abstract void resetState();
|
||||
|
||||
|
||||
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc) {
|
||||
byte[] description = link.descriptionBitmap;
|
||||
if (description == null) {
|
||||
return; // could be a beeline path
|
||||
}
|
||||
|
||||
boolean recordTransferNodes = detailMode || rc.countTraffic;
|
||||
|
||||
rc.nogoCost = 0.;
|
||||
|
||||
// extract the 3 positions of the first section
|
||||
int lon0 = origin.originLon;
|
||||
int lat0 = origin.originLat;
|
||||
|
||||
int lon1 = sourceNode.getILon();
|
||||
int lat1 = sourceNode.getILat();
|
||||
short ele1 = origin.selev;
|
||||
|
||||
int linkdisttotal = 0;
|
||||
|
||||
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;
|
||||
int lastpriorityclassifier = priorityclassifier;
|
||||
priorityclassifier = (int) rc.expctxWay.getPriorityClassifier();
|
||||
|
||||
// *** add initial cost if the classifier changed
|
||||
float newClassifier = rc.expctxWay.getInitialClassifier();
|
||||
float newInitialCost = rc.expctxWay.getInitialcost();
|
||||
float classifierDiff = newClassifier - lastClassifier;
|
||||
if (newClassifier != 0. && lastClassifier != 0. && (classifierDiff > 0.0005 || classifierDiff < -0.0005)) {
|
||||
float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost;
|
||||
if (initialcost >= 1000000.) {
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int iicost = (int) initialcost;
|
||||
if (message != null) {
|
||||
message.linkinitcost += iicost;
|
||||
}
|
||||
cost += iicost;
|
||||
}
|
||||
lastClassifier = newClassifier;
|
||||
lastInitialCost = newInitialCost;
|
||||
|
||||
// *** destination logic: no destination access in between
|
||||
int classifiermask = (int) rc.expctxWay.getClassifierMask();
|
||||
boolean newDestination = (classifiermask & 64) != 0;
|
||||
boolean oldDestination = getBit(IS_ON_DESTINATION_BIT);
|
||||
if (getBit(PATH_START_BIT)) {
|
||||
setBit(PATH_START_BIT, false);
|
||||
setBit(CAN_LEAVE_DESTINATION_BIT, newDestination);
|
||||
setBit(HAD_DESTINATION_START_BIT, newDestination);
|
||||
} else {
|
||||
if (oldDestination && !newDestination) {
|
||||
if (getBit(CAN_LEAVE_DESTINATION_BIT)) {
|
||||
setBit(CAN_LEAVE_DESTINATION_BIT, false);
|
||||
} else {
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
setBit(IS_ON_DESTINATION_BIT, newDestination);
|
||||
|
||||
|
||||
OsmTransferNode transferNode = link.geometry == null ? null
|
||||
: rc.geometryDecoder.decodeGeometry(link.geometry, sourceNode, targetNode, isReverse);
|
||||
|
||||
for (int nsection = 0; ; nsection++) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
boolean isStartpoint = lon0 == -1 && lat0 == -1;
|
||||
|
||||
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
|
||||
if (nsection == 0 && rc.considerTurnRestrictions && !detailMode && !isStartpoint) {
|
||||
if (rc.inverseDirection
|
||||
? TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode)
|
||||
: TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode)) {
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if recording, new MessageData for each section (needed for turn-instructions)
|
||||
if (message != null && message.wayKeyValues != null) {
|
||||
originElement.message = message;
|
||||
message = 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 everything
|
||||
cost = 0;
|
||||
resetState();
|
||||
lon0 = -1; // reset turncost-pipe
|
||||
lat0 = -1;
|
||||
isStartpoint = true;
|
||||
|
||||
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 (rc.checkPendingEndpoint()) {
|
||||
dist = rc.calcDistance(rc.ilonshortest, rc.ilatshortest, lon2, lat2);
|
||||
if (rc.shortestmatch) {
|
||||
stopAtEndpoint = true;
|
||||
ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
message.linkdist += dist;
|
||||
}
|
||||
linkdisttotal += dist;
|
||||
|
||||
// apply a start-direction if appropriate (by faking the origin position)
|
||||
if (isStartpoint) {
|
||||
if (rc.startDirectionValid) {
|
||||
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lon0 + lat1) >> 1);
|
||||
lon0 = lon1 - (int) (1000. * Math.sin(dir) / lonlat2m[0]);
|
||||
lat0 = lat1 - (int) (1000. * Math.cos(dir) / lonlat2m[1]);
|
||||
} else {
|
||||
lon0 = lon1 - (lon2 - lon1);
|
||||
lat0 = lat1 - (lat2 - lat1);
|
||||
}
|
||||
}
|
||||
double angle = rc.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
|
||||
double cosangle = rc.anglemeter.getCosAngle();
|
||||
|
||||
// *** elevation stuff
|
||||
double delta_h = 0.;
|
||||
if (ele2 == Short.MIN_VALUE) ele2 = ele1;
|
||||
if (ele1 != Short.MIN_VALUE) {
|
||||
delta_h = (ele2 - ele1) / 4.;
|
||||
if (rc.inverseDirection) {
|
||||
delta_h = -delta_h;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2 / 4.;
|
||||
|
||||
double sectionCost = processWaySection(rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier);
|
||||
if ((sectionCost < 0. || costfactor > 9998. && !detailMode) || sectionCost + cost >= 2000000000.) {
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTrafficBackbone) {
|
||||
sectionCost = 0.;
|
||||
}
|
||||
|
||||
cost += (int) sectionCost;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// compute kinematic
|
||||
computeKinematic(rc, dist, delta_h, detailMode);
|
||||
|
||||
if (message != null) {
|
||||
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) {
|
||||
if (recordTransferNodes) {
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic);
|
||||
originElement.cost = cost;
|
||||
if (message != null) {
|
||||
originElement.message = message;
|
||||
}
|
||||
}
|
||||
if (rc.nogoCost < 0) {
|
||||
cost = -1;
|
||||
} else {
|
||||
cost += rc.nogoCost;
|
||||
}
|
||||
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.nogoCost < 0) {
|
||||
cost = -1;
|
||||
return;
|
||||
} else {
|
||||
cost += rc.nogoCost;
|
||||
}
|
||||
|
||||
// add target-node costs
|
||||
double targetCost = processTargetNode(rc);
|
||||
if (targetCost < 0. || targetCost + cost >= 2000000000.) {
|
||||
cost = -1;
|
||||
return;
|
||||
}
|
||||
cost += (int) targetCost;
|
||||
}
|
||||
|
||||
|
||||
public short interpolateEle(short e1, short e2, double fraction) {
|
||||
if (e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE) {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
return (short) (e1 * (1. - fraction) + e2 * fraction);
|
||||
}
|
||||
|
||||
protected abstract double processWaySection(RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier);
|
||||
|
||||
protected abstract double processTargetNode(RoutingContext rc);
|
||||
|
||||
protected void computeKinematic(RoutingContext rc, double dist, double delta_h, boolean detailMode) {
|
||||
}
|
||||
|
||||
public abstract int elevationCorrection(RoutingContext rc);
|
||||
|
||||
public abstract boolean definitlyWorseThan(OsmPath p, RoutingContext rc);
|
||||
|
||||
public OsmNode getSourceNode() {
|
||||
return sourceNode;
|
||||
}
|
||||
|
||||
public OsmNode getTargetNode() {
|
||||
return targetNode;
|
||||
}
|
||||
|
||||
public OsmLink getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
public void setNextForLink(OsmLinkHolder holder) {
|
||||
nextForLink = holder;
|
||||
}
|
||||
|
||||
public OsmLinkHolder getNextForLink() {
|
||||
return nextForLink;
|
||||
}
|
||||
|
||||
public double getTotalTime() {
|
||||
return 0.;
|
||||
}
|
||||
|
||||
public double getTotalEnergy() {
|
||||
return 0.;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,136 +1,116 @@
|
|||
package btools.router;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmPos;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
/**
|
||||
* Container for link between two Osm nodes
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
// interface OsmPos
|
||||
public final int getILat()
|
||||
{
|
||||
return ilat;
|
||||
}
|
||||
|
||||
public final int getILon()
|
||||
{
|
||||
return ilon;
|
||||
}
|
||||
|
||||
public final short getSElev()
|
||||
{
|
||||
return selev;
|
||||
}
|
||||
|
||||
public final double getElev()
|
||||
{
|
||||
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 float getEnergy()
|
||||
{
|
||||
return message == null ? 0.f : message.energy;
|
||||
}
|
||||
|
||||
public final void setEnergy( float e )
|
||||
{
|
||||
if ( message != null )
|
||||
{
|
||||
message.energy = e;
|
||||
}
|
||||
}
|
||||
|
||||
public final long getIdFromPos()
|
||||
{
|
||||
return ((long)ilon)<<32 | ilat;
|
||||
}
|
||||
|
||||
public final int calcDistance( OsmPos p )
|
||||
{
|
||||
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
||||
}
|
||||
|
||||
public OsmPathElement origin;
|
||||
|
||||
// construct a path element from a path
|
||||
public static final OsmPathElement create( OsmPath path, boolean countTraffic )
|
||||
{
|
||||
OsmNode n = path.getTargetNode();
|
||||
OsmPathElement pe = create( n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic );
|
||||
pe.cost = path.cost;
|
||||
pe.message = path.message;
|
||||
return pe;
|
||||
}
|
||||
|
||||
public static final OsmPathElement create( int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic )
|
||||
{
|
||||
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
|
||||
pe.ilon = ilon;
|
||||
pe.ilat = ilat;
|
||||
pe.selev = selev;
|
||||
pe.origin = origin;
|
||||
return pe;
|
||||
}
|
||||
|
||||
protected OsmPathElement()
|
||||
{
|
||||
}
|
||||
|
||||
public void addTraffic( float traffic )
|
||||
{
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return ilon + "_" + ilat;
|
||||
}
|
||||
|
||||
public void writeToStream( DataOutput dos ) throws IOException
|
||||
{
|
||||
dos.writeInt( ilat );
|
||||
dos.writeInt( ilon );
|
||||
dos.writeShort( selev );
|
||||
dos.writeInt( cost );
|
||||
}
|
||||
|
||||
public static OsmPathElement readFromStream( DataInput dis ) throws IOException
|
||||
{
|
||||
OsmPathElement pe = new OsmPathElement();
|
||||
pe.ilat = dis.readInt();
|
||||
pe.ilon = dis.readInt();
|
||||
pe.selev = dis.readShort();
|
||||
pe.cost = dis.readInt();
|
||||
return pe;
|
||||
}
|
||||
}
|
||||
package btools.router;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmPos;
|
||||
import btools.util.CheapRuler;
|
||||
|
||||
/**
|
||||
* Container for link between two Osm nodes
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
// interface OsmPos
|
||||
public final int getILat() {
|
||||
return ilat;
|
||||
}
|
||||
|
||||
public final int getILon() {
|
||||
return ilon;
|
||||
}
|
||||
|
||||
public final short getSElev() {
|
||||
return selev;
|
||||
}
|
||||
|
||||
public final double getElev() {
|
||||
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 float getEnergy() {
|
||||
return message == null ? 0.f : message.energy;
|
||||
}
|
||||
|
||||
public final void setEnergy(float e) {
|
||||
if (message != null) {
|
||||
message.energy = e;
|
||||
}
|
||||
}
|
||||
|
||||
public final long getIdFromPos() {
|
||||
return ((long) ilon) << 32 | ilat;
|
||||
}
|
||||
|
||||
public final int calcDistance(OsmPos p) {
|
||||
return (int) (CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
|
||||
}
|
||||
|
||||
public OsmPathElement origin;
|
||||
|
||||
// construct a path element from a path
|
||||
public static final OsmPathElement create(OsmPath path, boolean countTraffic) {
|
||||
OsmNode n = path.getTargetNode();
|
||||
OsmPathElement pe = create(n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic);
|
||||
pe.cost = path.cost;
|
||||
pe.message = path.message;
|
||||
return pe;
|
||||
}
|
||||
|
||||
public static final OsmPathElement create(int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic) {
|
||||
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
|
||||
pe.ilon = ilon;
|
||||
pe.ilat = ilat;
|
||||
pe.selev = selev;
|
||||
pe.origin = origin;
|
||||
return pe;
|
||||
}
|
||||
|
||||
protected OsmPathElement() {
|
||||
}
|
||||
|
||||
public void addTraffic(float traffic) {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ilon + "_" + ilat;
|
||||
}
|
||||
|
||||
public void writeToStream(DataOutput dos) throws IOException {
|
||||
dos.writeInt(ilat);
|
||||
dos.writeInt(ilon);
|
||||
dos.writeShort(selev);
|
||||
dos.writeInt(cost);
|
||||
}
|
||||
|
||||
public static OsmPathElement readFromStream(DataInput dis) throws IOException {
|
||||
OsmPathElement pe = new OsmPathElement();
|
||||
pe.ilat = dis.readInt();
|
||||
pe.ilon = dis.readInt();
|
||||
pe.selev = dis.readShort();
|
||||
pe.cost = dis.readInt();
|
||||
return pe;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,19 +9,15 @@ import java.io.IOException;
|
|||
* @author ab
|
||||
*/
|
||||
|
||||
public final class OsmPathElementWithTraffic extends OsmPathElement
|
||||
{
|
||||
public final class OsmPathElementWithTraffic extends OsmPathElement {
|
||||
private int registerCount;
|
||||
private float farTraffic;
|
||||
private float nearTraffic;
|
||||
|
||||
public void register()
|
||||
{
|
||||
if ( registerCount++ == 0 )
|
||||
{
|
||||
if ( origin instanceof OsmPathElementWithTraffic )
|
||||
{
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)origin;
|
||||
|
||||
public void register() {
|
||||
if (registerCount++ == 0) {
|
||||
if (origin instanceof OsmPathElementWithTraffic) {
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
|
||||
ot.register();
|
||||
ot.farTraffic += farTraffic;
|
||||
ot.nearTraffic += nearTraffic;
|
||||
|
|
@ -30,42 +26,36 @@ public final class OsmPathElementWithTraffic extends OsmPathElement
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addTraffic( float traffic )
|
||||
{
|
||||
public void addTraffic(float traffic) {
|
||||
this.farTraffic += traffic;
|
||||
this.nearTraffic += traffic;
|
||||
}
|
||||
|
||||
// unregister from origin if our registercount is 0, else do nothing
|
||||
|
||||
public static double maxtraffic = 0.;
|
||||
public static double maxtraffic = 0.;
|
||||
|
||||
public boolean unregister( RoutingContext rc ) throws IOException
|
||||
{
|
||||
if ( --registerCount == 0 )
|
||||
{
|
||||
if ( origin instanceof OsmPathElementWithTraffic )
|
||||
{
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)origin;
|
||||
|
||||
int costdelta = cost-ot.cost;
|
||||
ot.farTraffic += farTraffic*Math.exp(-costdelta/rc.farTrafficDecayLength);
|
||||
ot.nearTraffic += nearTraffic*Math.exp(-costdelta/rc.nearTrafficDecayLength);
|
||||
public boolean unregister(RoutingContext rc) throws IOException {
|
||||
if (--registerCount == 0) {
|
||||
if (origin instanceof OsmPathElementWithTraffic) {
|
||||
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
|
||||
|
||||
if ( costdelta > 0 && farTraffic > maxtraffic ) maxtraffic = farTraffic;
|
||||
|
||||
int t2 = cost == ot.cost ? -1 : (int)(rc.farTrafficWeight*farTraffic + rc.nearTrafficWeight*nearTraffic);
|
||||
|
||||
if ( t2 > 4000 || t2 == -1 )
|
||||
{
|
||||
int costdelta = cost - ot.cost;
|
||||
ot.farTraffic += farTraffic * Math.exp(-costdelta / rc.farTrafficDecayLength);
|
||||
ot.nearTraffic += nearTraffic * Math.exp(-costdelta / rc.nearTrafficDecayLength);
|
||||
|
||||
if (costdelta > 0 && farTraffic > maxtraffic) maxtraffic = farTraffic;
|
||||
|
||||
int t2 = cost == ot.cost ? -1 : (int) (rc.farTrafficWeight * farTraffic + rc.nearTrafficWeight * nearTraffic);
|
||||
|
||||
if (t2 > 4000 || t2 == -1) {
|
||||
// System.out.println( "unregistered: " + this + " origin=" + ot + " farTraffic =" + farTraffic + " nearTraffic =" + nearTraffic + " cost=" + cost );
|
||||
if ( rc.trafficOutputStream != null )
|
||||
{
|
||||
rc.trafficOutputStream.writeLong( getIdFromPos());
|
||||
rc.trafficOutputStream.writeLong( ot.getIdFromPos());
|
||||
rc.trafficOutputStream.writeInt( t2 );
|
||||
if (rc.trafficOutputStream != null) {
|
||||
rc.trafficOutputStream.writeLong(getIdFromPos());
|
||||
rc.trafficOutputStream.writeLong(ot.getIdFromPos());
|
||||
rc.trafficOutputStream.writeInt(t2);
|
||||
}
|
||||
}
|
||||
farTraffic = 0;
|
||||
|
|
|
|||
|
|
@ -11,11 +11,10 @@ import btools.expressions.BExpressionContextNode;
|
|||
import btools.expressions.BExpressionContextWay;
|
||||
|
||||
|
||||
abstract class OsmPathModel
|
||||
{
|
||||
abstract class OsmPathModel {
|
||||
public abstract OsmPrePath createPrePath();
|
||||
|
||||
public abstract OsmPath createPath();
|
||||
|
||||
public abstract void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> keyValues );
|
||||
public abstract void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> keyValues);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,21 +9,19 @@ import btools.mapaccess.OsmLink;
|
|||
import btools.mapaccess.OsmNode;
|
||||
import btools.mapaccess.OsmTransferNode;
|
||||
|
||||
public abstract class OsmPrePath
|
||||
{
|
||||
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 )
|
||||
{
|
||||
public void init(OsmPath origin, OsmLink link, RoutingContext rc) {
|
||||
this.link = link;
|
||||
this.sourceNode = origin.getTargetNode();
|
||||
this.targetNode = link.getTarget( sourceNode );
|
||||
initPrePath(origin, rc );
|
||||
this.targetNode = link.getTarget(sourceNode);
|
||||
initPrePath(origin, rc);
|
||||
}
|
||||
|
||||
protected abstract void initPrePath(OsmPath origin, RoutingContext rc );
|
||||
protected abstract void initPrePath(OsmPath origin, RoutingContext rc);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,146 +11,125 @@ import btools.expressions.BExpressionContextNode;
|
|||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.expressions.BExpressionMetaData;
|
||||
|
||||
public final class ProfileCache
|
||||
{
|
||||
|
||||
public final class ProfileCache {
|
||||
|
||||
private static File lastLookupFile;
|
||||
private static long lastLookupTimestamp;
|
||||
|
||||
private BExpressionContextWay expctxWay;
|
||||
private BExpressionContextNode expctxNode;
|
||||
private File lastProfileFile;
|
||||
private long lastProfileTimestamp;
|
||||
private long lastProfileTimestamp;
|
||||
private boolean profilesBusy;
|
||||
private long lastUseTime;
|
||||
|
||||
private static ProfileCache[] apc = new ProfileCache[1];
|
||||
private static boolean debug = Boolean.getBoolean( "debugProfileCache" );
|
||||
|
||||
public static synchronized void setSize( int size )
|
||||
{
|
||||
private static ProfileCache[] apc = new ProfileCache[1];
|
||||
private static boolean debug = Boolean.getBoolean("debugProfileCache");
|
||||
|
||||
public static synchronized void setSize(int size) {
|
||||
apc = new ProfileCache[size];
|
||||
}
|
||||
|
||||
public static synchronized boolean parseProfile( RoutingContext rc )
|
||||
{
|
||||
String profileBaseDir = System.getProperty( "profileBaseDir" );
|
||||
File profileDir;
|
||||
File profileFile;
|
||||
if ( profileBaseDir == null )
|
||||
{
|
||||
profileDir = new File( rc.localFunction ).getParentFile();
|
||||
profileFile = new File( rc.localFunction ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
profileDir = new File( profileBaseDir );
|
||||
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ;
|
||||
}
|
||||
public static synchronized boolean parseProfile(RoutingContext rc) {
|
||||
String profileBaseDir = System.getProperty("profileBaseDir");
|
||||
File profileDir;
|
||||
File profileFile;
|
||||
if (profileBaseDir == null) {
|
||||
profileDir = new File(rc.localFunction).getParentFile();
|
||||
profileFile = new File(rc.localFunction);
|
||||
} else {
|
||||
profileDir = new File(profileBaseDir);
|
||||
profileFile = new File(profileDir, rc.localFunction + ".brf");
|
||||
}
|
||||
|
||||
rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum()<<24;
|
||||
File lookupFile = new File( profileDir, "lookups.dat" );
|
||||
|
||||
// invalidate cache at lookup-table update
|
||||
if ( !(lookupFile.equals( lastLookupFile ) && lookupFile.lastModified() == lastLookupTimestamp ) )
|
||||
{
|
||||
if ( lastLookupFile != null )
|
||||
{
|
||||
System.out.println( "******** invalidating profile-cache after lookup-file update ******** " );
|
||||
}
|
||||
apc = new ProfileCache[apc.length];
|
||||
lastLookupFile = lookupFile;
|
||||
lastLookupTimestamp = lookupFile.lastModified();
|
||||
}
|
||||
|
||||
ProfileCache lru = null;
|
||||
int unusedSlot =-1;
|
||||
rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum() << 24;
|
||||
File lookupFile = new File(profileDir, "lookups.dat");
|
||||
|
||||
// check for re-use
|
||||
for( int i=0; i<apc.length; i++)
|
||||
{
|
||||
ProfileCache pc = apc[i];
|
||||
|
||||
if ( pc != null )
|
||||
{
|
||||
if ( (!pc.profilesBusy) && profileFile.equals( pc.lastProfileFile ) )
|
||||
{
|
||||
if ( rc.profileTimestamp == pc.lastProfileTimestamp )
|
||||
{
|
||||
rc.expctxWay = pc.expctxWay;
|
||||
rc.expctxNode = pc.expctxNode;
|
||||
rc.readGlobalConfig();
|
||||
pc.profilesBusy = true;
|
||||
return true;
|
||||
}
|
||||
lru = pc; // name-match but timestamp-mismatch -> we overide this one
|
||||
unusedSlot = -1;
|
||||
break;
|
||||
}
|
||||
if ( lru == null || lru.lastUseTime > pc.lastUseTime )
|
||||
{
|
||||
lru = pc;
|
||||
// invalidate cache at lookup-table update
|
||||
if (!(lookupFile.equals(lastLookupFile) && lookupFile.lastModified() == lastLookupTimestamp)) {
|
||||
if (lastLookupFile != null) {
|
||||
System.out.println("******** invalidating profile-cache after lookup-file update ******** ");
|
||||
}
|
||||
apc = new ProfileCache[apc.length];
|
||||
lastLookupFile = lookupFile;
|
||||
lastLookupTimestamp = lookupFile.lastModified();
|
||||
}
|
||||
|
||||
ProfileCache lru = null;
|
||||
int unusedSlot = -1;
|
||||
|
||||
// check for re-use
|
||||
for (int i = 0; i < apc.length; i++) {
|
||||
ProfileCache pc = apc[i];
|
||||
|
||||
if (pc != null) {
|
||||
if ((!pc.profilesBusy) && profileFile.equals(pc.lastProfileFile)) {
|
||||
if (rc.profileTimestamp == pc.lastProfileTimestamp) {
|
||||
rc.expctxWay = pc.expctxWay;
|
||||
rc.expctxNode = pc.expctxNode;
|
||||
rc.readGlobalConfig();
|
||||
pc.profilesBusy = true;
|
||||
return true;
|
||||
}
|
||||
lru = pc; // name-match but timestamp-mismatch -> we overide this one
|
||||
unusedSlot = -1;
|
||||
break;
|
||||
}
|
||||
else if ( unusedSlot < 0 )
|
||||
{
|
||||
unusedSlot = i;
|
||||
if (lru == null || lru.lastUseTime > pc.lastUseTime) {
|
||||
lru = pc;
|
||||
}
|
||||
} else if (unusedSlot < 0) {
|
||||
unusedSlot = i;
|
||||
}
|
||||
|
||||
BExpressionMetaData meta = new BExpressionMetaData();
|
||||
|
||||
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" ) );
|
||||
}
|
||||
|
||||
rc.expctxWay.parseFile( profileFile, "global" );
|
||||
rc.expctxNode.parseFile( profileFile, "global" );
|
||||
BExpressionMetaData meta = new BExpressionMetaData();
|
||||
|
||||
rc.readGlobalConfig();
|
||||
|
||||
if ( rc.processUnusedTags )
|
||||
{
|
||||
rc.expctxWay.setAllTagsUsed();
|
||||
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"));
|
||||
|
||||
rc.expctxWay.parseFile(profileFile, "global");
|
||||
rc.expctxNode.parseFile(profileFile, "global");
|
||||
|
||||
rc.readGlobalConfig();
|
||||
|
||||
if (rc.processUnusedTags) {
|
||||
rc.expctxWay.setAllTagsUsed();
|
||||
}
|
||||
|
||||
if (lru == null || unusedSlot >= 0) {
|
||||
lru = new ProfileCache();
|
||||
if (unusedSlot >= 0) {
|
||||
apc[unusedSlot] = lru;
|
||||
if (debug)
|
||||
System.out.println("******* adding new profile at idx=" + unusedSlot + " for " + profileFile);
|
||||
}
|
||||
}
|
||||
|
||||
if ( lru == null || unusedSlot >= 0 )
|
||||
{
|
||||
lru = new ProfileCache();
|
||||
if ( unusedSlot >= 0 )
|
||||
{
|
||||
apc[unusedSlot] = lru;
|
||||
if ( debug ) System.out.println( "******* adding new profile at idx=" + unusedSlot + " for " + profileFile );
|
||||
}
|
||||
}
|
||||
if (lru.lastProfileFile != null) {
|
||||
if (debug)
|
||||
System.out.println("******* replacing profile of age " + ((System.currentTimeMillis() - lru.lastUseTime) / 1000L) + " sec " + lru.lastProfileFile + "->" + profileFile);
|
||||
}
|
||||
|
||||
if ( lru.lastProfileFile != null )
|
||||
{
|
||||
if ( debug ) System.out.println( "******* replacing profile of age " + ((System.currentTimeMillis()-lru.lastUseTime)/1000L) + " sec " + lru.lastProfileFile + "->" + profileFile );
|
||||
}
|
||||
|
||||
lru.lastProfileTimestamp = rc.profileTimestamp;
|
||||
lru.lastProfileFile = profileFile;
|
||||
lru.expctxWay = rc.expctxWay;
|
||||
lru.expctxNode = rc.expctxNode;
|
||||
lru.profilesBusy = true;
|
||||
lru.lastUseTime = System.currentTimeMillis();
|
||||
return false;
|
||||
lru.lastProfileTimestamp = rc.profileTimestamp;
|
||||
lru.lastProfileFile = profileFile;
|
||||
lru.expctxWay = rc.expctxWay;
|
||||
lru.expctxNode = rc.expctxNode;
|
||||
lru.profilesBusy = true;
|
||||
lru.lastUseTime = System.currentTimeMillis();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static synchronized void releaseProfile( RoutingContext rc )
|
||||
{
|
||||
for( int i=0; i<apc.length; i++)
|
||||
{
|
||||
public static synchronized void releaseProfile(RoutingContext rc) {
|
||||
for (int i = 0; i < apc.length; i++) {
|
||||
ProfileCache pc = apc[i];
|
||||
|
||||
if ( pc != null )
|
||||
{
|
||||
|
||||
if (pc != null) {
|
||||
// only the thread that holds the cached instance can release it
|
||||
if ( rc.expctxWay == pc.expctxWay && rc.expctxNode == pc.expctxNode )
|
||||
{
|
||||
if (rc.expctxWay == pc.expctxWay && rc.expctxNode == pc.expctxNode) {
|
||||
pc.profilesBusy = false;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -9,41 +9,33 @@ import java.io.File;
|
|||
|
||||
import btools.mapaccess.StorageConfigHelper;
|
||||
|
||||
public final class RoutingHelper
|
||||
{
|
||||
public static File getAdditionalMaptoolDir( File segmentDir )
|
||||
{
|
||||
return StorageConfigHelper.getAdditionalMaptoolDir(segmentDir);
|
||||
}
|
||||
public final class RoutingHelper {
|
||||
public static File getAdditionalMaptoolDir(File segmentDir) {
|
||||
return StorageConfigHelper.getAdditionalMaptoolDir(segmentDir);
|
||||
}
|
||||
|
||||
public static File getSecondarySegmentDir( File segmentDir )
|
||||
{
|
||||
return StorageConfigHelper.getSecondarySegmentDir(segmentDir);
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasDirectoryAnyDatafiles( File segmentDir )
|
||||
{
|
||||
if ( hasAnyDatafiles( segmentDir ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// check secondary, too
|
||||
File secondary = StorageConfigHelper.getSecondarySegmentDir( segmentDir );
|
||||
if ( secondary != null )
|
||||
{
|
||||
return hasAnyDatafiles( secondary );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static File getSecondarySegmentDir(File segmentDir) {
|
||||
return StorageConfigHelper.getSecondarySegmentDir(segmentDir);
|
||||
}
|
||||
|
||||
private static boolean hasAnyDatafiles( File dir )
|
||||
{
|
||||
String[] fileNames = dir.list();
|
||||
for( String fileName : fileNames )
|
||||
{
|
||||
if ( fileName.endsWith( ".rd5" ) ) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
public static boolean hasDirectoryAnyDatafiles(File segmentDir) {
|
||||
if (hasAnyDatafiles(segmentDir)) {
|
||||
return true;
|
||||
}
|
||||
// check secondary, too
|
||||
File secondary = StorageConfigHelper.getSecondarySegmentDir(segmentDir);
|
||||
if (secondary != null) {
|
||||
return hasAnyDatafiles(secondary);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasAnyDatafiles(File dir) {
|
||||
String[] fileNames = dir.list();
|
||||
for (String fileName : fileNames) {
|
||||
if (fileName.endsWith(".rd5")) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
package btools.router;
|
||||
|
||||
public class RoutingIslandException extends RuntimeException
|
||||
{
|
||||
public class RoutingIslandException extends RuntimeException {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,83 +8,80 @@ package btools.router;
|
|||
import btools.mapaccess.OsmNode;
|
||||
|
||||
|
||||
public final class SearchBoundary
|
||||
{
|
||||
public final class SearchBoundary {
|
||||
|
||||
private int minlon0;
|
||||
private int minlat0;
|
||||
private int maxlon0;
|
||||
private int maxlat0;
|
||||
private int minlon0;
|
||||
private int minlat0;
|
||||
private int maxlon0;
|
||||
private int maxlat0;
|
||||
|
||||
private int minlon;
|
||||
private int minlat;
|
||||
private int maxlon;
|
||||
private int maxlat;
|
||||
private int radius;
|
||||
private OsmNode p;
|
||||
private int minlon;
|
||||
private int minlat;
|
||||
private int maxlon;
|
||||
private int maxlat;
|
||||
private int radius;
|
||||
private OsmNode p;
|
||||
|
||||
int direction;
|
||||
int direction;
|
||||
|
||||
/**
|
||||
* @param radius Search radius in meters.
|
||||
*/
|
||||
public SearchBoundary( OsmNode n, int radius, int direction )
|
||||
{
|
||||
this.radius = radius;
|
||||
this.direction = direction;
|
||||
/**
|
||||
* @param radius Search radius in meters.
|
||||
*/
|
||||
public SearchBoundary(OsmNode n, int radius, int direction) {
|
||||
this.radius = radius;
|
||||
this.direction = direction;
|
||||
|
||||
p = new OsmNode( n.ilon, n.ilat );
|
||||
p = new OsmNode(n.ilon, n.ilat);
|
||||
|
||||
int lon = (n.ilon / 5000000 ) * 5000000;
|
||||
int lat = (n.ilat / 5000000 ) * 5000000;
|
||||
int lon = (n.ilon / 5000000) * 5000000;
|
||||
int lat = (n.ilat / 5000000) * 5000000;
|
||||
|
||||
minlon0 = lon - 5000000;
|
||||
minlat0 = lat - 5000000;
|
||||
maxlon0 = lon + 10000000;
|
||||
maxlat0 = lat + 10000000;
|
||||
minlon0 = lon - 5000000;
|
||||
minlat0 = lat - 5000000;
|
||||
maxlon0 = lon + 10000000;
|
||||
maxlat0 = lat + 10000000;
|
||||
|
||||
minlon = lon - 1000000;
|
||||
minlat = lat - 1000000;
|
||||
maxlon = lon + 6000000;
|
||||
maxlat = lat + 6000000;
|
||||
minlon = lon - 1000000;
|
||||
minlat = lat - 1000000;
|
||||
maxlon = lon + 6000000;
|
||||
maxlat = lat + 6000000;
|
||||
}
|
||||
|
||||
public static String getFileName(OsmNode n) {
|
||||
int lon = (n.ilon / 5000000) * 5000000;
|
||||
int lat = (n.ilat / 5000000) * 5000000;
|
||||
|
||||
int dlon = lon / 1000000 - 180;
|
||||
int dlat = lat / 1000000 - 90;
|
||||
|
||||
String slon = dlon < 0 ? "W" + (-dlon) : "E" + dlon;
|
||||
String slat = dlat < 0 ? "S" + (-dlat) : "N" + dlat;
|
||||
return slon + "_" + slat + ".trf";
|
||||
}
|
||||
|
||||
public boolean isInBoundary(OsmNode n, int cost) {
|
||||
if (radius > 0) {
|
||||
return n.calcDistance(p) < radius;
|
||||
}
|
||||
|
||||
public static String getFileName( OsmNode n )
|
||||
{
|
||||
int lon = (n.ilon / 5000000 ) * 5000000;
|
||||
int lat = (n.ilat / 5000000 ) * 5000000;
|
||||
|
||||
int dlon = lon / 1000000 -180;
|
||||
int dlat = lat / 1000000 - 90;
|
||||
|
||||
String slon = dlon < 0 ? "W" + (-dlon) : "E" + dlon;
|
||||
String slat = dlat < 0 ? "S" + (-dlat) : "N" + dlat;
|
||||
return slon + "_" + slat + ".trf";
|
||||
if (cost == 0) {
|
||||
return n.ilon > minlon0 && n.ilon < maxlon0 && n.ilat > minlat0 && n.ilat < maxlat0;
|
||||
}
|
||||
return n.ilon > minlon && n.ilon < maxlon && n.ilat > minlat && n.ilat < maxlat;
|
||||
}
|
||||
|
||||
public boolean isInBoundary( OsmNode n, int cost )
|
||||
{
|
||||
if ( radius > 0 )
|
||||
{
|
||||
return n.calcDistance( p ) < radius;
|
||||
}
|
||||
if ( cost == 0 )
|
||||
{
|
||||
return n.ilon > minlon0 && n.ilon < maxlon0 && n.ilat > minlat0 && n.ilat < maxlat0;
|
||||
}
|
||||
return n.ilon > minlon && n.ilon < maxlon && n.ilat > minlat && n.ilat < maxlat;
|
||||
}
|
||||
|
||||
public int getBoundaryDistance( OsmNode n )
|
||||
{
|
||||
switch( direction )
|
||||
{
|
||||
case 0: return n.calcDistance( new OsmNode( n.ilon, minlat ) );
|
||||
case 1: return n.calcDistance( new OsmNode( minlon, n.ilat ) );
|
||||
case 2: return n.calcDistance( new OsmNode( n.ilon, maxlat ) );
|
||||
case 3: return n.calcDistance( new OsmNode( maxlon, n.ilat ) );
|
||||
default: throw new IllegalArgumentException( "undefined direction: "+ direction );
|
||||
}
|
||||
public int getBoundaryDistance(OsmNode n) {
|
||||
switch (direction) {
|
||||
case 0:
|
||||
return n.calcDistance(new OsmNode(n.ilon, minlat));
|
||||
case 1:
|
||||
return n.calcDistance(new OsmNode(minlon, n.ilat));
|
||||
case 2:
|
||||
return n.calcDistance(new OsmNode(n.ilon, maxlat));
|
||||
case 3:
|
||||
return n.calcDistance(new OsmNode(maxlon, n.ilat));
|
||||
default:
|
||||
throw new IllegalArgumentException("undefined direction: " + direction);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,12 @@ import btools.expressions.BExpressionContextNode;
|
|||
import btools.expressions.BExpressionContextWay;
|
||||
|
||||
|
||||
final class StdModel extends OsmPathModel
|
||||
{
|
||||
public OsmPrePath createPrePath()
|
||||
{
|
||||
final class StdModel extends OsmPathModel {
|
||||
public OsmPrePath createPrePath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public OsmPath createPath()
|
||||
{
|
||||
public OsmPath createPath() {
|
||||
return new StdPath();
|
||||
}
|
||||
|
||||
|
|
@ -29,11 +26,10 @@ final class StdModel extends OsmPathModel
|
|||
|
||||
|
||||
@Override
|
||||
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> keyValues )
|
||||
{
|
||||
public void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> keyValues) {
|
||||
ctxWay = expctxWay;
|
||||
ctxNode = expctxNode;
|
||||
|
||||
|
||||
BExpressionContext expctxGlobal = expctxWay; // just one of them...
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ package btools.router;
|
|||
|
||||
import btools.util.FastMath;
|
||||
|
||||
final class StdPath extends OsmPath
|
||||
{
|
||||
final class StdPath extends OsmPath {
|
||||
/**
|
||||
* The elevation-hysteresis-buffer (0-10 m)
|
||||
*/
|
||||
|
|
@ -23,9 +22,8 @@ final class StdPath extends OsmPath
|
|||
private static final double GRAVITY = 9.81; // in meters per second^(-2)
|
||||
|
||||
@Override
|
||||
public void init( OsmPath orig )
|
||||
{
|
||||
StdPath origin = (StdPath)orig;
|
||||
public void init(OsmPath orig) {
|
||||
StdPath origin = (StdPath) orig;
|
||||
this.ehbd = origin.ehbd;
|
||||
this.ehbu = origin.ehbu;
|
||||
this.totalTime = origin.totalTime;
|
||||
|
|
@ -34,8 +32,7 @@ final class StdPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void resetState()
|
||||
{
|
||||
protected void resetState() {
|
||||
ehbd = 0;
|
||||
ehbu = 0;
|
||||
totalTime = 0.f;
|
||||
|
|
@ -44,8 +41,7 @@ final class StdPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double processWaySection( RoutingContext rc, double distance, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier )
|
||||
{
|
||||
protected double processWaySection(RoutingContext rc, double distance, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier) {
|
||||
// calculate the costfactor inputs
|
||||
float turncostbase = rc.expctxWay.getTurncost();
|
||||
float cfup = rc.expctxWay.getUphillCostfactor();
|
||||
|
|
@ -54,14 +50,13 @@ final class StdPath extends OsmPath
|
|||
cfup = cfup == 0.f ? cf : cfup;
|
||||
cfdown = cfdown == 0.f ? cf : cfdown;
|
||||
|
||||
int dist = (int)distance; // legacy arithmetics needs int
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
message.turnangle = (float) angle;
|
||||
}
|
||||
|
||||
double sectionCost = turncost;
|
||||
|
|
@ -70,81 +65,66 @@ final class StdPath extends OsmPath
|
|||
// 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);
|
||||
int delta_h_micros = (int) (1000000. * delta_h);
|
||||
ehbd += -delta_h_micros - dist * rc.downhillcutoff;
|
||||
ehbu += delta_h_micros - dist * rc.uphillcutoff;
|
||||
ehbu += delta_h_micros - dist * rc.uphillcutoff;
|
||||
|
||||
float downweight = 0.f;
|
||||
if ( ehbd > rc.elevationpenaltybuffer )
|
||||
{
|
||||
if (ehbd > rc.elevationpenaltybuffer) {
|
||||
downweight = 1.f;
|
||||
|
||||
int excess = ehbd - rc.elevationpenaltybuffer;
|
||||
int reduce = dist * rc.elevationbufferreduce;
|
||||
if ( reduce > excess )
|
||||
{
|
||||
downweight = ((float)excess)/reduce;
|
||||
if (reduce > excess) {
|
||||
downweight = ((float) excess) / reduce;
|
||||
reduce = excess;
|
||||
}
|
||||
excess = ehbd - rc.elevationmaxbuffer;
|
||||
if ( reduce < excess )
|
||||
{
|
||||
if (reduce < excess) {
|
||||
reduce = excess;
|
||||
}
|
||||
ehbd -= reduce;
|
||||
if ( rc.downhillcostdiv > 0 )
|
||||
{
|
||||
int elevationCost = reduce/rc.downhillcostdiv;
|
||||
if (rc.downhillcostdiv > 0) {
|
||||
int elevationCost = reduce / rc.downhillcostdiv;
|
||||
sectionCost += elevationCost;
|
||||
if ( message != null )
|
||||
{
|
||||
if (message != null) {
|
||||
message.linkelevationcost += elevationCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ehbd < 0 )
|
||||
{
|
||||
} else if (ehbd < 0) {
|
||||
ehbd = 0;
|
||||
}
|
||||
|
||||
float upweight = 0.f;
|
||||
if ( ehbu > rc.elevationpenaltybuffer )
|
||||
{
|
||||
if (ehbu > rc.elevationpenaltybuffer) {
|
||||
upweight = 1.f;
|
||||
|
||||
int excess = ehbu - rc.elevationpenaltybuffer;
|
||||
int reduce = dist * rc.elevationbufferreduce;
|
||||
if ( reduce > excess )
|
||||
{
|
||||
upweight = ((float)excess)/reduce;
|
||||
if (reduce > excess) {
|
||||
upweight = ((float) excess) / reduce;
|
||||
reduce = excess;
|
||||
}
|
||||
excess = ehbu - rc.elevationmaxbuffer;
|
||||
if ( reduce < excess )
|
||||
{
|
||||
if (reduce < excess) {
|
||||
reduce = excess;
|
||||
}
|
||||
ehbu -= reduce;
|
||||
if ( rc.uphillcostdiv > 0 )
|
||||
{
|
||||
int elevationCost = reduce/rc.uphillcostdiv;
|
||||
if (rc.uphillcostdiv > 0) {
|
||||
int elevationCost = reduce / rc.uphillcostdiv;
|
||||
sectionCost += elevationCost;
|
||||
if ( message != null )
|
||||
{
|
||||
if (message != null) {
|
||||
message.linkelevationcost += elevationCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ehbu < 0 )
|
||||
{
|
||||
} else if (ehbu < 0) {
|
||||
ehbu = 0;
|
||||
}
|
||||
|
||||
// get the effective costfactor (slope dependent)
|
||||
float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
|
||||
float costfactor = cfup * upweight + cf * (1.f - upweight - downweight) + cfdown * downweight;
|
||||
|
||||
if ( message != null )
|
||||
{
|
||||
if (message != null) {
|
||||
message.costfactor = costfactor;
|
||||
}
|
||||
|
||||
|
|
@ -154,22 +134,18 @@ final class StdPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double processTargetNode( RoutingContext rc )
|
||||
{
|
||||
protected double processTargetNode(RoutingContext rc) {
|
||||
// finally add node-costs for target node
|
||||
if ( targetNode.nodeDescription != null )
|
||||
{
|
||||
if (targetNode.nodeDescription != null) {
|
||||
boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
|
||||
rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
|
||||
rc.expctxNode.evaluate(nodeAccessGranted, targetNode.nodeDescription);
|
||||
float initialcost = rc.expctxNode.getInitialcost();
|
||||
if ( initialcost >= 1000000. )
|
||||
{
|
||||
if (initialcost >= 1000000.) {
|
||||
return -1.;
|
||||
}
|
||||
if ( message != null )
|
||||
{
|
||||
message.linknodecost += (int)initialcost;
|
||||
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
|
||||
if (message != null) {
|
||||
message.linknodecost += (int) initialcost;
|
||||
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription(nodeAccessGranted, targetNode.nodeDescription);
|
||||
}
|
||||
return initialcost;
|
||||
}
|
||||
|
|
@ -177,118 +153,96 @@ final class StdPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
public int elevationCorrection( RoutingContext rc )
|
||||
{
|
||||
return ( rc.downhillcostdiv > 0 ? ehbd/rc.downhillcostdiv : 0 )
|
||||
+ ( rc.uphillcostdiv > 0 ? ehbu/rc.uphillcostdiv : 0 );
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
return cost > c;
|
||||
}
|
||||
|
||||
private double calcIncline( double dist )
|
||||
{
|
||||
private double calcIncline(double dist) {
|
||||
double min_delta = 3.;
|
||||
double shift;
|
||||
if ( elevation_buffer > min_delta )
|
||||
{
|
||||
if (elevation_buffer > min_delta) {
|
||||
shift = -min_delta;
|
||||
}
|
||||
else if ( elevation_buffer < min_delta )
|
||||
{
|
||||
} else if (elevation_buffer < min_delta) {
|
||||
shift = -min_delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return 0.;
|
||||
}
|
||||
double decayFactor = FastMath.exp( - dist / 100. );
|
||||
float new_elevation_buffer = (float)( (elevation_buffer+shift) * decayFactor - shift);
|
||||
double incline = ( elevation_buffer - new_elevation_buffer ) / dist;
|
||||
double decayFactor = FastMath.exp(-dist / 100.);
|
||||
float new_elevation_buffer = (float) ((elevation_buffer + shift) * decayFactor - shift);
|
||||
double incline = (elevation_buffer - new_elevation_buffer) / dist;
|
||||
elevation_buffer = new_elevation_buffer;
|
||||
return incline;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeKinematic( RoutingContext rc, double dist, double delta_h, boolean detailMode )
|
||||
{
|
||||
if ( !detailMode )
|
||||
{
|
||||
protected void computeKinematic(RoutingContext rc, double dist, double delta_h, boolean detailMode) {
|
||||
if (!detailMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// compute incline
|
||||
elevation_buffer += delta_h;
|
||||
double incline = calcIncline( dist );
|
||||
double incline = calcIncline(dist);
|
||||
|
||||
double wayMaxspeed;
|
||||
|
||||
|
||||
wayMaxspeed = rc.expctxWay.getMaxspeed() / 3.6f;
|
||||
if (wayMaxspeed == 0)
|
||||
{
|
||||
wayMaxspeed = rc.maxSpeed;
|
||||
if (wayMaxspeed == 0) {
|
||||
wayMaxspeed = rc.maxSpeed;
|
||||
}
|
||||
wayMaxspeed = Math.min(wayMaxspeed,rc.maxSpeed);
|
||||
|
||||
wayMaxspeed = Math.min(wayMaxspeed, rc.maxSpeed);
|
||||
|
||||
double speed; // Travel speed
|
||||
double f_roll = rc.totalMass * GRAVITY * ( rc.defaultC_r + incline );
|
||||
if (rc.footMode || rc.expctxWay.getCostfactor() > 4.9 )
|
||||
{
|
||||
double f_roll = rc.totalMass * GRAVITY * (rc.defaultC_r + incline);
|
||||
if (rc.footMode || rc.expctxWay.getCostfactor() > 4.9) {
|
||||
// Use Tobler's hiking function for walking sections
|
||||
speed = rc.maxSpeed * 3.6;
|
||||
speed = (speed * FastMath.exp(-3.5 * Math.abs( incline + 0.05))) / 3.6;
|
||||
}
|
||||
else if (rc.bikeMode)
|
||||
{
|
||||
speed = solveCubic( rc.S_C_x, f_roll, rc.bikerPower );
|
||||
speed = (speed * FastMath.exp(-3.5 * Math.abs(incline + 0.05))) / 3.6;
|
||||
} else if (rc.bikeMode) {
|
||||
speed = solveCubic(rc.S_C_x, f_roll, rc.bikerPower);
|
||||
speed = Math.min(speed, wayMaxspeed);
|
||||
}
|
||||
else // all other
|
||||
} else // all other
|
||||
{
|
||||
speed = wayMaxspeed;
|
||||
}
|
||||
float dt = (float) ( dist / speed );
|
||||
float dt = (float) (dist / speed);
|
||||
totalTime += dt;
|
||||
// Calc energy assuming biking (no good model yet for hiking)
|
||||
// (Count only positive, negative would mean breaking to enforce maxspeed)
|
||||
double energy = dist*(rc.S_C_x*speed*speed + f_roll);
|
||||
if ( energy > 0. )
|
||||
{
|
||||
double energy = dist * (rc.S_C_x * speed * speed + f_roll);
|
||||
if (energy > 0.) {
|
||||
totalEnergy += energy;
|
||||
}
|
||||
}
|
||||
|
||||
private static double solveCubic( double a, double c, double d )
|
||||
{
|
||||
private static double solveCubic(double a, double c, double d) {
|
||||
// Solves a * v^3 + c * v = d with a Newton method
|
||||
// to get the speed v for the section.
|
||||
|
||||
double v = 8.;
|
||||
boolean findingStartvalue = true;
|
||||
for ( int i = 0; i < 10; i++ )
|
||||
{
|
||||
double y = ( a * v * v + c ) * v - d;
|
||||
if ( y < .1 )
|
||||
{
|
||||
if ( findingStartvalue )
|
||||
{
|
||||
for (int i = 0; i < 10; i++) {
|
||||
double y = (a * v * v + c) * v - d;
|
||||
if (y < .1) {
|
||||
if (findingStartvalue) {
|
||||
v *= 2.;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -302,14 +256,12 @@ final class StdPath extends OsmPath
|
|||
}
|
||||
|
||||
@Override
|
||||
public double getTotalTime()
|
||||
{
|
||||
public double getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTotalEnergy()
|
||||
{
|
||||
public double getTotalEnergy() {
|
||||
return totalEnergy;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,65 +2,58 @@ package btools.router;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
public class SuspectInfo
|
||||
{
|
||||
public static final int TRIGGER_DEAD_END = 1;
|
||||
public static final int TRIGGER_DEAD_START = 2;
|
||||
public static final int TRIGGER_NODE_BLOCK = 4;
|
||||
public static final int TRIGGER_BAD_ACCESS = 8;
|
||||
public static final int TRIGGER_UNK_ACCESS = 16;
|
||||
public static final int TRIGGER_SHARP_EXIT = 32;
|
||||
public class SuspectInfo {
|
||||
public static final int TRIGGER_DEAD_END = 1;
|
||||
public static final int TRIGGER_DEAD_START = 2;
|
||||
public static final int TRIGGER_NODE_BLOCK = 4;
|
||||
public static final int TRIGGER_BAD_ACCESS = 8;
|
||||
public static final int TRIGGER_UNK_ACCESS = 16;
|
||||
public static final int TRIGGER_SHARP_EXIT = 32;
|
||||
public static final int TRIGGER_SHARP_ENTRY = 64;
|
||||
public static final int TRIGGER_SHARP_LINK = 128;
|
||||
public static final int TRIGGER_BAD_TR = 256;
|
||||
public static final int TRIGGER_SHARP_LINK = 128;
|
||||
public static final int TRIGGER_BAD_TR = 256;
|
||||
|
||||
public int prio;
|
||||
public int triggers;
|
||||
|
||||
public static void addSuspect( Map<Long,SuspectInfo> map, long id, int prio, int trigger )
|
||||
{
|
||||
Long iD = Long.valueOf( id );
|
||||
SuspectInfo info = map.get( iD );
|
||||
if ( info == null )
|
||||
{
|
||||
|
||||
public static void addSuspect(Map<Long, SuspectInfo> map, long id, int prio, int trigger) {
|
||||
Long iD = Long.valueOf(id);
|
||||
SuspectInfo info = map.get(iD);
|
||||
if (info == null) {
|
||||
info = new SuspectInfo();
|
||||
map.put( iD, info );
|
||||
map.put(iD, info);
|
||||
}
|
||||
info.prio = Math.max( info.prio, prio );
|
||||
info.prio = Math.max(info.prio, prio);
|
||||
info.triggers |= trigger;
|
||||
}
|
||||
|
||||
public static SuspectInfo addTrigger( SuspectInfo old, int prio, int trigger )
|
||||
{
|
||||
if ( old == null )
|
||||
{
|
||||
|
||||
public static SuspectInfo addTrigger(SuspectInfo old, int prio, int trigger) {
|
||||
if (old == null) {
|
||||
old = new SuspectInfo();
|
||||
}
|
||||
old.prio = Math.max( old.prio, prio );
|
||||
old.prio = Math.max(old.prio, prio);
|
||||
old.triggers |= trigger;
|
||||
return old;
|
||||
}
|
||||
|
||||
public static String getTriggerText( int triggers )
|
||||
{
|
||||
|
||||
public static String getTriggerText(int triggers) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
addText( sb, "dead-end" , triggers, TRIGGER_DEAD_END );
|
||||
addText( sb, "dead-start" , triggers, TRIGGER_DEAD_START );
|
||||
addText( sb, "node-block" , triggers, TRIGGER_NODE_BLOCK );
|
||||
addText( sb, "bad-access" , triggers, TRIGGER_BAD_ACCESS );
|
||||
addText( sb, "unkown-access", triggers, TRIGGER_UNK_ACCESS );
|
||||
addText( sb, "sharp-exit" , triggers, TRIGGER_SHARP_EXIT );
|
||||
addText( sb, "sharp-entry" , triggers, TRIGGER_SHARP_ENTRY );
|
||||
addText( sb, "sharp-link" , triggers, TRIGGER_SHARP_LINK );
|
||||
addText( sb, "bad-tr" , triggers, TRIGGER_BAD_TR );
|
||||
addText(sb, "dead-end", triggers, TRIGGER_DEAD_END);
|
||||
addText(sb, "dead-start", triggers, TRIGGER_DEAD_START);
|
||||
addText(sb, "node-block", triggers, TRIGGER_NODE_BLOCK);
|
||||
addText(sb, "bad-access", triggers, TRIGGER_BAD_ACCESS);
|
||||
addText(sb, "unkown-access", triggers, TRIGGER_UNK_ACCESS);
|
||||
addText(sb, "sharp-exit", triggers, TRIGGER_SHARP_EXIT);
|
||||
addText(sb, "sharp-entry", triggers, TRIGGER_SHARP_ENTRY);
|
||||
addText(sb, "sharp-link", triggers, TRIGGER_SHARP_LINK);
|
||||
addText(sb, "bad-tr", triggers, TRIGGER_BAD_TR);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void addText( StringBuilder sb, String text, int mask, int bit )
|
||||
{
|
||||
if ( ( bit & mask ) == 0 ) return;
|
||||
if ( sb.length() > 0 ) sb.append( "," );
|
||||
sb.append( text );
|
||||
private static void addText(StringBuilder sb, String text, int mask, int bit) {
|
||||
if ((bit & mask) == 0) return;
|
||||
if (sb.length() > 0) sb.append(",");
|
||||
sb.append(text);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ package btools.router;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VoiceHint
|
||||
{
|
||||
public class VoiceHint {
|
||||
static final int C = 1; // continue (go straight)
|
||||
static final int TL = 2; // turn left
|
||||
static final int TSLL = 3; // turn slightly left
|
||||
|
|
@ -36,8 +35,7 @@ public class VoiceHint
|
|||
double distanceToNext;
|
||||
int indexInTrack;
|
||||
|
||||
public float getTime()
|
||||
{
|
||||
public float getTime() {
|
||||
return oldWay == null ? 0.f : oldWay.time;
|
||||
}
|
||||
|
||||
|
|
@ -47,269 +45,281 @@ public class VoiceHint
|
|||
|
||||
int roundaboutExit;
|
||||
|
||||
boolean isRoundabout()
|
||||
{
|
||||
boolean isRoundabout() {
|
||||
return roundaboutExit != 0;
|
||||
}
|
||||
|
||||
public void addBadWay( MessageData badWay )
|
||||
{
|
||||
if ( badWay == null )
|
||||
{
|
||||
|
||||
public void addBadWay(MessageData badWay) {
|
||||
if (badWay == null) {
|
||||
return;
|
||||
}
|
||||
if ( badWays == null )
|
||||
{
|
||||
if (badWays == null) {
|
||||
badWays = new ArrayList<MessageData>();
|
||||
}
|
||||
badWays.add( badWay );
|
||||
badWays.add(badWay);
|
||||
}
|
||||
|
||||
public int getCommand()
|
||||
{
|
||||
public int getCommand() {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public int getExitNumber()
|
||||
{
|
||||
public int getExitNumber() {
|
||||
return roundaboutExit;
|
||||
}
|
||||
|
||||
public String getCommandString()
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TU : return "TU";
|
||||
case TSHL : return "TSHL";
|
||||
case TL : return "TL";
|
||||
case TSLL : return "TSLL";
|
||||
case KL : return "KL";
|
||||
case C : return "C";
|
||||
case KR : return "KR";
|
||||
case TSLR : return "TSLR";
|
||||
case TR : return "TR";
|
||||
case TSHR : return "TSHR";
|
||||
case TRU : return "TRU";
|
||||
case RNDB : return "RNDB" + roundaboutExit;
|
||||
case RNLB : return "RNLB" + (-roundaboutExit);
|
||||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
}
|
||||
}
|
||||
|
||||
public String getSymbolString()
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TU : return "TU";
|
||||
case TSHL : return "TSHL";
|
||||
case TL : return "Left";
|
||||
case TSLL : return "TSLL";
|
||||
case KL : return "TSLL"; // ?
|
||||
case C : return "Straight";
|
||||
case KR : return "TSLR"; // ?
|
||||
case TSLR : return "TSLR";
|
||||
case TR : return "Right";
|
||||
case TSHR : return "TSHR";
|
||||
case TRU : return "TU";
|
||||
case RNDB : return "RNDB" + roundaboutExit;
|
||||
case RNLB : return "RNLB" + (-roundaboutExit);
|
||||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
public String getCommandString() {
|
||||
switch (cmd) {
|
||||
case TU:
|
||||
return "TU";
|
||||
case TSHL:
|
||||
return "TSHL";
|
||||
case TL:
|
||||
return "TL";
|
||||
case TSLL:
|
||||
return "TSLL";
|
||||
case KL:
|
||||
return "KL";
|
||||
case C:
|
||||
return "C";
|
||||
case KR:
|
||||
return "KR";
|
||||
case TSLR:
|
||||
return "TSLR";
|
||||
case TR:
|
||||
return "TR";
|
||||
case TSHR:
|
||||
return "TSHR";
|
||||
case TRU:
|
||||
return "TRU";
|
||||
case RNDB:
|
||||
return "RNDB" + roundaboutExit;
|
||||
case RNLB:
|
||||
return "RNLB" + (-roundaboutExit);
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public String getMessageString()
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TU : return "u-turn";
|
||||
case TSHL : return "sharp left";
|
||||
case TL : return "left";
|
||||
case TSLL : return "slight left";
|
||||
case KL : return "keep left";
|
||||
case C : return "straight";
|
||||
case KR : return "keep right";
|
||||
case TSLR : return "slight right";
|
||||
case TR : return "right";
|
||||
case TSHR : return "sharp right";
|
||||
case TRU : return "u-turn";
|
||||
case RNDB : return "Take exit " + roundaboutExit;
|
||||
case RNLB : return "Take exit " + (-roundaboutExit);
|
||||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
public String getSymbolString() {
|
||||
switch (cmd) {
|
||||
case TU:
|
||||
return "TU";
|
||||
case TSHL:
|
||||
return "TSHL";
|
||||
case TL:
|
||||
return "Left";
|
||||
case TSLL:
|
||||
return "TSLL";
|
||||
case KL:
|
||||
return "TSLL"; // ?
|
||||
case C:
|
||||
return "Straight";
|
||||
case KR:
|
||||
return "TSLR"; // ?
|
||||
case TSLR:
|
||||
return "TSLR";
|
||||
case TR:
|
||||
return "Right";
|
||||
case TSHR:
|
||||
return "TSHR";
|
||||
case TRU:
|
||||
return "TU";
|
||||
case RNDB:
|
||||
return "RNDB" + roundaboutExit;
|
||||
case RNLB:
|
||||
return "RNLB" + (-roundaboutExit);
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public int getLocusAction()
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TU : return 13;
|
||||
case TSHL : return 5;
|
||||
case TL : return 4;
|
||||
case TSLL : return 3;
|
||||
case KL : return 9; // ?
|
||||
case C : return 1;
|
||||
case KR : return 10; // ?
|
||||
case TSLR : return 6;
|
||||
case TR : return 7;
|
||||
case TSHR : return 8;
|
||||
case TRU : return 14;
|
||||
case RNDB : return 26 + roundaboutExit;
|
||||
case RNLB : return 26 - roundaboutExit;
|
||||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
public String getMessageString() {
|
||||
switch (cmd) {
|
||||
case TU:
|
||||
return "u-turn";
|
||||
case TSHL:
|
||||
return "sharp left";
|
||||
case TL:
|
||||
return "left";
|
||||
case TSLL:
|
||||
return "slight left";
|
||||
case KL:
|
||||
return "keep left";
|
||||
case C:
|
||||
return "straight";
|
||||
case KR:
|
||||
return "keep right";
|
||||
case TSLR:
|
||||
return "slight right";
|
||||
case TR:
|
||||
return "right";
|
||||
case TSHR:
|
||||
return "sharp right";
|
||||
case TRU:
|
||||
return "u-turn";
|
||||
case RNDB:
|
||||
return "Take exit " + roundaboutExit;
|
||||
case RNLB:
|
||||
return "Take exit " + (-roundaboutExit);
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public int getOruxAction()
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TU : return 1003;
|
||||
case TSHL : return 1019;
|
||||
case TL : return 1000;
|
||||
case TSLL : return 1017;
|
||||
case KL : return 1015; // ?
|
||||
case C : return 1002;
|
||||
case KR : return 1014; // ?
|
||||
case TSLR : return 1016;
|
||||
case TR : return 1001;
|
||||
case TSHR : return 1018;
|
||||
case TRU : return 1003;
|
||||
case RNDB : return 1008 + roundaboutExit;
|
||||
case RNLB : return 1008 + roundaboutExit;
|
||||
default : throw new IllegalArgumentException( "unknown command: " + cmd );
|
||||
}
|
||||
|
||||
public int getLocusAction() {
|
||||
switch (cmd) {
|
||||
case TU:
|
||||
return 13;
|
||||
case TSHL:
|
||||
return 5;
|
||||
case TL:
|
||||
return 4;
|
||||
case TSLL:
|
||||
return 3;
|
||||
case KL:
|
||||
return 9; // ?
|
||||
case C:
|
||||
return 1;
|
||||
case KR:
|
||||
return 10; // ?
|
||||
case TSLR:
|
||||
return 6;
|
||||
case TR:
|
||||
return 7;
|
||||
case TSHR:
|
||||
return 8;
|
||||
case TRU:
|
||||
return 14;
|
||||
case RNDB:
|
||||
return 26 + roundaboutExit;
|
||||
case RNLB:
|
||||
return 26 - roundaboutExit;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public void calcCommand()
|
||||
{
|
||||
public int getOruxAction() {
|
||||
switch (cmd) {
|
||||
case TU:
|
||||
return 1003;
|
||||
case TSHL:
|
||||
return 1019;
|
||||
case TL:
|
||||
return 1000;
|
||||
case TSLL:
|
||||
return 1017;
|
||||
case KL:
|
||||
return 1015; // ?
|
||||
case C:
|
||||
return 1002;
|
||||
case KR:
|
||||
return 1014; // ?
|
||||
case TSLR:
|
||||
return 1016;
|
||||
case TR:
|
||||
return 1001;
|
||||
case TSHR:
|
||||
return 1018;
|
||||
case TRU:
|
||||
return 1003;
|
||||
case RNDB:
|
||||
return 1008 + roundaboutExit;
|
||||
case RNLB:
|
||||
return 1008 + roundaboutExit;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public void calcCommand() {
|
||||
float lowerBadWayAngle = -181;
|
||||
float higherBadWayAngle = 181;
|
||||
if ( badWays != null )
|
||||
{
|
||||
for ( MessageData badWay : badWays )
|
||||
{
|
||||
if ( badWay.isBadOneway() )
|
||||
{
|
||||
if (badWays != null) {
|
||||
for (MessageData badWay : badWays) {
|
||||
if (badWay.isBadOneway()) {
|
||||
continue;
|
||||
}
|
||||
if ( lowerBadWayAngle < badWay.turnangle && badWay.turnangle < goodWay.turnangle )
|
||||
{
|
||||
if (lowerBadWayAngle < badWay.turnangle && badWay.turnangle < goodWay.turnangle) {
|
||||
lowerBadWayAngle = badWay.turnangle;
|
||||
}
|
||||
if ( higherBadWayAngle > badWay.turnangle && badWay.turnangle > goodWay.turnangle )
|
||||
{
|
||||
if (higherBadWayAngle > badWay.turnangle && badWay.turnangle > goodWay.turnangle) {
|
||||
higherBadWayAngle = badWay.turnangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float cmdAngle= angle;
|
||||
float cmdAngle = angle;
|
||||
|
||||
// fall back to local angle if otherwise inconsistent
|
||||
if ( lowerBadWayAngle > angle || higherBadWayAngle < angle )
|
||||
{
|
||||
if (lowerBadWayAngle > angle || higherBadWayAngle < angle) {
|
||||
cmdAngle = goodWay.turnangle;
|
||||
}
|
||||
|
||||
if (roundaboutExit > 0)
|
||||
{
|
||||
if (roundaboutExit > 0) {
|
||||
cmd = RNDB;
|
||||
}
|
||||
else if (roundaboutExit < 0)
|
||||
{
|
||||
} else if (roundaboutExit < 0) {
|
||||
cmd = RNLB;
|
||||
}
|
||||
else if ( cmdAngle < -159. )
|
||||
{
|
||||
} else if (cmdAngle < -159.) {
|
||||
cmd = TU;
|
||||
}
|
||||
else if ( cmdAngle < -135. )
|
||||
{
|
||||
} else if (cmdAngle < -135.) {
|
||||
cmd = TSHL;
|
||||
}
|
||||
else if ( cmdAngle < -45. )
|
||||
{
|
||||
} else if (cmdAngle < -45.) {
|
||||
// a TL can be pushed in either direction by a close-by alternative
|
||||
if ( higherBadWayAngle > -90. && higherBadWayAngle < -15. && lowerBadWayAngle < -180. )
|
||||
{
|
||||
if (higherBadWayAngle > -90. && higherBadWayAngle < -15. && lowerBadWayAngle < -180.) {
|
||||
cmd = TSHL;
|
||||
}
|
||||
else if ( lowerBadWayAngle > -180. && lowerBadWayAngle < -90. && higherBadWayAngle > 0. )
|
||||
{
|
||||
} else if (lowerBadWayAngle > -180. && lowerBadWayAngle < -90. && higherBadWayAngle > 0.) {
|
||||
cmd = TSLL;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cmd = TL;
|
||||
}
|
||||
}
|
||||
else if ( cmdAngle < -21. )
|
||||
{
|
||||
if ( cmd != KR ) // don't overwrite KR with TSLL
|
||||
} else if (cmdAngle < -21.) {
|
||||
if (cmd != KR) // don't overwrite KR with TSLL
|
||||
{
|
||||
cmd = TSLL;
|
||||
}
|
||||
}
|
||||
else if ( cmdAngle < 21. )
|
||||
{
|
||||
if ( cmd != KR && cmd != KL ) // don't overwrite KL/KR hints!
|
||||
} else if (cmdAngle < 21.) {
|
||||
if (cmd != KR && cmd != KL) // don't overwrite KL/KR hints!
|
||||
{
|
||||
cmd = C;
|
||||
}
|
||||
}
|
||||
else if ( cmdAngle < 45. )
|
||||
{
|
||||
if ( cmd != KL ) // don't overwrite KL with TSLR
|
||||
} else if (cmdAngle < 45.) {
|
||||
if (cmd != KL) // don't overwrite KL with TSLR
|
||||
{
|
||||
cmd = TSLR;
|
||||
}
|
||||
}
|
||||
else if ( cmdAngle < 135. )
|
||||
{
|
||||
} else if (cmdAngle < 135.) {
|
||||
// a TR can be pushed in either direction by a close-by alternative
|
||||
if ( higherBadWayAngle > 90. && higherBadWayAngle < 180. && lowerBadWayAngle < 0. )
|
||||
{
|
||||
if (higherBadWayAngle > 90. && higherBadWayAngle < 180. && lowerBadWayAngle < 0.) {
|
||||
cmd = TSLR;
|
||||
}
|
||||
else if ( lowerBadWayAngle > 15. && lowerBadWayAngle < 90. && higherBadWayAngle > 180. )
|
||||
{
|
||||
} else if (lowerBadWayAngle > 15. && lowerBadWayAngle < 90. && higherBadWayAngle > 180.) {
|
||||
cmd = TSHR;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cmd = TR;
|
||||
}
|
||||
}
|
||||
else if ( cmdAngle < 159. )
|
||||
{
|
||||
} else if (cmdAngle < 159.) {
|
||||
cmd = TSHR;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cmd = TRU;
|
||||
}
|
||||
}
|
||||
|
||||
public String formatGeometry()
|
||||
{
|
||||
public String formatGeometry() {
|
||||
float oldPrio = oldWay == null ? 0.f : oldWay.priorityclassifier;
|
||||
StringBuilder sb = new StringBuilder(30);
|
||||
sb.append( ' ' ).append( (int)oldPrio );
|
||||
appendTurnGeometry(sb,goodWay);
|
||||
if ( badWays != null )
|
||||
{
|
||||
for ( MessageData badWay : badWays )
|
||||
{
|
||||
sb.append( " " );
|
||||
appendTurnGeometry( sb, badWay );
|
||||
sb.append(' ').append((int) oldPrio);
|
||||
appendTurnGeometry(sb, goodWay);
|
||||
if (badWays != null) {
|
||||
for (MessageData badWay : badWays) {
|
||||
sb.append(" ");
|
||||
appendTurnGeometry(sb, badWay);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendTurnGeometry( StringBuilder sb, MessageData msg )
|
||||
{
|
||||
sb.append( "(" ).append( (int)(msg.turnangle+0.5) ).append( ")" ).append( (int)(msg.priorityclassifier) );
|
||||
private void appendTurnGeometry(StringBuilder sb, MessageData msg) {
|
||||
sb.append("(").append((int) (msg.turnangle + 0.5)).append(")").append((int) (msg.priorityclassifier));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,30 +9,24 @@ package btools.router;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VoiceHintList
|
||||
{
|
||||
public class VoiceHintList {
|
||||
private String transportMode;
|
||||
int turnInstructionMode;
|
||||
ArrayList<VoiceHint> list = new ArrayList<VoiceHint>();
|
||||
|
||||
public void setTransportMode( boolean isCar, boolean isBike )
|
||||
{
|
||||
transportMode = isCar ? "car" : ( isBike ? "bike" : "foot" );
|
||||
public void setTransportMode(boolean isCar, boolean isBike) {
|
||||
transportMode = isCar ? "car" : (isBike ? "bike" : "foot");
|
||||
}
|
||||
|
||||
public String getTransportMode()
|
||||
{
|
||||
public String getTransportMode() {
|
||||
return transportMode;
|
||||
}
|
||||
|
||||
public int getLocusRouteType()
|
||||
{
|
||||
if ( "car".equals( transportMode ) )
|
||||
{
|
||||
public int getLocusRouteType() {
|
||||
if ("car".equals(transportMode)) {
|
||||
return 0;
|
||||
}
|
||||
if ( "bike".equals( transportMode ) )
|
||||
{
|
||||
if ("bike".equals(transportMode)) {
|
||||
return 5;
|
||||
}
|
||||
return 3; // foot
|
||||
|
|
|
|||
|
|
@ -8,26 +8,21 @@ package btools.router;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class VoiceHintProcessor
|
||||
{
|
||||
public final class VoiceHintProcessor {
|
||||
private double catchingRange; // range to catch angles and merge turns
|
||||
private boolean explicitRoundabouts;
|
||||
|
||||
public VoiceHintProcessor( double catchingRange, boolean explicitRoundabouts )
|
||||
{
|
||||
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts) {
|
||||
this.catchingRange = catchingRange;
|
||||
this.explicitRoundabouts = explicitRoundabouts;
|
||||
}
|
||||
|
||||
private float sumNonConsumedWithinCatchingRange( List<VoiceHint> inputs, int offset )
|
||||
{
|
||||
private float sumNonConsumedWithinCatchingRange(List<VoiceHint> inputs, int offset) {
|
||||
double distance = 0.;
|
||||
float angle = 0.f;
|
||||
while( offset >= 0 && distance < catchingRange )
|
||||
{
|
||||
VoiceHint input = inputs.get( offset-- );
|
||||
if ( input.turnAngleConsumed )
|
||||
{
|
||||
while (offset >= 0 && distance < catchingRange) {
|
||||
VoiceHint input = inputs.get(offset--);
|
||||
if (input.turnAngleConsumed) {
|
||||
break;
|
||||
}
|
||||
angle += input.goodWay.turnangle;
|
||||
|
|
@ -44,10 +39,10 @@ public final class VoiceHintProcessor
|
|||
* order (from target to start), but output is
|
||||
* returned in travel-direction and only for
|
||||
* those nodes that trigger a voice hint.
|
||||
*
|
||||
* <p>
|
||||
* Input objects are expected for every segment
|
||||
* of the track, also for those without a junction
|
||||
*
|
||||
* <p>
|
||||
* VoiceHint objects in the output list are enriched
|
||||
* by the voice-command, the total angle and the distance
|
||||
* to the next hint
|
||||
|
|
@ -55,54 +50,46 @@ public final class VoiceHintProcessor
|
|||
* @param inputs tracknodes, un reverse order
|
||||
* @return voice hints, in forward order
|
||||
*/
|
||||
public List<VoiceHint> process( List<VoiceHint> inputs )
|
||||
{
|
||||
public List<VoiceHint> process(List<VoiceHint> inputs) {
|
||||
List<VoiceHint> results = new ArrayList<VoiceHint>();
|
||||
double distance = 0.;
|
||||
float roundAboutTurnAngle = 0.f; // sums up angles in roundabout
|
||||
|
||||
int roundaboutExit = 0;
|
||||
|
||||
for ( int hintIdx = 0; hintIdx < inputs.size(); hintIdx++ )
|
||||
{
|
||||
VoiceHint input = inputs.get( hintIdx );
|
||||
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
|
||||
VoiceHint input = inputs.get(hintIdx);
|
||||
|
||||
float turnAngle = input.goodWay.turnangle;
|
||||
distance += input.goodWay.linkdist;
|
||||
int currentPrio = input.goodWay.getPrio();
|
||||
int oldPrio = input.oldWay.getPrio();
|
||||
int minPrio = Math.min( oldPrio, currentPrio );
|
||||
int minPrio = Math.min(oldPrio, currentPrio);
|
||||
|
||||
boolean isLink2Highway = input.oldWay.isLinktType() && !input.goodWay.isLinktType();
|
||||
|
||||
if ( input.oldWay.isRoundabout() )
|
||||
{
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
if (input.oldWay.isRoundabout()) {
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
boolean isExit = roundaboutExit == 0; // exit point is always exit
|
||||
if ( input.badWays != null )
|
||||
{
|
||||
for ( MessageData badWay : input.badWays )
|
||||
{
|
||||
if ( !badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs( badWay.turnangle ) < 120. )
|
||||
{
|
||||
if (input.badWays != null) {
|
||||
for (MessageData badWay : input.badWays) {
|
||||
if (!badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs(badWay.turnangle) < 120.) {
|
||||
isExit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( isExit )
|
||||
{
|
||||
if (isExit) {
|
||||
roundaboutExit++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ( roundaboutExit > 0 )
|
||||
{
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
if (roundaboutExit > 0) {
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
input.angle = roundAboutTurnAngle;
|
||||
input.distanceToNext = distance;
|
||||
input.roundaboutExit = turnAngle < 0 ? -roundaboutExit : roundaboutExit;
|
||||
input.roundaboutExit = turnAngle < 0 ? -roundaboutExit : roundaboutExit;
|
||||
distance = 0.;
|
||||
results.add( input );
|
||||
results.add(input);
|
||||
roundAboutTurnAngle = 0.f;
|
||||
roundaboutExit = 0;
|
||||
continue;
|
||||
|
|
@ -114,91 +101,77 @@ public final class VoiceHintProcessor
|
|||
float minAngle = 180.f;
|
||||
float minAbsAngeRaw = 180.f;
|
||||
|
||||
if ( input.badWays != null )
|
||||
{
|
||||
for ( MessageData badWay : input.badWays )
|
||||
{
|
||||
if (input.badWays != null) {
|
||||
for (MessageData badWay : input.badWays) {
|
||||
int badPrio = badWay.getPrio();
|
||||
float badTurn = badWay.turnangle;
|
||||
|
||||
boolean isHighway2Link = !input.oldWay.isLinktType() && badWay.isLinktType();
|
||||
|
||||
if ( badPrio > maxPrioAll && !isHighway2Link )
|
||||
{
|
||||
if (badPrio > maxPrioAll && !isHighway2Link) {
|
||||
maxPrioAll = badPrio;
|
||||
}
|
||||
|
||||
if ( badWay.costfactor < 20.f && Math.abs( badTurn ) < minAbsAngeRaw )
|
||||
{
|
||||
minAbsAngeRaw = Math.abs( badTurn );
|
||||
if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
|
||||
minAbsAngeRaw = Math.abs(badTurn);
|
||||
}
|
||||
|
||||
if ( badPrio < minPrio )
|
||||
{
|
||||
if (badPrio < minPrio) {
|
||||
continue; // ignore low prio ways
|
||||
}
|
||||
|
||||
if ( badWay.isBadOneway() )
|
||||
{
|
||||
if (badWay.isBadOneway()) {
|
||||
continue; // ignore wrong oneways
|
||||
}
|
||||
|
||||
if ( Math.abs( badTurn ) - Math.abs( turnAngle ) > 80.f )
|
||||
{
|
||||
if (Math.abs(badTurn) - Math.abs(turnAngle) > 80.f) {
|
||||
continue; // ways from the back should not trigger a slight turn
|
||||
}
|
||||
|
||||
if ( badPrio > maxPrioCandidates )
|
||||
{
|
||||
if (badPrio > maxPrioCandidates) {
|
||||
maxPrioCandidates = badPrio;
|
||||
}
|
||||
if ( badTurn > maxAngle )
|
||||
{
|
||||
if (badTurn > maxAngle) {
|
||||
maxAngle = badTurn;
|
||||
}
|
||||
if ( badTurn < minAngle )
|
||||
{
|
||||
if (badTurn < minAngle) {
|
||||
minAngle = badTurn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasSomethingMoreStraight = Math.abs( turnAngle ) - minAbsAngeRaw > 20.;
|
||||
boolean hasSomethingMoreStraight = Math.abs(turnAngle) - minAbsAngeRaw > 20.;
|
||||
|
||||
// unconditional triggers are all junctions with
|
||||
// - higher detour prios than the minimum route prio (except link->highway junctions)
|
||||
// - or candidate detours with higher prio then the route exit leg
|
||||
boolean unconditionalTrigger = hasSomethingMoreStraight || ( maxPrioAll > minPrio && !isLink2Highway ) || ( maxPrioCandidates > currentPrio );
|
||||
boolean unconditionalTrigger = hasSomethingMoreStraight || (maxPrioAll > minPrio && !isLink2Highway) || (maxPrioCandidates > currentPrio);
|
||||
|
||||
// conditional triggers (=real turning angle required) are junctions
|
||||
// with candidate detours equal in priority than the route exit leg
|
||||
boolean conditionalTrigger = maxPrioCandidates >= minPrio;
|
||||
|
||||
if ( unconditionalTrigger || conditionalTrigger )
|
||||
{
|
||||
if (unconditionalTrigger || conditionalTrigger) {
|
||||
input.angle = turnAngle;
|
||||
input.calcCommand();
|
||||
boolean isStraight = input.cmd == VoiceHint.C;
|
||||
input.needsRealTurn = (!unconditionalTrigger) && isStraight;
|
||||
|
||||
// check for KR/KL
|
||||
if ( maxAngle < turnAngle && maxAngle > turnAngle - 45.f - (turnAngle > 0.f ? turnAngle : 0.f ) )
|
||||
{
|
||||
if (maxAngle < turnAngle && maxAngle > turnAngle - 45.f - (turnAngle > 0.f ? turnAngle : 0.f)) {
|
||||
input.cmd = VoiceHint.KR;
|
||||
}
|
||||
if ( minAngle > turnAngle && minAngle < turnAngle + 45.f - (turnAngle < 0.f ? turnAngle : 0.f ) )
|
||||
{
|
||||
if (minAngle > turnAngle && minAngle < turnAngle + 45.f - (turnAngle < 0.f ? turnAngle : 0.f)) {
|
||||
input.cmd = VoiceHint.KL;
|
||||
}
|
||||
|
||||
input.angle = sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
input.angle = sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
input.distanceToNext = distance;
|
||||
distance = 0.;
|
||||
results.add( input );
|
||||
results.add(input);
|
||||
}
|
||||
if ( results.size() > 0 && distance < catchingRange )
|
||||
{
|
||||
results.get( results.size()-1 ).angle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
if (results.size() > 0 && distance < catchingRange) {
|
||||
results.get(results.size() - 1).angle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,25 +180,21 @@ public final class VoiceHintProcessor
|
|||
|
||||
List<VoiceHint> results2 = new ArrayList<VoiceHint>();
|
||||
int i = results.size();
|
||||
while( i > 0 )
|
||||
{
|
||||
while (i > 0) {
|
||||
VoiceHint hint = results.get(--i);
|
||||
if ( hint.cmd == 0 )
|
||||
{
|
||||
if (hint.cmd == 0) {
|
||||
hint.calcCommand();
|
||||
}
|
||||
if ( ! ( hint.needsRealTurn && hint.cmd == VoiceHint.C ) )
|
||||
{
|
||||
if (!(hint.needsRealTurn && hint.cmd == VoiceHint.C)) {
|
||||
double dist = hint.distanceToNext;
|
||||
// sum up other hints within the catching range (e.g. 40m)
|
||||
while( dist < catchingRange && i > 0 )
|
||||
{
|
||||
VoiceHint h2 = results.get(i-1);
|
||||
while (dist < catchingRange && i > 0) {
|
||||
VoiceHint h2 = results.get(i - 1);
|
||||
dist = h2.distanceToNext;
|
||||
hint.distanceToNext+= dist;
|
||||
hint.distanceToNext += dist;
|
||||
hint.angle += h2.angle;
|
||||
i--;
|
||||
if ( h2.isRoundabout() ) // if we hit a roundabout, use that as the trigger
|
||||
if (h2.isRoundabout()) // if we hit a roundabout, use that as the trigger
|
||||
{
|
||||
h2.angle = hint.angle;
|
||||
hint = h2;
|
||||
|
|
@ -233,12 +202,11 @@ public final class VoiceHintProcessor
|
|||
}
|
||||
}
|
||||
|
||||
if ( !explicitRoundabouts )
|
||||
{
|
||||
if (!explicitRoundabouts) {
|
||||
hint.roundaboutExit = 0; // use an angular hint instead
|
||||
}
|
||||
hint.calcCommand();
|
||||
results2.add( hint );
|
||||
results2.add(hint);
|
||||
}
|
||||
}
|
||||
return results2;
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import btools.util.CheapRuler;
|
|||
|
||||
public class OsmNodeNamedTest {
|
||||
static int toOsmLon(double lon) {
|
||||
return (int)( ( lon + 180. ) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
|
||||
return (int) ((lon + 180.) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
|
||||
}
|
||||
|
||||
static int toOsmLat(double lat) {
|
||||
return (int)( ( lat + 90. ) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
|
||||
return (int) ((lat + 90.) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**********************************************************************************************
|
||||
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
|
||||
**********************************************************************************************/
|
||||
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
|
||||
**********************************************************************************************/
|
||||
package btools.router;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
|
@ -22,26 +22,26 @@ public class OsmNogoPolygonTest {
|
|||
static OsmNogoPolygon polygon;
|
||||
static OsmNogoPolygon polyline;
|
||||
|
||||
static final double[] lons = { 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.1, -1.0 };
|
||||
static final double[] lats = { -1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.1, -1.0 };
|
||||
static final double[] lons = {1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.1, -1.0};
|
||||
static final double[] lats = {-1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.1, -1.0};
|
||||
|
||||
static int toOsmLon(double lon, int offset_x) {
|
||||
return (int)( ( lon + 180. ) *1000000. + 0.5)+offset_x; // see ServerHandler.readPosition()
|
||||
return (int) ((lon + 180.) * 1000000. + 0.5) + offset_x; // see ServerHandler.readPosition()
|
||||
}
|
||||
|
||||
static int toOsmLat(double lat, int offset_y) {
|
||||
return (int)( ( lat + 90. ) *1000000. + 0.5)+offset_y;
|
||||
return (int) ((lat + 90.) * 1000000. + 0.5) + offset_y;
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() throws Exception {
|
||||
polygon = new OsmNogoPolygon(true);
|
||||
for (int i = 0; i<lons.length; i++) {
|
||||
polygon.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y));
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
polygon.addVertex(toOsmLon(lons[i], OFFSET_X), toOsmLat(lats[i], OFFSET_Y));
|
||||
}
|
||||
polyline = new OsmNogoPolygon(false);
|
||||
for (int i = 0; i<lons.length; i++) {
|
||||
polyline.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y));
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
polyline.addVertex(toOsmLon(lons[i], OFFSET_X), toOsmLat(lats[i], OFFSET_Y));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,162 +51,162 @@ public class OsmNogoPolygonTest {
|
|||
|
||||
@Test
|
||||
public void testCalcBoundingCircle() {
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( polygon.ilat );
|
||||
double[] lonlat2m = CheapRuler.getLonLatToMeterScales(polygon.ilat);
|
||||
double dlon2m = lonlat2m[0];
|
||||
double dlat2m = lonlat2m[1];
|
||||
|
||||
polygon.calcBoundingCircle();
|
||||
double r = polygon.radius;
|
||||
for (int i=0; i<lons.length; i++) {
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
double dpx = (toOsmLon(lons[i], OFFSET_X) - polygon.ilon) * dlon2m;
|
||||
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polygon.ilat) * dlat2m;
|
||||
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
|
||||
double diff = r-r1;
|
||||
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
|
||||
double diff = r - r1;
|
||||
assertTrue("i: " + i + " r(" + r + ") >= r1(" + r1 + ")", diff >= 0);
|
||||
}
|
||||
polyline.calcBoundingCircle();
|
||||
r = polyline.radius;
|
||||
for (int i=0; i<lons.length; i++) {
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
double dpx = (toOsmLon(lons[i], OFFSET_X) - polyline.ilon) * dlon2m;
|
||||
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polyline.ilat) * dlat2m;
|
||||
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
|
||||
double diff = r-r1;
|
||||
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
|
||||
double diff = r - r1;
|
||||
assertTrue("i: " + i + " r(" + r + ") >= r1(" + r1 + ")", diff >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWithin() {
|
||||
double[] plons = { 0.0, 0.5, 1.0, -1.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, };
|
||||
double[] plats = { 0.0, 1.5, 0.0, 0.5, -1.5, -1.0, -0.1, -0.1, 0.0, 0.1, };
|
||||
boolean[] within = { true, false, false, false, false, true, true, true, true, true, };
|
||||
double[] plons = {0.0, 0.5, 1.0, -1.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5,};
|
||||
double[] plats = {0.0, 1.5, 0.0, 0.5, -1.5, -1.0, -0.1, -0.1, 0.0, 0.1,};
|
||||
boolean[] within = {true, false, false, false, false, true, true, true, true, true,};
|
||||
|
||||
for (int i=0; i<plons.length; i++) {
|
||||
assertEquals("("+plons[i]+","+plats[i]+")",within[i],polygon.isWithin(toOsmLon(plons[i], OFFSET_X), toOsmLat(plats[i], OFFSET_Y)));
|
||||
for (int i = 0; i < plons.length; i++) {
|
||||
assertEquals("(" + plons[i] + "," + plats[i] + ")", within[i], polygon.isWithin(toOsmLon(plons[i], OFFSET_X), toOsmLat(plats[i], OFFSET_Y)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectsPolygon() {
|
||||
double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0 };
|
||||
double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0 };
|
||||
double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5 };
|
||||
double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5 };
|
||||
boolean[] within = { false, false, false, true, true, true, false, true, true, true };
|
||||
double[] p0lons = {0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0};
|
||||
double[] p0lats = {0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0};
|
||||
double[] p1lons = {0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5};
|
||||
double[] p1lats = {0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5};
|
||||
boolean[] within = {false, false, false, true, true, true, false, true, true, true};
|
||||
|
||||
for (int i=0; i<p0lons.length; i++) {
|
||||
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polygon.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
|
||||
for (int i = 0; i < p0lons.length; i++) {
|
||||
assertEquals("(" + p0lons[i] + "," + p0lats[i] + ")-(" + p1lons[i] + "," + p1lats[i] + ")", within[i], polygon.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectsPolyline() {
|
||||
double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0 };
|
||||
double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0 };
|
||||
double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5 };
|
||||
double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5 };
|
||||
boolean[] within = { false, false, false, true, true, true, false, true, true, false };
|
||||
double[] p0lons = {0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0};
|
||||
double[] p0lats = {0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0};
|
||||
double[] p1lons = {0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5};
|
||||
double[] p1lats = {0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5};
|
||||
boolean[] within = {false, false, false, true, true, true, false, true, true, false};
|
||||
|
||||
for (int i=0; i<p0lons.length; i++) {
|
||||
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polyline.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
|
||||
for (int i = 0; i < p0lons.length; i++) {
|
||||
assertEquals("(" + p0lons[i] + "," + p0lats[i] + ")-(" + p1lons[i] + "," + p1lats[i] + ")", within[i], polyline.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBelongsToLine() {
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 10,20));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10,10, 20,10, 10,10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,20, 10,10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10,15, 10,10, 10,20));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(15,10, 10,10, 20,10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,30));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(20,30, 10,10, 20,30));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(15,20, 10,10, 20,30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 10,20));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 20,10));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(15,21, 10,10, 20,30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(15,19, 10,10, 20,30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(0,-10, 10,10, 20,30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(30,50, 10,10, 20,30));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 10, 20));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 20, 10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 20, 10, 10, 10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 20, 10, 10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10, 15, 10, 10, 10, 20));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(15, 10, 10, 10, 20, 10));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 20, 30));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(20, 30, 10, 10, 20, 30));
|
||||
assertTrue(OsmNogoPolygon.isOnLine(15, 20, 10, 10, 20, 30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(11, 11, 10, 10, 10, 20));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(11, 11, 10, 10, 20, 10));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(15, 21, 10, 10, 20, 30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(15, 19, 10, 10, 20, 30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(0, -10, 10, 10, 20, 30));
|
||||
assertFalse(OsmNogoPolygon.isOnLine(30, 50, 10, 10, 20, 30));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistanceWithinPolygon() {
|
||||
// Testing polygon
|
||||
final double[] lons = { 2.333523, 2.333432, 2.333833, 2.333983, 2.334815, 2.334766 };
|
||||
final double[] lats = { 48.823778, 48.824091, 48.82389, 48.824165, 48.824232, 48.82384 };
|
||||
OsmNogoPolygon polygon = new OsmNogoPolygon(true);
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
|
||||
}
|
||||
OsmNogoPolygon polyline = new OsmNogoPolygon(false);
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
polyline.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
|
||||
}
|
||||
// Testing polygon
|
||||
final double[] lons = {2.333523, 2.333432, 2.333833, 2.333983, 2.334815, 2.334766};
|
||||
final double[] lats = {48.823778, 48.824091, 48.82389, 48.824165, 48.824232, 48.82384};
|
||||
OsmNogoPolygon polygon = new OsmNogoPolygon(true);
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
|
||||
}
|
||||
OsmNogoPolygon polyline = new OsmNogoPolygon(false);
|
||||
for (int i = 0; i < lons.length; i++) {
|
||||
polyline.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
|
||||
}
|
||||
|
||||
// Check with a segment with a single intersection with the polygon
|
||||
int lon1 = toOsmLon(2.33308732509613, 0);
|
||||
int lat1 = toOsmLat(48.8238790443901, 0);
|
||||
int lon2 = toOsmLon(2.33378201723099, 0);
|
||||
int lat2 = toOsmLat(48.8239585098974, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length for a segment with a single intersection",
|
||||
17.5,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 17.5
|
||||
);
|
||||
// Check with a segment with a single intersection with the polygon
|
||||
int lon1 = toOsmLon(2.33308732509613, 0);
|
||||
int lat1 = toOsmLat(48.8238790443901, 0);
|
||||
int lon2 = toOsmLon(2.33378201723099, 0);
|
||||
int lat2 = toOsmLat(48.8239585098974, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length for a segment with a single intersection",
|
||||
17.5,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 17.5
|
||||
);
|
||||
|
||||
// Check with a segment crossing multiple times the polygon
|
||||
lon2 = toOsmLon(2.33488172292709, 0);
|
||||
lat2 = toOsmLat(48.8240891862353, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length for a segment with multiple intersections",
|
||||
85,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 85
|
||||
);
|
||||
// Check with a segment crossing multiple times the polygon
|
||||
lon2 = toOsmLon(2.33488172292709, 0);
|
||||
lat2 = toOsmLat(48.8240891862353, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length for a segment with multiple intersections",
|
||||
85,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 85
|
||||
);
|
||||
|
||||
// Check that it works when a point is within the polygon
|
||||
lon2 = toOsmLon(2.33433187007904, 0);
|
||||
lat2 = toOsmLat(48.8240238480664, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length when last point is within the polygon",
|
||||
50,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 50
|
||||
);
|
||||
lon1 = toOsmLon(2.33433187007904, 0);
|
||||
lat1 = toOsmLat(48.8240238480664, 0);
|
||||
lon2 = toOsmLon(2.33488172292709, 0);
|
||||
lat2 = toOsmLat(48.8240891862353, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length when first point is within the polygon",
|
||||
35,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 35
|
||||
);
|
||||
// Check that it works when a point is within the polygon
|
||||
lon2 = toOsmLon(2.33433187007904, 0);
|
||||
lat2 = toOsmLat(48.8240238480664, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length when last point is within the polygon",
|
||||
50,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 50
|
||||
);
|
||||
lon1 = toOsmLon(2.33433187007904, 0);
|
||||
lat1 = toOsmLat(48.8240238480664, 0);
|
||||
lon2 = toOsmLon(2.33488172292709, 0);
|
||||
lat2 = toOsmLat(48.8240891862353, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length when first point is within the polygon",
|
||||
35,
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * 35
|
||||
);
|
||||
|
||||
lon1 = toOsmLon(2.333523, 0);
|
||||
lat1 = toOsmLat(48.823778, 0);
|
||||
lon2 = toOsmLon(2.333432, 0);
|
||||
lat2 = toOsmLat(48.824091, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length if the segment overlaps with an edge of the polygon",
|
||||
CheapRuler.distance(lon1, lat1, lon2, lat2),
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
|
||||
);
|
||||
lon1 = toOsmLon(2.333523, 0);
|
||||
lat1 = toOsmLat(48.823778, 0);
|
||||
lon2 = toOsmLon(2.333432, 0);
|
||||
lat2 = toOsmLat(48.824091, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length if the segment overlaps with an edge of the polygon",
|
||||
CheapRuler.distance(lon1, lat1, lon2, lat2),
|
||||
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
|
||||
);
|
||||
|
||||
lon1 = toOsmLon(2.333523, 0);
|
||||
lat1 = toOsmLat(48.823778, 0);
|
||||
lon2 = toOsmLon(2.3334775, 0);
|
||||
lat2 = toOsmLat(48.8239345, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length if the segment overlaps with a polyline",
|
||||
CheapRuler.distance(lon1, lat1, lon2, lat2),
|
||||
polyline.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
|
||||
);
|
||||
lon1 = toOsmLon(2.333523, 0);
|
||||
lat1 = toOsmLat(48.823778, 0);
|
||||
lon2 = toOsmLon(2.3334775, 0);
|
||||
lat2 = toOsmLat(48.8239345, 0);
|
||||
assertEquals(
|
||||
"Should give the correct length if the segment overlaps with a polyline",
|
||||
CheapRuler.distance(lon1, lat1, lon2, lat2),
|
||||
polyline.distanceWithinPolygon(lon1, lat1, lon2, lat2),
|
||||
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue