Merge branch 'master' into rerouting

This commit is contained in:
afischerdev 2024-03-03 18:20:44 +01:00 committed by GitHub
commit 09248679db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 393 additions and 84 deletions

View file

@ -18,10 +18,10 @@ jobs:
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'

View file

@ -15,9 +15,9 @@ jobs:
runs-on: ubuntu-latest
environment: BRouter
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
@ -37,7 +37,7 @@ jobs:
ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD: ${{ secrets.BROUTER_STORE_PASSWORD }}
run: ./gradlew build
- name: Upload ZIP
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ZIP
path: brouter-server/build/distributions/brouter-*.zip

View file

@ -153,7 +153,9 @@ public class FormatGpx extends Formatter {
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

View file

@ -501,7 +501,8 @@ public final class OsmTrack {
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();
@ -514,13 +515,12 @@ public final class OsmTrack {
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;
}

View file

@ -44,6 +44,7 @@ public class VoiceHint {
float angle = Float.MAX_VALUE;
boolean turnAngleConsumed;
boolean needsRealTurn;
int maxBadPrio = -1;
int roundaboutExit;

View file

@ -10,23 +10,50 @@ import java.util.ArrayList;
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

View file

@ -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) {
@ -81,10 +83,21 @@ public final class VoiceHintProcessor {
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 final class VoiceHintProcessor {
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 final class VoiceHintProcessor {
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 final class VoiceHintProcessor {
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 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
// - 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<>();
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;
} else {
if (inputLast != null) { // when drop add distance to last
inputLast.distanceToNext += input.distanceToNext;
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 (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;
}
}

View file

@ -194,6 +194,10 @@ public class RouteServer extends Thread implements Comparable<RouteServer> {
if (wplist.size() < 10) {
SuspectManager.nearRecentWps.add(wplist);
}
if (params.containsKey("profile")) {
// already handled in readRoutingContext
params.remove("profile");
}
int engineMode = 0;
if (params.containsKey("engineMode")) {
engineMode = Integer.parseInt(params.get("engineMode"));

View file

@ -39,12 +39,45 @@ 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.
### 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 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
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
To be flexible it is possible to send a profile to BRouter - server or app.

View 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
```

View file

@ -176,7 +176,7 @@ All expressions have one of the following basic forms:
- `and <boolean expression 1> <boolean expression 2>`
- `xor <boolean expression 1> <boolean 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>`
- `sub <numeric expression 1> <numeric expression 2>`
- `max <numeric expression 1> <numeric expression 2>`

View file

@ -67,3 +67,29 @@ application profiles"/>
The BRouter app should be launched before OsmAnd for this specific entry to
appear in OsmAnd. Therefore, if you cannot find "BRouter (offline)" navigation
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"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB