diff --git a/CHANGELOG.md b/CHANGELOG.md
index cae2710f95b..ba57f7de94f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
+# Changelog
+
# Unreleased
- Changes from 6.0.0
+ - Features
+ - ADDED: Pedestrian area routing [#7161](https://github.com/Project-OSRM/osrm-backend/pull/7161)
- Routing:
- FIXED: Crash when route starts or ends at `type=manoeuvre` relation via node [#7287](https://github.com/Project-OSRM/osrm-backend/issues/7287)
- Extraction:
@@ -232,7 +236,7 @@
- CHANGED: Docker build, enabled arm64 build layer [#6172](https://github.com/Project-OSRM/osrm-backend/pull/6172)
- CHANGED: Docker build, enabled apt-get update/install caching in separate layer for build phase [#6175](https://github.com/Project-OSRM/osrm-backend/pull/6175)
- FIXED: Bump CI complete meta job to ubuntu-20.04 [#6323](https://github.com/Project-OSRM/osrm-backend/pull/6323)
- - CHANGED: Node packages are now scoped by @project-osrm [#6386](https://github.com/Project-OSRM/osrm-backend/issues/6386)
+ - CHANGED: Node packages are now scoped by \@project-osrm [#6386](https://github.com/Project-OSRM/osrm-backend/issues/6386)
- Routing:
- CHANGED: Lazily generate optional route path data [#6045](https://github.com/Project-OSRM/osrm-backend/pull/6045)
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
@@ -267,7 +271,7 @@
- Build:
- CHANGED: Node binaries now use Github Releases for hosting [#6030](https://github.com/Project-OSRM/osrm-backend/pull/6030)
- Misc:
- - FIXED: Upgrade to @mapbox/node-pre-gyp fix various bugs with Node 12/14 [#5991](https://github.com/Project-OSRM/osrm-backend/pull/5991)
+ - FIXED: Upgrade to \@mapbox/node-pre-gyp fix various bugs with Node 12/14 [#5991](https://github.com/Project-OSRM/osrm-backend/pull/5991)
- FIXED: `valid` type in documentation examples [#5990](https://github.com/Project-OSRM/osrm-backend/issues/5990)
- FIXED: Remove redundant loading of .osrm.cell_metrics [#6019](https://github.com/Project-OSRM/osrm-backend/issues/6019)
- CHANGED: Increase PackedOSMIDs size to 34 bits. This breaks the **data format** [#6020](https://github.com/Project-OSRM/osrm-backend/issues/6020)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a6115254f1e..1627a660210 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,14 +1,16 @@
-# Everyone
+# Contributing
+
+## Everyone
Please take some time to review our [code of conduct](CODE-OF-CONDUCT.md) to help guide your interactions with others on this project.
-# User
+## User
Before you open a new issue, please search for older ones that cover the same issue.
In general "me too" comments/issues are frowned upon.
You can add a :+1: emoji reaction to the issue if you want to express interest in this.
-# Developer
+## Developer
We follow the [LLVM AI Tool policy](https://llvm.org/docs/AIToolPolicy.html).
@@ -23,6 +25,7 @@ If you can not follow these guidelines PLEASE REFRAIN FROM CONTRIBUTING.
We use `clang-format` version `15` to consistently format the code base. There is a helper script under `scripts/format.sh`.
The format is automatically checked by the `mason-linux-release` job of a Travis CI build.
To save development time a local hook `.git/hooks/pre-push`
+
```
#!/bin/sh
@@ -43,11 +46,10 @@ Also the `pre-push` hook rejects direct pushes to `origin/master`.
⚠️ `scripts/format.sh` checks all local files that match `*.cpp` or `*.hpp` patterns.
-
In general changes that affect the API and/or increase the memory consumption need to be discussed first.
Often we don't include changes that would increase the memory consumption a lot if they are not generally usable (e.g. elevation data is a good example).
-## Pull Request
+### Pull Request
Every pull-request that changes the API needs to update the docs in `docs/http.md` and add an entry to `CHANGELOG.md`.
Breaking changes need to have a BREAKING prefix. See the [releasing documentation](docs/releasing.md) on how this affects the version.
@@ -67,25 +69,25 @@ If you do have commit access there are in general two accepted styles to merging
1. Make sure the branch is up to date with `master`. Run `git rebase master` to find out.
2. Once that is ensured you can either:
- - Click the nice green merge button (for a non-fast-forward merge)
- - Merge by hand using a fast-forward merge
+
+- Click the nice green merge button (for a non-fast-forward merge)
+- Merge by hand using a fast-forward merge
Which merge you prefer is up to personal preference. In general it is recommended to use fast-forward merges because it creates a history that is sequential and easier to understand.
-# Maintainer
+## Maintainer
-## Doing a release
+### Doing a release
There is an in-depth guide around how to push out a release once it is ready [here](docs/releasing.md).
-## The API
+### The API
Changes to the API need to be discussed and signed off by the team. Breaking changes even more so than additive changes.
-## Milestones
+### Milestones
If a pull request or an issue is applicable for the current or next milestone, depends on the target version number.
Since we use semantic versioning we restrict breaking changes to major releases.
After a Release Candidate is released we usually don't change the API anymore if it is not critical.
Bigger code changes after a RC was released should also be avoided.
-
diff --git a/Doxyfile.in b/Doxyfile.in
index dd51b16d724..1ca9c4a914e 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -13,14 +13,14 @@ QUIET = YES
INPUT = @CMAKE_CURRENT_SOURCE_DIR@
USE_MDFILE_AS_MAINPAGE = @CMAKE_CURRENT_SOURCE_DIR@/README.md
-FILE_PATTERNS = *.h *.hpp *.c *.cc *.cpp *.md
+FILE_PATTERNS = *.h *.hpp *.c *.cc *.cpp *.md *.dox
RECURSIVE = YES
EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/third_party \
@CMAKE_CURRENT_SOURCE_DIR@/build \
@CMAKE_CURRENT_SOURCE_DIR@/node_modules \
@CMAKE_CURRENT_SOURCE_DIR@/unit_tests \
- @CMAKE_CURRENT_SOURCE_DIR@/benchmarks \
+ @CMAKE_CURRENT_SOURCE_DIR@/benchmarks \
@CMAKE_CURRENT_SOURCE_DIR@/features
SOURCE_BROWSER = YES
@@ -40,5 +40,4 @@ CALLER_GRAPH = YES
DOT_IMAGE_FORMAT = svg
INTERACTIVE_SVG = YES
DOT_GRAPH_MAX_NODES = 500
-DOT_TRANSPARENT = YES
DOT_MULTI_TARGETS = YES
diff --git a/README.md b/README.md
index e14cf92a3bc..d6c8e7054ec 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,6 @@ Related [Project-OSRM](https://github.com/Project-OSRM) repositories:
- [Hosted documentation](http://project-osrm.org)
- [osrm-routed HTTP API documentation](docs/http.md)
-- [libosrm API documentation](docs/libosrm.md)
## Contact
diff --git a/docs/areas.md b/docs/areas.md
new file mode 100644
index 00000000000..b869e749aef
--- /dev/null
+++ b/docs/areas.md
@@ -0,0 +1,109 @@
+# How to route inside pedestrian areas {#pedestrian_areas}
+
+How to route inside pedestrian areas, or over the interior of an area where you can
+travel freely in all directions.
+
+%OSRM can create routes crossing the interior of an area by generating virtual ways
+between every pair of entry points to the area. This process is called @em meshing. The
+generated ways follow lines of sight, avoid obstacles, and use existing nodes. An entry
+point is where another way connects to the perimeter of the area.
+
+This feature is still EXPERIMENTAL.
+
+## Configuration
+
+To opt-in to this feature, you must declare an algorithm to be used for area meshing.
+Find your LUA profile's @ref setup function and insert this line:
+
+```lua
+function setup()
+ ...
+ area_manager:init('visgraph+dijkstra')
+ ...
+end
+```
+
+Note: Only the `visgraph+dijkstra` algorithm is available at present.
+
+All areas to be meshed must be registered with the @ref AreaManager. In OpenStreetMap
+areas are mapped either as a closed way or as a multipolygon relation. Both flavours
+must be configured separately.
+
+### Meshing closed ways
+
+To mesh a closed way you must register it in your @ref process_way function. Insert
+following lines into your existing `process_way` function, immediately after the "quick
+initial test":
+
+```lua
+function process_way(profile, way, result, relations)
+ ...
+ if way:has_tag('highway', 'pedestrian') and way:has_true_tag('area') then
+ -- register the way
+ area_manager:way(way)
+ return
+ end
+ ...
+end
+```
+
+(Note that open ways cannot be meshed and will be ignored.)
+
+### Meshing multipolygon relations
+
+To mesh a multipolygon relation you must register it in the @ref process_relation
+function. The `process_relation` function is a newly introduced function that is called
+for every relation in the input file. You'll have to create the function like this:
+
+```lua
+function process_relation(profile, relation, relations)
+ if relation:has_tag('type', 'multipolygon') and relation:has_tag('highway', 'pedestrian') then
+ -- register the relation
+ area_manager:relation(relation)
+ end
+end
+```
+
+And you must also return the `process_relation` function at the end of your profile:
+
+```lua
+return {
+ setup = setup,
+ process_way = process_way,
+ process_node = process_node,
+ process_relation = process_relation, -- << add this line
+ ...
+}
+```
+
+At this point you have a working basic configuration. Remember that you must run
+`osrm-extract` before your changes become effective.
+
+### Processing the generated ways
+
+While not necessary, you may want to apply further processing to the @em generated ways.
+The generated ways are passed to the @ref process_way function in the usual fashion.
+They have the same tags as the original way or relation, except:
+
+- the `area` tag is removed on ways,
+- the `type` tag is removed on relations,
+- an `osrm:virtual=yes` tag is added.
+
+You can pick generated ways like this:
+
+```lua
+function process_way(profile, way, result, relations)
+ ...
+ if way:has_key('osrm:virtual') then
+ -- do something with the way here
+ end
+ ...
+end
+```
+
+@sa AreaManager
+
A complete example profile is found in the file: [profiles/foot_area.lua](../profiles/foot_area.lua).
+
https://wiki.openstreetmap.org/wiki/Relation:multipolygon
+
https://wiki.openstreetmap.org/wiki/Key:area
+
https://wiki.openstreetmap.org/wiki/Tag:highway%3Dpedestrian#Squares_and_plazas
diff --git a/docs/lua-types.dox b/docs/lua-types.dox
new file mode 100644
index 00000000000..8d48b22f0f6
--- /dev/null
+++ b/docs/lua-types.dox
@@ -0,0 +1,466 @@
+/**
+ * @defgroup LUA LUA Types
+ *
+ * This page is about types as seen from inside the LUA scripting language.
+ *
+ * @{
+ */
+
+class Boolean;
+class Float;
+class Integer;
+class String;
+class Table;
+class Location;
+
+/**
+ * @brief The type of an OSM object
+ */
+enum class item_type
+{
+ node = 1, /**< An OSM node */
+ way = 2, /**< An OSM way */
+ relation = 3 /**< An OSM relation */
+};
+
+/** @brief Represents an OSM object
+
+ Example:
+
+ ```.lua
+ if object:type() == item_type.way and object:id() == 42 then
+ local highway = object:get_key_by_value("highway")
+ local oneway = object:has_true_tag("oneway")
+ ...
+ end
+ ```
+ */
+class OSMObject
+{
+ public:
+ /** @brief Return the id of the OSM object. */
+ Integer id();
+
+ /** @brief Return the item type of the OSM object. */
+ item_type type();
+
+ /** @brief Return the version of the OSM object. */
+ Integer version();
+
+ /** @brief Return the value of the tag identified by key. If the key is not found, return
+ * `nil`. */
+ String get_value_by_key(String key);
+
+ /** @brief Return the value of the tag identified by key. If the key is not found, return the
+ default value. */
+ String get_value_by_key(String key, String default_value);
+
+ /** @brief Return true if a tag identified by the given key is found. */
+ Boolean has_key(String key);
+
+ /** @brief Return true if a tag with the given key and value is found. */
+ Boolean has_tag(String key, String value);
+
+ /**
+ * @brief Return true if a tag with the given key and a truthy value is found.
+ *
+ * Truthy values are: "yes", "true", and "1".
+ */
+ Boolean has_true_tag(String key);
+
+ /**
+ * @brief Return true if a tag with the given key and a falsey value is found.
+ *
+ * Falsey values are: "no", "false", and "0".
+ */
+ Boolean has_false_tag(String key);
+};
+
+/**
+ * @brief Represents a node
+ */
+class Node : public OSMObject
+{
+ public:
+ /** @brief Return the Location of the node. */
+ Location location();
+
+ /**
+ @brief Return location data for the node.
+
+ Location data is compiled by geographic region.
+
+ ```.lua
+ local driving_side = way:get_location_tag('driving_side')
+ ```
+ */
+ String get_location_tag(String key);
+};
+
+/**
+ * @brief Represents a way
+ */
+class Way : public OSMObject
+{
+ public:
+ /**
+ * @brief Return the number of nodes.
+ */
+ Integer size();
+
+ /**
+ * @brief Return true if the way is closed.
+ */
+ Boolean is_closed();
+
+ /**
+ * @brief Return the nodes.
+ * @return A table of Node objects.
+ */
+ Table get_nodes();
+
+ /**
+ * @brief Return location data for the way.
+ */
+ String get_location_tag(String key);
+};
+
+/**
+ * @brief Represents a relation
+ */
+class Relation : public OSMObject
+{
+ public:
+ /** @brief Return the role the given objects has in the relation or nil. */
+ String get_role(OSMObject);
+
+ /**
+ * @brief Return the members of the relation.
+ * @return A table of RelationMember objects.
+ */
+ Table get_members();
+};
+
+/**
+ * @brief Represents a relation member
+ */
+class RelationMember
+{
+ public:
+ /** @brief Return the OSM id of the member. */
+ Integer ref();
+ /** @brief Return the @ref item_type of the member: node, way, or relation. */
+ item_type type();
+ /** @brief Return the role of the member, eg. `outer`. */
+ String role();
+};
+
+/** @brief A storage container for relations.
+
+This container stores all relations that have one of the types configured in @ref
+relation_types plus all multipolygon relations registered for area meshing. It is
+passed as parameter `relations` to the @ref process_node, @ref process_way, and @ref
+process_relation functions. By querying this container you can find out if a node or
+way or relation is member of any stored relation.
+
+Example:
+
+```lua
+for _, rel_id in pairs(relations:get_relations(way))
+ local rel = relations:relation(rel_id)
+ if rel:get_value_by_key('type') == 'route' then
+ local role = rel:get_role(way)
+ local dir = rel:get_value_by_key('direction')
+ ...
+ end
+end
+```
+*/
+class Relations
+{
+ public:
+ /**
+ * @brief Return the ids of the relations that contain the given object.
+ *
+ * OSMObject may be a Node, Way or Relation.
+ *
+ * @return A table of Integer.
+ */
+ Table get_relations(OSMObject);
+ /**
+ * @brief Return the relation with the given id.
+ */
+ Relation relation(Integer relation_id);
+};
+
+/**
+ * @brief Represents the location of a node.
+ */
+class Location
+{
+ public:
+ /** @brief Return the latitude. */
+ Float lat();
+ /** @brief Return the longitude. */
+ Float lon();
+ /** @brief Return true if the location is valid. */
+ Boolean valid();
+};
+
+/**
+ * @brief The type of the obstacle
+ */
+enum class obstacle_type
+{
+ none, /**< No obstacle */
+ /**
+ * This and the following values have the same semantics as in the `highway` tag in
+ * OSM.
+ */
+ barrier,
+ traffic_signals,
+ stop,
+ give_way,
+ crossing,
+ traffic_calming,
+ mini_roundabout,
+ turning_loop,
+ turning_circle
+};
+
+/**
+ * @brief The direction of the obstacle
+ *
+ * The direction always refers to the way that the node is in. If the node is at either
+ * end of a way the direction may be undefined.
+ */
+enum class obstacle_direction
+{
+ none, /**< No obstacle */
+ forward, /**< The obstacle is present only in the forward direction. */
+ backward, /**< The obstacle is present only in the backward direction. */
+ both /**< The obstacle is present in both directions. */
+};
+
+/** @brief An obstacle on the road or a place where you can turn around.
+
+This may be a completely impassable obstacle like a barrier, a temporary obstacle like a
+traffic light or a stop sign, or an obstacle that just slows you down like a
+traffic_calming. The obstacle may be present in both directions or in one direction
+only.
+
+This also represents a good turning point like a `mini_roundabout`, `turning_loop`, or
+`turning_circle`.
+
+An object of this type is immutable once constructed.
+
+```lua
+local obs = Obstacle.new(
+ obstacle_type.traffic_signals,
+ obstacle_direction.forward,
+ 2.5,
+ 0
+)
+assert(obs.duration == 2.5)
+```
+*/
+
+class Obstacle
+{
+ public:
+ /** The type of the obstacle */
+ obstacle_type type;
+ /** The direction of the obstacle */
+ obstacle_direction direction;
+ /** The expected delay in seconds */
+ Float duration;
+ /** The obstacle weight */
+ Float weight;
+};
+
+/** @brief A registry for obstacles.
+
+The LUA global variable `obstacle_map` is an instance of this class.
+
+The canonical workflow is: to store obstacles in @ref process_node and retrieve them in
+@ref process_turn.
+
+Note: In the course of processing, between the `process_node()` stage and the
+`process_turn()` stage, the extractor switches from using OSM nodes to using internal
+nodes. Both types have different ids. You can only store OSM nodes and only retrieve
+internal nodes. This implies that, in `process_node()`, you cannot retrieve an obstacle
+you have just stored.
+*/
+
+class ObstacleMap
+{
+ public:
+ /**
+ @brief Register a new obstacle
+
+ Call this function inside @ref process_node to register an obstacle on a node. You
+ can register as many different obstacles as you wish on any given node. It is your
+ responsibility to register the same obstacle only once.
+
+ In a following step -- likely in @ref process_turn -- you can retrieve all
+ obstacles registered at any given node. This function works with OSM nodes.
+
+ Example:
+
+ ```lua
+ function process_node(profile, node, result, relations)
+ ...
+ obstacle_map:add(node,
+ Obstacle.new(
+ obstacle_type.traffic_signal,
+ obstacle_direction.forward,
+ 2, 0))
+ end
+ ```
+ */
+ void add(Node, Obstacle);
+
+ /**
+ @brief Return true if there are any obstacles
+
+ Return true if there are any obstacles at node `to` when coming from node
+ `from` and having the type `type`.
+
+ You will likely call this function inside @ref process_turn.
+ Note that this works only with internal nodes, not with OSM nodes.
+
+ Usage examples:
+
+ ```lua
+ function process_turn(profile, turn)
+ if obstacle_map:any(turn.via) then
+ ...
+ end
+ if obstacle_map:any(turn.from, turn.via, obstacle_type.traffic_signal) then
+ turn.duration = turn.duration + 2
+ end
+ end
+ ```
+
+ @param from The leading node. Optional.
+ @param to The node with the obstacle.
+ @param type The obstacle type. Defaults to all types. May be a bitwise-or
+ combination of types.
+
+ @return True if there are any obstacles satisfiying the given criteria.
+ */
+ Boolean any(Node from, Node to, obstacle_type type);
+ /** @overload */
+ Boolean any(Node from, Node to);
+ /** @overload */
+ Boolean any(Node to);
+
+ /** @brief Return all obstacles located at node.
+
+ This function retrieves all registered obstacles at node `to` when coming from the node
+ `from` and having the type `type`.
+
+ You will likely call this function inside @ref process_turn. Note that this works only
+ with internal nodes, not with OSM nodes.
+
+ @param from The leading node. Optional.
+ @param to The node with the obstacle.
+ @param type The obstacle type. Defaults to all types. May be a bitwise-or
+ combination of types.
+
+ @return A table of Obstacle objects.
+
+ Example:
+
+ ```lua
+ function process_turn(profile, turn)
+ for _, obs in pairs(obstacle_map:get(turn.via)) do
+ if obs.type == obstacle_type.barrier then
+ turn.duration = turn.duration + obs.duration
+ end
+ end
+ for _, obs in pairs(obstacle_map:get(
+ turn.from, turn.via, obstacle_type.traffic_signal)) do
+ turn.duration = turn.duration + obs.duration
+ end
+ end
+ ```
+ */
+ Table get(Node from, Node to, obstacle_type type);
+ /** @overload */
+ Table get(Node from, Node to);
+ /** @overload */
+ Table get(Node to);
+};
+
+/**
+ * @brief A registry for pedestrian areas.
+ *
+ * The LUA global variable `area_manager` is an instance of this class.
+ */
+class AreaManager
+{
+ public:
+ /**
+ * @brief Initialize the area manager
+ *
+ * Call this function inside @ref setup to initialize the area manager.
+ * The supplied algorithm will be used for meshing.
+ *
+ * @param algorithm_name The algorithm to use for meshing. At present only one
+ * algorithm is supported: 'visgraph+dijkstra'.
+ */
+ void init(String algorithm_name);
+
+ /**
+ * @brief Register a multipolygon relation for meshing.
+ *
+ * Call this function inside @ref process_relation to register a relation for
+ * meshing. The relation must be a multipolygon relation.
+ */
+ void relation(Relation);
+
+ /**
+ * @brief Register a closed way for meshing.
+ *
+ * Call this function inside @ref process_way to register a way for
+ * meshing. The way must be closed.
+ */
+ void way(Way);
+
+ /**
+ * @brief Return the registered relations for this node.
+ *
+ * Call this functions inside @ref process_node. If this node is a member of a
+ * relation that was registered for meshing, those relations will be returned.
+ *
+ * @return A Table of Relation objects.
+ */
+ Table get_relations(Node);
+
+ /**
+ @brief Return the registered relations for this way.
+
+ Call this functions inside @ref process_way. If this way is a member of a
+ relation that was registered for meshing, those relations will be returned.
+
+ @return A Table of Relation objects.
+ */
+ Table get_relations(Way);
+};
+
+/**
+ * @brief Return true if the value is truthy.
+ *
+ * Truthy values are: "yes", "true", and "1".
+ */
+Boolean is_true(String value); // NOLINT
+
+/**
+ * @brief Return true if the value is falsey.
+ *
+ * Falsey values are: "no", "false", and "0".
+ */
+Boolean is_false(String value); // NOLINT
+
+/** @} */
diff --git a/docs/profiles.md b/docs/profiles.md
index 48e8aebd986..54fb59b0605 100644
--- a/docs/profiles.md
+++ b/docs/profiles.md
@@ -47,7 +47,7 @@ A profile can also define various local functions it needs.
Looking at [car.lua](../profiles/car.lua) as an example, at the top of the file the api version is defined and then required library files are included.
-Then follows the `setup` function, which is called once when the profile is loaded. It returns a big hash table of configurations, specifying things like what speed to use for different way types. The configurations are used later in the various processing functions. Many adjustments can be done just by modifying this configuration table.
+Then follows the @ref setup function, which is called once when the profile is loaded. It returns a big hash table of configurations, specifying things like what speed to use for different way types. The configurations are used later in the various processing functions. Many adjustments can be done just by modifying this configuration table.
The setup function is also where you can do other setup, like loading an elevation data source if you want to consider that when processing ways.
@@ -79,6 +79,7 @@ If you set rate = speed on all ways, the result will be fastest path routing.
If you want to prioritize certain streets, increase the rate on these.
## Elements
+
### api_version
A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 4.
@@ -98,50 +99,65 @@ guidance.lua | Function for processing guidance attributes
They all return a table of functions when you use `require` to load them. You can either store this table and reference its functions later, or if you need only a single function you can store that directly.
-### setup()
+### setup() {#setup}
The `setup` function is called once when the profile is loaded and must return a table of configurations. It's also where you can do other global setup, like loading data sources that are used during processing.
Note that processing of data is parallelized and several unconnected Lua interpreters will be running at the same time. The `setup` function will be called once for each. Each Lua interpreter will have its own set of globals.
+@anchor properties
The following global properties can be set under `properties` in the hash you return in the `setup` function:
-Attribute | Type | Notes
--------------------------------------|----------|----------------------------------------------------------------------------
-weight_name | String | Name used in output for the routing weight property (default `'duration'`)
-weight_precision | Unsigned | Decimal precision of edge weights (default `1`)
-left_hand_driving | Boolean | Are vehicles assumed to drive on the left? (used in guidance, default `false`)
-use_turn_restrictions | Boolean | Are turn restrictions followed? (default `false`)
-continue_straight_at_waypoint | Boolean | Must the route continue straight on at a via point, or are U-turns allowed? (default `true`)
-max_speed_for_map_matching | Float | Maximum vehicle speed to be assumed in matching (in m/s)
-max_turn_weight | Float | Maximum turn penalty weight
-force_split_edges | Boolean | True value forces a split of forward and backward edges of extracted ways and guarantees that `process_segment` will be called for all segments (default `false`)
-
+Attribute | Type | Notes
+------------------------------|----------|----------------------------------------------------------------------------
+weight_name | String | Name used in output for the routing weight property (default `"duration"`)
+weight_precision | Unsigned | Decimal precision of edge weights (default `1`)
+left_hand_driving | Boolean | Are vehicles assumed to drive on the left? (used in guidance, default `false`)
+use_turn_restrictions | Boolean | Are turn restrictions followed? (default `false`)
+continue_straight_at_waypoint | Boolean | Must the route continue straight on at a via point, or are U-turns allowed? (default `true`)
+max_speed_for_map_matching | Float | Maximum vehicle speed to be assumed in matching (in m/s)
+max_turn_weight | Float | Maximum turn penalty weight
+force_split_edges | Boolean | True value forces a split of forward and backward edges of extracted ways and guarantees that `process_segment` will be called for all segments (default `false`)
The following additional global properties can be set in the hash you return in the `setup` function:
-Attribute | Type | Notes
--------------------------------------|------------------|----------------------------------------------------------------------------
-excludable | Sequence of Sets | Determines which class-combinations are supported by the `exclude` option at query time. E.g. `Sequence{Set{"ferry", "motorway"}, Set{"motorway"}}` will allow you to exclude ferries and motorways, or only motorways.
-classes | Sequence | Determines the allowed classes that can be referenced using `{forward,backward}_classes` on the way in the `process_way` function.
-restrictions | Sequence | Determines which turn restrictions will be used for this profile.
-suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
-relation_types | Sequence | Determines which relations should be cached for processing in this profile. It contains relations types
+Attribute | Type | Notes
+--------------------------------------|------------------|----------------------------------------------------------------------------
+excludable | Sequence of Sets | Determines which class-combinations are supported by the `exclude` option at query time. E.g. `Sequence{Set{"ferry", "motorway"}, Set{"motorway"}}` will allow you to exclude ferries and motorways, or only motorways.
+classes | Sequence | Determines the allowed classes that can be referenced using `{forward,backward}_classes` on the way in the `process_way` function.
+restrictions | Sequence | Determines which turn restrictions will be used for this profile.
+suffix_list | Set | List of name suffixes needed for determining if "Highway 101 NW" the same road as "Highway 101 ES".
+relation_types @anchor relation_types | Sequence | Determines which relation types should be stored for reference. Only these relation types will be queryable using the `relations` parameter in @ref process_node, @ref process_way, and @ref process_relation.
+
+### process_relation(profile, relation, relations) {#process_relation}
+
+@note This function is called only if @ref pedestrian_areas "area meshing" is
+configured. At present the only thing you can do here is to register areas for meshing.
-### process_node(profile, node, result, relations)
+The `process_relation` function is called for every relation in an early stage, before
+@ref process_node and @ref process_way are being called.
+
+Argument | Type | Description
+----------|------------|-------------------------------------------
+profile | Properties | The @ref properties configured in `setup`.
+relation | Relation | The relation to process.
+relations | Relations | Contains the parent relations of `relation`.
+
+### process_node(profile, node, result, relations) {#process_node}
Process an OSM node to determine whether this node is an obstacle, if it can be passed at all and whether passing it incurs a delay.
-Argument | Description
----------|-------------------------------------------------------
-profile | The configuration table you returned in `setup`.
-node | The input node to process (read-only).
-result | The output that you will modify.
-relations| Storage of relations to access relations, where `node` is a member.
+Argument | Type | Description
+----------|------------|-------------------------------------------
+profile | Properties | The @ref properties configured in `setup`.
+node | Node | The input node to process (read-only).
+result | | The output that you will modify.
+relations | Relations | Contains the parent relations of `node`.
+
+@note For new code use ObstacleMap instead of `result`.
The following attributes can be set on `result`:
-(Note: for new code use the `obstacle_map`.
Attribute | Type | Notes
-----------------|---------|---------------------------------------------------------
+----------------|---------|--------------------------------------------------------
barrier | Boolean | Is it an impassable barrier?
traffic_lights | Boolean | Is it a traffic light (incurs delay in `process_turn`)?
@@ -311,14 +327,15 @@ end
```
### process_way(profile, way, result, relations)
+>>>>>>> origin/master
Given an OpenStreetMap way, the `process_way` function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash.
-Argument | Description
----------|-------------------------------------------------------
-profile | The configuration table you returned in `setup`.
-way | The input way to process (read-only).
-result | The output that you will modify.
-relations| Storage of relations to access relations, where `way` is a member.
+Argument | Type | Description
+----------|------------|-------------------------------------------------
+profile | Properties | The @ref properties configured in `setup`.
+way | Way | The input way to process (read-only).
+result | | The output that you will modify.
+relations | Relations | Contains the parent relations of `way`.
Importantly it will set `result.forward_mode` and `result.backward_mode` to indicate the travel mode in each direction, as well as set `result.forward_speed` and `result.backward_speed` to integer values representing the speed for traversing the way.
@@ -405,7 +422,7 @@ distance | Read | Float | Length of segment
weight | Read/write | Float | Routing weight for this segment
duration | Read/write | Float | Duration for this segment
-### process_turn(profile, turn)
+### process_turn(profile, turn) {#process_turn}
The `process_turn` function is called for every possible turn in the network. Based on the angle and type of turn you assign the weight and duration of the movement.
The following attributes can be read and set on the result in `process_turn`:
@@ -446,10 +463,10 @@ weight | Read/write | Float |
duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds)
-#### `from`, `via`, and `to`
-Use these node IDs to retrieve obstacles. See: `obstacle_map:get`.
+#### from, via, and to
+Use these node IDs to retrieve obstacles. See: @ref ObstacleMap::get.
-#### `source_road`, `target_road`, `roads_on_the_right`, and `roads_on_the_left`
+#### source_road, target_road, roads_on_the_right, and roads_on_the_left
The information of `source_road`, `target_road`, `roads_on_the_right`, and
`roads_on_the_left` that can be read are as follows:
@@ -532,7 +549,7 @@ Forks can be emitted between roads of similar priority category only. Obvious ch
### Using raster data
OSRM has built-in support for loading an interpolating raster data in ASCII format. This can be used e.g. for factoring in elevation when computing routes.
-Use `raster:load()` in your `setup` function to load data and store the source in your configuration hash:
+Use `raster:load()` in your @ref setup function to load data and store the source in your configuration hash:
```lua
function setup()
@@ -588,3 +605,5 @@ There are a few helper functions defined in the global scope that profiles can u
- `trimLaneString`
- `applyAccessTokens`
- `canonicalizeStringList`
+- @ref is_true
+- @ref is_false
diff --git a/features/bicycle/alley.feature b/features/bicycle/alley.feature
index db7b624a7ea..968401b3d38 100644
--- a/features/bicycle/alley.feature
+++ b/features/bicycle/alley.feature
@@ -27,8 +27,7 @@ Feature: Bicycle - Route around alleys
| cf | residential | |
When I route I should get
- | from | to | a:nodes | weight | # |
- | a | f | 1:2:3:6 | 196.2 | Avoids d,e,f |
- | a | e | 1:2:5 | 172.2 | Take the alley b,e if neccessary |
- | d | f | 4:1:2:3:6 | 248.4 | Avoids the alley d,e,f |
-
+ | from | to | a:nodes | weight | # |
+ | a | f | abcf | 196.2 | Avoids d,e,f |
+ | a | e | abe | 172.2 | Take the alley b,e if neccessary |
+ | d | f | dabcf | 248.4 | Avoids the alley d,e,f |
diff --git a/features/car/traffic_light_penalties.feature b/features/car/traffic_light_penalties.feature
index 5311599b6df..340cd756b62 100644
--- a/features/car/traffic_light_penalties.feature
+++ b/features/car/traffic_light_penalties.feature
@@ -294,8 +294,8 @@ Feature: Car - Handle traffic lights
When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
- | a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
- | c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
+ | a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | abc | 18:18 | 11.1:11.1 | 11.1:11.1 |
+ | c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | cba | 18:18 | 11.1:11.1 | 11.1:11.1 |
@traffic
@@ -326,8 +326,8 @@ Feature: Car - Handle traffic lights
When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
- | a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
- | c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
+ | a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | abc | 18:18 | 11.1:11.1 | 11.1:11.1 |
+ | c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | cba | 18:18 | 11.1:11.1 | 11.1:11.1 |
@traffic
@@ -358,8 +358,8 @@ Feature: Car - Handle traffic lights
When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
- | a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
- | c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
+ | a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | abc | 18:18 | 11.1:11.1 | 11.1:11.1 |
+ | c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | cba | 18:18 | 11.1:11.1 | 11.1:11.1 |
Scenario: Car - Traffic signal straight direction with edge compression
diff --git a/features/foot/area_mesh.feature b/features/foot/area_mesh.feature
new file mode 100644
index 00000000000..e3b0c8b0717
--- /dev/null
+++ b/features/foot/area_mesh.feature
@@ -0,0 +1,126 @@
+@routing @foot @area
+Feature: Foot - Pedestrian areas
+
+ Background:
+ Given the profile "foot_area"
+ Given a grid size of 50 meters
+ Given the extract extra arguments "--verbosity DEBUG"
+ Given the query options
+ | annotations | nodes |
+
+ Scenario: Foot - Route across a closed way area
+ Given the node map
+ """
+ e-a---b-f
+ | |
+ h-d---c-g
+ """
+
+ And the ways
+ | nodes | highway | area | name |
+ | abcda | pedestrian | yes | Plaza |
+ | ea | pedestrian | | A |
+ | bf | pedestrian | | B |
+ | hd | pedestrian | | C |
+ | cg | pedestrian | | D |
+
+ When I route I should get
+ | from | to | a:nodes | route |
+ | e | g | eacg | A,Plaza,D |
+ | g | e | gcae | D,Plaza,A |
+ | h | f | hdbf | C,Plaza,B |
+ | f | h | fbdh | B,Plaza,C |
+
+ Scenario: Foot - Do not route across a closed way w/o area
+ Given the node map
+ """
+ e-a--b-f
+ | \
+ h-d---c-g
+ """
+
+ And the ways
+ | nodes | highway |
+ | abcda | pedestrian |
+ | ea | pedestrian |
+ | bf | pedestrian |
+ | hd | pedestrian |
+ | cg | pedestrian |
+
+ When I route I should get
+ | from | to | a:nodes |
+ | e | g | eabcg |
+ | g | e | gcbae |
+ | h | f | hdabf |
+ | f | h | fbadh |
+
+ Scenario: Foot - Route across a multipolygon area
+ Given the node map
+ """
+ e-a-------b-f
+ | u-v |
+ | x-w |
+ h-d-------c-g
+ """
+
+ And the ways
+ | nodes | highway | name |
+ | abcda | (nil) | |
+ | uvwxu | (nil) | |
+ | ea | pedestrian | A |
+ | bf | pedestrian | B |
+ | hd | pedestrian | C |
+ | cg | pedestrian | D |
+
+ And the relations
+ | type | highway | name | way:outer | way:inner |
+ | multipolygon | pedestrian | Plaza | abcda | uvwxu |
+
+ When I route I should get
+ | from | to | a:nodes | route |
+ | e | g | eavcg | A,Plaza,D |
+ | g | e | gcvae | D,Plaza,A |
+ | f | h | fbwdh | B,Plaza,C |
+ | h | f | hdwbf | C,Plaza,B |
+
+ Scenario: Foot - Route across a complex multipolygon area
+ Given the node map
+ """
+ g-a---------------b-h
+ | z-y |
+ | | | |
+ l-f | | v--u |
+ | w-x | | |
+ | | | c-i
+ | | | |
+ | s--t |
+ k-e---------------d-j
+ """
+
+ And the ways
+ | nodes | highway |
+ | abcdefa | (nil) |
+ | zwxyz | (nil) |
+ | vstuv | (nil) |
+ | ag | pedestrian |
+ | bh | pedestrian |
+ | ci | pedestrian |
+ | dj | pedestrian |
+ | ek | pedestrian |
+ | fl | pedestrian |
+
+ And the relations
+ | type | highway | way:outer | way:inner |
+ | multipolygon | pedestrian | abcdefa | vstuv,zwxyz |
+
+ When I route I should get
+ | from | to | a:nodes |
+ | g | h | gabh |
+ | g | i | gauci |
+ | g | j | gaysdj |
+ | l | h | lfzbh |
+ | l | i | lfwxvuci |
+ | l | j | lfwsdj |
+ | k | h | kebh |
+ | k | i | ketci |
+ | k | j | kedj |
diff --git a/features/support/data.js b/features/support/data.js
index 4fbc421b140..8aeb24de072 100644
--- a/features/support/data.js
+++ b/features/support/data.js
@@ -161,6 +161,7 @@ export default class Data {
);
this.OSMDB.addNode(node);
this.nameNodeHash[name] = node;
+ this.idNodeHash[id] = node;
}
// Adds named location for test coordinate references
@@ -189,6 +190,16 @@ export default class Data {
return fromNode;
}
+ findNodeById(id) {
+ return this.idNodeHash[id.toString()];
+ }
+
+ nodeNameById(id) {
+ const fromNode = this.findNodeById(id) || {};
+ const tags = fromNode.tags || {};
+ return tags.name || '?';
+ }
+
// find a node based on an array containing lon/lat
findNodeByLocation(node_location) {
const searched_coordinate = new classes.Location(
@@ -235,6 +246,7 @@ export default class Data {
resetOSM() {
this.OSMDB.clear();
this.nameNodeHash = {};
+ this.idNodeHash = {};
this.locationHash = {};
this.shortcutsHash = {};
this.nameWayHash = {};
diff --git a/features/support/shared_steps.js b/features/support/shared_steps.js
index acfeb8060d3..d584cec06ac 100644
--- a/features/support/shared_steps.js
+++ b/features/support/shared_steps.js
@@ -222,6 +222,10 @@ export default class SharedSteps {
new Error('Annotation not found in response', a_type),
);
got[k] = (annotation && annotation[a_type]) || '';
+ // replaces node ids by their names: "0:1:2:3" -> "abcd"
+ if (a_type == 'nodes') {
+ got[k] = got[k].split(':').map(this.nodeNameById).join('');
+ }
} else if (k.match(/^am:/)) {
const a_type = k.slice(3);
if (metadata_whitelist.indexOf(a_type) == -1)
diff --git a/features/testbot/annotations.feature b/features/testbot/annotations.feature
index cff8461b244..f7c6dc4f5b9 100644
--- a/features/testbot/annotations.feature
+++ b/features/testbot/annotations.feature
@@ -23,9 +23,9 @@ Feature: Annotations
When I route I should get
| from | to | route | a:speed | a:weight | a:nodes |
- | h | j | hk,jk,jk | 6.7:6.7 | 15:15 | 1:4:3 |
- | i | m | il,lm,lm | 6.7:6.7 | 15:15 | 2:5:6 |
- | j | m | jk,lm | 6.7:6.7:6.7 | 15:15:15 | 3:4:5:6 |
+ | h | j | hk,jk,jk | 6.7:6.7 | 15:15 | hkj |
+ | i | m | il,lm,lm | 6.7:6.7 | 15:15 | ilm |
+ | j | m | jk,lm | 6.7:6.7:6.7 | 15:15:15 | jklm |
Scenario: There should be different forward/reverse datasources
@@ -114,5 +114,5 @@ Feature: Annotations
| bearings | 90,5;180,5 |
When I route I should get
- | from | to | route | a:speed | a:distance | a:duration | a:nodes |
- | a | c | abc,abc | 10:10 | 249.9876189:299.962882 | 25:30 | 1:2:3 |
+ | from | to | route | a:speed | a:distance | a:duration | a:nodes |
+ | a | c | abc,abc | 10:10 | 249.9876189:299.962882 | 25:30 | abc |
diff --git a/features/testbot/traffic_speeds.feature b/features/testbot/traffic_speeds.feature
index db3b2372b10..f6e7248af97 100644
--- a/features/testbot/traffic_speeds.feature
+++ b/features/testbot/traffic_speeds.feature
@@ -136,13 +136,13 @@ Feature: Traffic - speeds
When I route I should get
| from | to | route | speed | weights | a:datasources | a:speed | a:nodes|
- | a | b | fb,fb | 36 km/h | 328.9,0 | 0 | 10 | 6:2 |
- | a | c | fb,bc,bc | 30 km/h | 328.9,737.2,0 | 0:1 | 10:7.5 | 6:2:3 |
- | b | c | bc,bc | 27 km/h | 737.2,0 | 1 | 7.5 | 2:3 |
- | a | d | fb,df,df | 36 km/h | 139.8,486.8,0 | 0:0 | 10:10 | 2:6:4 |
- | d | c | dc,dc | 36 km/h | 955.4,0 | 0 | 10 | 4:3 |
- | g | b | fb,fb | 36 km/h | 164.4,0 | 0 | 10 | 6:2 |
- | a | g | fb,fb | 36 km/h | 164.5,0 | 0 | 10 | 6:2 |
+ | a | b | fb,fb | 36 km/h | 328.9,0 | 0 | 10 | fb |
+ | a | c | fb,bc,bc | 30 km/h | 328.9,737.2,0 | 0:1 | 10:7.5 | fbc |
+ | b | c | bc,bc | 27 km/h | 737.2,0 | 1 | 7.5 | bc |
+ | a | d | fb,df,df | 36 km/h | 139.8,486.8,0 | 0:0 | 10:10 | bfd |
+ | d | c | dc,dc | 36 km/h | 955.4,0 | 0 | 10 | dc |
+ | g | b | fb,fb | 36 km/h | 164.4,0 | 0 | 10 | fb |
+ | a | g | fb,fb | 36 km/h | 164.5,0 | 0 | 10 | fb |
Scenario: Verify that negative values cause an error, they're not valid at all
diff --git a/include/extractor/area/area_manager.hpp b/include/extractor/area/area_manager.hpp
new file mode 100644
index 00000000000..5a839f4c748
--- /dev/null
+++ b/include/extractor/area/area_manager.hpp
@@ -0,0 +1,83 @@
+#ifndef OSRM_EXTRACTOR_AREA_AREA_MANAGER_HPP
+#define OSRM_EXTRACTOR_AREA_AREA_MANAGER_HPP
+
+#include "extractor/extraction_relation.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace osrm::extractor::area
+{
+
+/**
+ * @brief A registry for area objects.
+ *
+ * This class backs the `area_manager` global variable in all LUA scripts. Call
+ * AreaManager::way() if you want to turn a closed way into an area, call
+ * AreaMananger::relation() if you want to turn a multipolygon relation into an area.
+ */
+class AreaManager
+ : public osmium::relations::RelationsManager
+{
+ osmium::area::AssemblerConfig m_assembler_config;
+ using MutexType = tbb::mutex;
+ /** Mutex to protect relations_manager */
+ MutexType mutex;
+
+ using relation_ids = std::vector;
+ std::string algorithm_name;
+ bool enabled{false};
+
+ public:
+ AreaManager(ExtractionRelationContainer &c) : relations_stash{c}
+ {
+ m_assembler_config.debug_level = 0;
+ };
+
+ void init(const char *algorithm_name);
+ void way(const osmium::Way &way);
+ void relation(const osmium::Relation &relation);
+ void prepare_for_lookup();
+ bool is_registered_closed_way(osmium::object_id_type way_id) const;
+ relation_ids get_relations_for_node(const osmium::Node &) const;
+ relation_ids get_relations_for_way(const osmium::Way &) const;
+
+ void complete_relation(const osmium::Relation &relation);
+ void after_way(const osmium::Way &way);
+ bool is_enabled() { return enabled; }
+
+ std::size_t number_of_ways{0};
+ std::size_t number_of_relations{0};
+
+ /**
+ * This collects the closed ways and the outer ring members of the relations we have
+ * registered for meshing. They are also used for collecting the intersecting ways.
+ */
+ tbb::concurrent_vector registered_closed_ways;
+ /** Map of way_id -> rel_id: if way is a member of rel */
+ tbb::concurrent_map m_way_relation;
+ /** Map of node_id -> rel_id: if node is a member of rel */
+ tbb::concurrent_map m_node_relation;
+ /**
+ * @brief Contains every node of every way we have seen.
+ *
+ * This is used later to find all intersecting ways.
+ */
+ tbb::concurrent_set node_ids;
+ /**
+ * @brief Storage for relations
+ *
+ * Registered relations are also stored here.
+ */
+ ExtractionRelationContainer &relations_stash;
+};
+
+} // namespace osrm::extractor::area
+
+#endif // AREA_MANAGER.HPP
diff --git a/include/extractor/area/area_mesher.hpp b/include/extractor/area/area_mesher.hpp
new file mode 100644
index 00000000000..e7245842606
--- /dev/null
+++ b/include/extractor/area/area_mesher.hpp
@@ -0,0 +1,106 @@
+#ifndef OSRM_EXTRACTOR_AREA_AREA_MESHER_HPP
+#define OSRM_EXTRACTOR_AREA_AREA_MESHER_HPP
+
+#include "extractor/extraction_relation.hpp"
+#include "typedefs.hpp"
+
+#include "extractor/extraction_containers.hpp"
+#include "util/typedefs.hpp"
+
+#include
+#include
+
+#include
+#include
+
+namespace osmium
+{
+namespace memory
+{
+class Buffer;
+};
+
+}; // namespace osmium
+
+namespace osrm::extractor::area
+{
+
+class AreaManager;
+
+/**
+ * @brief A class that "meshes" areas
+ *
+ * This class "meshes" an area by creating OSM ways for each shortest path between all
+ * pairs of entry points to the area. It first generates a @ref VisibilityGraph
+ * "visibility map", then uses @ref Dijkstra "Dijkstra's shortest-path algorithm" to
+ * reduce the number of edges. The generated ways are returned in an
+ * osmium::memory::Buffer.
+ */
+class AreaMesher
+{
+ public:
+ void init(const AreaManager &manager, const extractor::ExtractionContainers &containers);
+ OsmiumMultiPolygon area_builder(const osmium::Area &area);
+ NodeRefSet get_entry_points(const OsmiumPolygon &poly);
+ NodeRefSet get_obstacle_vertices(const OsmiumPolygon &poly);
+ void mesh_area(const osmium::Area &area,
+ osmium::memory::Buffer &out_buffer,
+ ExtractionRelationContainer &relations);
+
+ void mesh_buffer(const osmium::memory::Buffer &in_buffer,
+ osmium::memory::Buffer &out_buffer,
+ ExtractionRelationContainer &relations);
+ osmium::memory::Buffer read();
+
+ int added_ways{0};
+ /** Refuse to mesh more vertices */
+ size_t max_vertices{100};
+
+ private:
+ using NodeIDVector = std::vector;
+ using WayNodeIDOffsets = std::vector;
+ using WayIDVector = std::vector;
+
+ std::set run_dijkstra(const OsmiumPolygon &poly,
+ std::set &vis_map,
+ const NodeRefSet &entry_points);
+
+ osmium::object_id_type get_relations(const osmium::Area &area,
+ const ExtractionRelationContainer &relations);
+
+ std::unordered_multimap node_id2way_index;
+ osmium::object_id_type next_way_id{(1ULL << 34) - 1}; // see: packed_osm_ids.hpp
+#ifndef NDEBUG
+ osmium::object_id_type next_node_id{(1ULL << 34) - 1}; // see: packed_osm_ids.hpp
+#endif
+};
+
+/**
+ * @brief Implements a reader for a buffer.
+ *
+ * This class allows you to read from a osmium::memory::Buffer in the same way you
+ * would read an OSM file using a osmium::io::Reader.
+ */
+class BufferReader
+{
+ osmium::memory::Buffer::const_iterator iter;
+ const osmium::memory::Buffer::const_iterator end;
+ enum class status
+ {
+ okay = 0, // normal reading
+ error = 1, // some error occurred while reading
+ closed = 2, // close() called
+ eof = 3 // eof of file was reached without error
+ };
+ status m_status{status::okay};
+
+ public:
+ BufferReader(const osmium::memory::Buffer &in_buffer)
+ : iter{in_buffer.cbegin()}, end{in_buffer.cend()} {};
+
+ osmium::memory::Buffer read();
+};
+
+} // namespace osrm::extractor::area
+
+#endif // AREA_MESHER.HPP
diff --git a/include/extractor/area/dijkstra.hpp b/include/extractor/area/dijkstra.hpp
new file mode 100644
index 00000000000..c12d988d14c
--- /dev/null
+++ b/include/extractor/area/dijkstra.hpp
@@ -0,0 +1,167 @@
+#ifndef OSRM_EXTRACTOR_AREA_DIJKSTRA_HPP
+#define OSRM_EXTRACTOR_AREA_DIJKSTRA_HPP
+
+#include "index_priority_queue.hpp"
+
+#include
+#include
+#include