/**
* Container for routig configs
*
* @author ab
*/
package btools.router;
import java.io.DataOutput;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import btools.expressions.BExpressionContext;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.mapaccess.GeometryDecoder;
public final class RoutingContext
{
public void setAlternativeIdx( int idx )
{
alternativeIdx = idx;
}
public int getAlternativeIdx(int min, int max)
{
return alternativeIdx < min ? min : (alternativeIdx > max ? max : alternativeIdx);
}
public int alternativeIdx = 0;
public String localFunction;
public long profileTimestamp;
public String rawTrackPath;
public String getProfileName()
{
String name = localFunction == null ? "unknown" : localFunction;
if ( name.endsWith( ".brf" ) ) name = name.substring( 0, localFunction.length() - 4 );
int idx = name.lastIndexOf( File.separatorChar );
if ( idx >= 0 ) name = name.substring( idx+1 );
return name;
}
public BExpressionContextWay expctxWay;
public BExpressionContextNode expctxNode;
public GeometryDecoder geometryDecoder = new GeometryDecoder();
public int memoryclass = 64;
public int downhillcostdiv;
public int downhillcutoff;
public int uphillcostdiv;
public int uphillcutoff;
public boolean carMode;
public boolean bikeMode;
public boolean considerTurnRestrictions;
public boolean processUnusedTags;
public boolean forceSecondaryData;
public double pass1coefficient;
public double pass2coefficient;
public int elevationpenaltybuffer;
public int elevationmaxbuffer;
public int elevationbufferreduce;
public double cost1speed;
public double additionalcostfactor;
public double changetime;
public double buffertime;
public double waittimeadjustment;
public double inittimeadjustment;
public double starttimeoffset;
public boolean transitonly;
public void readGlobalConfig( BExpressionContext expctxGlobal )
{
downhillcostdiv = (int)expctxGlobal.getVariableValue( "downhillcost", 0.f );
downhillcutoff = (int)(expctxGlobal.getVariableValue( "downhillcutoff", 0.f )*10000);
uphillcostdiv = (int)expctxGlobal.getVariableValue( "uphillcost", 0.f );
uphillcutoff = (int)(expctxGlobal.getVariableValue( "uphillcutoff", 0.f )*10000);
if ( downhillcostdiv != 0 ) downhillcostdiv = 1000000/downhillcostdiv;
if ( uphillcostdiv != 0 ) uphillcostdiv = 1000000/uphillcostdiv;
carMode = 0.f != expctxGlobal.getVariableValue( "validForCars", 0.f );
bikeMode = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f );
// turn-restrictions used per default for car profiles
considerTurnRestrictions = 0.f != expctxGlobal.getVariableValue( "considerTurnRestrictions", carMode ? 1.f : 0.f );
// process tags not used in the profile (to have them in the data-tab)
processUnusedTags = 0.f != expctxGlobal.getVariableValue( "processUnusedTags", 0.f );
forceSecondaryData = 0.f != expctxGlobal.getVariableValue( "forceSecondaryData", 0.f );
pass1coefficient = expctxGlobal.getVariableValue( "pass1coefficient", 1.5f );
pass2coefficient = expctxGlobal.getVariableValue( "pass2coefficient", 0.f );
elevationpenaltybuffer = (int)(expctxGlobal.getVariableValue( "elevationpenaltybuffer", 5.f )*1000000);
elevationmaxbuffer = (int)(expctxGlobal.getVariableValue( "elevationmaxbuffer", 10.f )*1000000);
elevationbufferreduce = (int)(expctxGlobal.getVariableValue( "elevationbufferreduce", 0.f )*10000);
cost1speed = expctxGlobal.getVariableValue( "cost1speed", 22.f );
additionalcostfactor = expctxGlobal.getVariableValue( "additionalcostfactor", 1.5f );
changetime = expctxGlobal.getVariableValue( "changetime", 180.f );
buffertime = expctxGlobal.getVariableValue( "buffertime", 120.f );
waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f );
inittimeadjustment = expctxGlobal.getVariableValue( "inittimeadjustment", 0.2f );
starttimeoffset = expctxGlobal.getVariableValue( "starttimeoffset", 0.f );
transitonly = expctxGlobal.getVariableValue( "transitonly", 0.f ) != 0.f;
farTrafficWeight = expctxGlobal.getVariableValue( "farTrafficWeight", 2.f );
nearTrafficWeight = expctxGlobal.getVariableValue( "nearTrafficWeight", 2.f );
farTrafficDecayLength = expctxGlobal.getVariableValue( "farTrafficDecayLength", 30000.f );
nearTrafficDecayLength = expctxGlobal.getVariableValue( "nearTrafficDecayLength", 3000.f );
trafficDirectionFactor = expctxGlobal.getVariableValue( "trafficDirectionFactor", 0.9f );
trafficSourceExponent = expctxGlobal.getVariableValue( "trafficSourceExponent", -0.7f );
trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.f );
int tiMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f );
if ( tiMode != 1 ) // automatic selection from coordinate source
{
turnInstructionMode = tiMode;
}
turnInstructionCatchingRange = expctxGlobal.getVariableValue( "turnInstructionCatchingRange", 40.f );
turnInstructionRoundabouts = expctxGlobal.getVariableValue( "turnInstructionRoundabouts", 1.f ) != 0.f;
}
public List<OsmNodeNamed> nogopoints = null;
private List<OsmNodeNamed> keepnogopoints = null;
public Integer startDirection;
public boolean startDirectionValid;
private double coslat;
public boolean nogomatch = false;
public boolean isEndpoint = false;
public boolean shortestmatch = false;
public double wayfraction;
public int ilatshortest;
public int ilonshortest;
public boolean countTraffic;
public boolean inverseDirection;
public DataOutput trafficOutputStream;
public double farTrafficWeight;
public double nearTrafficWeight;
public double farTrafficDecayLength;
public double nearTrafficDecayLength;
public double trafficDirectionFactor;
public double trafficSourceExponent;
public double trafficSourceMinDist;
public int turnInstructionMode; // 0=none, 1=auto, 2=locus, 3=osmand, 4=comment-style, 5=gpsies-style
public double turnInstructionCatchingRange;
public boolean turnInstructionRoundabouts;
public static void prepareNogoPoints( List<OsmNodeNamed> nogos )
{
for( OsmNodeNamed nogo : nogos )
{
String s = nogo.name;
int idx = s.indexOf( ' ' );
if ( idx > 0 ) s = s.substring( 0 , idx );
int ir = 20; // default radius
if ( s.length() > 4 )
{
try { ir = Integer.parseInt( s.substring( 4 ) ); }
catch( Exception e ) { /* ignore */ }
}
nogo.radius = ir / 111894.; // 6378000. / 57.;
}
}
public void cleanNogolist( List<OsmNodeNamed> waypoints )
{
if ( nogopoints == null ) return;
List<OsmNodeNamed> nogos = new ArrayList<OsmNodeNamed>();
for( OsmNodeNamed nogo : nogopoints )
{
int radiusInMeter = (int)(nogo.radius * 111894.);
boolean goodGuy = true;
for( OsmNodeNamed wp : waypoints )
{
if ( wp.calcDistance( nogo ) < radiusInMeter )
{
goodGuy = false;
break;
}
}
if ( goodGuy ) nogos.add( nogo );
}
nogopoints = nogos.isEmpty() ? null : nogos;
}
public long[] getNogoChecksums()
{
long[] cs = new long[3];
int n = nogopoints == null ? 0 : nogopoints.size();
for( int i=0; i<n; i++ )
{
OsmNodeNamed nogo = nogopoints.get(i);
cs[0] += nogo.ilon;
cs[1] += nogo.ilat;
cs[2] += (long) ( nogo.radius*111894.*10.);
}
return cs;
}
public void setWaypoint( OsmNodeNamed wp, boolean endpoint )
{
keepnogopoints = nogopoints;
nogopoints = new ArrayList<OsmNodeNamed>();
nogopoints.add( wp );
if ( keepnogopoints != null ) nogopoints.addAll( keepnogopoints );
isEndpoint = endpoint;
}
public void unsetWaypoint()
{
nogopoints = keepnogopoints;
isEndpoint = false;
}
public int calcDistance( int lon1, int lat1, int lon2, int lat2 )
{
double l = (lat2 - 90000000) * 0.00000001234134;
double l2 = l*l;
double l4 = l2*l2;
coslat = 1.- l2 + l4 / 6.;
double coslat6 = coslat*0.000001;
double dx = (lon2 - lon1 ) * coslat6;
double dy = (lat2 - lat1 ) * 0.000001;
double d = Math.sqrt( dy*dy + dx*dx );
shortestmatch = false;
if ( nogopoints != null && !nogopoints.isEmpty() && d > 0. )
{
for( int ngidx = 0; ngidx < nogopoints.size(); ngidx++ )
{
OsmNodeNamed nogo = nogopoints.get(ngidx);
double x1 = (lon1 - nogo.ilon) * coslat6;
double y1 = (lat1 - nogo.ilat) * 0.000001;
double x2 = (lon2 - nogo.ilon) * coslat6;
double y2 = (lat2 - nogo.ilat) * 0.000001;
double r12 = x1*x1 + y1*y1;
double r22 = x2*x2 + y2*y2;
double radius = Math.abs( r12 < r22 ? y1*dx - x1*dy : y2*dx - x2*dy ) / d;
if ( radius < nogo.radius ) // 20m
{
double s1 = x1*dx + y1*dy;
double s2 = x2*dx + y2*dy;
if ( s1 < 0. ) { s1 = -s1; s2 = -s2; }
if ( s2 > 0. )
{
radius = Math.sqrt( s1 < s2 ? r12 : r22 );
if ( radius > nogo.radius ) continue; // 20m ^ 2
}
if ( nogo.isNogo ) nogomatch = true;
else
{
shortestmatch = true;
nogo.radius = radius; // shortest distance to way
// calculate remaining distance
if ( s2 < 0. )
{
wayfraction = -s2 / (d*d);
double xm = x2 - wayfraction*dx;
double ym = y2 - wayfraction*dy;
ilonshortest = (int)(xm / coslat6 + nogo.ilon);
ilatshortest = (int)(ym / 0.000001 + nogo.ilat);
}
else if ( s1 > s2 )
{
wayfraction = 0.;
ilonshortest = lon2;
ilatshortest = lat2;
}
else
{
wayfraction = 1.;
ilonshortest = lon1;
ilatshortest = lat1;
}
// here it gets nasty: there can be nogo-points in the list
// *after* the shortest distance point. In case of a shortest-match
// we use the reduced way segment for nogo-matching, in order not
// to cut our escape-way if we placed a nogo just in front of where we are
if ( isEndpoint )
{
wayfraction = 1. - wayfraction;
lon2 = ilonshortest;
lat2 = ilatshortest;
}
else
{
nogomatch = false;
lon1 = ilonshortest;
lat1 = ilatshortest;
}
dx = (lon2 - lon1 ) * coslat6;
dy = (lat2 - lat1 ) * 0.000001;
d = Math.sqrt( dy*dy + dx*dx );
}
}
}
}
double dd = d * 111894.7368; // 6378000. / 57.;
return (int)(dd + 1.0 );
}
// assumes that calcDistance/calcCosAngle called in sequence, so coslat valid
public double calcCosAngle( int lon0, int lat0, int lon1, int lat1, int lon2, int lat2 )
{
double dlat1 = (lat1 - lat0);
double dlon1 = (lon1 - lon0) * coslat;
double dlat2 = (lat2 - lat1);
double dlon2 = (lon2 - lon1) * coslat;
double dd = Math.sqrt( (dlat1*dlat1 + dlon1*dlon1)*(dlat2*dlat2 + dlon2*dlon2) );
if ( dd == 0. ) return 0.;
double cosp = (dlat1*dlat2 + dlon1*dlon2)/dd;
return 1.-cosp; // don't care to really do acos..
}
public double calcAngle( int lon0, int lat0, int lon1, int lat1, int lon2, int lat2 )
{
double dlat1 = (lat1 - lat0);
double dlon1 = (lon1 - lon0) * coslat;
double dlat2 = (lat2 - lat1);
double dlon2 = (lon2 - lon1) * coslat;
double dd = Math.sqrt( (dlat1*dlat1 + dlon1*dlon1)*(dlat2*dlat2 + dlon2*dlon2) );
if ( dd == 0. ) return 0.;
double sinp = (dlat1*dlon2 - dlon1*dlat2)/dd;
double cosp = (dlat1*dlat2 + dlon1*dlon2)/dd;
double p;
if ( sinp > -0.7 && sinp < 0.7 )
{
p = Math.asin( sinp )*57.3;
if ( cosp < 0. )
{
p = 180. - p;
}
}
else
{
p = Math.acos( cosp )*57.3;
if ( sinp < 0. )
{
p = - p;
}
}
if ( p > 180. )
{
p -= 360.;
}
return p;
}
}