voice hints update
This commit is contained in:
parent
ccf2eb28d3
commit
23d1812371
16 changed files with 564 additions and 102 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" );
|
||||
if ( turnInstructionMode == 2 ) // locus style
|
||||
{
|
||||
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" );
|
||||
sb.append( " creator=\"BRouter-1.3.2\" version=\"1.1\">\n" );
|
||||
|
||||
if ( voiceHints != null )
|
||||
if ( turnInstructionMode == 3)
|
||||
{
|
||||
for( VoiceHint hint: voiceHints )
|
||||
{
|
||||
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>" );
|
||||
sb.append(" creator=\"OsmAndRouter\" version=\"1.1\">\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "<sym>" ).append( hint.symbol.toLowerCase() ).append( "</sym>" )
|
||||
.append( "<type>" ).append( hint.symbol ).append( "</type>" );
|
||||
}
|
||||
sb.append( "</wpt>\n" );
|
||||
}
|
||||
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.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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
@ -35,57 +59,167 @@ 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. )
|
||||
{
|
||||
symbol = "TSHL";
|
||||
message = "sharp left";
|
||||
locusAction = 5;
|
||||
}
|
||||
else if ( angle < -65. )
|
||||
|
||||
public String getSymbolString()
|
||||
{
|
||||
symbol = "Left";
|
||||
message = "left";
|
||||
locusAction = 4;
|
||||
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 );
|
||||
}
|
||||
else if ( angle < -15. )
|
||||
{
|
||||
symbol = "TSLL";
|
||||
message = "slight left";
|
||||
locusAction = 3;
|
||||
}
|
||||
else if ( angle < 15. )
|
||||
|
||||
public String getMessageString()
|
||||
{
|
||||
symbol = "Straight";
|
||||
message = "straight";
|
||||
locusAction = 1;
|
||||
return false;
|
||||
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 );
|
||||
}
|
||||
else if ( angle < 65. )
|
||||
{
|
||||
symbol = "TSLR";
|
||||
message = "slight right";
|
||||
locusAction = 6;
|
||||
}
|
||||
else if ( angle < 115. )
|
||||
|
||||
public int getLocusAction()
|
||||
{
|
||||
symbol = "Right";
|
||||
message = "right";
|
||||
locusAction = 7;
|
||||
switch ( cmd )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
public void calcCommand()
|
||||
{
|
||||
if (roundaboutExit > 0)
|
||||
{
|
||||
cmd = RNDB;
|
||||
}
|
||||
else if (roundaboutExit < 0)
|
||||
{
|
||||
cmd = RNLB;
|
||||
}
|
||||
else if ( angle < -159. )
|
||||
{
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
cmd = TRU;
|
||||
}
|
||||
}
|
||||
|
||||
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) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
40
brouter-core/src/main/java/btools/router/VoiceHintList.java
Normal file
40
brouter-core/src/main/java/btools/router/VoiceHintList.java
Normal 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; // ??
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
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 )
|
||||
{
|
||||
roundAboutTurnAngle += sumNonConsumedWithin40( inputs, hintIdx );
|
||||
boolean isExit = roundaboutExit == 0; // exit point is always exit
|
||||
if ( input.badWays != null )
|
||||
{
|
||||
float maxprio = 0.f;
|
||||
for ( MessageData badWay : input.badWays )
|
||||
{
|
||||
// System.out.println( " --> badWay: " + badWay );
|
||||
if ( badWay.priorityclassifier > maxprio )
|
||||
if ( badWay.onwaydirection >= 0 && badWay.isGoodForCars() && Math.abs( badWay.turnangle ) < 120. )
|
||||
{
|
||||
maxprio = badWay.priorityclassifier;
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
return results;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -346,9 +346,13 @@ public class BRouterView extends View
|
|||
if ( wp.name.equals( waypoint ) )
|
||||
{
|
||||
if ( wp.ilat != 0 || wp.ilat != 0 )
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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>>();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -18,6 +18,12 @@ public class CoordinateReaderNone extends CoordinateReader
|
|||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTurnInstructionMode()
|
||||
{
|
||||
return 0; // none
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readPointmap() throws Exception
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue