voice hints update
This commit is contained in:
parent
47cfb4b83c
commit
23968b2a5b
7 changed files with 103 additions and 32 deletions
|
@ -17,9 +17,8 @@ final class MessageData implements Cloneable
|
|||
|
||||
float costfactor;
|
||||
int priorityclassifier;
|
||||
int classifiermask;
|
||||
float turnangle;
|
||||
int onwaydirection;
|
||||
int roundaboutdirection;
|
||||
String wayKeyValues;
|
||||
String nodeKeyValues;
|
||||
|
||||
|
@ -77,11 +76,32 @@ final class MessageData implements Cloneable
|
|||
|
||||
public int getPrio()
|
||||
{
|
||||
return Math.abs( priorityclassifier );
|
||||
return priorityclassifier;
|
||||
}
|
||||
|
||||
public boolean isBadOneway()
|
||||
{
|
||||
return ( classifiermask & 1 ) != 0;
|
||||
}
|
||||
|
||||
public boolean isGoodOneway()
|
||||
{
|
||||
return ( classifiermask & 2 ) != 0;
|
||||
}
|
||||
|
||||
public boolean isRoundabout()
|
||||
{
|
||||
return ( classifiermask & 4 ) != 0;
|
||||
}
|
||||
|
||||
public boolean isLinktType()
|
||||
{
|
||||
return ( classifiermask & 8 ) != 0;
|
||||
}
|
||||
|
||||
public boolean isGoodForCars()
|
||||
{
|
||||
return priorityclassifier > 0;
|
||||
return ( classifiermask & 16 ) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -338,8 +338,7 @@ final class OsmPath implements OsmLinkHolder
|
|||
{
|
||||
msgData.costfactor = costfactor;
|
||||
msgData.priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
|
||||
msgData.onwaydirection = (int)rc.expctxWay.getOnewayDirection();
|
||||
msgData.roundaboutdirection = (int)rc.expctxWay.getRoundaboutDirection();
|
||||
msgData.classifiermask = (int)rc.expctxWay.getClassifierMask();
|
||||
msgData.lon = lon2;
|
||||
msgData.lat = lat2;
|
||||
msgData.ele = ele2;
|
||||
|
|
|
@ -657,7 +657,7 @@ public final class OsmTrack
|
|||
input.ilon = node.origin.getILon();
|
||||
input.indexInTrack = --nodeNr;
|
||||
input.goodWay = node.message;
|
||||
input.oldWay = node.origin.message;
|
||||
input.oldWay = node.origin.message == null ? node.message : node.origin.message;
|
||||
|
||||
OsmPathElementHolder detours = detourMap.get( node.origin.getIdFromPos() );
|
||||
if ( detours != null )
|
||||
|
@ -674,7 +674,8 @@ public final class OsmTrack
|
|||
node = node.origin;
|
||||
}
|
||||
|
||||
List<VoiceHint> results = VoiceHintProcessor.process( inputs );
|
||||
VoiceHintProcessor vproc = new VoiceHintProcessor( rc.turnInstructionCatchingRange, rc.turnInstructionRoundabouts );
|
||||
List<VoiceHint> results = vproc.process( inputs );
|
||||
for( VoiceHint hint : results )
|
||||
{
|
||||
voiceHints.list.add( hint );
|
||||
|
|
|
@ -101,6 +101,8 @@ public final class RoutingContext implements DistanceChecker
|
|||
{
|
||||
turnInstructionMode = tiMode;
|
||||
}
|
||||
turnInstructionCatchingRange = expctxGlobal.getVariableValue( "trafficSourceMinDist", 40.f );
|
||||
turnInstructionRoundabouts = expctxGlobal.getVariableValue( "turnInstructionRoundabouts", 1.f ) != 0.f;
|
||||
}
|
||||
|
||||
public RoutingMessageHandler messageHandler = new RoutingMessageHandler();
|
||||
|
@ -130,6 +132,8 @@ public final class RoutingContext implements DistanceChecker
|
|||
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 )
|
||||
{
|
||||
|
|
|
@ -10,11 +10,20 @@ import java.util.List;
|
|||
|
||||
public final class VoiceHintProcessor
|
||||
{
|
||||
private static float sumNonConsumedWithin40( List<VoiceHint> inputs, int offset )
|
||||
private double catchingRange; // range to catch angles and merge turns
|
||||
private boolean explicitRoundabouts;
|
||||
|
||||
public VoiceHintProcessor( double catchingRange, boolean explicitRoundabouts )
|
||||
{
|
||||
this.catchingRange = catchingRange;
|
||||
this.explicitRoundabouts = explicitRoundabouts;
|
||||
}
|
||||
|
||||
private float sumNonConsumedWithinCatchingRange( List<VoiceHint> inputs, int offset )
|
||||
{
|
||||
double distance = 0.;
|
||||
float angle = 0.f;
|
||||
while( offset >= 0 && distance < 40. )
|
||||
while( offset >= 0 && distance < catchingRange )
|
||||
{
|
||||
VoiceHint input = inputs.get( offset-- );
|
||||
if ( input.turnAngleConsumed )
|
||||
|
@ -29,7 +38,24 @@ public final class VoiceHintProcessor
|
|||
}
|
||||
|
||||
|
||||
public static List<VoiceHint> process( List<VoiceHint> inputs )
|
||||
/**
|
||||
* process voice hints. Uses VoiceHint objects
|
||||
* for both input and output. Input is in reverse
|
||||
* order (from target to start), but output is
|
||||
* returned in travel-direction and only for
|
||||
* those nodes that trigger a voice hint.
|
||||
*
|
||||
* Input objects are expected for every segment
|
||||
* of the track, also for those without a junction
|
||||
*
|
||||
* VoiceHint objects in the output list are enriched
|
||||
* by the voice-command, the total angle and the distance
|
||||
* to the next hint
|
||||
*
|
||||
* @param inputs tracknodes, un reverse order
|
||||
* @return voice hints, in forward order
|
||||
*/
|
||||
public List<VoiceHint> process( List<VoiceHint> inputs )
|
||||
{
|
||||
List<VoiceHint> results = new ArrayList<VoiceHint>();
|
||||
double distance = 0.;
|
||||
|
@ -44,22 +70,20 @@ public final class VoiceHintProcessor
|
|||
float turnAngle = input.goodWay.turnangle;
|
||||
distance += input.goodWay.linkdist;
|
||||
int currentPrio = input.goodWay.getPrio();
|
||||
int oldPrio = input.oldWay == null ? currentPrio : input.oldWay.getPrio();
|
||||
int oldPrio = input.oldWay.getPrio();
|
||||
int minPrio = Math.min( oldPrio, currentPrio );
|
||||
|
||||
// odd priorities are link-types
|
||||
boolean isLink2Highway = ( ( oldPrio & 1 ) == 1 ) && ( ( currentPrio & 1 ) == 0 );
|
||||
boolean isLink2Highway = input.oldWay.isLinktType() && !input.goodWay.isLinktType();
|
||||
|
||||
boolean inRoundabout = input.oldWay != null && input.oldWay.roundaboutdirection != 0;
|
||||
if ( inRoundabout )
|
||||
if ( input.oldWay.isRoundabout() )
|
||||
{
|
||||
roundAboutTurnAngle += sumNonConsumedWithin40( inputs, hintIdx );
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
boolean isExit = roundaboutExit == 0; // exit point is always exit
|
||||
if ( input.badWays != null )
|
||||
{
|
||||
for ( MessageData badWay : input.badWays )
|
||||
{
|
||||
if ( badWay.onwaydirection >= 0 && badWay.isGoodForCars() && Math.abs( badWay.turnangle ) < 120. )
|
||||
if ( !badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs( badWay.turnangle ) < 120. )
|
||||
{
|
||||
isExit = true;
|
||||
}
|
||||
|
@ -73,7 +97,7 @@ public final class VoiceHintProcessor
|
|||
}
|
||||
if ( roundaboutExit > 0 )
|
||||
{
|
||||
roundAboutTurnAngle += sumNonConsumedWithin40( inputs, hintIdx );
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
input.angle = roundAboutTurnAngle;
|
||||
input.distanceToNext = distance;
|
||||
input.roundaboutExit = turnAngle < 0 ? -roundaboutExit : roundaboutExit;
|
||||
|
@ -88,31 +112,37 @@ public final class VoiceHintProcessor
|
|||
|
||||
float maxAngle = -180.f;
|
||||
float minAngle = 180.f;
|
||||
float minAbsAngeRaw = 180.f;
|
||||
|
||||
if ( input.badWays != null )
|
||||
{
|
||||
for ( MessageData badWay : input.badWays )
|
||||
{
|
||||
int badPrio = badWay.getPrio();
|
||||
boolean badOneway = badWay.onwaydirection < 0;
|
||||
float badTurn = badWay.turnangle;
|
||||
|
||||
boolean isHighway2Link = ( ( badPrio & 1 ) == 1 ) && ( ( currentPrio & 1 ) == 0 );
|
||||
boolean isHighway2Link = !input.oldWay.isLinktType() && badWay.isLinktType();
|
||||
|
||||
if ( badPrio > maxPrioAll && !isHighway2Link )
|
||||
{
|
||||
maxPrioAll = badPrio;
|
||||
}
|
||||
|
||||
if ( badWay.costfactor < 20.f && Math.abs( badTurn ) < minAbsAngeRaw )
|
||||
{
|
||||
minAbsAngeRaw = Math.abs( badTurn );
|
||||
}
|
||||
|
||||
if ( badPrio < minPrio )
|
||||
{
|
||||
continue; // ignore low prio ways
|
||||
}
|
||||
|
||||
if ( badOneway )
|
||||
if ( badWay.isBadOneway() )
|
||||
{
|
||||
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
|
||||
|
@ -133,10 +163,12 @@ public final class VoiceHintProcessor
|
|||
}
|
||||
}
|
||||
|
||||
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 = ( 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
|
||||
|
@ -159,14 +191,14 @@ public final class VoiceHintProcessor
|
|||
input.cmd = VoiceHint.KL;
|
||||
}
|
||||
|
||||
input.angle = sumNonConsumedWithin40( inputs, hintIdx );
|
||||
input.angle = sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
input.distanceToNext = distance;
|
||||
distance = 0.;
|
||||
results.add( input );
|
||||
}
|
||||
if ( results.size() > 0 && distance < 40. )
|
||||
if ( results.size() > 0 && distance < catchingRange )
|
||||
{
|
||||
results.get( results.size()-1 ).angle += sumNonConsumedWithin40( inputs, hintIdx );
|
||||
results.get( results.size()-1 ).angle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,8 +217,8 @@ public final class VoiceHintProcessor
|
|||
if ( ! ( hint.needsRealTurn && hint.cmd == VoiceHint.C ) )
|
||||
{
|
||||
double dist = hint.distanceToNext;
|
||||
// sum up other hints within 40m
|
||||
while( dist < 40. && i > 0 )
|
||||
// sum up other hints within the catching range (e.g. 40m)
|
||||
while( dist < catchingRange && i > 0 )
|
||||
{
|
||||
VoiceHint h2 = results.get(i-1);
|
||||
dist = h2.distanceToNext;
|
||||
|
@ -200,6 +232,11 @@ public final class VoiceHintProcessor
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !explicitRoundabouts )
|
||||
{
|
||||
hint.roundaboutExit = 0; // use an angular hint instead
|
||||
}
|
||||
hint.calcCommand();
|
||||
results2.add( hint );
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ final class BExpression
|
|||
private static final int MAX_EXP = 22;
|
||||
private static final int EQUAL_EXP = 23;
|
||||
private static final int GREATER_EXP = 24;
|
||||
private static final int MIN_EXP = 25;
|
||||
|
||||
private static final int SWITCH_EXP = 30;
|
||||
private static final int ASSIGN_EXP = 31;
|
||||
|
@ -102,6 +103,10 @@ final class BExpression
|
|||
{
|
||||
exp.typ = MAX_EXP;
|
||||
}
|
||||
else if ( "min".equals( operator ) )
|
||||
{
|
||||
exp.typ = MIN_EXP;
|
||||
}
|
||||
else if ( "equal".equals( operator ) )
|
||||
{
|
||||
exp.typ = EQUAL_EXP;
|
||||
|
@ -230,6 +235,7 @@ final class BExpression
|
|||
case ADD_EXP: return op1.evaluate(ctx) + op2.evaluate(ctx);
|
||||
case MULTIPLY_EXP: return op1.evaluate(ctx) * op2.evaluate(ctx);
|
||||
case MAX_EXP: return max( op1.evaluate(ctx), op2.evaluate(ctx) );
|
||||
case MIN_EXP: return min( op1.evaluate(ctx), op2.evaluate(ctx) );
|
||||
case EQUAL_EXP: return op1.evaluate(ctx) == op2.evaluate(ctx) ? 1.f : 0.f;
|
||||
case GREATER_EXP: return op1.evaluate(ctx) > op2.evaluate(ctx) ? 1.f : 0.f;
|
||||
case SWITCH_EXP: return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx);
|
||||
|
@ -247,4 +253,9 @@ final class BExpression
|
|||
{
|
||||
return v1 > v2 ? v1 : v2;
|
||||
}
|
||||
|
||||
private float min( float v1, float v2 )
|
||||
{
|
||||
return v1 < v2 ? v1 : v2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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", "onewaydirection", "roundaboutdirection"};
|
||||
{ "costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask" };
|
||||
|
||||
protected String[] getBuildInVariableNames()
|
||||
{
|
||||
|
@ -30,8 +30,7 @@ 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 float getClassifierMask() { return getBuildInVariable(10); }
|
||||
|
||||
public BExpressionContextWay( BExpressionMetaData meta )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue