voice hints update

This commit is contained in:
Arndt 2016-05-05 12:46:27 +02:00
parent 47cfb4b83c
commit 23968b2a5b
7 changed files with 103 additions and 32 deletions

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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 );

View file

@ -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 )
{

View file

@ -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 );
}

View file

@ -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;
}
}

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", "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 )
{