voice hints update

This commit is contained in:
Arndt 2016-04-30 17:23:02 +02:00
parent ccf2eb28d3
commit 23d1812371
16 changed files with 564 additions and 102 deletions

View file

@ -16,8 +16,10 @@ final class MessageData implements Cloneable
int linkinitcost = 0;
float costfactor;
float priorityclassifier;
int priorityclassifier;
float turnangle;
int onwaydirection;
int roundaboutdirection;
String wayKeyValues;
String nodeKeyValues;
@ -72,4 +74,14 @@ final class MessageData implements Cloneable
{
return "dist=" + linkdist + " prio=" + priorityclassifier + " turn=" + turnangle;
}
public int getPrio()
{
return Math.abs( priorityclassifier );
}
public boolean isGoodForCars()
{
return priorityclassifier > 0;
}
}

View file

@ -304,7 +304,7 @@ final class OsmPath implements OsmLinkHolder
}
float fcost = dist * costfactor + 0.5f;
if ( costfactor > 9999. || fcost + cost >= 2000000000. )
if ( ( costfactor > 9999. && !detailMode ) || fcost + cost >= 2000000000. )
{
cost = -1;
return;
@ -337,7 +337,9 @@ final class OsmPath implements OsmLinkHolder
if ( recordMessageData )
{
msgData.costfactor = costfactor;
msgData.priorityclassifier = rc.expctxWay.getPriorityClassifier();
msgData.priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
msgData.onwaydirection = (int)rc.expctxWay.getOnewayDirection();
msgData.roundaboutdirection = (int)rc.expctxWay.getRoundaboutDirection();
msgData.lon = lon2;
msgData.lat = lat2;
msgData.ele = ele2;

View file

@ -45,7 +45,7 @@ public final class OsmTrack
private CompactLongMap<OsmPathElementHolder> detourMap;
private List<VoiceHint> voiceHints;
private VoiceHintList voiceHints;
public String message = null;
public ArrayList<String> messageList = null;
@ -261,9 +261,13 @@ public final class OsmTrack
if ( t.voiceHints != null )
{
for( VoiceHint hint : t.voiceHints )
if ( voiceHints == null )
{
addVoiceHint( hint );
voiceHints = t.voiceHints;
}
else
{
voiceHints.list.addAll( t.voiceHints.list );
}
}
@ -295,6 +299,7 @@ public final class OsmTrack
public String formatAsGpx()
{
StringBuilder sb = new StringBuilder( 8192 );
int turnInstructionMode = voiceHints != null ? voiceHints.turnInstructionMode : 0;
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
for ( int i = messageList.size() - 1; i >= 0; i-- )
@ -305,46 +310,107 @@ public final class OsmTrack
if ( message != null )
sb.append( "<!-- " ).append( message ).append( " -->\n" );
}
if ( turnInstructionMode == 4 ) // comment style
{
sb.append( "<!-- $transport-mode$").append( voiceHints.getTransportMode() ).append( "$ -->\n" );
sb.append( "<!-- cmd idx lon lat d2next geometry -->\n" );
sb.append( "<!-- $turn-instruction-start$\n" );
for( VoiceHint hint: voiceHints.list )
{
sb.append( String.format( " $turn$%6s;%6d;%10s;%10s;%6d;%s$\n", hint.getCommandString(), hint.indexInTrack,
formatILon( hint.ilon ), formatILat( hint.ilat ), (int)(hint.distanceToNext), hint.formatGeometry() ) );
}
sb.append( " $turn-instruction-end$ -->\n" );
}
sb.append( "<gpx \n" );
sb.append( " xmlns=\"http://www.topografix.com/GPX/1/1\" \n" );
sb.append( " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" );
sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" );
sb.append( " creator=\"BRouter-1.3.2\" version=\"1.1\">\n" );
if ( voiceHints != null )
if ( turnInstructionMode == 2 ) // locus style
{
for( VoiceHint hint: voiceHints )
sb.append( " xmlns:locus=\"http://www.locusmap.eu\" \n" );
}
sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" );
if ( turnInstructionMode == 3)
{
sb.append(" creator=\"OsmAndRouter\" version=\"1.1\">\n" );
}
else
{
sb.append( " creator=\"BRouter-1.3.2\" version=\"1.1\">\n" );
}
if ( turnInstructionMode == 3) // osmand style
{
sb.append(" <rte>\n");
for( VoiceHint hint: voiceHints.list )
{
sb.append(" <rtept lat=\"").append( formatILat( hint.ilat ) ).append( "\" lon=\"" )
.append( formatILon( hint.ilon ) ).append( "\">\n" )
.append ( " <desc>" ).append( hint.getMessageString() ).append( "</desc>\n <extensions>\n <turn>" )
.append( hint.getCommandString() ).append("</turn>\n <turn-angle>").append( hint.angle )
.append("</turn-angle>\n <offset>").append( hint.indexInTrack ).append("</offset>\n </extensions>\n </rtept>\n");
}
sb.append("</rte>\n");
}
if ( turnInstructionMode == 2 ) // locus style
{
for( VoiceHint hint: voiceHints.list )
{
sb.append( " <wpt lon=\"" ).append( formatILon( hint.ilon ) ).append( "\" lat=\"" )
.append( formatILat( hint.ilat ) ).append( "\">" )
.append( "<name>" ).append( hint.message ).append( "</name>" );
if ( hint.turnInstructionMode == 2 )
{
sb.append( "<extensions><locus:rteDistance>" ).append( hint.distanceToNext ).append( "</locus:rteDistance>" )
.append( "<locus:rtePointAction>" ).append( hint.locusAction ).append( "</locus:rtePointAction></extensions>" );
}
else
{
sb.append( "<sym>" ).append( hint.symbol.toLowerCase() ).append( "</sym>" )
.append( "<type>" ).append( hint.symbol ).append( "</type>" );
}
sb.append( "</wpt>\n" );
.append( "<name>" ).append( hint.getMessageString() ).append( "</name>" )
.append( "<extensions><locus:rteDistance>" ).append( hint.distanceToNext ).append( "</locus:rteDistance>" )
.append( "<locus:rtePointAction>" ).append( hint.getLocusAction() ).append( "</locus:rtePointAction></extensions>" )
.append( "</wpt>\n" );
}
}
if ( turnInstructionMode == 5 ) // gpsies style
{
for( VoiceHint hint: voiceHints.list )
{
sb.append( " <wpt lon=\"" ).append( formatILon( hint.ilon ) ).append( "\" lat=\"" )
.append( formatILat( hint.ilat ) ).append( "\">" )
.append( "<name>" ).append( hint.getMessageString() ).append( "</name>" )
.append( "<sym>" ).append( hint.getSymbolString().toLowerCase() ).append( "</sym>" )
.append( "<type>" ).append( hint.getSymbolString() ).append( "</type>" )
.append( "</wpt>\n" );
}
}
sb.append( " <trk>\n" );
sb.append( " <name>" ).append( name ).append( "</name>\n" );
if ( voiceHints != null && voiceHints.size() > 0 && voiceHints.get(0).turnInstructionMode == 2 )
if ( turnInstructionMode == 1 ) // trkpt/sym style
{
sb.append( " <extensions><locus:rteComputeType>" ).append( voiceHints.get(0).locusRouteType ).append( "</locus:rteComputeType></extensions>\n" );
sb.append( " <type>" ).append( voiceHints.getTransportMode() ).append( "</type>\n" );
}
if ( turnInstructionMode == 2 )
{
int routeType = voiceHints.getLocusRouteType();
if ( routeType != 4 ) // 4 = car = default seems to work better as default
{
sb.append( " <extensions><locus:rteComputeType>" ).append( voiceHints.getLocusRouteType() ).append( "</locus:rteComputeType></extensions>\n" );
}
}
sb.append( " <trkseg>\n" );
for ( OsmPathElement n : nodes )
for ( int idx = 0; idx < nodes.size(); idx++ )
{
OsmPathElement n = nodes.get(idx);
String sele = n.getSElev() == Short.MIN_VALUE ? "" : "<ele>" + n.getElev() + "</ele>";
if ( turnInstructionMode == 1 ) // trkpt/sym style
{
for ( VoiceHint hint : voiceHints.list )
{
if ( hint.indexInTrack == idx )
{
sele += "<sym>" + hint.getCommandString() + "</sym>";
}
}
}
sb.append( " <trkpt lon=\"" ).append( formatILon( n.getILon() ) ).append( "\" lat=\"" )
.append( formatILat( n.getILat() ) ).append( "\">" ).append( sele ).append( "</trkpt>\n" );
}
@ -568,22 +634,18 @@ public final class OsmTrack
return true;
}
private void addVoiceHint( VoiceHint hint )
{
if ( voiceHints == null )
{
voiceHints = new ArrayList<VoiceHint>();
}
voiceHints.add( hint );
}
public void processVoiceHints( RoutingContext rc )
{
voiceHints = new VoiceHintList();
voiceHints.setTransportMode( rc.carMode );
voiceHints.turnInstructionMode = rc.turnInstructionMode;
if ( detourMap == null )
{
return;
}
OsmPathElement node = nodes.get( nodes.size() - 1 );
int nodeNr = nodes.size() - 1;
OsmPathElement node = nodes.get( nodeNr );
List<VoiceHint> inputs = new ArrayList<VoiceHint>();
while (node != null)
{
@ -593,9 +655,9 @@ public final class OsmTrack
inputs.add( input );
input.ilat = node.origin.getILat();
input.ilon = node.origin.getILon();
input.locusRouteType = rc.carMode ? 4 : 5;
input.turnInstructionMode = rc.turnInstructionMode;
input.indexInTrack = --nodeNr;
input.goodWay = node.message;
input.oldWay = node.origin.message;
OsmPathElementHolder detours = detourMap.get( node.origin.getIdFromPos() );
if ( detours != null )
@ -613,9 +675,9 @@ public final class OsmTrack
}
List<VoiceHint> results = VoiceHintProcessor.process( inputs );
for( int i=results.size()-1; i >= 0; i-- )
for( VoiceHint hint : results )
{
addVoiceHint( results.get(i) );
voiceHints.list.add( hint );
}
}

View file

@ -96,7 +96,11 @@ public final class RoutingContext implements DistanceChecker
trafficSourceExponent = expctxGlobal.getVariableValue( "trafficSourceExponent", -0.7f );
trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.f );
turnInstructionMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f );
int tiMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f );
if ( tiMode != 1 ) // automatic selection from coordinate source
{
turnInstructionMode = tiMode;
}
}
public RoutingMessageHandler messageHandler = new RoutingMessageHandler();
@ -125,7 +129,7 @@ public final class RoutingContext implements DistanceChecker
public double trafficSourceExponent;
public double trafficSourceMinDist;
public int turnInstructionMode; // 0=none, 1=osmand, 2=locus
public int turnInstructionMode; // 0=none, 1=auto, 2=locus, 3=osmand, 4=comment-style, 5=gpsies-style
public static void prepareNogoPoints( List<OsmNodeNamed> nogos )
{

View file

@ -11,16 +11,40 @@ import java.util.List;
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
static final int TSHL = 4; // turn sharply left
static final int TR = 5; // turn right
static final int TSLR = 6; // turn slightly right
static final int TSHR = 7; // turn sharply right
static final int KL = 8; // keep left
static final int KR = 9; // keep right
static final int TU = 10; // U-turn
static final int TRU = 11; // Right U-turn
static final int OFFR = 12; // Off route
static final int RNDB = 13; // Roundabout
static final int RNLB = 14; // Roundabout left
int ilon;
int ilat;
String message;
String symbol;
int locusAction;
int cmd;
MessageData oldWay;
MessageData goodWay;
List<MessageData> badWays;
double distanceToNext;
int locusRouteType;
int turnInstructionMode;
int indexInTrack;
float angle;
boolean turnAngleConsumed;
boolean needsRealTurn;
int roundaboutExit;
boolean isRoundabout()
{
return roundaboutExit != 0;
}
public void addBadWay( MessageData badWay )
{
@ -34,58 +58,168 @@ public class VoiceHint
}
badWays.add( badWay );
}
public boolean setTurnAngle( float angle )
public String getCommandString()
{
if ( angle < -165. || angle > 165. )
switch ( cmd )
{
symbol = "TU";
message = "u-turn";
locusAction = 12;
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 );
}
else if ( angle < -115. )
}
public String getSymbolString()
{
switch ( cmd )
{
symbol = "TSHL";
message = "sharp left";
locusAction = 5;
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 );
}
else if ( angle < -65. )
}
public String getMessageString()
{
switch ( cmd )
{
symbol = "Left";
message = "left";
locusAction = 4;
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 );
}
else if ( angle < -15. )
}
public int getLocusAction()
{
switch ( cmd )
{
symbol = "TSLL";
message = "slight left";
locusAction = 3;
case TU : return 12;
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 12;
case RNDB : return 26 + roundaboutExit;
case RNLB : return 26 - roundaboutExit;
default : throw new IllegalArgumentException( "unknown command: " + cmd );
}
else if ( angle < 15. )
}
public void calcCommand()
{
if (roundaboutExit > 0)
{
symbol = "Straight";
message = "straight";
locusAction = 1;
return false;
cmd = RNDB;
}
else if ( angle < 65. )
else if (roundaboutExit < 0)
{
symbol = "TSLR";
message = "slight right";
locusAction = 6;
cmd = RNLB;
}
else if ( angle < 115. )
else if ( angle < -159. )
{
symbol = "Right";
message = "right";
locusAction = 7;
cmd = TU;
}
else if ( angle < -113. )
{
cmd = TSHL;
}
else if ( angle < -67. )
{
cmd = TL;
}
else if ( angle < -21. )
{
if ( cmd != KR ) // don't overwrite KR with TSLL
{
cmd = TSLL;
}
}
else if ( angle < 21. )
{
if ( cmd != KR && cmd != KL ) // don't overwrite KL/KR hints!
{
cmd = C;
}
}
else if ( angle < 67. )
{
if ( cmd != KL ) // don't overwrite KL with TSLR
{
cmd = TSLR;
}
}
else if ( angle < 113. )
{
cmd = TR;
}
else if ( angle < 159. )
{
cmd = TSHR;
}
else
{
symbol = "TSHR";
message = "sharp right";
locusAction = 8;
cmd = TRU;
}
return true;
}
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 );
}
}
return sb.toString();
}
private void appendTurnGeometry( StringBuilder sb, MessageData msg )
{
sb.append( "(" ).append( (int)(msg.turnangle+0.5) ).append( ")" ).append( (int)(msg.priorityclassifier) );
}
}

