Merge branch 'master' into rerouting
This commit is contained in:
commit
09248679db
13 changed files with 393 additions and 84 deletions
4
.github/workflows/gradle-publish.yml
vendored
4
.github/workflows/gradle-publish.yml
vendored
|
@ -18,10 +18,10 @@ jobs:
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK 11
|
- name: Set up JDK 11
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
6
.github/workflows/gradle.yml
vendored
6
.github/workflows/gradle.yml
vendored
|
@ -15,9 +15,9 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: BRouter
|
environment: BRouter
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Set up JDK 11
|
- name: Set up JDK 11
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
@ -37,7 +37,7 @@ jobs:
|
||||||
ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD: ${{ secrets.BROUTER_STORE_PASSWORD }}
|
ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD: ${{ secrets.BROUTER_STORE_PASSWORD }}
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
- name: Upload ZIP
|
- name: Upload ZIP
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ZIP
|
name: ZIP
|
||||||
path: brouter-server/build/distributions/brouter-*.zip
|
path: brouter-server/build/distributions/brouter-*.zip
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -501,7 +501,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();
|
||||||
|
@ -514,13 +515,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,80 +283,132 @@ 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 (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
if (nextInput == null) {
|
||||||
int badWayPrio = 0;
|
if (input.cmd == VoiceHint.C && !input.goodWay.isLinktType()) {
|
||||||
if (input.badWays != null) {
|
if (input.goodWay.getPrio() < input.maxBadPrio && (inputLastSaved != null && inputLastSaved.distanceToNext > catchingRange)) {
|
||||||
for (MessageData md : input.badWays) {
|
results.add(input);
|
||||||
badWayPrio = Math.max(badWayPrio, md.getPrio());
|
} else {
|
||||||
|
if (inputLast != null) { // when drop add distance to last
|
||||||
|
inputLast.distanceToNext += input.distanceToNext;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (input.goodWay.getPrio() < badWayPrio) {
|
|
||||||
results.add(input);
|
|
||||||
} else {
|
} else {
|
||||||
if (inputLast != null) { // when drop add distance to last
|
results.add(input);
|
||||||
inputLast.distanceToNext += input.distanceToNext;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
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) {
|
||||||
save = true;
|
if (inputLastSaved != null && inputLastSaved.cmd != VoiceHint.C
|
||||||
break;
|
&& (inputLastSaved != null && inputLastSaved.distanceToNext > minRange)
|
||||||
} else if (Math.abs(angles) > 180 - SIGNIFICANT_ANGLE) { // u-turn, collects e.g. two left turns in range
|
&& transportMode != VoiceHintList.TRANS_MODE_CAR) {
|
||||||
input.angle = angles;
|
// add when straight and not linktype
|
||||||
input.calcCommand();
|
// and last vh not straight
|
||||||
input.distanceToNext += h2.distanceToNext;
|
save = true;
|
||||||
save = true;
|
// remove when next straight and not linktype
|
||||||
hintIdx++;
|
if (nextInput != null &&
|
||||||
break;
|
nextInput.cmd == VoiceHint.C &&
|
||||||
} else if (Math.abs(angles) < SIGNIFICANT_ANGLE && input.distanceToNext < minRange) {
|
!nextInput.goodWay.isLinktType()) {
|
||||||
input.angle = angles;
|
input.distanceToNext += nextInput.distanceToNext;
|
||||||
input.calcCommand();
|
hintIdx++;
|
||||||
input.distanceToNext += h2.distanceToNext;
|
}
|
||||||
save = true;
|
}
|
||||||
hintIdx++;
|
|
||||||
break;
|
} else {
|
||||||
} else if (Math.abs(input.angle) > SIGNIFICANT_ANGLE) {
|
if (inputLastSaved != null) { // when drop add distance to last
|
||||||
tmpList.add(h2);
|
inputLastSaved.distanceToNext += input.distanceToNext;
|
||||||
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++;
|
} 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) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,6 +194,10 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
|
||||||
if (wplist.size() < 10) {
|
if (wplist.size() < 10) {
|
||||||
SuspectManager.nearRecentWps.add(wplist);
|
SuspectManager.nearRecentWps.add(wplist);
|
||||||
}
|
}
|
||||||
|
if (params.containsKey("profile")) {
|
||||||
|
// already handled in readRoutingContext
|
||||||
|
params.remove("profile");
|
||||||
|
}
|
||||||
int engineMode = 0;
|
int engineMode = 0;
|
||||||
if (params.containsKey("engineMode")) {
|
if (params.containsKey("engineMode")) {
|
||||||
engineMode = Integer.parseInt(params.get("engineMode"));
|
engineMode = Integer.parseInt(params.get("engineMode"));
|
||||||
|
|
|
@ -39,19 +39,52 @@ Please note: when they have a parameter 'weight' the result is not an absolute n
|
||||||
|
|
||||||
This parameters are needed to tell BRouter what to do.
|
This parameters are needed to tell BRouter what to do.
|
||||||
|
|
||||||
|
### using profiles
|
||||||
|
|
||||||
|
For calulation BRouter uses a set of rules defined in a profile. See description of profile [rules](https://github.com/abrensch/brouter/blob/master/docs/developers/profile_developers_guide.md).
|
||||||
|
|
||||||
|
Here we talk about how we let BRouter know witch profile to use.
|
||||||
|
There are three ways:
|
||||||
|
|
||||||
|
1. use the parameter 'v' and 'fast'
|
||||||
|
```
|
||||||
|
"v"-->[motorcar|bicycle|foot]
|
||||||
|
"fast"-->[0|1]
|
||||||
|
This enables BRouter to look into the file serviceconfig.dat.
|
||||||
|
In there BRouter find the profile associated for e.g bicyle_fast trekking
|
||||||
|
This could be changed by the user calling the BRouter app server-mode.
|
||||||
|
```
|
||||||
|
|
||||||
|
2. use the profile parameter
|
||||||
|
```
|
||||||
|
profile=trekking
|
||||||
|
It needs an available file in the BRouter profile folder e.g. trekking.brf
|
||||||
|
```
|
||||||
|
|
||||||
|
3. use a remote profile
|
||||||
|
```
|
||||||
|
remoteProfile=a long string with routing rules
|
||||||
|
This is saved in BRouter profile folder temporary with the file name 'remote.brf'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### profile parameter
|
### profile parameter
|
||||||
|
|
||||||
Profile parameters affect the result of a profile.
|
Profile parameters affect the result of a profile.
|
||||||
|
The variables inside a profile predefine a value e.g. avoidsteps=1
|
||||||
|
A parameter call gives the chance to change this start value without changing the profile e.g. avoidsteps=0
|
||||||
For the app it is a list of params concatenated by '&'. E.g. extraParams=avoidferry=1&avoidsteps=0
|
For the app it is a list of params concatenated by '&'. E.g. extraParams=avoidferry=1&avoidsteps=0
|
||||||
The server calls profile params by a prefix 'profile:'. E.g. ...&profile:avoidferry=1&profile:avoidsteps=0
|
The server calls profile params by a prefix 'profile:'. E.g. ...&profile:avoidferry=1&profile:avoidsteps=0
|
||||||
|
|
||||||
|
By using this parameter logic, there is no need to edit a profile before sending.
|
||||||
|
|
||||||
### using profile parameter inside an app
|
### using profile parameter inside an app
|
||||||
|
|
||||||
To be flexible it is possible to send a profile to BRouter - server or app.
|
To be flexible it is possible to send a profile to BRouter - server or app.
|
||||||
|
|
||||||
Another variant is to send parameters for an existing profile that are different from the original profile.
|
Another variant is to send parameters for an existing profile that are different from the original profile.
|
||||||
|
|
||||||
With the version 1.7.1 it is possible to collect parameters from the profile.
|
With the version 1.7.1 it is possible to collect parameters from the profile.
|
||||||
The variable parameters are defined like this
|
The variable parameters are defined like this
|
||||||
```
|
```
|
||||||
assign avoid_path = false # %avoid_path% | Set to true to avoid pathes | boolean
|
assign avoid_path = false # %avoid_path% | Set to true to avoid pathes | boolean
|
||||||
|
@ -61,9 +94,9 @@ Now you could do that with an calling app.
|
||||||
|
|
||||||
What to do to get it work?
|
What to do to get it work?
|
||||||
|
|
||||||
- First copy the [RoutingParam](brouter-routing-app/src/main/java/btools/routingapp/RoutingParam.java) class to your source - use the same name and package name.
|
- First copy the [RoutingParam](brouter-routing-app/src/main/java/btools/routingapp/RoutingParam.java) class to your source - use the same name and package name.
|
||||||
- Second analyze the profile for which you need the parameter.
|
- Second analyze the profile for which you need the parameter.
|
||||||
This [BRouter routine](https://github.com/abrensch/brouter/blob/086503e529da7c044cc0f88f86c394fdb574d6cf/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java#L103) can do that, just copy it to your source to use it in your app.
|
This [BRouter routine](https://github.com/abrensch/brouter/blob/086503e529da7c044cc0f88f86c394fdb574d6cf/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java#L103) can do that, just copy it to your source to use it in your app.
|
||||||
It builds a List<RoutingParam> you could send to BRouter app.
|
It builds a List<RoutingParam> you could send to BRouter app.
|
||||||
- You find the call of BRouter app in comment at [RoutingParameterDialog](https://github.com/abrensch/brouter/blob/086503e529da7c044cc0f88f86c394fdb574d6cf/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java#L33)
|
- You find the call of BRouter app in comment at [RoutingParameterDialog](https://github.com/abrensch/brouter/blob/086503e529da7c044cc0f88f86c394fdb574d6cf/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java#L33)
|
||||||
|
|
||||||
|
@ -79,7 +112,7 @@ intent.putExtra("runsilent", true);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
```
|
```
|
||||||
|
|
||||||
This suppress the first question after installation for the BRouter path, generates the BRouter folders in main space and starts the download dialog.
|
This suppress the first question after installation for the BRouter path, generates the BRouter folders in main space and starts the download dialog.
|
||||||
|
|
||||||
### silent app call
|
### silent app call
|
||||||
|
|
||||||
|
@ -92,7 +125,7 @@ intent.putExtra("runsilent", true);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
```
|
```
|
||||||
|
|
||||||
This suppress the first question after installation for the BRouter path, generates the BRouter folders in main space and starts the download dialog.
|
This suppress the first question after installation for the BRouter path, generates the BRouter folders in main space and starts the download dialog.
|
||||||
|
|
||||||
## other routing engine modes in app
|
## other routing engine modes in app
|
||||||
|
|
||||||
|
|
125
docs/developers/docker_guide.md
Normal file
125
docs/developers/docker_guide.md
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
---
|
||||||
|
parent: Developers
|
||||||
|
---
|
||||||
|
|
||||||
|
# Docker help
|
||||||
|
|
||||||
|
In addition to the intro in readme.md about Docker, here are a few commands for daily work with the system.
|
||||||
|
|
||||||
|
Build the Docker with a version based name
|
||||||
|
```
|
||||||
|
$ docker build -t brouter-1.7.2 .
|
||||||
|
```
|
||||||
|
|
||||||
|
Start Docker with name additional to the Docker image name.
|
||||||
|
Please note:
|
||||||
|
The path for segments are on a Windows system.
|
||||||
|
Here the port used in server.sh is published.
|
||||||
|
```
|
||||||
|
$ docker run --rm -v "I:/Data/test/segment4":/segments4 --publish 17777:17777 --name brouter-1.7.2 brouter-1.7.2
|
||||||
|
```
|
||||||
|
|
||||||
|
and with a mount for profiles as well
|
||||||
|
```
|
||||||
|
$ docker run --rm -v "I:/Data/test/segment4":/segments4 -v "I:/Data/test/profiles2":/profiles2 --name brouter-1.7.2 brouter-1.7.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Show the running Docker processes
|
||||||
|
```
|
||||||
|
$ docker ps
|
||||||
|
|
||||||
|
output:
|
||||||
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
|
b23518e8791d brouter-1.7.2 "/bin/sh -c /bin/ser…" 5 minutes ago Up 5 minutes 0.0.0.0:17777->17777/tcp brouter-1.7.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Fire some curl or wget commands to test if is realy useful running.
|
||||||
|
|
||||||
|
Stop a running Docker image - please note, this only works when starts docker image with name, see above
|
||||||
|
```
|
||||||
|
$ docker stop brouter-1.7.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Docker available images
|
||||||
|
|
||||||
|
```
|
||||||
|
$ docker images
|
||||||
|
|
||||||
|
output:
|
||||||
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
brouter-1.7.2 latest e39703dec2fa 2 hours ago 410MB
|
||||||
|
brouter latest 728f122c7388 3 hours ago 410MB
|
||||||
|
```
|
||||||
|
|
||||||
|
Control
|
||||||
|
## Docker with docker-compose
|
||||||
|
|
||||||
|
Use a git clone to build a local folder with last version.
|
||||||
|
Make a Docker container with version number inside your repository folder.
|
||||||
|
```
|
||||||
|
$ docker build -t brouter:1.7.2 .
|
||||||
|
|
||||||
|
$ docker images
|
||||||
|
|
||||||
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
brouter-1.7.2 latest e39703dec2fa 3 hours ago 410MB
|
||||||
|
brouter 1.7.2 e39703dec2fa 3 hours ago 410MB
|
||||||
|
```
|
||||||
|
|
||||||
|
Start a container with composer
|
||||||
|
This needs a docker config file docker-compose.yml
|
||||||
|
Something like this:
|
||||||
|
```
|
||||||
|
version: '2'
|
||||||
|
services:
|
||||||
|
brouter:
|
||||||
|
image: brouter:1.7.2
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 17777:17777
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: "I:/Data/test/segment4"
|
||||||
|
target: /segments4
|
||||||
|
# - type: bind
|
||||||
|
# source: "I:/Data/test/profiles2"
|
||||||
|
# target: /profiles2
|
||||||
|
```
|
||||||
|
|
||||||
|
Start it
|
||||||
|
```
|
||||||
|
$ docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Have a look what is running
|
||||||
|
```
|
||||||
|
$ docker-compose ps
|
||||||
|
or
|
||||||
|
$ docker-compose ls
|
||||||
|
or
|
||||||
|
$ docker ps
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Now update your repository (git pull) and build your Docker container with the new version tag
|
||||||
|
```
|
||||||
|
$ docker build -t brouter:1.7.3 .
|
||||||
|
|
||||||
|
$ docker images
|
||||||
|
|
||||||
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
brouter 1.7.3 5edc998cb5ae 3 hours ago 410MB
|
||||||
|
brouter-1.7.2 latest e39703dec2fa 6 hours ago 410MB
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the version in Docker config file docker-compose.yml
|
||||||
|
```
|
||||||
|
image: brouter:1.7.3
|
||||||
|
```
|
||||||
|
|
||||||
|
Stop old running container and start the new one
|
||||||
|
```
|
||||||
|
$ docker-compose down
|
||||||
|
|
||||||
|
$ docker-compose up -d
|
||||||
|
```
|
|
@ -176,7 +176,7 @@ All expressions have one of the following basic forms:
|
||||||
- `and <boolean expression 1> <boolean expression 2>`
|
- `and <boolean expression 1> <boolean expression 2>`
|
||||||
- `xor <boolean expression 1> <boolean expression 2>`
|
- `xor <boolean expression 1> <boolean expression 2>`
|
||||||
- `multiply <numeric expression 1> <numeric expression 2>`
|
- `multiply <numeric expression 1> <numeric expression 2>`
|
||||||
- `div <numeric expression 1> <numeric expression 2>`
|
- `divide <numeric expression 1> <numeric expression 2>`
|
||||||
- `add <numeric expression 1> <numeric expression 2>`
|
- `add <numeric expression 1> <numeric expression 2>`
|
||||||
- `sub <numeric expression 1> <numeric expression 2>`
|
- `sub <numeric expression 1> <numeric expression 2>`
|
||||||
- `max <numeric expression 1> <numeric expression 2>`
|
- `max <numeric expression 1> <numeric expression 2>`
|
||||||
|
|
|
@ -67,3 +67,29 @@ application profiles"/>
|
||||||
The BRouter app should be launched before OsmAnd for this specific entry to
|
The BRouter app should be launched before OsmAnd for this specific entry to
|
||||||
appear in OsmAnd. Therefore, if you cannot find "BRouter (offline)" navigation
|
appear in OsmAnd. Therefore, if you cannot find "BRouter (offline)" navigation
|
||||||
option, you should force quit OsmAnd and restart it.
|
option, you should force quit OsmAnd and restart it.
|
||||||
|
|
||||||
|
|
||||||
|
## OsmAnd version 4.7.1
|
||||||
|
|
||||||
|
From version 4.7.1 upwards Osmand supports the profile parameter for mapping:
|
||||||
|
Since Osmand version 3, many profiles can be defined in Osmand and the user can easily switch between these profiles.
|
||||||
|
This allow now when using the service-interface to address different brouter-profiles in a more flexible and better comprehensive way.
|
||||||
|
|
||||||
|
- If in Osmand a profile has "BRouter" defined as navigation service
|
||||||
|
- AND the profile-name looks like "Brouter[mysting]
|
||||||
|
|
||||||
|
==> then the profile "mystring" will be used in the Brouter-app!
|
||||||
|
(this new mapping replaces in that case the basic mapping defined above and based on the file "serviceconfig.dat)
|
||||||
|
|
||||||
|
### Examples: Osmand-profile name Brouter-app
|
||||||
|
```
|
||||||
|
[Brouter[trekking] "trekking" profile will be used (file trekking.brf)
|
||||||
|
[Brouter[racebike] "racebike" profile will be used (file racebike.brf)
|
||||||
|
....
|
||||||
|
```
|
||||||
|
Remark:
|
||||||
|
Currently Osmand do not check the defined name (case sensitiv) for the Brouter-profile (mystring).
|
||||||
|
If no profile is found, the routing will fail with "Could not calculate route.."!
|
||||||
|
|
||||||
|
<img src="osmand/brouter-osmand-4.7.1.png" alt="BRouter configuration in OsmAnd
|
||||||
|
application profiles"/>
|
||||||
|
|
BIN
docs/users/osmand/brouter-osmand-4.7.1.png
Normal file
BIN
docs/users/osmand/brouter-osmand-4.7.1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 232 KiB |
Loading…
Reference in a new issue