Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework on voicehints #665

Merged
merged 11 commits into from
Mar 3, 2024
4 changes: 3 additions & 1 deletion brouter-core/src/main/java/btools/router/FormatGpx.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ public String formatAsGpx(BufferedWriter sb, OsmTrack t) throws IOException {
sb.append(" <wpt lon=\"").append(formatILon(hint.ilon)).append("\" lat=\"")
.append(formatILat(hint.ilat)).append("\">")
.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>");
float rteTime = t.getVoiceHintTime(i + 1);
if (rteTime != lastRteTime) { // add timing only if available
Expand Down
12 changes: 6 additions & 6 deletions brouter-core/src/main/java/btools/router/OsmTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,8 @@ public void processVoiceHints(RoutingContext rc) {
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);

double minDistance = getMinDistance();
Expand All @@ -511,13 +512,12 @@ public void processVoiceHints(RoutingContext rc) {

int getMinDistance() {
if (voiceHints != null) {
switch (voiceHints.getTransportMode()) {
case "car":
switch (voiceHints.transportMode()) {
case VoiceHintList.TRANS_MODE_CAR:
return 20;
case "bike":
return 5;
case "foot":
case VoiceHintList.TRANS_MODE_FOOT:
return 3;
case VoiceHintList.TRANS_MODE_BIKE:
default:
return 5;
}
Expand Down
1 change: 1 addition & 0 deletions brouter-core/src/main/java/btools/router/VoiceHint.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public float getTime() {
float angle = Float.MAX_VALUE;
boolean turnAngleConsumed;
boolean needsRealTurn;
int maxBadPrio = -1;

int roundaboutExit;

Expand Down
35 changes: 31 additions & 4 deletions brouter-core/src/main/java/btools/router/VoiceHintList.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,50 @@
import java.util.List;

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;
List<VoiceHint> list = new ArrayList<>();

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() {
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;
}

public int getLocusRouteType() {
if ("car".equals(transportMode)) {
if (transportMode == TRANS_MODE_CAR) {
return 0;
}
if ("bike".equals(transportMode)) {
if (transportMode == TRANS_MODE_BIKE) {
return 5;
}
return 3; // foot
Expand Down
213 changes: 152 additions & 61 deletions brouter-core/src/main/java/btools/router/VoiceHintProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ public final class VoiceHintProcessor {

// private double catchingRange; // range to catch angles and merge turns
private boolean explicitRoundabouts;
private int transportMode;

public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts) {
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts, int transportMode) {
// this.catchingRange = catchingRange;
this.explicitRoundabouts = explicitRoundabouts;
this.transportMode = transportMode;
}

private float sumNonConsumedWithinCatchingRange(List<VoiceHint> inputs, int offset) {
Expand Down Expand Up @@ -81,10 +83,21 @@ public List<VoiceHint> process(List<VoiceHint> inputs) {
if (explicitRoundabouts && input.oldWay.isRoundabout()) {
if (roundaboudStartIdx == -1) roundaboudStartIdx = 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
if (input.badWays != null) {
for (MessageData badWay : input.badWays) {
if (!badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs(badWay.turnangle) < 120.) {
if (!badWay.isBadOneway() &&
badWay.isGoodForCars()) {
isExit = true;
}
}
Expand All @@ -95,12 +108,35 @@ public List<VoiceHint> process(List<VoiceHint> inputs) {
continue;
}
if (roundaboutExit > 0) {
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
double startTurn = (roundaboudStartIdx != -1 ? inputs.get(roundaboudStartIdx).goodWay.turnangle : turnAngle);
//roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
//double startTurn = (roundaboudStartIdx != -1 ? inputs.get(roundaboudStartIdx + 1).goodWay.turnangle : turnAngle);
input.angle = roundAboutTurnAngle;
input.goodWay.turnangle = roundAboutTurnAngle;
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.;

input.badWays = tmpRndAbt.badWays;

results.add(input);
roundAboutTurnAngle = 0.f;
roundaboutExit = 0;
Expand All @@ -127,10 +163,7 @@ public List<VoiceHint> process(List<VoiceHint> inputs) {

if (badPrio > maxPrioAll && !isBadHighway2Link) {
maxPrioAll = badPrio;
}

if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
minAbsAngeRaw = Math.abs(badTurn);
input.maxBadPrio = Math.max(input.maxBadPrio, badPrio);
}

if (badPrio < minPrio) {
Expand All @@ -145,8 +178,13 @@ public List<VoiceHint> process(List<VoiceHint> inputs) {
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) {
maxPrioCandidates = badPrio;
input.maxBadPrio = Math.max(input.maxBadPrio, badPrio);
}
if (badTurn > maxAngle) {
maxAngle = badTurn;
Expand All @@ -157,7 +195,8 @@ public List<VoiceHint> process(List<VoiceHint> inputs) {
}
}

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
// - higher detour prios than the minimum route prio (except link->highway junctions)
Expand Down Expand Up @@ -244,80 +283,132 @@ public List<VoiceHint> postProcess(List<VoiceHint> inputs, double catchingRange,
List<VoiceHint> results = new ArrayList<>();
double distance = 0;
VoiceHint inputLast = null;
ArrayList<VoiceHint> tmpList = new ArrayList<>();
VoiceHint inputLastSaved = null;
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
VoiceHint input = inputs.get(hintIdx);
VoiceHint nextInput = null;
if (hintIdx + 1 < inputs.size()) {
nextInput = inputs.get(hintIdx + 1);
}

if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
int badWayPrio = 0;
if (input.badWays != null) {
for (MessageData md : input.badWays) {
badWayPrio = Math.max(badWayPrio, md.getPrio());
if (nextInput == null) {
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
if (input.goodWay.getPrio() < input.maxBadPrio && (inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange)) {
results.add(input);
} else {
if (inputLast != null) { // when drop add distance to last
inputLast.distanceToNext += input.distanceToNext;
}
continue;
}
}
if (input.goodWay.getPrio() < badWayPrio) {
results.add(input);
} else {
if (inputLast != null) { // when drop add distance to last
inputLast.distanceToNext += input.distanceToNext;
}
continue;
results.add(input);
}
} else {
if (input.distanceToNext < catchingRange) {
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;
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;
boolean save = false;

dist += nextInput.distanceToNext;
angles += nextInput.angle;

if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
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;
// remove when next straight and not linktype
if (nextInput != null &&
nextInput.cmd == VoiceHint.C &&
!nextInput.goodWay.isLinktType()) {
input.distanceToNext += nextInput.distanceToNext;
hintIdx++;
}
}

} else {
if (inputLast != null) { // when drop add distance to last
inputLast.distanceToNext += input.distanceToNext;
if (inputLastSaved != null) { // when drop add distance to last
inputLastSaved.distanceToNext += input.distanceToNext;
}
save = false;
}
i++;
} 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.calcCommand();
input.distanceToNext += nextInput.distanceToNext;
save = true;
hintIdx++;
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
input.angle = angles;
input.calcCommand();
input.distanceToNext += nextInput.distanceToNext;
save = true;
hintIdx++;
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
// add when angle above 22.5 deg
save = true;
} else if (Math.abs(input.angle) < SIGNIFICANT_ANGLE) {
// add when angle below 22.5 deg ???
// save = true;
} else {
// otherwise ignore but add distance to next
if (nextInput != null) { // when drop add distance to last
nextInput.distanceToNext += input.distanceToNext;
}
save = false;
}

if (save) {
results.add(input); // add when last
if (tmpList.size() > 0) { // add when something in stock
results.addAll(tmpList);
hintIdx += tmpList.size() - 1;
}
inputLastSaved = input;
}
} else {
results.add(input);
inputLastSaved = input;
}
inputLast = input;
}
inputLast = input;
}

return results;
}


}
Loading