View file

@ -0,0 +1,40 @@
/**
* Container for a voice hint
* (both input- and result data for voice hint processing)
*
* @author ab
*/
package btools.router;
import java.util.ArrayList;
import java.util.List;
public class VoiceHintList
{
private String transportMode;
int turnInstructionMode;
ArrayList<VoiceHint> list = new ArrayList<VoiceHint>();
public void setTransportMode( boolean isCar )
{
transportMode = isCar ? "car" : "bike";
}
public String getTransportMode()
{
return transportMode;
}
public int getLocusRouteType()
{
if ( "car".equals( transportMode ) )
{
return 4;
}
if ( "bike".equals( transportMode ) )
{
return 5;
}
return 5; // ??
}
}

View file

@ -10,39 +10,201 @@ import java.util.List;
public final class VoiceHintProcessor
{
private static float sumNonConsumedWithin40( List<VoiceHint> inputs, int offset )
{
double distance = 0.;
float angle = 0.f;
while( offset >= 0 && distance < 40. )
{
VoiceHint input = inputs.get( offset-- );
if ( input.turnAngleConsumed )
{
break;
}
angle += input.goodWay.turnangle;
distance += input.goodWay.linkdist;
input.turnAngleConsumed = true;
}
return angle;
}
public static List<VoiceHint> process( List<VoiceHint> inputs )
{
List<VoiceHint> results = new ArrayList<VoiceHint>();
double distance = 0.;
for ( VoiceHint input : inputs )
float roundAboutTurnAngle = 0.f; // sums up angles in roundabout
int roundaboutExit = 0;
for ( int hintIdx = 0; hintIdx < inputs.size(); hintIdx++ )
{
// System.out.println( "***** processing: " + input.ilat + " " + input.ilon + " goodWay=" + input.goodWay );
VoiceHint input = inputs.get( hintIdx );
float turnAngle = input.goodWay.turnangle;
distance += input.goodWay.linkdist;
if ( input.badWays != null )
int currentPrio = input.goodWay.getPrio();
int oldPrio = input.oldWay == null ? currentPrio : input.oldWay.getPrio();
int minPrio = Math.min( oldPrio, currentPrio );
// odd priorities are link-types
boolean isLink2Highway = ( ( oldPrio & 1 ) == 1 ) && ( ( currentPrio & 1 ) == 0 );
boolean inRoundabout = input.oldWay != null && input.oldWay.roundaboutdirection != 0;
if ( inRoundabout )
{
float maxprio = 0.f;
for ( MessageData badWay : input.badWays )
roundAboutTurnAngle += sumNonConsumedWithin40( inputs, hintIdx );
boolean isExit = roundaboutExit == 0; // exit point is always exit
if ( input.badWays != null )
{
// System.out.println( " --> badWay: " + badWay );
if ( badWay.priorityclassifier > maxprio )
for ( MessageData badWay : input.badWays )
{
maxprio = badWay.priorityclassifier;
if ( badWay.onwaydirection >= 0 && badWay.isGoodForCars() && Math.abs( badWay.turnangle ) < 120. )
{
isExit = true;
}
}
}
if ( maxprio > 0. && maxprio >= input.goodWay.priorityclassifier )
if ( isExit )
{
boolean isTurn = input.setTurnAngle( input.goodWay.turnangle );
if ( isTurn || input.goodWay.priorityclassifier < maxprio )
roundaboutExit++;
}
continue;
}
if ( roundaboutExit > 0 )
{
roundAboutTurnAngle += sumNonConsumedWithin40( inputs, hintIdx );
input.angle = roundAboutTurnAngle;
input.distanceToNext = distance;
input.roundaboutExit = turnAngle < 0 ? -roundaboutExit : roundaboutExit;
distance = 0.;
results.add( input );
roundAboutTurnAngle = 0.f;
roundaboutExit = 0;
continue;
}
int maxPrioAll = -1; // max prio of all detours
int maxPrioCandidates = -1; // max prio of real candidates
float maxAngle = -180.f;
float minAngle = 180.f;
if ( input.badWays != null )
{
for ( MessageData badWay : input.badWays )
{
int badPrio = badWay.getPrio();
boolean badOneway = badWay.onwaydirection < 0;
boolean isHighway2Link = ( ( badPrio & 1 ) == 1 ) && ( ( currentPrio & 1 ) == 0 );
if ( badPrio > maxPrioAll && !isHighway2Link )
{
input.distanceToNext = distance;
distance = 0.;
results.add( input );
maxPrioAll = badPrio;
}
if ( badPrio < minPrio )
{
continue; // ignore low prio ways
}
if ( badOneway )
{
continue; // ignore wrong oneways
}
float badTurn = badWay.turnangle;
if ( Math.abs( badTurn ) - Math.abs( turnAngle ) > 80.f )
{
continue; // ways from the back should not trigger a slight turn
}
if ( badPrio > maxPrioCandidates )
{
maxPrioCandidates = badPrio;
}
if ( badTurn > maxAngle )
{
maxAngle = badTurn;
}
if ( badTurn < minAngle )
{
minAngle = badTurn;
}
}
}
// 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 = ( 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 )
{
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 ) )
{
input.cmd = VoiceHint.KR;
}
if ( minAngle > turnAngle && minAngle < turnAngle + 45.f - (turnAngle < 0.f ? turnAngle : 0.f ) )
{
input.cmd = VoiceHint.KL;
}
input.angle = sumNonConsumedWithin40( inputs, hintIdx );
input.distanceToNext = distance;
distance = 0.;
results.add( input );
}
if ( results.size() > 0 && distance < 40. )
{
results.get( results.size()-1 ).angle += sumNonConsumedWithin40( inputs, hintIdx );
}
}
return results;
// go through the hint list again in reverse order (=travel direction)
// and filter out non-signficant hints and hints too close to it's predecessor
List<VoiceHint> results2 = new ArrayList<VoiceHint>();
int i = results.size();
while( i > 0 )
{
VoiceHint hint = results.get(--i);
if ( hint.cmd == 0 )
{
hint.calcCommand();
}
if ( ! ( hint.needsRealTurn && hint.cmd == VoiceHint.C ) )
{
double dist = hint.distanceToNext;
// sum up other hints within 40m
while( dist < 40. && i > 0 )
{
VoiceHint h2 = results.get(i-1);
dist = h2.distanceToNext;
hint.distanceToNext+= dist;
hint.angle += h2.angle;
i--;
if ( h2.isRoundabout() ) // if we hit a roundabout, use that as the trigger
{
h2.angle = hint.angle;
hint = h2;
break;
}
}
hint.calcCommand();
results2.add( hint );
}
}
return results2;
}
}

