Merge pull request #665 from afischerdev/rework-voicehint
Rework on voicehints
This commit is contained in:
commit
531f913c5b
5 changed files with 194 additions and 73 deletions
|
@ -153,7 +153,9 @@ public class FormatGpx extends Formatter {
|
||||||
sb.append(" <wpt lon=\"").append(formatILon(hint.ilon)).append("\" lat=\"")
|
sb.append(" <wpt lon=\"").append(formatILon(hint.ilon)).append("\" lat=\"")
|
||||||
.append(formatILat(hint.ilat)).append("\">")
|
.append(formatILat(hint.ilat)).append("\">")
|
||||||
.append(hint.selev == Short.MIN_VALUE ? "" : "<ele>" + (hint.selev / 4.) + "</ele>")
|
.append(hint.selev == Short.MIN_VALUE ? "" : "<ele>" + (hint.selev / 4.) + "</ele>")
|
||||||
.append("<name>").append(hint.getMessageString()).append("</name>")
|
.append("<name>")
|
||||||
|
.append(hint.getMessageString())
|
||||||
|
.append("</name>")
|
||||||
.append("<extensions><locus:rteDistance>").append("" + hint.distanceToNext).append("</locus:rteDistance>");
|
.append("<extensions><locus:rteDistance>").append("" + hint.distanceToNext).append("</locus:rteDistance>");
|
||||||
float rteTime = t.getVoiceHintTime(i + 1);
|
float rteTime = t.getVoiceHintTime(i + 1);
|
||||||
if (rteTime != lastRteTime) { // add timing only if available
|
if (rteTime != lastRteTime) { // add timing only if available
|
||||||
|
|
|
@ -500,7 +500,8 @@ public final class OsmTrack {
|
||||||
node = node.origin;
|
node = node.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
VoiceHintProcessor vproc = new VoiceHintProcessor(rc.turnInstructionCatchingRange, rc.turnInstructionRoundabouts);
|
int transportMode = voiceHints.transportMode();
|
||||||
|
VoiceHintProcessor vproc = new VoiceHintProcessor(rc.turnInstructionCatchingRange, rc.turnInstructionRoundabouts, transportMode);
|
||||||
List<VoiceHint> results = vproc.process(inputs);
|
List<VoiceHint> results = vproc.process(inputs);
|
||||||
|
|
||||||
double minDistance = getMinDistance();
|
double minDistance = getMinDistance();
|
||||||
|
@ -513,13 +514,12 @@ public final class OsmTrack {
|
||||||
|
|
||||||
int getMinDistance() {
|
int getMinDistance() {
|
||||||
if (voiceHints != null) {
|
if (voiceHints != null) {
|
||||||
switch (voiceHints.getTransportMode()) {
|
switch (voiceHints.transportMode()) {
|
||||||
case "car":
|
case VoiceHintList.TRANS_MODE_CAR:
|
||||||
return 20;
|
return 20;
|
||||||
case "bike":
|
case VoiceHintList.TRANS_MODE_FOOT:
|
||||||
return 5;
|
|
||||||
case "foot":
|
|
||||||
return 3;
|
return 3;
|
||||||
|
case VoiceHintList.TRANS_MODE_BIKE:
|
||||||
default:
|
default:
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class VoiceHint {
|
||||||
float angle = Float.MAX_VALUE;
|
float angle = Float.MAX_VALUE;
|
||||||
boolean turnAngleConsumed;
|
boolean turnAngleConsumed;
|
||||||
boolean needsRealTurn;
|
boolean needsRealTurn;
|
||||||
|
int maxBadPrio = -1;
|
||||||
|
|
||||||
int roundaboutExit;
|
int roundaboutExit;
|
||||||
|
|
||||||
|
|
|
@ -10,23 +10,50 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class VoiceHintList {
|
public class VoiceHintList {
|
||||||
private String transportMode;
|
|
||||||
|
static final int TRANS_MODE_NONE = 0;
|
||||||
|
static final int TRANS_MODE_FOOT = 1;
|
||||||
|
static final int TRANS_MODE_BIKE = 2;
|
||||||
|
static final int TRANS_MODE_CAR = 3;
|
||||||
|
|
||||||
|
private int transportMode = TRANS_MODE_BIKE;
|
||||||
int turnInstructionMode;
|
int turnInstructionMode;
|
||||||
List<VoiceHint> list = new ArrayList<>();
|
List<VoiceHint> list = new ArrayList<>();
|
||||||
|
|
||||||
public void setTransportMode(boolean isCar, boolean isBike) {
|
public void setTransportMode(boolean isCar, boolean isBike) {
|
||||||
transportMode = isCar ? "car" : (isBike ? "bike" : "foot");
|
transportMode = isCar ? TRANS_MODE_CAR : (isBike ? TRANS_MODE_BIKE : TRANS_MODE_FOOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransportMode(int mode) {
|
||||||
|
transportMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTransportMode() {
|
public String getTransportMode() {
|
||||||
|
String ret;
|
||||||
|
switch (transportMode) {
|
||||||
|
case TRANS_MODE_FOOT:
|
||||||
|
ret = "foot";
|
||||||
|
break;
|
||||||
|
case TRANS_MODE_CAR:
|
||||||
|
ret = "car";
|
||||||
|
break;
|
||||||
|
case TRANS_MODE_BIKE:
|
||||||
|
default:
|
||||||
|
ret = "bike";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int transportMode() {
|
||||||
return transportMode;
|
return transportMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLocusRouteType() {
|
public int getLocusRouteType() {
|
||||||
if ("car".equals(transportMode)) {
|
if (transportMode == TRANS_MODE_CAR) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ("bike".equals(transportMode)) {
|
if (transportMode == TRANS_MODE_BIKE) {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
return 3; // foot
|
return 3; // foot
|
||||||
|
|
|
@ -15,10 +15,12 @@ public final class VoiceHintProcessor {
|
||||||
|
|
||||||
// private double catchingRange; // range to catch angles and merge turns
|
// private double catchingRange; // range to catch angles and merge turns
|
||||||
private boolean explicitRoundabouts;
|
private boolean explicitRoundabouts;
|
||||||
|
private int transportMode;
|
||||||
|
|
||||||
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts) {
|
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts, int transportMode) {
|
||||||
// this.catchingRange = catchingRange;
|
// this.catchingRange = catchingRange;
|
||||||
this.explicitRoundabouts = explicitRoundabouts;
|
this.explicitRoundabouts = explicitRoundabouts;
|
||||||
|
this.transportMode = transportMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float sumNonConsumedWithinCatchingRange(List<VoiceHint> inputs, int offset) {
|
private float sumNonConsumedWithinCatchingRange(List<VoiceHint> inputs, int offset) {
|
||||||
|
@ -81,10 +83,21 @@ public final class VoiceHintProcessor {
|
||||||
if (explicitRoundabouts && input.oldWay.isRoundabout()) {
|
if (explicitRoundabouts && input.oldWay.isRoundabout()) {
|
||||||
if (roundaboudStartIdx == -1) roundaboudStartIdx = hintIdx;
|
if (roundaboudStartIdx == -1) roundaboudStartIdx = hintIdx;
|
||||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||||
|
if (roundaboudStartIdx == hintIdx) {
|
||||||
|
if (input.badWays != null) {
|
||||||
|
// remove goodWay
|
||||||
|
roundAboutTurnAngle -= input.goodWay.turnangle;
|
||||||
|
// add a badWay
|
||||||
|
for (MessageData badWay : input.badWays) {
|
||||||
|
if (!badWay.isBadOneway()) roundAboutTurnAngle += badWay.turnangle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
boolean isExit = roundaboutExit == 0; // exit point is always exit
|
boolean isExit = roundaboutExit == 0; // exit point is always exit
|
||||||
if (input.badWays != null) {
|
if (input.badWays != null) {
|
||||||
for (MessageData badWay : input.badWays) {
|
for (MessageData badWay : input.badWays) {
|
||||||
if (!badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs(badWay.turnangle) < 120.) {
|
if (!badWay.isBadOneway() &&
|
||||||
|
badWay.isGoodForCars()) {
|
||||||
isExit = true;
|
isExit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,12 +108,35 @@ public final class VoiceHintProcessor {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (roundaboutExit > 0) {
|
if (roundaboutExit > 0) {
|
||||||
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
//roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
|
||||||
double startTurn = (roundaboudStartIdx != -1 ? inputs.get(roundaboudStartIdx).goodWay.turnangle : turnAngle);
|
//double startTurn = (roundaboudStartIdx != -1 ? inputs.get(roundaboudStartIdx + 1).goodWay.turnangle : turnAngle);
|
||||||
input.angle = roundAboutTurnAngle;
|
input.angle = roundAboutTurnAngle;
|
||||||
|
input.goodWay.turnangle = roundAboutTurnAngle;
|
||||||
input.distanceToNext = distance;
|
input.distanceToNext = distance;
|
||||||
input.roundaboutExit = startTurn < 0 ? -roundaboutExit : roundaboutExit;
|
//input.roundaboutExit = startTurn < 0 ? roundaboutExit : -roundaboutExit;
|
||||||
|
input.roundaboutExit = roundAboutTurnAngle < 0 ? roundaboutExit : -roundaboutExit;
|
||||||
|
float tmpangle = 0;
|
||||||
|
VoiceHint tmpRndAbt = new VoiceHint();
|
||||||
|
tmpRndAbt.badWays = new ArrayList<>();
|
||||||
|
for (int i = hintIdx-1; i > roundaboudStartIdx; i--) {
|
||||||
|
VoiceHint vh = inputs.get(i);
|
||||||
|
tmpangle += inputs.get(i).goodWay.turnangle;
|
||||||
|
if (vh.badWays != null) {
|
||||||
|
for (MessageData badWay : vh.badWays) {
|
||||||
|
if (!badWay.isBadOneway()) {
|
||||||
|
MessageData md = new MessageData();
|
||||||
|
md.linkdist = vh.goodWay.linkdist;
|
||||||
|
md.priorityclassifier = vh.goodWay.priorityclassifier;
|
||||||
|
md.turnangle = tmpangle;
|
||||||
|
tmpRndAbt.badWays.add(md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
distance = 0.;
|
distance = 0.;
|
||||||
|
|
||||||
|
input.badWays = tmpRndAbt.badWays;
|
||||||
|
|
||||||
results.add(input);
|
results.add(input);
|
||||||
roundAboutTurnAngle = 0.f;
|
roundAboutTurnAngle = 0.f;
|
||||||
roundaboutExit = 0;
|
roundaboutExit = 0;
|
||||||
|
@ -127,10 +163,7 @@ public final class VoiceHintProcessor {
|
||||||
|
|
||||||
if (badPrio > maxPrioAll && !isBadHighway2Link) {
|
if (badPrio > maxPrioAll && !isBadHighway2Link) {
|
||||||
maxPrioAll = badPrio;
|
maxPrioAll = badPrio;
|
||||||
}
|
input.maxBadPrio = Math.max(input.maxBadPrio, badPrio);
|
||||||
|
|
||||||
if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
|
|
||||||
minAbsAngeRaw = Math.abs(badTurn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badPrio < minPrio) {
|
if (badPrio < minPrio) {
|
||||||
|
@ -145,8 +178,13 @@ public final class VoiceHintProcessor {
|
||||||
continue; // ways from the back should not trigger a slight turn
|
continue; // ways from the back should not trigger a slight turn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
|
||||||
|
minAbsAngeRaw = Math.abs(badTurn);
|
||||||
|
}
|
||||||
|
|
||||||
if (badPrio > maxPrioCandidates) {
|
if (badPrio > maxPrioCandidates) {
|
||||||
maxPrioCandidates = badPrio;
|
maxPrioCandidates = badPrio;
|
||||||
|
input.maxBadPrio = Math.max(input.maxBadPrio, badPrio);
|
||||||
}
|
}
|
||||||
if (badTurn > maxAngle) {
|
if (badTurn > maxAngle) {
|
||||||
maxAngle = badTurn;
|
maxAngle = badTurn;
|
||||||
|
@ -157,7 +195,8 @@ public final class VoiceHintProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasSomethingMoreStraight = (Math.abs(turnAngle) - minAbsAngeRaw) > 20.;
|
// boolean hasSomethingMoreStraight = (Math.abs(turnAngle) - minAbsAngeRaw) > 20.;
|
||||||
|
boolean hasSomethingMoreStraight = (Math.abs(turnAngle - minAbsAngeRaw)) > 20. && input.badWays != null; // && !ignoreBadway;
|
||||||
|
|
||||||
// unconditional triggers are all junctions with
|
// unconditional triggers are all junctions with
|
||||||
// - higher detour prios than the minimum route prio (except link->highway junctions)
|
// - higher detour prios than the minimum route prio (except link->highway junctions)
|
||||||
|
@ -244,18 +283,17 @@ public final class VoiceHintProcessor {
|
||||||
List<VoiceHint> results = new ArrayList<>();
|
List<VoiceHint> results = new ArrayList<>();
|
||||||
double distance = 0;
|
double distance = 0;
|
||||||
VoiceHint inputLast = null;
|
VoiceHint inputLast = null;
|
||||||
ArrayList<VoiceHint> tmpList = new ArrayList<>();
|
VoiceHint inputLastSaved = null;
|
||||||
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
|
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
|
||||||
VoiceHint input = inputs.get(hintIdx);
|
VoiceHint input = inputs.get(hintIdx);
|
||||||
|
VoiceHint nextInput = null;
|
||||||
|
if (hintIdx + 1 < inputs.size()) {
|
||||||
|
nextInput = inputs.get(hintIdx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextInput == null) {
|
||||||
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||||
int badWayPrio = 0;
|
if (input.goodWay.getPrio() < input.maxBadPrio && (inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange)) {
|
||||||
if (input.badWays != null) {
|
|
||||||
for (MessageData md : input.badWays) {
|
|
||||||
badWayPrio = Math.max(badWayPrio, md.getPrio());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (input.goodWay.getPrio() < badWayPrio) {
|
|
||||||
results.add(input);
|
results.add(input);
|
||||||
} else {
|
} else {
|
||||||
if (inputLast != null) { // when drop add distance to last
|
if (inputLast != null) { // when drop add distance to last
|
||||||
|
@ -264,60 +302,113 @@ public final class VoiceHintProcessor {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (input.distanceToNext < catchingRange) {
|
results.add(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange) || input.distanceToNext > catchingRange) {
|
||||||
|
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||||
|
if (input.goodWay.getPrio() < input.maxBadPrio
|
||||||
|
&& (inputLastSaved != null && inputLastSaved.distanceToNext > minRange)
|
||||||
|
&& (input.distanceToNext > minRange)) {
|
||||||
|
// add only on prio
|
||||||
|
results.add(input);
|
||||||
|
inputLastSaved = input;
|
||||||
|
} else {
|
||||||
|
if (inputLastSaved != null) { // when drop add distance to last
|
||||||
|
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// add all others
|
||||||
|
// ignore motorway / primary continue
|
||||||
|
if (((input.goodWay.getPrio() != 28) &&
|
||||||
|
(input.goodWay.getPrio() != 30) &&
|
||||||
|
(input.goodWay.getPrio() != 26))
|
||||||
|
|| input.isRoundabout()
|
||||||
|
|| Math.abs(input.angle) > 21.f) {
|
||||||
|
results.add(input);
|
||||||
|
inputLastSaved = input;
|
||||||
|
} else {
|
||||||
|
if (inputLastSaved != null) { // when drop add distance to last
|
||||||
|
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (input.distanceToNext < catchingRange) {
|
||||||
double dist = input.distanceToNext;
|
double dist = input.distanceToNext;
|
||||||
float angles = input.angle;
|
float angles = input.angle;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
boolean save = true;
|
boolean save = false;
|
||||||
tmpList.clear();
|
|
||||||
while (dist < catchingRange && hintIdx + i < inputs.size()) {
|
dist += nextInput.distanceToNext;
|
||||||
VoiceHint h2 = inputs.get(hintIdx + i);
|
angles += nextInput.angle;
|
||||||
dist += h2.distanceToNext;
|
|
||||||
angles += h2.angle;
|
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||||
if (VoiceHint.is180DegAngle(input.angle) || VoiceHint.is180DegAngle(h2.angle)) { // u-turn, 180 degree
|
if (input.goodWay.getPrio() < input.maxBadPrio) {
|
||||||
|
if (inputLastSaved != null && inputLastSaved.cmd != VoiceHint.C
|
||||||
|
&& (inputLastSaved != null && inputLastSaved.distanceToNext > minRange)
|
||||||
|
&& transportMode != VoiceHintList.TRANS_MODE_CAR) {
|
||||||
|
// add when straight and not linktype
|
||||||
|
// and last vh not straight
|
||||||
save = true;
|
save = true;
|
||||||
break;
|
// remove when next straight and not linktype
|
||||||
} else if (Math.abs(angles) > 180 - SIGNIFICANT_ANGLE) { // u-turn, collects e.g. two left turns in range
|
if (nextInput != null &&
|
||||||
|
nextInput.cmd == VoiceHint.C &&
|
||||||
|
!nextInput.goodWay.isLinktType()) {
|
||||||
|
input.distanceToNext += nextInput.distanceToNext;
|
||||||
|
hintIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (inputLastSaved != null) { // when drop add distance to last
|
||||||
|
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (VoiceHint.is180DegAngle(input.angle)) {
|
||||||
|
// add u-turn, 180 degree
|
||||||
|
save = true;
|
||||||
|
} else if (transportMode == VoiceHintList.TRANS_MODE_CAR && Math.abs(angles) > 180 - SIGNIFICANT_ANGLE) {
|
||||||
|
// add when inc car mode and u-turn, collects e.g. two left turns in range
|
||||||
input.angle = angles;
|
input.angle = angles;
|
||||||
input.calcCommand();
|
input.calcCommand();
|
||||||
input.distanceToNext += h2.distanceToNext;
|
input.distanceToNext += nextInput.distanceToNext;
|
||||||
save = true;
|
save = true;
|
||||||
hintIdx++;
|
hintIdx++;
|
||||||
break;
|
|
||||||
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
|
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
|
||||||
input.angle = angles;
|
input.angle = angles;
|
||||||
input.calcCommand();
|
input.calcCommand();
|
||||||
input.distanceToNext += h2.distanceToNext;
|
input.distanceToNext += nextInput.distanceToNext;
|
||||||
save = true;
|
save = true;
|
||||||
hintIdx++;
|
hintIdx++;
|
||||||
break;
|
|
||||||
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
|
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
|
||||||
tmpList.add(h2);
|
// add when angle above 22.5 deg
|
||||||
hintIdx++;
|
save = true;
|
||||||
} else if (dist > catchingRange) { // distance reached
|
} else if (Math.abs(input.angle) < SIGNIFICANT_ANGLE) {
|
||||||
break;
|
// add when angle below 22.5 deg ???
|
||||||
|
// save = true;
|
||||||
} else {
|
} else {
|
||||||
if (inputLast != null) { // when drop add distance to last
|
// otherwise ignore but add distance to next
|
||||||
inputLast.distanceToNext += input.distanceToNext;
|
if (nextInput != null) { // when drop add distance to last
|
||||||
|
nextInput.distanceToNext += input.distanceToNext;
|
||||||
}
|
}
|
||||||
save = false;
|
save = false;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (save) {
|
if (save) {
|
||||||
results.add(input); // add when last
|
results.add(input); // add when last
|
||||||
if (tmpList.size() > 0) { // add when something in stock
|
inputLastSaved = input;
|
||||||
results.addAll(tmpList);
|
|
||||||
hintIdx += tmpList.size() - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
results.add(input);
|
results.add(input);
|
||||||
|
inputLastSaved = input;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inputLast = input;
|
inputLast = input;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue