/**
* 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 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;
short selev;
int cmd;
MessageData oldWay;
MessageData goodWay;
List<MessageData> badWays;
double distanceToNext;
int indexInTrack;
float angle;
boolean turnAngleConsumed;
boolean needsRealTurn;
int roundaboutExit;
boolean isRoundabout()
{
return roundaboutExit != 0;
}
public void addBadWay( MessageData badWay )
{
if ( badWay == null )
{
return;
}
if ( badWays == null )
{
badWays = new ArrayList<MessageData>();
}
badWays.add( badWay );
}
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 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 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()
{
float lowerBadWayAngle = -181;
float higherBadWayAngle = 181;
if ( badWays != null )
{
for ( MessageData badWay : badWays )
{
if ( badWay.isBadOneway() )
{
continue;
}
if ( lowerBadWayAngle < badWay.turnangle && badWay.turnangle < goodWay.turnangle )
{
lowerBadWayAngle = badWay.turnangle;
}
if ( higherBadWayAngle > badWay.turnangle && badWay.turnangle > goodWay.turnangle )
{
higherBadWayAngle = badWay.turnangle;
}
}
}
float cmdAngle= angle;
// fall back to local angle if otherwise inconsistent
if ( lowerBadWayAngle > angle || higherBadWayAngle < angle )
{
cmdAngle = goodWay.turnangle;
}
if (roundaboutExit > 0)
{
cmd = RNDB;
}
else if (roundaboutExit < 0)
{
cmd = RNLB;
}
else if ( cmdAngle < -159. )
{
cmd = TU;
}
else if ( cmdAngle < -135. )
{
cmd = TSHL;
}
else if ( cmdAngle < -45. )
{
// a TL can be pushed in either direction by a close-by alternative
if ( higherBadWayAngle > -90. && higherBadWayAngle < -15. && lowerBadWayAngle < -180. )
{
cmd = TSHL;
}
else if ( lowerBadWayAngle > -180. && lowerBadWayAngle < -90. && higherBadWayAngle > 0. )
{
cmd = TSLL;
}
else
{
cmd = TL;
}
}
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!
{
cmd = C;
}
}
else if ( cmdAngle < 45. )
{
if ( cmd != KL ) // don't overwrite KL with TSLR
{
cmd = TSLR;
}
}
else if ( cmdAngle < 135. )
{
// a TR can be pushed in either direction by a close-by alternative
if ( higherBadWayAngle > 90. && higherBadWayAngle < 180. && lowerBadWayAngle < 0. )
{
cmd = TSLR;
}
else if ( lowerBadWayAngle > 15. && lowerBadWayAngle < 90. && higherBadWayAngle > 180. )
{
cmd = TSHR;
}
else
{
cmd = TR;
}
}
else if ( cmdAngle < 159. )
{
cmd = TSHR;
}
else
{
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) );
}
}