Merge pull request #508 from afischerdev/update-lib-five
Update lib part five - change voicehints
This commit is contained in:
commit
b735cd3e4e
6 changed files with 459 additions and 58 deletions
|
@ -121,11 +121,26 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
|
||||
protected abstract void resetState();
|
||||
|
||||
static int seg = 1;
|
||||
|
||||
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc) {
|
||||
byte[] description = link.descriptionBitmap;
|
||||
if (description == null) {
|
||||
return; // could be a beeline path
|
||||
if (description == null) { // could be a beeline path
|
||||
message = new MessageData();
|
||||
if (message != null) {
|
||||
message.turnangle = 0;
|
||||
message.time = (float) 1;
|
||||
message.energy = (float) 0;
|
||||
message.priorityclassifier = 0;
|
||||
message.classifiermask = 0;
|
||||
message.lon = targetNode.getILon();
|
||||
message.lat = targetNode.getILat();
|
||||
message.ele = Short.MIN_VALUE;
|
||||
message.linkdist = sourceNode.calcDistance(targetNode);
|
||||
message.wayKeyValues = "direct_segment=" + seg;
|
||||
}
|
||||
seg++;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean recordTransferNodes = detailMode || rc.countTraffic;
|
||||
|
@ -208,16 +223,18 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
int lon2;
|
||||
int lat2;
|
||||
short ele2;
|
||||
short originEle2;
|
||||
|
||||
if (transferNode == null) {
|
||||
lon2 = targetNode.ilon;
|
||||
lat2 = targetNode.ilat;
|
||||
ele2 = targetNode.selev;
|
||||
originEle2 = targetNode.selev;
|
||||
} else {
|
||||
lon2 = transferNode.ilon;
|
||||
lat2 = transferNode.ilat;
|
||||
ele2 = transferNode.selev;
|
||||
originEle2 = transferNode.selev;
|
||||
}
|
||||
ele2 = originEle2;
|
||||
|
||||
boolean isStartpoint = lon0 == -1 && lat0 == -1;
|
||||
|
||||
|
@ -334,13 +351,13 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
message.classifiermask = classifiermask;
|
||||
message.lon = lon2;
|
||||
message.lat = lat2;
|
||||
message.ele = ele2;
|
||||
message.ele = originEle2;
|
||||
message.wayKeyValues = rc.expctxWay.getKeyValueDescription(isReverse, description);
|
||||
}
|
||||
|
||||
if (stopAtEndpoint) {
|
||||
if (recordTransferNodes) {
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic);
|
||||
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, originEle2, originElement, rc.countTraffic);
|
||||
originElement.cost = cost;
|
||||
if (message != null) {
|
||||
originElement.message = message;
|
||||
|
@ -366,7 +383,7 @@ abstract class OsmPath implements OsmLinkHolder {
|
|||
transferNode = transferNode.next;
|
||||
|
||||
if (recordTransferNodes) {
|
||||
originElement = OsmPathElement.create(lon2, lat2, ele2, originElement, rc.countTraffic);
|
||||
originElement = OsmPathElement.create(lon2, lat2, originEle2, originElement, rc.countTraffic);
|
||||
originElement.cost = cost;
|
||||
originElement.addTraffic(traffic);
|
||||
traffic = 0;
|
||||
|
|
|
@ -1080,7 +1080,9 @@ public final class OsmTrack {
|
|||
VoiceHintProcessor vproc = new VoiceHintProcessor(rc.turnInstructionCatchingRange, rc.turnInstructionRoundabouts);
|
||||
List<VoiceHint> results = vproc.process(inputs);
|
||||
|
||||
for (VoiceHint hint : results) {
|
||||
double minDistance = getMinDistance();
|
||||
List < VoiceHint > resultsLast = vproc.postProcess(results, rc.turnInstructionCatchingRange, minDistance);
|
||||
for (VoiceHint hint: resultsLast) {
|
||||
voiceHints.list.add(hint);
|
||||
}
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ public class RoutingEngine extends Thread {
|
|||
int ind = s.indexOf("%");
|
||||
if (ind != -1)
|
||||
s = s.substring(0, ind);
|
||||
ind = s.indexOf("<EFBFBD>");
|
||||
ind = s.indexOf("°");
|
||||
if (ind != -1)
|
||||
s = s.substring(0, ind);
|
||||
tmpincline = Double.parseDouble(s.trim());
|
||||
|
@ -313,7 +313,7 @@ public class RoutingEngine extends Thread {
|
|||
if (startincline == 0) {
|
||||
startincline = tmpincline;
|
||||
} else if (startincline < 0 && tmpincline > 0) {
|
||||
// for the way ?p find the exit point
|
||||
// for the way up find the exit point
|
||||
double diff = endElev - selev;
|
||||
tmpincline = diff / (distRest / 100.);
|
||||
}
|
||||
|
@ -733,7 +733,7 @@ public class RoutingEngine extends Thread {
|
|||
lon2 = t.nodes.get(i).getILon();
|
||||
lat2 = t.nodes.get(i).getILat();
|
||||
nLast = t.nodes.get(0);
|
||||
dist = routingContext.calcDistance(lon0, lat0, lon1, lat1);
|
||||
dist = nLast.calcDistance(n);
|
||||
} else {
|
||||
lon0 = t.nodes.get(i - 2).getILon();
|
||||
lat0 = t.nodes.get(i - 2).getILat();
|
||||
|
@ -742,7 +742,7 @@ public class RoutingEngine extends Thread {
|
|||
lon2 = t.nodes.get(i).getILon();
|
||||
lat2 = t.nodes.get(i).getILat();
|
||||
nLast = t.nodes.get(i - 1);
|
||||
dist = routingContext.calcDistance(lon1, lat1, lon2, lat2);
|
||||
dist = nLast.calcDistance(n);
|
||||
}
|
||||
angle = routingContext.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
|
||||
n.message.linkdist = dist;
|
||||
|
|
|
@ -19,11 +19,13 @@ public class VoiceHint {
|
|||
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
|
||||
static final int TLU = 10; // U-turn
|
||||
static final int TU = 11; // 180 degree u-turn
|
||||
static final int TRU = 12; // Right U-turn
|
||||
static final int OFFR = 13; // Off route
|
||||
static final int RNDB = 14; // Roundabout
|
||||
static final int RNLB = 15; // Roundabout left
|
||||
static final int BL = 16; // Beeline routing
|
||||
|
||||
int ilon;
|
||||
int ilat;
|
||||
|
@ -39,7 +41,7 @@ public class VoiceHint {
|
|||
return oldWay == null ? 0.f : oldWay.time;
|
||||
}
|
||||
|
||||
float angle;
|
||||
float angle = Float.MAX_VALUE;
|
||||
boolean turnAngleConsumed;
|
||||
boolean needsRealTurn;
|
||||
|
||||
|
@ -67,8 +69,13 @@ public class VoiceHint {
|
|||
return roundaboutExit;
|
||||
}
|
||||
|
||||
/*
|
||||
* used by comment style, osmand style
|
||||
*/
|
||||
public String getCommandString() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return "TU"; // should be changed to TLU when osmand uses new voice hint constants
|
||||
case TU:
|
||||
return "TU";
|
||||
case TSHL:
|
||||
|
@ -100,8 +107,51 @@ public class VoiceHint {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by trkpt/sym style
|
||||
*/
|
||||
public String getCommandString(int c) {
|
||||
switch (c) {
|
||||
case TLU:
|
||||
return "TLU";
|
||||
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:
|
||||
return "unknown command: " + c;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by gpsies style
|
||||
*/
|
||||
public String getSymbolString() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return "TU";
|
||||
case TU:
|
||||
return "TU";
|
||||
case TSHL:
|
||||
|
@ -133,8 +183,53 @@ public class VoiceHint {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by new locus trkpt style
|
||||
*/
|
||||
public String getLocusSymbolString() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return "u-turn_left";
|
||||
case TU:
|
||||
return "u-turn";
|
||||
case TSHL:
|
||||
return "left_sharp";
|
||||
case TL:
|
||||
return "left";
|
||||
case TSLL:
|
||||
return "left_slight";
|
||||
case KL:
|
||||
return "stay_left"; // ?
|
||||
case C:
|
||||
return "straight";
|
||||
case KR:
|
||||
return "stay_right"; // ?
|
||||
case TSLR:
|
||||
return "right_slight";
|
||||
case TR:
|
||||
return "right";
|
||||
case TSHR:
|
||||
return "right_sharp";
|
||||
case TRU:
|
||||
return "u-turn_right";
|
||||
case RNDB:
|
||||
return "roundabout_e" + roundaboutExit;
|
||||
case RNLB:
|
||||
return "roundabout_e" + (-roundaboutExit);
|
||||
case BL:
|
||||
return "beeline";
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by osmand style
|
||||
*/
|
||||
public String getMessageString() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return "u-turn"; // should be changed to u-turn-left when osmand uses new voice hint constants
|
||||
case TU:
|
||||
return "u-turn";
|
||||
case TSHL:
|
||||
|
@ -156,7 +251,7 @@ public class VoiceHint {
|
|||
case TSHR:
|
||||
return "sharp right";
|
||||
case TRU:
|
||||
return "u-turn";
|
||||
return "u-turn"; // should be changed to u-turn-right when osmand uses new voice hint constants
|
||||
case RNDB:
|
||||
return "Take exit " + roundaboutExit;
|
||||
case RNLB:
|
||||
|
@ -166,10 +261,15 @@ public class VoiceHint {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by old locus style
|
||||
*/
|
||||
public int getLocusAction() {
|
||||
switch (cmd) {
|
||||
case TU:
|
||||
case TLU:
|
||||
return 13;
|
||||
case TU:
|
||||
return 12;
|
||||
case TSHL:
|
||||
return 5;
|
||||
case TL:
|
||||
|
@ -199,8 +299,13 @@ public class VoiceHint {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by orux style
|
||||
*/
|
||||
public int getOruxAction() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return 1003;
|
||||
case TU:
|
||||
return 1003;
|
||||
case TSHL:
|
||||
|
@ -232,6 +337,86 @@ public class VoiceHint {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by cruiser, equivalent to getCommandString() - osmand style - when osmand changes the voice hint constants
|
||||
*/
|
||||
public String getCruiserCommandString() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return "TLU";
|
||||
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);
|
||||
case BL:
|
||||
return "BL";
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* used by cruiser, equivalent to getMessageString() - osmand style - when osmand changes the voice hint constants
|
||||
*/
|
||||
public String getCruiserMessageString() {
|
||||
switch (cmd) {
|
||||
case TLU:
|
||||
return "u-turn left";
|
||||
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 right";
|
||||
case RNDB:
|
||||
return "Take exit " + roundaboutExit;
|
||||
case RNLB:
|
||||
return "Take exit " + (-roundaboutExit);
|
||||
case BL:
|
||||
return "Beeline";
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown command: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public void calcCommand() {
|
||||
float lowerBadWayAngle = -181;
|
||||
float higherBadWayAngle = 181;
|
||||
|
@ -252,58 +437,98 @@ public class VoiceHint {
|
|||
float cmdAngle = angle;
|
||||
|
||||
// fall back to local angle if otherwise inconsistent
|
||||
if (lowerBadWayAngle > angle || higherBadWayAngle < angle) {
|
||||
//if ( lowerBadWayAngle > angle || higherBadWayAngle < angle )
|
||||
//{
|
||||
//cmdAngle = goodWay.turnangle;
|
||||
//}
|
||||
if (angle == Float.MAX_VALUE) {
|
||||
cmdAngle = goodWay.turnangle;
|
||||
}
|
||||
if (cmd == BL) return;
|
||||
|
||||
if (roundaboutExit > 0) {
|
||||
cmd = RNDB;
|
||||
} else if (roundaboutExit < 0) {
|
||||
cmd = RNLB;
|
||||
} else if (cmdAngle < -159.) {
|
||||
} else if (is180DegAngle(cmdAngle) && cmdAngle <= -179.f && higherBadWayAngle == 181.f && lowerBadWayAngle == -181.f) {
|
||||
cmd = TU;
|
||||
} else if (cmdAngle < -135.) {
|
||||
} else if (cmdAngle < -159.f) {
|
||||
cmd = TLU;
|
||||
} else if (cmdAngle < -135.f) {
|
||||
cmd = TSHL;
|
||||
} else if (cmdAngle < -45.) {
|
||||
} else if (cmdAngle < -45.f) {
|
||||
// a TL can be pushed in either direction by a close-by alternative
|
||||
if (higherBadWayAngle > -90. && higherBadWayAngle < -15. && lowerBadWayAngle < -180.) {
|
||||
if (cmdAngle < -95.f && higherBadWayAngle < -30.f && lowerBadWayAngle < -180.f) {
|
||||
cmd = TSHL;
|
||||
} else if (lowerBadWayAngle > -180. && lowerBadWayAngle < -90. && higherBadWayAngle > 0.) {
|
||||
} else if (cmdAngle > -85.f && lowerBadWayAngle > -180.f && higherBadWayAngle > -10.f) {
|
||||
cmd = TSLL;
|
||||
} else {
|
||||
cmd = TL;
|
||||
if (cmdAngle < -110.f) {
|
||||
cmd = TSHL;
|
||||
} else if (cmdAngle > -60.f) {
|
||||
cmd = TSLL;
|
||||
} else {
|
||||
cmd = TL;
|
||||
}
|
||||
}
|
||||
} else if (cmdAngle < -21.) {
|
||||
if (cmd != KR) // don't overwrite KR with TSLL
|
||||
{
|
||||
} else if (cmdAngle < -21.f) {
|
||||
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!
|
||||
{
|
||||
} else if (cmdAngle < -5.f) {
|
||||
if (lowerBadWayAngle < -100.f && higherBadWayAngle < 45.f) {
|
||||
cmd = TSLL;
|
||||
} else if (lowerBadWayAngle >= -100.f && higherBadWayAngle < 45.f) {
|
||||
cmd = KL;
|
||||
} else {
|
||||
cmd = C;
|
||||
}
|
||||
} else if (cmdAngle < 45.) {
|
||||
if (cmd != KL) // don't overwrite KL with TSLR
|
||||
{
|
||||
cmd = TSLR;
|
||||
} else if (cmdAngle < 5.f) {
|
||||
if (lowerBadWayAngle > -30.f) {
|
||||
cmd = KR;
|
||||
} else if (higherBadWayAngle < 30.f) {
|
||||
cmd = KL;
|
||||
} else {
|
||||
cmd = C;
|
||||
}
|
||||
} else if (cmdAngle < 135.) {
|
||||
} else if (cmdAngle < 21.f) {
|
||||
// a TR can be pushed in either direction by a close-by alternative
|
||||
if (higherBadWayAngle > 90. && higherBadWayAngle < 180. && lowerBadWayAngle < 0.) {
|
||||
if (lowerBadWayAngle > -45.f && higherBadWayAngle > 100.f) {
|
||||
cmd = TSLR;
|
||||
} else if (lowerBadWayAngle > 15. && lowerBadWayAngle < 90. && higherBadWayAngle > 180.) {
|
||||
} else if (lowerBadWayAngle > -45.f && higherBadWayAngle <= 100.f) {
|
||||
cmd = KR;
|
||||
} else {
|
||||
cmd = C;
|
||||
}
|
||||
} else if (cmdAngle < 45.f) {
|
||||
cmd = TSLR;
|
||||
} else if (cmdAngle < 135.f) {
|
||||
if (cmdAngle < 85.f && higherBadWayAngle < 180.f && lowerBadWayAngle < 10.f) {
|
||||
cmd = TSLR;
|
||||
} else if (cmdAngle > 95.f && lowerBadWayAngle > 30.f && higherBadWayAngle > 180.f) {
|
||||
cmd = TSHR;
|
||||
} else {
|
||||
cmd = TR;
|
||||
if (cmdAngle > 110.) {
|
||||
cmd = TSHR;
|
||||
} else if (cmdAngle < 60.) {
|
||||
cmd = TSLR;
|
||||
} else {
|
||||
cmd = TR;
|
||||
}
|
||||
}
|
||||
} else if (cmdAngle < 159.) {
|
||||
} else if (cmdAngle < 159.f) {
|
||||
cmd = TSHR;
|
||||
} else if (is180DegAngle(cmdAngle) && cmdAngle >= 179.f && higherBadWayAngle == 181.f && lowerBadWayAngle == -181.f) {
|
||||
cmd = TU;
|
||||
} else {
|
||||
cmd = TRU;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean is180DegAngle(float angle) {
|
||||
return (Math.abs(angle) <= 180.f && Math.abs(angle) >= 179.f);
|
||||
}
|
||||
|
||||
public String formatGeometry() {
|
||||
float oldPrio = oldWay == null ? 0.f : oldWay.priorityclassifier;
|
||||
StringBuilder sb = new StringBuilder(30);
|
||||
|
|
|
@ -9,18 +9,22 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
public final class VoiceHintProcessor {
|
||||
private double catchingRange; // range to catch angles and merge turns
|
||||
|
||||
double SIGNIFICANT_ANGLE = 22.5;
|
||||
double INTERNAL_CATCHING_RANGE = 2.;
|
||||
|
||||
// private double catchingRange; // range to catch angles and merge turns
|
||||
private boolean explicitRoundabouts;
|
||||
|
||||
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts) {
|
||||
this.catchingRange = catchingRange;
|
||||
// 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 < catchingRange) {
|
||||
while (offset >= 0 && distance < INTERNAL_CATCHING_RANGE) {
|
||||
VoiceHint input = inputs.get(offset--);
|
||||
if (input.turnAngleConsumed) {
|
||||
break;
|
||||
|
@ -60,6 +64,10 @@ public final class VoiceHintProcessor {
|
|||
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
|
||||
VoiceHint input = inputs.get(hintIdx);
|
||||
|
||||
if (input.cmd == VoiceHint.BL) {
|
||||
results.add(input);
|
||||
continue;
|
||||
}
|
||||
float turnAngle = input.goodWay.turnangle;
|
||||
distance += input.goodWay.linkdist;
|
||||
int currentPrio = input.goodWay.getPrio();
|
||||
|
@ -67,6 +75,7 @@ public final class VoiceHintProcessor {
|
|||
int minPrio = Math.min(oldPrio, currentPrio);
|
||||
|
||||
boolean isLink2Highway = input.oldWay.isLinktType() && !input.goodWay.isLinktType();
|
||||
boolean isHighway2Link = !input.oldWay.isLinktType() && input.goodWay.isLinktType();
|
||||
|
||||
if (input.oldWay.isRoundabout()) {
|
||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
|
@ -101,14 +110,18 @@ public final class VoiceHintProcessor {
|
|||
float minAngle = 180.f;
|
||||
float minAbsAngeRaw = 180.f;
|
||||
|
||||
boolean isBadwayLink = false;
|
||||
|
||||
if (input.badWays != null) {
|
||||
for (MessageData badWay : input.badWays) {
|
||||
int badPrio = badWay.getPrio();
|
||||
float badTurn = badWay.turnangle;
|
||||
if (badWay.isLinktType()) {
|
||||
isBadwayLink = true;
|
||||
}
|
||||
boolean isBadHighway2Link = !input.oldWay.isLinktType() && badWay.isLinktType();
|
||||
|
||||
boolean isHighway2Link = !input.oldWay.isLinktType() && badWay.isLinktType();
|
||||
|
||||
if (badPrio > maxPrioAll && !isHighway2Link) {
|
||||
if (badPrio > maxPrioAll && !isBadHighway2Link) {
|
||||
maxPrioAll = badPrio;
|
||||
}
|
||||
|
||||
|
@ -140,12 +153,17 @@ public final class VoiceHintProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
boolean hasSomethingMoreStraight = Math.abs(turnAngle) - minAbsAngeRaw > 20.;
|
||||
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 = hasSomethingMoreStraight || (maxPrioAll > minPrio && !isLink2Highway) || (maxPrioCandidates > currentPrio);
|
||||
boolean unconditionalTrigger = hasSomethingMoreStraight ||
|
||||
(maxPrioAll > minPrio && !isLink2Highway) ||
|
||||
(maxPrioCandidates > currentPrio) ||
|
||||
VoiceHint.is180DegAngle(turnAngle) ||
|
||||
(!isHighway2Link && isBadwayLink && Math.abs(turnAngle) > 5.f) ||
|
||||
(isHighway2Link && !isBadwayLink && Math.abs(turnAngle) < 5.f);
|
||||
|
||||
// conditional triggers (=real turning angle required) are junctions
|
||||
// with candidate detours equal in priority than the route exit leg
|
||||
|
@ -158,11 +176,13 @@ public final class VoiceHintProcessor {
|
|||
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;
|
||||
if (Math.abs(turnAngle) > 5.) { // don't use to small angles
|
||||
if (maxAngle < turnAngle && maxAngle > turnAngle - 45.f - (Math.max(turnAngle, 0.f))) {
|
||||
input.cmd = VoiceHint.KR;
|
||||
}
|
||||
if (minAngle > turnAngle && minAngle < turnAngle + 45.f - (Math.min(turnAngle, 0.f))) {
|
||||
input.cmd = VoiceHint.KL;
|
||||
}
|
||||
}
|
||||
|
||||
input.angle = sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
|
@ -170,7 +190,7 @@ public final class VoiceHintProcessor {
|
|||
distance = 0.;
|
||||
results.add(input);
|
||||
}
|
||||
if (results.size() > 0 && distance < catchingRange) {
|
||||
if (results.size() > 0 && distance < INTERNAL_CATCHING_RANGE) { //catchingRange
|
||||
results.get(results.size() - 1).angle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||
}
|
||||
}
|
||||
|
@ -185,10 +205,10 @@ public final class VoiceHintProcessor {
|
|||
if (hint.cmd == 0) {
|
||||
hint.calcCommand();
|
||||
}
|
||||
if (!(hint.needsRealTurn && hint.cmd == VoiceHint.C)) {
|
||||
if (!(hint.needsRealTurn && (hint.cmd == VoiceHint.C || hint.cmd == VoiceHint.BL))) {
|
||||
double dist = hint.distanceToNext;
|
||||
// sum up other hints within the catching range (e.g. 40m)
|
||||
while (dist < catchingRange && i > 0) {
|
||||
while (dist < INTERNAL_CATCHING_RANGE && i > 0) {
|
||||
VoiceHint h2 = results.get(i - 1);
|
||||
dist = h2.distanceToNext;
|
||||
hint.distanceToNext += dist;
|
||||
|
@ -207,9 +227,92 @@ public final class VoiceHintProcessor {
|
|||
}
|
||||
hint.calcCommand();
|
||||
results2.add(hint);
|
||||
} else if (hint.cmd == VoiceHint.BL) {
|
||||
results2.add(hint);
|
||||
} else {
|
||||
if (results2.size() > 0)
|
||||
results2.get(results2.size() - 1).distanceToNext += hint.distanceToNext;
|
||||
}
|
||||
}
|
||||
return results2;
|
||||
}
|
||||
|
||||
public List<VoiceHint> postProcess(List<VoiceHint> inputs, double catchingRange, double minRange) {
|
||||
List<VoiceHint> results = new ArrayList<VoiceHint>();
|
||||
double distance = 0;
|
||||
VoiceHint inputLast = null;
|
||||
ArrayList<VoiceHint> tmpList = new ArrayList<>();
|
||||
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
|
||||
VoiceHint input = inputs.get(hintIdx);
|
||||
|
||||
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||
int badWayPrio = 0;
|
||||
for (MessageData md : input.badWays) {
|
||||
badWayPrio = Math.max(badWayPrio, md.getPrio());
|
||||
}
|
||||
if (input.goodWay.getPrio() < badWayPrio) {
|
||||
results.add(input);
|
||||
} else {
|
||||
if (inputLast != null) { // when drop add distance to last
|
||||
inputLast.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (input.distanceToNext < catchingRange) {
|
||||
double dist = input.distanceToNext;
|
||||
float angles = input.angle;
|
||||
int i = 1;
|
||||
boolean save = true;
|
||||
tmpList.clear();
|
||||
while (dist < catchingRange && hintIdx + i < inputs.size()) {
|
||||
VoiceHint h2 = inputs.get(hintIdx + i);
|
||||
dist += h2.distanceToNext;
|
||||
angles += h2.angle;
|
||||
if (VoiceHint.is180DegAngle(input.angle) || VoiceHint.is180DegAngle(h2.angle)) { // u-turn, 180 degree
|
||||
save = true;
|
||||
break;
|
||||
} else if (Math.abs(angles) > 180 - SIGNIFICANT_ANGLE) { // u-turn, collects e.g. two left turns in range
|
||||
input.angle = angles;
|
||||
input.calcCommand();
|
||||
input.distanceToNext += h2.distanceToNext;
|
||||
save = true;
|
||||
hintIdx++;
|
||||
break;
|
||||
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
|
||||
input.angle = angles;
|
||||
input.calcCommand();
|
||||
input.distanceToNext += h2.distanceToNext;
|
||||
save = true;
|
||||
hintIdx++;
|
||||
break;
|
||||
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
|
||||
tmpList.add(h2);
|
||||
hintIdx++;
|
||||
} else if (dist > catchingRange) { // distance reached
|
||||
break;
|
||||
} else {
|
||||
if (inputLast != null) { // when drop add distance to last
|
||||
inputLast.distanceToNext += input.distanceToNext;
|
||||
}
|
||||
save = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (save) {
|
||||
results.add(input); // add when last
|
||||
if (tmpList.size() > 0) { // add when something in stock
|
||||
results.addAll(tmpList);
|
||||
hintIdx += tmpList.size() - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results.add(input);
|
||||
}
|
||||
inputLast = input;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
54
docs/features/voicehints.md
Normal file
54
docs/features/voicehints.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
parent: Features
|
||||
---
|
||||
|
||||
# Remarks on Voice Hints
|
||||
|
||||
BRouter calculates voice hints but they are not present in all export formats. And within formats,
|
||||
how they are presented will vary.
|
||||
|
||||
There are gpx formats for
|
||||
* OsmAnd
|
||||
* Locus
|
||||
* Comment-style
|
||||
* Gpsies
|
||||
* Orux
|
||||
|
||||
The calculation starts with angles and comparing with the 'bad ways' (ways that are not
|
||||
used on this junction). So e.g. an almost 90 degree hint can become "sharp right turn" if another
|
||||
way is at 110 degrees.
|
||||
|
||||
And there are other rules
|
||||
* show 'continue' only if the way crosses a higher priority way
|
||||
* roundabouts have an exit marker
|
||||
* u-turn between -179 and +179 degree
|
||||
* merge two hints when near to each other - e.g. left, left to u-turn left
|
||||
* marker when highway exit and continue nearly same direction
|
||||
* beeline goes direct from via to via point
|
||||
|
||||
There are some variables in the profiles that affect on the voice hint generation:
|
||||
* considerTurnRestrictions -
|
||||
* turnInstructionCatchingRange - check distance to merge voice hints
|
||||
* turnInstructionRoundabouts - use voice hints on roundabouts
|
||||
|
||||
Voice hint variables
|
||||
|
||||
| short | description |
|
||||
| :----- | :----- |
|
||||
| C | continue (go straight) |
|
||||
| TL | turn left |
|
||||
| TSLL | turn slightly left |
|
||||
| TSHL | turn sharply left |
|
||||
| TR | turn right |
|
||||
| TSLR | turn slightly right |
|
||||
| TSHR | turn sharply right |
|
||||
| KL | keep left |
|
||||
| KR | keep right |
|
||||
| TLU | u-turn left |
|
||||
| TU | 180 degree u-turn |
|
||||
| TRU | u-turn right |
|
||||
| OFFR | off route |
|
||||
| RNDB | roundabout |
|
||||
| RNLB | roundabout left |
|
||||
| BL | beeline routing |
|
||||
|
Loading…
Reference in a new issue