View file

@ -13,7 +13,7 @@ import btools.codec.TagValueValidator;
public final class BExpressionContextWay extends BExpressionContext implements TagValueValidator
{
private static String[] buildInVariables =
{ "costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier" };
{ "costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "onewaydirection", "roundaboutdirection"};
protected String[] getBuildInVariableNames()
{
@ -30,7 +30,8 @@ public final class BExpressionContextWay extends BExpressionContext implements T
public float getTrafficSourceDensity() { return getBuildInVariable(7); }
public float getIsTrafficBackbone() { return getBuildInVariable(8); }
public float getPriorityClassifier() { return getBuildInVariable(9); }
public float getOnewayDirection() { return getBuildInVariable(10); }
public float getRoundaboutDirection() { return getBuildInVariable(11); }
public BExpressionContextWay( BExpressionMetaData meta )
{

View file

@ -347,7 +347,11 @@ public class BRouterView extends View
{
if ( wp.ilat != 0 || wp.ilat != 0 )
{
wpList.add( wp );
int nwp = wpList.size();
if ( nwp == 0 || wpList.get( nwp-1 ) != wp )
{
wpList.add( wp );
}
}
return;
}
@ -405,6 +409,7 @@ public class BRouterView extends View
RoutingContext rc = new RoutingContext();
rc.localFunction = profilePath;
rc.turnInstructionMode = cor.getTurnInstructionMode();
int plain_distance = 0;
int maxlon = Integer.MIN_VALUE;

View file

@ -41,6 +41,19 @@ public class BRouterWorker
RoutingContext rc = new RoutingContext();
rc.rawTrackPath = rawTrackPath;
rc.localFunction = profilePath;
String tiFormat = params.getString( "turnInstructionFormat" );
if ( tiFormat != null )
{
if ( "osmand".equalsIgnoreCase( tiFormat ) )
{
rc.turnInstructionMode = 3;
}
else if ( "locus".equalsIgnoreCase( tiFormat ) )
{
rc.turnInstructionMode = 2;
}
}
if ( nogoList != null )
{
rc.prepareNogoPoints( nogoList );

View file

@ -40,6 +40,8 @@ public abstract class CoordinateReader
public abstract long getTimeStamp() throws Exception;
public abstract int getTurnInstructionMode();
public void readAllPoints() throws Exception
{
allpointsMap = new TreeMap<String, Map<String,OsmNodeNamed>>();

View file

@ -25,6 +25,12 @@ public class CoordinateReaderLocus extends CoordinateReader
return t1;
}
@Override
public int getTurnInstructionMode()
{
return 2; // locus style
}
/*
* read the from and to position from a ggx-file
* (with hardcoded name for now)

View file

@ -18,6 +18,12 @@ public class CoordinateReaderNone extends CoordinateReader
return 0L;
}
@Override
public int getTurnInstructionMode()
{
return 0; // none
}
@Override
public void readPointmap() throws Exception
{

View file

@ -25,6 +25,12 @@ public class CoordinateReaderOrux extends CoordinateReader
return t1;
}
@Override
public int getTurnInstructionMode()
{
return 0; // none
}
/*
* read the from and to position from a ggx-file
* (with hardcoded name for now)

View file

@ -44,6 +44,12 @@ public class CoordinateReaderOsmAnd extends CoordinateReader
return t1 > t2 ? t1 : t2;
}
@Override
public int getTurnInstructionMode()
{
return 3; // osmand style
}
/*
* read the from and to position from a gpx-file
* (with hardcoded name for now)

View file

@ -8,6 +8,7 @@ interface IBRouterService {
// "pathToFileResult"-->String with the path to where the result must be saved, including file name and extension
// -->if null, the track is passed via the return argument
// "maxRunningTime"-->String with a number of seconds for the routing timeout, default = 60
// "turnInstructionFormat"-->String selecting the format for turn-instructions values: osmand, locus
// "trackFormat"-->[kml|gpx] default = gpx
// "lats"-->double[] array of latitudes; 2 values at least.
// "lons"-->double[] array of longitudes; 2 values at least.