diff --git a/brouter-core/src/main/java/btools/router/FormatGpx.java b/brouter-core/src/main/java/btools/router/FormatGpx.java index 0ed6cc5ba..8a6f7618b 100644 --- a/brouter-core/src/main/java/btools/router/FormatGpx.java +++ b/brouter-core/src/main/java/btools/router/FormatGpx.java @@ -153,7 +153,9 @@ public String formatAsGpx(BufferedWriter sb, OsmTrack t) throws IOException { sb.append(" ") .append(hint.selev == Short.MIN_VALUE ? "" : "" + (hint.selev / 4.) + "") - .append("").append(hint.getMessageString()).append("") + .append("") + .append(hint.getMessageString()) + .append("") .append("").append("" + hint.distanceToNext).append(""); float rteTime = t.getVoiceHintTime(i + 1); if (rteTime != lastRteTime) { // add timing only if available diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java index 9ccff98e9..c336c3800 100644 --- a/brouter-core/src/main/java/btools/router/OsmTrack.java +++ b/brouter-core/src/main/java/btools/router/OsmTrack.java @@ -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 results = vproc.process(inputs); double minDistance = getMinDistance(); @@ -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; } diff --git a/brouter-core/src/main/java/btools/router/VoiceHint.java b/brouter-core/src/main/java/btools/router/VoiceHint.java index 2f858beb0..3d0b425cf 100644 --- a/brouter-core/src/main/java/btools/router/VoiceHint.java +++ b/brouter-core/src/main/java/btools/router/VoiceHint.java @@ -44,6 +44,7 @@ public float getTime() { float angle = Float.MAX_VALUE; boolean turnAngleConsumed; boolean needsRealTurn; + int maxBadPrio = -1; int roundaboutExit; diff --git a/brouter-core/src/main/java/btools/router/VoiceHintList.java b/brouter-core/src/main/java/btools/router/VoiceHintList.java index 229f4abd2..e377e24a3 100644 --- a/brouter-core/src/main/java/btools/router/VoiceHintList.java +++ b/brouter-core/src/main/java/btools/router/VoiceHintList.java @@ -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 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 diff --git a/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java b/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java index 1a63a0a1a..cb6039078 100644 --- a/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java +++ b/brouter-core/src/main/java/btools/router/VoiceHintProcessor.java @@ -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 inputs, int offset) { @@ -81,10 +83,21 @@ public List process(List 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; } } @@ -95,12 +108,35 @@ public List process(List 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; @@ -127,10 +163,7 @@ public List process(List 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) { @@ -145,8 +178,13 @@ public List process(List 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; @@ -157,7 +195,8 @@ public List process(List 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) @@ -244,80 +283,132 @@ public List postProcess(List inputs, double catchingRange, List results = new ArrayList<>(); double distance = 0; VoiceHint inputLast = null; - ArrayList 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; } + }