From 61d43c98440112509b1980200292fbaeb5ec6de6 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 3 Dec 2019 14:37:00 +0100 Subject: [PATCH 1/4] Spitting out all the details of a routing profile --- docs/itinero/basic-concepts/profiles/lua.md | 163 +++++++++++++++++--- 1 file changed, 142 insertions(+), 21 deletions(-) diff --git a/docs/itinero/basic-concepts/profiles/lua.md b/docs/itinero/basic-concepts/profiles/lua.md index 5de2849..14583a8 100644 --- a/docs/itinero/basic-concepts/profiles/lua.md +++ b/docs/itinero/basic-concepts/profiles/lua.md @@ -11,15 +11,37 @@ The default way to define a vehicle profile is by using [Lua](https://en.wikiped A vehicle can be defined by one lua script. This vehicle definition gets embedded in a @routerdb when created. This is the minimum code needed to define a profile: ```lua + +-- every vehicle type has a name: name = "car" --- whitelists for profile and meta + +-- which tags can be used by the profile to calculate weights - see explanation below profile_whitelist = { "highway" } + +-- which tags are kept in the output profile - see explanation below meta_whitelist = { "name" } --- profile definitions linking a function to a profile + + +--[[ +Profiles is used by itinero to know what behaviours of the vehicle are known; in this case these are 'car', 'car.shortest' and 'car.specificProfile'. + +Each profile has the following attributes: + +- name: the name of the subprofile +- function_name: a function that calculates the behaviour of this profile, for each segment: + - the speed for this segment in km/h that segment + - the factor (per meter) for that segment +- metric: what is the metric that we will optimize for. Can be one of the following: + - distance: only keep distance into account, neither speed nor factor will be used. Think speed=1 and factor=1 + - time: for every segment, the factor used is 1/speed (aka: time needed for this segment); the routeplanner will optimize for that + - custom: the weight (per meter) for each segment will be used. This custom factor will be minimized + + +--]] profiles = { { name = "", @@ -30,17 +52,75 @@ profiles = { name = "shortest", function_name = "factor_and_speed", metric = "distance", - } + }, + { + name = "specificProfile", + function_name = "some_factor_and_speed", + metric = "custom" + } } --- the main function turning attributes into a factor_and_speed and a tag whitelist -function factor_and_speed (attributes, result) - result.speed = 0 - result.direction = 0 - result.canstop = true - result.attributes_to_keep = {} +--[[ + +A "factor and speed function" converts a set of attributes into a speed and/or factor. +The input 'attributes' are the tags of the segment, as saved in OSM. +The input 'result' is pointer to a table where some values have to be specified by the end of the procedure call - see in this procedure for docs + + +Usually the default _factor_and_speed_ will define a speed for each possible set of profile attributes. Based on this Itinero can define a _fastest_ and a _shortest_ profile with metrics being _time_ and _distance_ respectively. + +A _custom_ profile uses a _factor_ to define weights of edges. This way, the factor can be used to guess a feeling of comfort, safety, preferences for certain roads, ... + +- With metric _distance_: Itinero will use the function to get the speed and set factor to a constant, usually 1. +- With metric _time_: Itinero will use the function to get the speed and set factor to 1/speed. +- With metric _custom_: Itinero will use the function to get the speed and the factor. + +]]-- +function factor_and_speed (attributes, result) - -- get default speed profiles + --[[ + Can this edge be accessed? + 0: no + 1: yes + ]]-- + result.access = 0 + + + --[[ + Do we have to drive in a certain direction? + 0: twoway + 1: oneway with the drawing direction of the highway + -1: oneway against the drawing direction of the highway + ]] + result.direction = 0 + + --[[ + Can a vehicle stop halfway the edge? + (e.g. can we drop of a package in the middle of the motorway or do we have to drive around to the nearby residential?) + ]] + result.canstop = true + + --[[ + On average, how fast would we be driving here (in km/h)? + This is used exclusively if 'time' is the used metric + Note: this should never exceed the legal max speed + ]] + result.speed = 0 + + --[[ + What is the weight (per kilometer) of this edge? + This is used exclusively if 'custom' is the used metric and will be minimized. + Note that setting `result.factor = 1 / speed` is equivalent to using the `time`-metric + ]] + result.factor = 0 + + --[[ + Which attributes (aka. key/value-pairs aka. tags) of this highway did we use to determine speed and factor ? + ]] + result.attributes_to_keep = {} + + + -- An example is: local highway = attributes.highway if highway == "motorway" or highway == "motorway_link" then @@ -60,23 +140,64 @@ The main _factor_and_speed_ is function is the most important active part of the - _profiles_: Defines the profiles for this vehicle, by default at minimum _fastest_ (with no name) and _shortest_ have to be defined. - _factor_and_speed_: The core of the vehicle definition, converts edge attributes into a factor and speed. -#### Profiles -A profile describes **the behaviour of a vehicle** and is defined by a _metric_, a function to calculate speed/factor and a name: +#### The profile and meta whitelists -- _metric_: This can be _time_, _distance_ or completely _custom_. -- _function_name_: The name of the function to calculate factor and/or speed. -- _name_: The name of the profile (an empty string automatically means 'fastest', the default). +_summary_: + - Tags of which the key is in `profile_whitelist` are used to determine speed and factor and visible in the called procedure. They must be copied if the tag is used to determine a factor. + - Tags of which the key is in `meta_whitelist` are copied from OSM and only visible in the constructed route. + - There are a few subtle pitfalls, read them below. -#### Factor and speed functions +When building a route planner, the routeplanner cares about certain information at certain times. The first phase consists of knowing how much time every street takes, the second phase is to find a sequence of streets so that the resulting sequence has a minimal time. At last, this sequence has to be translated into a useable format which has extra information such as streetnames. -A factor and speed function converts a set of attributes into a speed and/or factor. Usually the default _factor_and_speed_ will define a speed for each possible set of profile attributes. Based on this Itinero can define a _fastest_ and a _shortest_ profile with metrics being _time_ and _distance_ respectively. A _custom_ profile uses a _factor_ to define weights of edges. For shortest this factor is constant, usually equal to 1. +Ofcourse, the streetname has no effect on the speed or comfort of a street. In other words, it is only necessary to load the streetnames during the last phase, the translation. -To summarize there are three options when using a _factor_and_speed_ function: +To support this, two lists are defined: `profile_whitelist` and `meta_whitelist`. -- With metric _distance_: Itinero will use the function to get the speed and set factor to a constant, usually 1. -- With metric _time_: Itinero will use the function to get the speed and set factor to 1/speed. -- With metric _custom_: Itinero will use the function to get the speed and the factor. +The *profile_whitelist* contains the keys that can be used during the weight calculation. Typical examples are `highway` (in order to read the road classification), `access` (to know if a vehicle is allowed on the path), `maxspeed`, `surface` (to calculate comfort or even incorportate that a bad surface will go slower). + +The function called by the profile (in the example `factor_and_speed`) gets a table called `attributes`. This table only contains tags where the key is within `profile_whitelist`. + +Note that, whenever an attribute is used to determine speed and/or factor, the value must ALWAYS be added to `result.attributes_to_keep`. Itinero uses further optimizations based on the attribute table. Using a tag and not adding it will result in bugs. + + +The *meta_whitelist* contains values that are needed only in the output route. The prime example here is `name` and `ref`, the streetname of the road. Other examples are `bridge` and `tunnel` - they do not have an impact on speed or comfort, but they can be important clues for navigation. Another example is `colour` can contain colour of (cycle)networks, which might be needed as well. + +Having a value in the `meta_whitelist` means that the OSM tag is immediatly copied to the output. + +### Handling relations + +If you need information from relations to do route planning (e.g. prefer cycling networks), add a function called `relation_tag_processor`. +Important: the keys mentioned in `attributes_to_keep` have to be in the `profile_whitelist`, the keys needed by this function must be in `meta_whitelist`. + +```Lua + +-- Processes the relation. All tags which are added to result.attributes_to_keep will be copied to 'attributes' of each individual way +function relation_tag_processor (attributes, result) + result.attributes_to_keep = {} + if attributes.network == "lcn" then + result.attributes_to_keep.lcn = "yes" + end + + if attributes.colour ~= nil and + (result.attributes_to_keep.brussels == "yes" or result.attributes_to_keep.genk == "yes") + then + result.attributes_to_keep.cyclecolour = attributes.colour + end +end +``` + +### Logging and debugging + +In case of debugging, the following code can be used to debug a table (e.g. attributes): + + + for k, v in pairs( attributes ) do + itinero.log(tostring(k) .. "-->" .. tostring(v)) + end + itinero.log("\n------------------\n") + +This kills performance, don't use in production ## Default profiles From b742b39f3cdadd0a2f1edc46fdf56fa29d761729 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 3 Dec 2019 15:37:52 +0100 Subject: [PATCH 2/4] Add extra clarifications --- docs/itinero/basic-concepts/profiles/lua.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/itinero/basic-concepts/profiles/lua.md b/docs/itinero/basic-concepts/profiles/lua.md index 14583a8..cebefd6 100644 --- a/docs/itinero/basic-concepts/profiles/lua.md +++ b/docs/itinero/basic-concepts/profiles/lua.md @@ -15,6 +15,12 @@ A vehicle can be defined by one lua script. This vehicle definition gets embedde -- every vehicle type has a name: name = "car" +-- Enable extra optimizations; stronlgy urged to set to 'true'. No functional impact towards route planning +normalize = true + +-- Turn restrictions applying to these vehicles will be applied: +vehicle_types = {"vehicle", "car"} + -- which tags can be used by the profile to calculate weights - see explanation below profile_whitelist = { "highway" @@ -75,6 +81,8 @@ A _custom_ profile uses a _factor_ to define weights of edges. This way, the fac - With metric _time_: Itinero will use the function to get the speed and set factor to 1/speed. - With metric _custom_: Itinero will use the function to get the speed and the factor. +NOTE: the name of this function can be chosen, it only has to match the name given above. + ]]-- function factor_and_speed (attributes, result) From 2c6dc7775b87d9d86cd7c2fc5309ee27d53db1b7 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 4 Dec 2019 16:21:14 +0100 Subject: [PATCH 3/4] More clarifications --- docs/itinero/basic-concepts/profiles/lua.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/itinero/basic-concepts/profiles/lua.md b/docs/itinero/basic-concepts/profiles/lua.md index cebefd6..27e5dd0 100644 --- a/docs/itinero/basic-concepts/profiles/lua.md +++ b/docs/itinero/basic-concepts/profiles/lua.md @@ -98,7 +98,7 @@ function factor_and_speed (attributes, result) Do we have to drive in a certain direction? 0: twoway 1: oneway with the drawing direction of the highway - -1: oneway against the drawing direction of the highway + 2: oneway against the drawing direction of the highway ]] result.direction = 0 @@ -176,6 +176,10 @@ Having a value in the `meta_whitelist` means that the OSM tag is immediatly copi ### Handling relations If you need information from relations to do route planning (e.g. prefer cycling networks), add a function called `relation_tag_processor`. +This function is called for every relation. The tags that should be kept must be copied into `result.attributes_to_keep`. + +All these attributes are then added onto the attributes of every element which is part of the relation. If a key already exists in the tagcollection of that way, the new value will be appended with `,` between them. + Important: the keys mentioned in `attributes_to_keep` have to be in the `profile_whitelist`, the keys needed by this function must be in `meta_whitelist`. ```Lua @@ -195,6 +199,14 @@ function relation_tag_processor (attributes, result) end ``` +### Handling nodes + +At the moment, giving delays for e.g. traffic lights is not supported. + +[https://github.com/itinero/routing/issues/285] + +`node_restrictions` can calculate that a road is not accessible, see an example here: [https://github.com/itinero/routing/blob/develop/src/Itinero/Osm/Vehicles/car.lua#L93] + ### Logging and debugging In case of debugging, the following code can be used to debug a table (e.g. attributes): From 9ace7f5e1a9d7143bfcf37f4458787f81b198f8f Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Wed, 4 Dec 2019 17:17:48 +0100 Subject: [PATCH 4/4] Extra clarification --- docs/itinero/basic-concepts/profiles/lua.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/itinero/basic-concepts/profiles/lua.md b/docs/itinero/basic-concepts/profiles/lua.md index 27e5dd0..8e0bc06 100644 --- a/docs/itinero/basic-concepts/profiles/lua.md +++ b/docs/itinero/basic-concepts/profiles/lua.md @@ -44,7 +44,7 @@ Each profile has the following attributes: - metric: what is the metric that we will optimize for. Can be one of the following: - distance: only keep distance into account, neither speed nor factor will be used. Think speed=1 and factor=1 - time: for every segment, the factor used is 1/speed (aka: time needed for this segment); the routeplanner will optimize for that - - custom: the weight (per meter) for each segment will be used. This custom factor will be minimized + - custom: the weight (per meter) for each segment will be used. This custom factor will be minimized. This implies that the metric 'speed' will not be used anymore for determining the route --]]