This commit is contained in:
Manuel Fuhr 2021-11-30 18:41:50 +01:00
parent dfc4bff7fd
commit 87a5cd21e8

View file

@ -4,51 +4,43 @@ Profile developers guide - Technical reference for BRouter profile scripts
The tag-value lookup table The tag-value lookup table
-------------------------- --------------------------
Within the routing data files (rd5), tag information Within the routing data files (rd5), tag information is encoded in a binary
is encoded in a binary bitstream for the way tags and bitstream for the way tags and the node tags each.
the node tags each.
To encode and decode to/from this bitstream, a lookup To encode and decode to/from this bitstream, a lookup table is used that
table is used that contains all the tags and values contains all the tags and values that are considered for encoding.
that are considered for encoding.
For each tag there are 2 special values: For each tag there are 2 special values:
- `<empty>` if the tag is not set or the value is empty - `<empty>` if the tag is not set or the value is empty
- `unknown` if the value is not contained in the table - `unknown` if the value is not contained in the table
Each value can have optional *aliases*, these alias Each value can have optional *aliases*, these alias values are encoded into the
values are encoded into the same binary value as the same binary value as the associated primary value.
associated primary value.
A profile must use the primary value in expressions, as A profile must use the primary value in expressions, as aliases trigger a parse
aliases trigger a parse error. E.g. if there is a line error. E.g. if there is a line in `lookups.dat` file:
in `lookups.dat` file:
`bicycle;0001245560 yes allowed` `bicycle;0001245560 yes allowed`
then a profile must use `bicycle=yes`, as `bicycle=allowed` then a profile must use `bicycle=yes`, as `bicycle=allowed` gives an error.
gives an error.
The numbers in the lookup table are statistical The numbers in the lookup table are statistical information on the frequency of
information on the frequency of the values in the the values in the map of Germany - these are just informational and are not
map of Germany - these are just informational and processed by BRouter.
are not processed by BRouter.
Context-Separation Context-Separation
------------------ ------------------
Way-tags and Node-Tags are treated independently, Way-tags and Node-Tags are treated independently, so there are different
so there are different sections in the lookup table sections in the lookup table as well as in the profile scripts for each context.
as well as in the profile scripts for each context. The special tags: `---context:way` and `---context:node` mark the beginning of
The special tags: `---context:way` and `---context:node` each section.
mark the beginning of each section.
An exception from context separation is the node-context, An exception from context separation is the node-context, where variables from
where variables from the way-context of the originating the way-context of the originating way can be accessed using the `way:` prefix.
way can be accessed using the `way:` prefix. For the For the variable nodeaccessgranted there's an additional legacy-hack to access
variable nodeaccessgranted there's an additional it as a lookup value without prefix:
legacy-hack to access it as a lookup value without prefix:
`if nodeaccessgranted=yes then ...` `if nodeaccessgranted=yes then ...`
@ -56,19 +48,17 @@ while in the general case the prefixed expressions are variables:
`if greater way:costfactor 5 then ...` `if greater way:costfactor 5 then ...`
In the profile scripts there is a third context `global` In the profile scripts there is a third context `global` which contains global
which contains global configuration which is shared for configuration which is shared for all contexts and is accessible by the routing
all contexts and is accessible by the routing engine. engine.
The variables from the `global` section in the profile The variables from the `global` section in the profile scripts are read-only
scripts are read-only visible in the `way` and visible in the `way` and `node` sections of the scripts.
`node` sections of the scripts.
Predefined variables in the profile scripts Predefined variables in the profile scripts
------------------------------------------- -------------------------------------------
Some variable names are pre-defined and accessed by Some variable names are pre-defined and accessed by the routing engine:
the routing engine:
- for the global section these are: - for the global section these are:
@ -88,30 +78,29 @@ the routing engine:
- `validForFoot` - `validForFoot`
- `validForCars` - `validForCars`
- 2 variables to change the heuristic - 2 variables to change the heuristic coefficients for the 2 routing passes (
coefficients for the 2 routing passes <0 disables a routing pass )
( <0 disables a routing pass )
- `pass1coefficient` - `pass1coefficient`
- `pass2coefficient` - `pass2coefficient`
- 3 variables to influence the generation of turn-instructions - 3 variables to influence the generation of turn-instructions
- `turnInstructionMode` 0=none, 1=auto-choose, 2=locus-style, 3=osmand-style - `turnInstructionMode` 0=none, 1=auto-choose, 2=locus-style,
3=osmand-style
- `turnInstructionCatchingRange` default=40m - `turnInstructionCatchingRange` default=40m
- `turnInstructionRoundabouts` default=true generate explicit roundabout hints - `turnInstructionRoundabouts` default=true generate explicit roundabout
hints
- variables to modify BRouter behaviour - variables to modify BRouter behaviour
- `processUnusedTags` default=false - `processUnusedTags` default=false
If an OSM tag is unused within the profile, If an OSM tag is unused within the profile, BRouter totally ignores the
BRouter totally ignores the tag existence. tag existence. Skipping unused tags improves BRouter speed. As a side
Skipping unused tags improves BRouter speed. effect, the tag is not even listed in the route segment table nor the
As a side effect, the tag is not even listed table exported as CSV. Setting it to true/1, Brouter-web Data page will
in the route segment table nor the table exported as CSV. list all tags present in the RD5 file.
Setting it to true/1, Brouter-web Data page will list
all tags present in the RD5 file.
- for the way section these are - for the way section these are
@ -133,21 +122,18 @@ Operators of the profile scripts
The profile scripts use polish notation (operator first). The profile scripts use polish notation (operator first).
The `assign` operator is special: it can be used The `assign` operator is special: it can be used only on the top level of the
only on the top level of the expression hierarchy expression hierarchy and has 2 operands:
and has 2 operands:
`assign <variable-name> <expression>` `assign <variable-name> <expression>`
It just assigns the expression value to this It just assigns the expression value to this variable (which can be a predefined
variable (which can be a predefined variable or variable or any other variable, which in this case is defined implicitly). The
any other variable, which in this case is defined expression can be a complex expression using other operators.
implicitly). The expression can be a complex expression
using other operators.
All other operators can be used recursively to an unlimited All other operators can be used recursively to an unlimited complexity, which
complexity, which means that each operand can be a composed means that each operand can be a composed expression starting with an operator
expression starting with an operator and so on. and so on.
All expressions have one of the following basic forms: All expressions have one of the following basic forms:
@ -158,13 +144,13 @@ All expressions have one of the following basic forms:
- `<2-op-operator> <operand> <operand>` - `<2-op-operator> <operand> <operand>`
- `<3-op-operator> <operand> <operand> <operand>` - `<3-op-operator> <operand> <operand> <operand>`
- A numeric value is just a number, floating point, with `.` as - A numeric value is just a number, floating point, with `.` as decimal
decimal separator. Boolean values are treated as numbers as well, separator. Boolean values are treated as numbers as well, with `0` = `false`
with `0` = `false` and every nonzero value = `true`. and every nonzero value = `true`.
- A lookup match has the form `<tag-name>=<value>`, e.g. `highway=primary` - A lookup match has the form `<tag-name>=<value>`, e.g. `highway=primary` Only
Only the primary values can be used in lookup-matches, not aliases. the primary values can be used in lookup-matches, not aliases. The `<empty>`
The `<empty>` value is referred to as an empty string, e.g. `access=` value is referred to as an empty string, e.g. `access=`
- 1 Operand operators are: - 1 Operand operators are:
@ -188,26 +174,26 @@ All expressions have one of the following basic forms:
- `switch <boolean-expression> <true-expression> <false-expression>` - `switch <boolean-expression> <true-expression> <false-expression>`
So the switch expression has a numeric value which is the So the switch expression has a numeric value which is the true-expression if
true-expression if the boolean expression is true, the the boolean expression is true, the false-expression otherwise.
false-expression otherwise.
Syntactic Sugar Syntactic Sugar
--------------- ---------------
To improve the readablity of the profile scripts, some syntactic variations To improve the readablity of the profile scripts, some syntactic variations are
are possible: possible:
- if then else: `if` can be used instead of the `switch` operator, if the - if then else: `if` can be used instead of the `switch` operator, if the
additional keywords `then` and `else` are placed between the operators: additional keywords `then` and `else` are placed between the operators:
`if <boolean-expression> then <true-expression> else <false-expression>` `if <boolean-expression> then <true-expression> else <false-expression>`
- Parentheses: each expression can be surrounded by parentheses: `(<expression>)` - Parentheses: each expression can be surrounded by parentheses:
`(<expression>)`
Please note that the profile syntax, due to the polish notation, does not Please note that the profile syntax, due to the polish notation, does not need
need parentheses, they are always optional. However, if there are parentheses, parentheses, they are always optional. However, if there are parentheses, the
the parser checks if they really match the expression boundaries. parser checks if they really match the expression boundaries.
- or-ing lookup-matches: the pipe-symbol can be used as a short syntax for - or-ing lookup-matches: the pipe-symbol can be used as a short syntax for
lookup matches where more than one value is accepted for a key: lookup matches where more than one value is accepted for a key:
@ -219,42 +205,42 @@ are possible:
- boolean constants: `true` and `false` can be used instead of 1 and 0 - boolean constants: `true` and `false` can be used instead of 1 and 0
Please note that the tokenizer always expects blank space to separate Please note that the tokenizer always expects blank space to separate symbols
symbols and expressions so it is not allowed to place parentheses or and expressions so it is not allowed to place parentheses or the `=` symbol
the `=` symbol without separating blank space! without separating blank space!
The initial cost classifier The initial cost classifier
--------------------------- ---------------------------
To trigger the addition of the `initialcost`, another variable is used: To trigger the addition of the `initialcost`, another variable is used:
`initialclassifier` - any change in the value of that variable leads `initialclassifier` - any change in the value of that variable leads to adding
to adding the value of `initialcost`. the value of `initialcost`.
Initial cost is used typically for a ferry, where you want to apply Initial cost is used typically for a ferry, where you want to apply a penalty
a penalty independent of the length of the ferry line. independent of the length of the ferry line.
Another useful case may be an initial cost for bicycle mounting/dismounting, Another useful case may be an initial cost for bicycle mounting/dismounting,
having set an initialclassifier for ways without bicycle access, with high initialcost. having set an initialclassifier for ways without bicycle access, with high
For backward compatibility, if `initialclassifier` = 0, it is replaced initialcost. For backward compatibility, if `initialclassifier` = 0, it is
by the costfactor. replaced by the costfactor.
The priority classifier The priority classifier
----------------------- -----------------------
`priorityclassifier` is a BRouter numerical parameter `priorityclassifier` is a BRouter numerical parameter calculated for ways and
calculated for ways and used for generation of pictogram/voice navigation instructions. used for generation of pictogram/voice navigation instructions.
Higher values means the more significant (noticeable) way, Higher values means the more significant (noticeable) way, as far as it can be
as far as it can be predicted from OSM data. predicted from OSM data.
To avoid a navigation instruction flood, it was decided To avoid a navigation instruction flood, it was decided that the instructions
that the instructions are provided only if: are provided only if:
1. You are supposed to turn at a crossroad/junction 1. You are supposed to turn at a crossroad/junction and some other ways having
and some other ways having the same or higher `priorityclassifier` value. the same or higher `priorityclassifier` value.
2. You are supposed to go straight ahead 2. You are supposed to go straight ahead and some other ways having the higher
and some other ways having the higher `priorityclassifier` value. `priorityclassifier` value.
The elevation buffer ( From Poutnik's glossary ) The elevation buffer ( From Poutnik's glossary )
------------------------------------------------ ------------------------------------------------
@ -265,21 +251,22 @@ With related 3 internal BRouter variables:
- `elevationmaxbuffer` - `elevationmaxbuffer`
- `elevationbufferreduce` - `elevationbufferreduce`
the Elevation Buffer is BRouter feature to filter elevation noise along the route. the Elevation Buffer is BRouter feature to filter elevation noise along the
It may be real, or caused by the artefacts of used SRTM elevation data. route. It may be real, or caused by the artefacts of used SRTM elevation data.
From every elevation change is at the first place cut out amount `10*up/downhillcutoff` From every elevation change is at the first place cut out amount
per every km of the way length. What remains, starts to accumulate in the buffer. `10*up/downhillcutoff` per every km of the way length. What remains, starts to
IF cutoff demand of elevation per length is not saturated from incoming elevation, accumulate in the buffer. IF cutoff demand of elevation per length is not
it is applied on elevation remaining in the buffer as well. saturated from incoming elevation, it is applied on elevation remaining in the
buffer as well.
E.g. if the way climbs 20 m along 500 m, and `uphillcutoff=3.0`, then `10*3.0*0.5 km = 15 m` E.g. if the way climbs 20 m along 500 m, and `uphillcutoff=3.0`, then
is taken away and only remaining 5 m accumulates. But if it climbed only 10 m `10*3.0*0.5 km = 15 m` is taken away and only remaining 5 m accumulates. But if
on those 500 m, all 10 m would be *swallowed* by cutoff, it climbed only 10 m on those 500 m, all 10 m would be *swallowed* by cutoff,
together with up to 5 m from the buffer, if there were any. together with up to 5 m from the buffer, if there were any.
When elevation does not fit the buffer of size `elevationmaxbuffer`, When elevation does not fit the buffer of size `elevationmaxbuffer`, it is
it is converted by up/downhillcost ratio to Elevationcost portion of Equivalentlength. converted by up/downhillcost ratio to Elevationcost portion of Equivalentlength.
Up/downhillcostfactors are used, if defined, otherwise costfactor is used. Up/downhillcostfactors are used, if defined, otherwise costfactor is used.
- `elevationpenaltybuffer` - default 5(m). - `elevationpenaltybuffer` - default 5(m).
@ -315,43 +302,41 @@ All slopes within 0 .. 1.5% are swallowed by the cutoff.
- For slope 1.75%, there will remain 0.25%. - For slope 1.75%, there will remain 0.25%.
That saturates the elevationbufferreduce 0.5% by 50%. That gives Way That saturates the elevationbufferreduce 0.5% by 50%. That gives Way cost to
cost to be calculated 50% from costfactor and 50% from be calculated 50% from costfactor and 50% from Up/downhillcostfactor.
Up/downhillcostfactor. Additionally, 0.25% gives 2.5m per 1km, Additionally, 0.25% gives 2.5m per 1km, converted to 2.5*60 = 150m of
converted to 2.5*60 = 150m of Elevationcost. Elevationcost.
- For slope 2.0%, there will remain 0.5%. - For slope 2.0%, there will remain 0.5%.
That saturates the elevationbufferreduce 0.5% by 100%. That gives Way That saturates the elevationbufferreduce 0.5% by 100%. That gives Way cost to
cost to be calculated fully from `up/downhillcostfactor`. be calculated fully from `up/downhillcostfactor`. Additionally, 0.5% gives 5m
Additionally, 0.5% gives 5m per 1km, converted to 5*60 = 300m of per 1km, converted to 5*60 = 300m of Elevationcost. Up to slope 2.0% the
Elevationcost. Up to slope 2.0% the buffer value stays at 5m = buffer value stays at 5m = `elevationpenaltybuffer`.
`elevationpenaltybuffer`.
- For slope 2.5%, there will remain 1.0% after cutoff subtract, and 0.5% - For slope 2.5%, there will remain 1.0% after cutoff subtract, and 0.5% after
after the buffer reduce subtract. the buffer reduce subtract.
The remaining 0.5% accumulates in the buffer by rate 5 m/km. When the The remaining 0.5% accumulates in the buffer by rate 5 m/km. When the buffer
buffer is full (elevationmaxbuffer), the elevation transforms to is full (elevationmaxbuffer), the elevation transforms to elevationcost by
elevationcost by full rate of 1.0%, i.e. 10 m/km, giving elevationcost full rate of 1.0%, i.e. 10 m/km, giving elevationcost 10*60=600 m/km.
10*60=600 m/km.
Technical constraints Technical constraints
--------------------- ---------------------
- The costfactor is required to be >= 1, otherwise the cost-cutoff - The costfactor is required to be >= 1, otherwise the cost-cutoff logic of the
logic of the routing algorithm does not work and you get wrong results. routing algorithm does not work and you get wrong results.
- The profile should be able to find a route with an average costfactor - The profile should be able to find a route with an average costfactor not very
not very much larger than one, because otherwise the routing algorithm much larger than one, because otherwise the routing algorithm will not find a
will not find a reasonable cost-cutoff, leading to a very large reasonable cost-cutoff, leading to a very large search area and thus to long
search area and thus to long processing times. processing times.
- Forbidden ways or nodes must be treated as very high cost, because - Forbidden ways or nodes must be treated as very high cost, because there is no
there is no *forbidden* value. Technically, values >= 10000 for a *forbidden* value. Technically, values >= 10000 for a (way-)costfactor, and >=
(way-)costfactor, and >= 1000000 for a nodes `initalcost` are treated 1000000 for a nodes `initalcost` are treated as infinity, so please use these
as infinity, so please use these as the *forbidden* values. as the *forbidden* values.
- Ways with costfactor >= 10000 are considered as if they did not exist at all. - Ways with costfactor >= 10000 are considered as if they did not exist at all.
@ -362,52 +347,49 @@ Technical constraints
Developing and debugging scripts Developing and debugging scripts
-------------------------------- --------------------------------
For developing scripts, the *brouter-web* web-application is your For developing scripts, the *brouter-web* web-application is your friend. You
friend. You can use that either online at https://brouter.de/brouter-web can use that either online at https://brouter.de/brouter-web or set up a local
or set up a local installation. installation.
*brouter-web* has a window at the lower left corner with a *Profile* *brouter-web* has a window at the lower left corner with a *Profile* and a
and a *Data* tab. Here, you can upload profile scripts and see *Data* tab. Here, you can upload profile scripts and see the individual cost
the individual cost calculations per way-section in the *Data*-tab. calculations per way-section in the *Data*-tab.
For profile debugging activate `assign processUnusedTags = true` For profile debugging activate `assign processUnusedTags = true` to see all
to see all present OSM tags on the Data tab, not just those used in the tested profile. present OSM tags on the Data tab, not just those used in the tested profile.
Lookup-Table evolution and the the *major* and *minor* versions Lookup-Table evolution and the the *major* and *minor* versions
--------------------------------------------------------------- ---------------------------------------------------------------
The lookup-table is allowed to grow over time, to include more tags The lookup-table is allowed to grow over time, to include more tags and values
and values as needed. To support that evolution, it carries a major as needed. To support that evolution, it carries a major and a minor version
and a minor version number. These numbers are also encoded into number. These numbers are also encoded into the routing data files, taken from
the routing data files, taken from the lookups.dat that is used the lookups.dat that is used to pre-process the routing data files.
to pre-process the routing data files.
A major version change is considered to always break compatibility A major version change is considered to always break compatibility between the
between the routing datafiles and the lookup table. routing datafiles and the lookup table.
A minor version change keeps the routing data files and the lookup-table A minor version change keeps the routing data files and the lookup-table
compatible in both directions, using the following rules: compatible in both directions, using the following rules:
- if the data contains a key that is not contained in the lookup - if the data contains a key that is not contained in the lookup tables, it is
tables, it is ignored ignored
- if the data contains a value that is not contained in the lookup - if the data contains a value that is not contained in the lookup tables (but
tables (but its key is known) that value is treated as `unknown` its key is known) that value is treated as `unknown`
- if a profile uses a key that is not present in the data, - if a profile uses a key that is not present in the data, it sees empty
it sees empty (=unset) values for that key (=unset) values for that key
- if a profile uses a value that is not present in the data, - if a profile uses a value that is not present in the data, lookup matches for
lookup matches for that value are always false. that value are always false.
For a minor version change it is required that tags are only For a minor version change it is required that tags are only appended at the end
appended at the end of the table (or replace one of the dummy of the table (or replace one of the dummy tags located between the way-tags and
tags located between the way-tags and the relation pseudo-tags), the relation pseudo-tags), and that values are only appended at the end of the
and that values are only appended at the end of the value lists. value lists. This is because the routing data files address tags and values by
This is because the routing data files address tags and values their sequence numbers, so changing sequences would produce garbage data.
by their sequence numbers, so changing sequences would produce
garbage data.
Other resources Other resources
--------------- ---------------