Support maneuver relations (#4676)
This commit is contained in:
		
							parent
							
								
									1aed13500d
								
							
						
					
					
						commit
						5531cace7f
					
				@ -1,6 +1,7 @@
 | 
			
		||||
# UNRELEASED
 | 
			
		||||
  - Changes from 5.15.1:
 | 
			
		||||
    - Guidance
 | 
			
		||||
      - ADDED #4676: Support for maneuver override relation, allowing data-driven overrides for turn-by-turn instructions [#4676](https://github.com/Project-OSRM/osrm-backend/pull/4676)
 | 
			
		||||
      - CHANGED #4830: Announce reference change if names are empty
 | 
			
		||||
      - CHANGED #4835: MAXIMAL_ALLOWED_SEPARATION_WIDTH increased to 12 meters
 | 
			
		||||
    - Profile:
 | 
			
		||||
 | 
			
		||||
@ -1061,3 +1061,28 @@ Feature: Car - Turn restrictions
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | from | to | route              |
 | 
			
		||||
            | a    | d  | ab,bc,bc,bge,de,de |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Scenario: Ambiguous ways
 | 
			
		||||
        Given the node map
 | 
			
		||||
            """
 | 
			
		||||
            x---a----b-----c---z
 | 
			
		||||
                     |
 | 
			
		||||
                     d
 | 
			
		||||
            """
 | 
			
		||||
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes |
 | 
			
		||||
            | abc   |
 | 
			
		||||
            | bd    |
 | 
			
		||||
            | xa    |
 | 
			
		||||
            | cz    |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type        | way:from | way:to | node:via | restriction  |
 | 
			
		||||
            | restriction | bd       | abc    | b        | no_left_turn |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | from | to | route        |
 | 
			
		||||
            | d    | x  | bd,abc,xa,xa |
 | 
			
		||||
            | d    | z  | bd,abc,cz,cz |
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										208
									
								
								features/guidance/maneuver-tag.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								features/guidance/maneuver-tag.feature
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,208 @@
 | 
			
		||||
# The route results with #original are what the result should be if the maneuver tag is removed
 | 
			
		||||
@routing @guidance @maneuver
 | 
			
		||||
Feature: Maneuver tag support
 | 
			
		||||
 | 
			
		||||
    Background:
 | 
			
		||||
        Given the profile "car"
 | 
			
		||||
        Given a grid size of 5 meters
 | 
			
		||||
 | 
			
		||||
    Scenario: simple override #1
 | 
			
		||||
        Given the node map
 | 
			
		||||
            """
 | 
			
		||||
            a--b---c----d---e
 | 
			
		||||
                   |
 | 
			
		||||
                   g
 | 
			
		||||
                   |
 | 
			
		||||
            h------i--------j
 | 
			
		||||
            """
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes | name     | oneway |
 | 
			
		||||
            | abc   | A Street | no     |
 | 
			
		||||
            | cde   | B Street | no     |
 | 
			
		||||
            | cgi   | C Street | no     |
 | 
			
		||||
            | hij   | J Street | no     |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type     | way:from | node:via | way:to | maneuver | direction   |
 | 
			
		||||
            | maneuver | abc      | c        | cgi    | turn     | sharp_right |
 | 
			
		||||
            | maneuver | hij      | i        | cde    | turn     | sharp_left  |
 | 
			
		||||
            | maneuver | abc      | c        | cde    | turn     | slight_left |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | waypoints | route                               | turns                                    |
 | 
			
		||||
        # Testing directly connected from/to 
 | 
			
		||||
            | a,j       | A Street,C Street,J Street,J Street | depart,turn sharp right,turn left,arrive |
 | 
			
		||||
            | b,g       | A Street,C Street,C Street          | depart,turn sharp right,arrive           |
 | 
			
		||||
        # Testing re-awakening suppressed turns
 | 
			
		||||
            | a,e       | A Street,B Street,B Street          | depart,turn slight left,arrive           |
 | 
			
		||||
 | 
			
		||||
    Scenario: single via-way
 | 
			
		||||
      Given the node map
 | 
			
		||||
          """"
 | 
			
		||||
            a--b---c----d---e
 | 
			
		||||
                   |
 | 
			
		||||
                   g
 | 
			
		||||
                   |
 | 
			
		||||
            h------i--------j
 | 
			
		||||
          """
 | 
			
		||||
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes | name     | oneway |
 | 
			
		||||
            | abc   | A Street | no     |
 | 
			
		||||
            | cde   | B Street | no     |
 | 
			
		||||
            | cgi   | C Street | no     |
 | 
			
		||||
            | hi    | J Street | no     |
 | 
			
		||||
            | ij    | J Street | no     |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type     | way:from | way:via | way:to | node:via | maneuver | direction   |
 | 
			
		||||
            | maneuver | abc      | cgi     | ij     | c        | turn     | sharp_right |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | waypoints | route                               | turns                                    |
 | 
			
		||||
            | a,j       | A Street,C Street,J Street,J Street | depart,turn sharp right,turn left,arrive |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Scenario: multiple via-way
 | 
			
		||||
      Given the node map
 | 
			
		||||
          """"
 | 
			
		||||
            a--b---c----d---e
 | 
			
		||||
                   |
 | 
			
		||||
                   g-----k
 | 
			
		||||
                   |
 | 
			
		||||
            h------i--------j
 | 
			
		||||
          """
 | 
			
		||||
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes | name     | oneway |
 | 
			
		||||
            | abc   | A Street | no     |
 | 
			
		||||
            | cde   | B Street | no     |
 | 
			
		||||
            | cg    | C Street | no     |
 | 
			
		||||
            | gi    | C Street | no     |
 | 
			
		||||
            | hi    | J Street | no     |
 | 
			
		||||
            | ij    | J Street | no     |
 | 
			
		||||
            | gk    | G Street | no     |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type     | way:from | way:via | way:via | way:to | node:via | maneuver | direction   |
 | 
			
		||||
            | maneuver | abc      | cg      | gi      | ij     | c        | turn     | sharp_right |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | waypoints | route                               | turns                                    |
 | 
			
		||||
            | a,j       | A Street,C Street,J Street,J Street | depart,turn sharp right,end of road left,arrive |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Scenario: Use maneuver tag to announce a particular turn type
 | 
			
		||||
        Given the node map
 | 
			
		||||
            """
 | 
			
		||||
            f
 | 
			
		||||
            *
 | 
			
		||||
            *
 | 
			
		||||
             *
 | 
			
		||||
              *
 | 
			
		||||
                *
 | 
			
		||||
                  *
 | 
			
		||||
                    *
 | 
			
		||||
                     *
 | 
			
		||||
                      *
 | 
			
		||||
             t. ..     *                h
 | 
			
		||||
                  .. ....m**           *
 | 
			
		||||
                        /    *       *
 | 
			
		||||
                       /       * * *
 | 
			
		||||
                      /
 | 
			
		||||
                     /
 | 
			
		||||
                    |
 | 
			
		||||
                    |
 | 
			
		||||
                     \
 | 
			
		||||
                      \
 | 
			
		||||
                       o
 | 
			
		||||
            """
 | 
			
		||||
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes | name      | oneway | highway      |
 | 
			
		||||
            | fm    | CA-120    | no     | secondary    |
 | 
			
		||||
            | mh    | CA-120    | no     | secondary    |
 | 
			
		||||
            | mt    | Priest Rd | no     | unclassified |
 | 
			
		||||
            | mo    |           | no     | service      |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type     | way:from | node:via | way:to | maneuver | direction |
 | 
			
		||||
            | maneuver | mh       | m        | mt     | turn     | left      |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | waypoints | route                        | turns                        |
 | 
			
		||||
            | h,t       | CA-120,Priest Rd,Priest Rd   | depart,turn left,arrive      |
 | 
			
		||||
  #original | h,t       | CA-120,Priest Rd,Priest Rd   | depart,turn straight,arrive  |
 | 
			
		||||
 | 
			
		||||
    Scenario: Use maneuver tag to announce lane guidance
 | 
			
		||||
        Given a grid size of 10 meters
 | 
			
		||||
        Given the node map
 | 
			
		||||
            """
 | 
			
		||||
               ad
 | 
			
		||||
              / \
 | 
			
		||||
             /   \
 | 
			
		||||
            /     \
 | 
			
		||||
            |     |
 | 
			
		||||
            |     |
 | 
			
		||||
            |     |
 | 
			
		||||
            b-----c------e
 | 
			
		||||
            |     |
 | 
			
		||||
            |     |
 | 
			
		||||
            |     |
 | 
			
		||||
            |     |
 | 
			
		||||
            r     w
 | 
			
		||||
            """
 | 
			
		||||
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes | name      | oneway | highway   |
 | 
			
		||||
            | ab    | Marsh Rd  | yes    | secondary |
 | 
			
		||||
            | br    | Marsh Rd  | yes    | secondary |
 | 
			
		||||
            | cd    | Marsh Rd  | yes    | secondary |
 | 
			
		||||
            | cw    | Marsh Rd  | yes    | secondary |
 | 
			
		||||
            | bc    | service   | no     | service   |
 | 
			
		||||
            | ce    | service   | no     | service   |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type     | way:from | node:via | way:via | way:to | maneuver |
 | 
			
		||||
            | maneuver | ab       | c        | bc      | cd     | uturn    |
 | 
			
		||||
            | maneuver | ab       | b        | bc      | cd     | suppress |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | waypoints | route                         | turns                    |
 | 
			
		||||
            | a,d       | Marsh Rd,Marsh Rd,Marsh Rd    | depart,turn uturn,arrive |
 | 
			
		||||
  #original | a,d       | Marsh Rd,service,Marsh Rd,Marsh Rd | depart,turn left,turn left,arrive |
 | 
			
		||||
 | 
			
		||||
    Scenario: Use maneuver tag to suppress a turn
 | 
			
		||||
        Given the node map
 | 
			
		||||
            """
 | 
			
		||||
              c
 | 
			
		||||
              |
 | 
			
		||||
              |
 | 
			
		||||
          v---y----------z
 | 
			
		||||
              |
 | 
			
		||||
          n---p----------k
 | 
			
		||||
              |\
 | 
			
		||||
              | \
 | 
			
		||||
              b  t
 | 
			
		||||
            """
 | 
			
		||||
 | 
			
		||||
        And the ways
 | 
			
		||||
            | nodes | name    | oneway | highway       |
 | 
			
		||||
            | zy    | NY Ave  | yes    | primary       |
 | 
			
		||||
            | yv    | NY Ave  | yes    | primary       |
 | 
			
		||||
            | np    | NY Ave  | yes    | primary       |
 | 
			
		||||
            | pk    | NY Ave  | yes    | primary       |
 | 
			
		||||
            | cp    | 4th St  | no     | tertiary      |
 | 
			
		||||
            | yp    |         | no     | motorway_link |
 | 
			
		||||
            | pb    | 4th St  | no     | primary       |
 | 
			
		||||
            | pt    | 395     | no     | primary       |
 | 
			
		||||
 | 
			
		||||
        And the relations
 | 
			
		||||
            | type     | way:from | node:via | way:via | way:to | maneuver  |
 | 
			
		||||
            | maneuver | zy       | p        | yp      | pt     | suppress  |
 | 
			
		||||
 | 
			
		||||
        When I route I should get
 | 
			
		||||
            | waypoints | route           | turns                      |
 | 
			
		||||
            | z,t       | NY Ave,395,395  | depart,on ramp left,arrive |
 | 
			
		||||
  #original | z,t       | NY Ave,,395,395 | depart,on ramp left,fork slight left,arrive |
 | 
			
		||||
 | 
			
		||||
@ -185,31 +185,34 @@ module.exports = function () {
 | 
			
		||||
 | 
			
		||||
        let q = d3.queue();
 | 
			
		||||
 | 
			
		||||
        let addRelation = (row, cb) => {
 | 
			
		||||
        let addRelation = (headers, row, cb) => {
 | 
			
		||||
            let relation = new OSM.Relation(this.makeOSMId(), this.OSM_USER, this.OSM_TIMESTAMP, this.OSM_UID);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var name = null;
 | 
			
		||||
            for (let key in row) {
 | 
			
		||||
            for (let index in row) {
 | 
			
		||||
 | 
			
		||||
                var key = headers[index];
 | 
			
		||||
                var value = row[index];
 | 
			
		||||
                let isNode = key.match(/^node:?(.*)/),
 | 
			
		||||
                    isWay = key.match(/^way:?(.*)/),
 | 
			
		||||
                    isRelation = key.match(/^relation:?(.*)/),
 | 
			
		||||
                    isColonSeparated = key.match(/^(.*):(.*)/);
 | 
			
		||||
                if (isNode) {
 | 
			
		||||
                    row[key].split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => {
 | 
			
		||||
                    value.split(',').map(function(v) { return v.trim(); }).forEach((nodeName) => {
 | 
			
		||||
                        if (nodeName.length !== 1) throw new Error(util.format('*** invalid relation node member "%s"', nodeName));
 | 
			
		||||
                        let node = this.findNodeByName(nodeName);
 | 
			
		||||
                        if (!node) throw new Error(util.format('*** unknown relation node member "%s"', nodeName));
 | 
			
		||||
                        relation.addMember('node', node.id, isNode[1]);
 | 
			
		||||
                    });
 | 
			
		||||
                } else if (isWay) {
 | 
			
		||||
                    row[key].split(',').map(function(v) { return v.trim(); }).forEach((wayName) => {
 | 
			
		||||
                    value.split(',').map(function(v) { return v.trim(); }).forEach((wayName) => {
 | 
			
		||||
                        let way = this.findWayByName(wayName);
 | 
			
		||||
                        if (!way) throw new Error(util.format('*** unknown relation way member "%s"', wayName));
 | 
			
		||||
                        relation.addMember('way', way.id, isWay[1]);
 | 
			
		||||
                    });
 | 
			
		||||
                } else if (isRelation) {
 | 
			
		||||
                    row[key].split(',').map(function(v) { return v.trim(); }).forEach((relName) => {
 | 
			
		||||
                    value.split(',').map(function(v) { return v.trim(); }).forEach((relName) => {
 | 
			
		||||
                        let otherrelation = this.findRelationByName(relName);
 | 
			
		||||
                        if (!otherrelation) throw new Error(util.format('*** unknown relation relation member "%s"', relName));
 | 
			
		||||
                        relation.addMember('relation', otherrelation.id, isRelation[1]);
 | 
			
		||||
@ -217,8 +220,8 @@ module.exports = function () {
 | 
			
		||||
                } else if (isColonSeparated && isColonSeparated[1] !== 'restriction') {
 | 
			
		||||
                    throw new Error(util.format('*** unknown relation member type "%s:%s", must be either "node" or "way"', isColonSeparated[1], isColonSeparated[2]));
 | 
			
		||||
                } else {
 | 
			
		||||
                    relation.addTag(key, row[key]);
 | 
			
		||||
                    if (key.match(/name/)) name = row[key];
 | 
			
		||||
                    relation.addTag(key, value);
 | 
			
		||||
                    if (key.match(/name/)) name = value;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            relation.uid = this.OSM_UID;
 | 
			
		||||
@ -233,7 +236,8 @@ module.exports = function () {
 | 
			
		||||
            cb();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        table.hashes().forEach((row) => q.defer(addRelation, row));
 | 
			
		||||
        var headers = table.raw()[0];
 | 
			
		||||
        table.rows().forEach((row) => q.defer(addRelation, headers, row));
 | 
			
		||||
 | 
			
		||||
        q.awaitAll(callback);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef ENGINE_API_ROUTE_HPP
 | 
			
		||||
#define ENGINE_API_ROUTE_HPP
 | 
			
		||||
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "engine/api/base_api.hpp"
 | 
			
		||||
#include "engine/api/json_factory.hpp"
 | 
			
		||||
#include "engine/api/route_parameters.hpp"
 | 
			
		||||
@ -19,6 +20,8 @@
 | 
			
		||||
 | 
			
		||||
#include "engine/internal_route_result.hpp"
 | 
			
		||||
 | 
			
		||||
#include "guidance/turn_instruction.hpp"
 | 
			
		||||
 | 
			
		||||
#include "util/coordinate.hpp"
 | 
			
		||||
#include "util/integer_range.hpp"
 | 
			
		||||
#include "util/json_util.hpp"
 | 
			
		||||
@ -130,6 +133,7 @@ class RouteAPI : public BaseAPI
 | 
			
		||||
                                             reversed_target,
 | 
			
		||||
                                             parameters.steps);
 | 
			
		||||
 | 
			
		||||
            util::Log(logDEBUG) << "Assembling steps " << std::endl;
 | 
			
		||||
            if (parameters.steps)
 | 
			
		||||
            {
 | 
			
		||||
                auto steps = guidance::assembleSteps(BaseAPI::facade,
 | 
			
		||||
@ -140,6 +144,10 @@ class RouteAPI : public BaseAPI
 | 
			
		||||
                                                     reversed_source,
 | 
			
		||||
                                                     reversed_target);
 | 
			
		||||
 | 
			
		||||
                // Apply maneuver overrides before any other post
 | 
			
		||||
                // processing is performed
 | 
			
		||||
                guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry);
 | 
			
		||||
 | 
			
		||||
                /* Perform step-based post-processing.
 | 
			
		||||
                 *
 | 
			
		||||
                 * Using post-processing on basis of route-steps for a single leg at a time
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@
 | 
			
		||||
#include "extractor/datasources.hpp"
 | 
			
		||||
#include "extractor/edge_based_node.hpp"
 | 
			
		||||
#include "extractor/intersection_bearings_container.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/node_data_container.hpp"
 | 
			
		||||
#include "extractor/packed_osm_ids.hpp"
 | 
			
		||||
#include "extractor/profile_properties.hpp"
 | 
			
		||||
@ -205,6 +206,9 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
 | 
			
		||||
    util::vector_view<std::size_t> m_datasource_name_lengths;
 | 
			
		||||
    util::vector_view<util::guidance::LaneTupleIdPair> m_lane_tupel_id_pairs;
 | 
			
		||||
 | 
			
		||||
    util::vector_view<extractor::StorageManeuverOverride> m_maneuver_overrides;
 | 
			
		||||
    util::vector_view<NodeID> m_maneuver_override_node_sequences;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<SharedRTree> m_static_rtree;
 | 
			
		||||
    std::unique_ptr<SharedGeospatialQuery> m_geospatial_query;
 | 
			
		||||
    boost::filesystem::path file_index_path;
 | 
			
		||||
@ -499,6 +503,21 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
 | 
			
		||||
        m_entry_class_table = std::move(entry_class_table);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void InitializeManeuverOverridePointers(storage::DataLayout &data_layout, char *memory_block)
 | 
			
		||||
    {
 | 
			
		||||
        auto maneuver_overrides_ptr = data_layout.GetBlockPtr<extractor::StorageManeuverOverride>(
 | 
			
		||||
            memory_block, storage::DataLayout::MANEUVER_OVERRIDES);
 | 
			
		||||
        m_maneuver_overrides = util::vector_view<extractor::StorageManeuverOverride>(
 | 
			
		||||
            maneuver_overrides_ptr,
 | 
			
		||||
            data_layout.num_entries[storage::DataLayout::MANEUVER_OVERRIDES]);
 | 
			
		||||
 | 
			
		||||
        auto maneuver_override_node_sequences_ptr = data_layout.GetBlockPtr<NodeID>(
 | 
			
		||||
            memory_block, storage::DataLayout::MANEUVER_OVERRIDE_NODE_SEQUENCES);
 | 
			
		||||
        m_maneuver_override_node_sequences = util::vector_view<NodeID>(
 | 
			
		||||
            maneuver_override_node_sequences_ptr,
 | 
			
		||||
            data_layout.num_entries[storage::DataLayout::MANEUVER_OVERRIDE_NODE_SEQUENCES]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void InitializeInternalPointers(storage::DataLayout &data_layout,
 | 
			
		||||
                                    char *memory_block,
 | 
			
		||||
                                    const std::size_t exclude_index)
 | 
			
		||||
@ -515,6 +534,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
 | 
			
		||||
        InitializeProfilePropertiesPointer(data_layout, memory_block, exclude_index);
 | 
			
		||||
        InitializeRTreePointers(data_layout, memory_block);
 | 
			
		||||
        InitializeIntersectionClassPointers(data_layout, memory_block);
 | 
			
		||||
        InitializeManeuverOverridePointers(data_layout, memory_block);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
@ -890,6 +910,39 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
 | 
			
		||||
    {
 | 
			
		||||
        return edge_based_node_data.IsSegregated(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<extractor::ManeuverOverride>
 | 
			
		||||
    GetOverridesThatStartAt(const NodeID edge_based_node_id) const override final
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<extractor::ManeuverOverride> results;
 | 
			
		||||
 | 
			
		||||
        // heterogeneous comparison:
 | 
			
		||||
        struct Comp
 | 
			
		||||
        {
 | 
			
		||||
            bool operator()(const extractor::StorageManeuverOverride &s, NodeID i) const
 | 
			
		||||
            {
 | 
			
		||||
                return s.start_node < i;
 | 
			
		||||
            }
 | 
			
		||||
            bool operator()(NodeID i, const extractor::StorageManeuverOverride &s) const
 | 
			
		||||
            {
 | 
			
		||||
                return i < s.start_node;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        auto found_range = std::equal_range(
 | 
			
		||||
            m_maneuver_overrides.begin(), m_maneuver_overrides.end(), edge_based_node_id, Comp{});
 | 
			
		||||
 | 
			
		||||
        std::for_each(found_range.first, found_range.second, [&](const auto & override) {
 | 
			
		||||
            std::vector<NodeID> sequence(
 | 
			
		||||
                m_maneuver_override_node_sequences.begin() + override.node_sequence_offset_begin,
 | 
			
		||||
                m_maneuver_override_node_sequences.begin() + override.node_sequence_offset_end);
 | 
			
		||||
            results.push_back(extractor::ManeuverOverride{std::move(sequence),
 | 
			
		||||
                                                          override.instruction_node,
 | 
			
		||||
                                                          override.override_type,
 | 
			
		||||
                                                          override.direction});
 | 
			
		||||
        });
 | 
			
		||||
        return results;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename AlgorithmT> class ContiguousInternalMemoryDataFacade;
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,9 @@
 | 
			
		||||
 | 
			
		||||
#include "extractor/class_data.hpp"
 | 
			
		||||
#include "extractor/edge_based_node_segment.hpp"
 | 
			
		||||
//#include "extractor/guidance/turn_lane_types.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
//#include "extractor/original_edge_data.hpp"
 | 
			
		||||
#include "extractor/query_node.hpp"
 | 
			
		||||
#include "extractor/travel_mode.hpp"
 | 
			
		||||
#include "extractor/turn_lane_types.hpp"
 | 
			
		||||
@ -192,6 +195,9 @@ class BaseDataFacade
 | 
			
		||||
    virtual bool IsLeftHandDriving(const NodeID id) const = 0;
 | 
			
		||||
 | 
			
		||||
    virtual bool IsSegregated(const NodeID) const = 0;
 | 
			
		||||
 | 
			
		||||
    virtual std::vector<extractor::ManeuverOverride>
 | 
			
		||||
    GetOverridesThatStartAt(const NodeID edge_based_node_id) const = 0;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
 | 
			
		||||
                // intersections contain the classes of exiting road
 | 
			
		||||
                intersection.classes = facade.GetClasses(path_point.classes);
 | 
			
		||||
 | 
			
		||||
                steps.push_back(RouteStep{step_name_id,
 | 
			
		||||
                steps.push_back(RouteStep{path_point.from_edge_based_node,
 | 
			
		||||
                                          step_name_id,
 | 
			
		||||
                                          is_segregated,
 | 
			
		||||
                                          name.to_string(),
 | 
			
		||||
                                          ref.to_string(),
 | 
			
		||||
@ -209,7 +210,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
 | 
			
		||||
        // intersections contain the classes of exiting road
 | 
			
		||||
        intersection.classes = facade.GetClasses(facade.GetClassData(target_node_id));
 | 
			
		||||
        BOOST_ASSERT(duration >= 0);
 | 
			
		||||
        steps.push_back(RouteStep{step_name_id,
 | 
			
		||||
        steps.push_back(RouteStep{leg_data[leg_data.size() - 1].from_edge_based_node,
 | 
			
		||||
                                  step_name_id,
 | 
			
		||||
                                  is_segregated,
 | 
			
		||||
                                  facade.GetNameForID(step_name_id).to_string(),
 | 
			
		||||
                                  facade.GetRefForID(step_name_id).to_string(),
 | 
			
		||||
@ -253,7 +255,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
 | 
			
		||||
        BOOST_ASSERT(target_duration >= source_duration || weight == 0);
 | 
			
		||||
        const EdgeWeight duration = std::max(0, target_duration - source_duration);
 | 
			
		||||
 | 
			
		||||
        steps.push_back(RouteStep{source_name_id,
 | 
			
		||||
        steps.push_back(RouteStep{source_node_id,
 | 
			
		||||
                                  source_name_id,
 | 
			
		||||
                                  is_segregated,
 | 
			
		||||
                                  facade.GetNameForID(source_name_id).to_string(),
 | 
			
		||||
                                  facade.GetRefForID(source_name_id).to_string(),
 | 
			
		||||
@ -295,7 +298,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
 | 
			
		||||
                0};
 | 
			
		||||
 | 
			
		||||
    BOOST_ASSERT(!leg_geometry.locations.empty());
 | 
			
		||||
    steps.push_back(RouteStep{target_name_id,
 | 
			
		||||
    steps.push_back(RouteStep{target_node_id,
 | 
			
		||||
                              target_name_id,
 | 
			
		||||
                              facade.IsSegregated(target_node_id),
 | 
			
		||||
                              facade.GetNameForID(target_name_id).to_string(),
 | 
			
		||||
                              facade.GetRefForID(target_name_id).to_string(),
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef ENGINE_GUIDANCE_POST_PROCESSING_HPP
 | 
			
		||||
#define ENGINE_GUIDANCE_POST_PROCESSING_HPP
 | 
			
		||||
 | 
			
		||||
#include "engine/datafacade/datafacade_base.hpp"
 | 
			
		||||
#include "engine/guidance/leg_geometry.hpp"
 | 
			
		||||
#include "engine/guidance/route_step.hpp"
 | 
			
		||||
#include "engine/phantom_node.hpp"
 | 
			
		||||
@ -45,6 +46,18 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps);
 | 
			
		||||
OSRM_ATTR_WARN_UNUSED
 | 
			
		||||
LegGeometry resyncGeometry(LegGeometry leg_geometry, const std::vector<RouteStep> &steps);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Apply maneuver override relations to the selected route.
 | 
			
		||||
 * Should be called before any other post-processing is performed
 | 
			
		||||
 * to ensure that all sequences of edge-based-nodes are still in the
 | 
			
		||||
 * steps list.
 | 
			
		||||
 *
 | 
			
		||||
 * @param steps the steps of the route
 | 
			
		||||
 */
 | 
			
		||||
void applyOverrides(const datafacade::BaseDataFacade &facade,
 | 
			
		||||
                    std::vector<RouteStep> &steps,
 | 
			
		||||
                    const LegGeometry &geometry);
 | 
			
		||||
 | 
			
		||||
} // namespace guidance
 | 
			
		||||
} // namespace engine
 | 
			
		||||
} // namespace osrm
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,7 @@ inline IntermediateIntersection getInvalidIntersection()
 | 
			
		||||
 | 
			
		||||
struct RouteStep
 | 
			
		||||
{
 | 
			
		||||
    NodeID from_id;
 | 
			
		||||
    unsigned name_id;
 | 
			
		||||
    bool is_segregated;
 | 
			
		||||
    std::string name;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,9 @@ namespace engine
 | 
			
		||||
 | 
			
		||||
struct PathData
 | 
			
		||||
{
 | 
			
		||||
    // id of via node of the turn
 | 
			
		||||
    // from edge-based-node id
 | 
			
		||||
    NodeID from_edge_based_node;
 | 
			
		||||
    // the internal OSRM id of the OSM node id that is the via node of the turn
 | 
			
		||||
    NodeID turn_via_node;
 | 
			
		||||
    // name of the street that leads to the turn
 | 
			
		||||
    unsigned name_id;
 | 
			
		||||
 | 
			
		||||
@ -192,7 +192,8 @@ void annotatePath(const FacadeT &facade,
 | 
			
		||||
        BOOST_ASSERT(start_index < end_index);
 | 
			
		||||
        for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
 | 
			
		||||
        {
 | 
			
		||||
            unpacked_path.push_back(PathData{id_vector[segment_idx + 1],
 | 
			
		||||
            unpacked_path.push_back(PathData{*node_from,
 | 
			
		||||
                                             id_vector[segment_idx + 1],
 | 
			
		||||
                                             name_index,
 | 
			
		||||
                                             is_segregated,
 | 
			
		||||
                                             weight_vector[segment_idx],
 | 
			
		||||
@ -266,7 +267,8 @@ void annotatePath(const FacadeT &facade,
 | 
			
		||||
        BOOST_ASSERT(segment_idx < id_vector.size() - 1);
 | 
			
		||||
        BOOST_ASSERT(facade.GetTravelMode(target_node_id) > 0);
 | 
			
		||||
        unpacked_path.push_back(
 | 
			
		||||
            PathData{id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
 | 
			
		||||
            PathData{target_node_id,
 | 
			
		||||
                     id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
 | 
			
		||||
                     facade.GetNameIndex(target_node_id),
 | 
			
		||||
                     facade.IsSegregated(target_node_id),
 | 
			
		||||
                     weight_vector[segment_idx],
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@
 | 
			
		||||
#include "extractor/edge_based_edge.hpp"
 | 
			
		||||
#include "extractor/edge_based_node_segment.hpp"
 | 
			
		||||
#include "extractor/extraction_turn.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/nbg_to_ebg.hpp"
 | 
			
		||||
#include "extractor/node_data_container.hpp"
 | 
			
		||||
#include "extractor/query_node.hpp"
 | 
			
		||||
@ -83,9 +84,11 @@ class EdgeBasedGraphFactory
 | 
			
		||||
             const std::string &turn_penalties_index_filename,
 | 
			
		||||
             const std::string &cnbg_ebg_mapping_path,
 | 
			
		||||
             const std::string &conditional_penalties_filename,
 | 
			
		||||
             const std::string &maneuver_overrides_filename,
 | 
			
		||||
             const RestrictionMap &node_restriction_map,
 | 
			
		||||
             const ConditionalRestrictionMap &conditional_restriction_map,
 | 
			
		||||
             const WayRestrictionMap &way_restriction_map);
 | 
			
		||||
             const WayRestrictionMap &way_restriction_map,
 | 
			
		||||
             const std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    // The following get access functions destroy the content in the factory
 | 
			
		||||
    void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
 | 
			
		||||
@ -168,14 +171,17 @@ class EdgeBasedGraphFactory
 | 
			
		||||
 | 
			
		||||
    // Edge-expanded edges are generate for all valid turns. The validity can be checked via the
 | 
			
		||||
    // restriction maps
 | 
			
		||||
    void GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                                   const std::string &turn_weight_penalties_filename,
 | 
			
		||||
                                   const std::string &turn_duration_penalties_filename,
 | 
			
		||||
                                   const std::string &turn_penalties_index_filename,
 | 
			
		||||
                                   const std::string &conditional_turn_penalties_filename,
 | 
			
		||||
                                   const RestrictionMap &node_restriction_map,
 | 
			
		||||
                                   const ConditionalRestrictionMap &conditional_restriction_map,
 | 
			
		||||
                                   const WayRestrictionMap &way_restriction_map);
 | 
			
		||||
    void
 | 
			
		||||
    GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                              const std::string &turn_weight_penalties_filename,
 | 
			
		||||
                              const std::string &turn_duration_penalties_filename,
 | 
			
		||||
                              const std::string &turn_penalties_index_filename,
 | 
			
		||||
                              const std::string &conditional_turn_penalties_filename,
 | 
			
		||||
                              const std::string &maneuver_overrides_filename,
 | 
			
		||||
                              const RestrictionMap &node_restriction_map,
 | 
			
		||||
                              const ConditionalRestrictionMap &conditional_restriction_map,
 | 
			
		||||
                              const WayRestrictionMap &way_restriction_map,
 | 
			
		||||
                              const std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ namespace extractor
 | 
			
		||||
class ExtractionContainers
 | 
			
		||||
{
 | 
			
		||||
    void PrepareNodes();
 | 
			
		||||
    void PrepareManeuverOverrides();
 | 
			
		||||
    void PrepareRestrictions();
 | 
			
		||||
    void PrepareEdges(ScriptingEnvironment &scripting_environment);
 | 
			
		||||
 | 
			
		||||
@ -63,6 +64,9 @@ class ExtractionContainers
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
 | 
			
		||||
    std::vector<TurnRestriction> unconditional_turn_restrictions;
 | 
			
		||||
 | 
			
		||||
    std::vector<InputManeuverOverride> external_maneuver_overrides_list;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> internal_maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    ExtractionContainers();
 | 
			
		||||
 | 
			
		||||
    void PrepareData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
#include "extractor/edge_based_graph_factory.hpp"
 | 
			
		||||
#include "extractor/extractor_config.hpp"
 | 
			
		||||
#include "extractor/graph_compressor.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/packed_osm_ids.hpp"
 | 
			
		||||
 | 
			
		||||
#include "guidance/guidance_processing.hpp"
 | 
			
		||||
@ -62,7 +63,8 @@ class Extractor
 | 
			
		||||
 | 
			
		||||
    std::tuple<LaneDescriptionMap,
 | 
			
		||||
               std::vector<TurnRestriction>,
 | 
			
		||||
               std::vector<ConditionalTurnRestriction>>
 | 
			
		||||
               std::vector<ConditionalTurnRestriction>,
 | 
			
		||||
               std::vector<UnresolvedManeuverOverride>>
 | 
			
		||||
    ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
 | 
			
		||||
 | 
			
		||||
    EdgeID BuildEdgeExpandedGraph(
 | 
			
		||||
@ -76,6 +78,7 @@ class Extractor
 | 
			
		||||
        const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
        const std::unordered_set<EdgeID> &segregated_edges,
 | 
			
		||||
        const util::NameTable &name_table,
 | 
			
		||||
        const std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
 | 
			
		||||
        const LaneDescriptionMap &turn_lane_map,
 | 
			
		||||
        // for calculating turn penalties
 | 
			
		||||
        ScriptingEnvironment &scripting_environment,
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,7 @@ struct ExtractionWay;
 | 
			
		||||
struct ExtractionRelation;
 | 
			
		||||
struct ProfileProperties;
 | 
			
		||||
struct InputConditionalTurnRestriction;
 | 
			
		||||
struct InputManeuverOverride;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is used by the extractor with the results of the
 | 
			
		||||
@ -90,6 +91,9 @@ class ExtractorCallbacks
 | 
			
		||||
 | 
			
		||||
    // warning: caller needs to take care of synchronization!
 | 
			
		||||
    void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way);
 | 
			
		||||
 | 
			
		||||
    // warning: caller needs to take care of synchronization!
 | 
			
		||||
    void ProcessManeuverOverride(const InputManeuverOverride & override);
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,8 @@ struct ExtractorConfig final : storage::IOConfig
 | 
			
		||||
                                      ".osrm.properties",
 | 
			
		||||
                                      ".osrm.icd",
 | 
			
		||||
                                      ".osrm.cnbg",
 | 
			
		||||
                                      ".osrm.cnbg_to_ebg"}),
 | 
			
		||||
                                      ".osrm.cnbg_to_ebg",
 | 
			
		||||
                                      ".osrm.maneuver_overrides"}),
 | 
			
		||||
                                 requested_num_threads(0),
 | 
			
		||||
                                 parse_conditionals(false),
 | 
			
		||||
                                 use_locations_cache(true)
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
#include "extractor/scripting_environment.hpp"
 | 
			
		||||
#include "util/typedefs.hpp"
 | 
			
		||||
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "util/node_based_graph.hpp"
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
@ -28,6 +29,7 @@ class GraphCompressor
 | 
			
		||||
                  ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                  std::vector<TurnRestriction> &turn_restrictions,
 | 
			
		||||
                  std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
                  std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
 | 
			
		||||
                  util::NodeBasedDynamicGraph &graph,
 | 
			
		||||
                  const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
 | 
			
		||||
                  CompressedEdgeContainer &geometry_compressor);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										120
									
								
								include/extractor/maneuver_override.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								include/extractor/maneuver_override.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
#ifndef MANUEVER_OVERRIDE_HPP
 | 
			
		||||
#define MANUEVER_OVERRIDE_HPP
 | 
			
		||||
 | 
			
		||||
#include "guidance/turn_instruction.hpp"
 | 
			
		||||
#include "util/typedefs.hpp"
 | 
			
		||||
 | 
			
		||||
#include "storage/shared_memory_ownership.hpp"
 | 
			
		||||
#include "util/vector_view.hpp"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <boost/functional/hash.hpp>
 | 
			
		||||
 | 
			
		||||
namespace osrm
 | 
			
		||||
{
 | 
			
		||||
namespace extractor
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
// Data that is loaded from the OSM datafile directly
 | 
			
		||||
struct InputManeuverOverride
 | 
			
		||||
{
 | 
			
		||||
    std::vector<OSMWayID> via_ways;
 | 
			
		||||
    OSMNodeID via_node;
 | 
			
		||||
    std::string maneuver;
 | 
			
		||||
    std::string direction;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Object returned by the datafacade
 | 
			
		||||
struct ManeuverOverride
 | 
			
		||||
{
 | 
			
		||||
    // util::ViewOrVector<NodeID, storage::Ownership::View> node_sequence;
 | 
			
		||||
    std::vector<NodeID> node_sequence;
 | 
			
		||||
    // before the turn, then later, the edge_based_node_id of the turn
 | 
			
		||||
    NodeID instruction_node; // node-based node ID
 | 
			
		||||
    guidance::TurnType::Enum override_type;
 | 
			
		||||
    guidance::DirectionModifier::Enum direction;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Object returned by the datafacade
 | 
			
		||||
struct StorageManeuverOverride
 | 
			
		||||
{
 | 
			
		||||
    std::uint32_t node_sequence_offset_begin;
 | 
			
		||||
    std::uint32_t node_sequence_offset_end;
 | 
			
		||||
    NodeID start_node;
 | 
			
		||||
    // before the turn, then later, the edge_based_node_id of the turn
 | 
			
		||||
    NodeID instruction_node; // node-based node ID
 | 
			
		||||
    guidance::TurnType::Enum override_type;
 | 
			
		||||
    guidance::DirectionModifier::Enum direction;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct NodeBasedTurn
 | 
			
		||||
{
 | 
			
		||||
    NodeID from;
 | 
			
		||||
    NodeID via;
 | 
			
		||||
    NodeID to;
 | 
			
		||||
 | 
			
		||||
    bool operator==(const NodeBasedTurn &other) const
 | 
			
		||||
    {
 | 
			
		||||
        return other.from == from && other.via == via && other.to == to;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct UnresolvedManeuverOverride
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    std::vector<NodeBasedTurn>
 | 
			
		||||
        turn_sequence; // initially the internal node-based-node ID of the node
 | 
			
		||||
    // before the turn, then later, the edge_based_node_id of the turn
 | 
			
		||||
    NodeID instruction_node; // node-based node ID
 | 
			
		||||
    guidance::TurnType::Enum override_type;
 | 
			
		||||
    guidance::DirectionModifier::Enum direction;
 | 
			
		||||
 | 
			
		||||
    // check if all parts of the restriction reference an actual node
 | 
			
		||||
    bool Valid() const
 | 
			
		||||
    {
 | 
			
		||||
        return !turn_sequence.empty() && std::none_of(turn_sequence.begin(),
 | 
			
		||||
                                                      turn_sequence.end(),
 | 
			
		||||
                                                      [](const auto &n) {
 | 
			
		||||
                                                          return n.from == SPECIAL_NODEID ||
 | 
			
		||||
                                                                 n.via == SPECIAL_NODEID ||
 | 
			
		||||
                                                                 n.to == SPECIAL_NODEID;
 | 
			
		||||
                                                      }) &&
 | 
			
		||||
               (direction != guidance::DirectionModifier::MaxDirectionModifier ||
 | 
			
		||||
                override_type != guidance::TurnType::Invalid);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// custom specialization of std::hash can be injected in namespace std
 | 
			
		||||
namespace std
 | 
			
		||||
{
 | 
			
		||||
template <> struct hash<osrm::extractor::NodeBasedTurn>
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    typedef osrm::extractor::NodeBasedTurn argument_type;
 | 
			
		||||
    typedef std::size_t result_type;
 | 
			
		||||
    result_type operator()(argument_type const &s) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        std::size_t seed = 0;
 | 
			
		||||
        boost::hash_combine(seed, s.from);
 | 
			
		||||
        boost::hash_combine(seed, s.via);
 | 
			
		||||
        boost::hash_combine(seed, s.to);
 | 
			
		||||
 | 
			
		||||
        return seed;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
/*
 | 
			
		||||
from=1
 | 
			
		||||
to=3
 | 
			
		||||
via=b
 | 
			
		||||
 | 
			
		||||
      101      a      102      b        103
 | 
			
		||||
---------------+---------------+-------------- (way 1)
 | 
			
		||||
      99        \      98       \       97
 | 
			
		||||
             51  \ 2          50 \ 3
 | 
			
		||||
                  \               \
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										65
									
								
								include/extractor/maneuver_override_relation_parser.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								include/extractor/maneuver_override_relation_parser.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
#ifndef MANEUVER_OVERRIDE_RELATION_PARSER_HPP
 | 
			
		||||
#define MANEUVER_OVERRIDE_RELATION_PARSER_HPP
 | 
			
		||||
 | 
			
		||||
#include "maneuver_override.hpp"
 | 
			
		||||
 | 
			
		||||
#include <boost/optional.hpp>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace osmium
 | 
			
		||||
{
 | 
			
		||||
class Relation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace osrm
 | 
			
		||||
{
 | 
			
		||||
namespace extractor
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class ScriptingEnvironment;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parses the relations that represents maneuver overrides.
 | 
			
		||||
 * These are structured similarly to turn restrictions, with some slightly
 | 
			
		||||
 * different fields.
 | 
			
		||||
 *
 | 
			
		||||
 * Simple, via-node overrides (the maneuver at the "via" point is overridden)
 | 
			
		||||
 * <relation>
 | 
			
		||||
 *   <tag k="type" v="maneuver"/>
 | 
			
		||||
 *   <member type="way" ref="1234" role="from"/>
 | 
			
		||||
 *   <member type="way" ref="5678" role="to"/>
 | 
			
		||||
 *   <member type="node" ref="9999" role="via"/>
 | 
			
		||||
 *   <tag k="maneuver" v="turn"/>
 | 
			
		||||
 *   <tag k="direction" v="slight_right"/>
 | 
			
		||||
 * </relation>
 | 
			
		||||
 *
 | 
			
		||||
 * Via-way descriptions are also supported - this is helpful if
 | 
			
		||||
 * you only want to update an instruction if a certain sequence of
 | 
			
		||||
 * road transitions are taken.
 | 
			
		||||
 *
 | 
			
		||||
 * <relation>
 | 
			
		||||
 *   <tag k="type" v="maneuver"/>
 | 
			
		||||
 *   <member type="way" ref="1234" role="from"/>
 | 
			
		||||
 *   <member type="way" ref="5678" role="to"/>
 | 
			
		||||
 *   <member type="way" ref="9012" role="via"/> <!-- note via way here -->
 | 
			
		||||
 *   <member type="node" ref="9999" role="via"/>
 | 
			
		||||
 *   <tag k="maneuver" v="turn"/>
 | 
			
		||||
 *   <tag k="direction" v="slight_right"/>
 | 
			
		||||
 * </relation>
 | 
			
		||||
 *
 | 
			
		||||
 * For via-way restrictions, ways must be connected end-to-end, i.e.
 | 
			
		||||
 * referenced ways must be split if the turn points are partway
 | 
			
		||||
 * along the original way.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class ManeuverOverrideRelationParser
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    ManeuverOverrideRelationParser();
 | 
			
		||||
    boost::optional<InputManeuverOverride> TryParse(const osmium::Relation &relation) const;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* RESTRICTION_PARSER_HPP */
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
#define OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_
 | 
			
		||||
 | 
			
		||||
#include "extractor/compressed_edge_container.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/node_based_edge.hpp"
 | 
			
		||||
#include "extractor/node_data_container.hpp"
 | 
			
		||||
#include "extractor/packed_osm_ids.hpp"
 | 
			
		||||
@ -39,7 +40,8 @@ class NodeBasedGraphFactory
 | 
			
		||||
    NodeBasedGraphFactory(const boost::filesystem::path &input_file,
 | 
			
		||||
                          ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                          std::vector<TurnRestriction> &turn_restrictions,
 | 
			
		||||
                          std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
 | 
			
		||||
                          std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
                          std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    auto const &GetGraph() const { return compressed_output_graph; }
 | 
			
		||||
    auto const &GetBarriers() const { return barriers; }
 | 
			
		||||
@ -67,7 +69,8 @@ class NodeBasedGraphFactory
 | 
			
		||||
    // edges into a single representative form
 | 
			
		||||
    void Compress(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                  std::vector<TurnRestriction> &turn_restrictions,
 | 
			
		||||
                  std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
 | 
			
		||||
                  std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
                  std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    // Most ways are bidirectional, making the geometry in forward and backward direction the same,
 | 
			
		||||
    // except for reversal. We make use of this fact by keeping only one representation of the
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
 | 
			
		||||
#define OSRM_EXTRACTOR_RESTRICTION_COMPRESSOR_HPP_
 | 
			
		||||
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/restriction.hpp"
 | 
			
		||||
#include "util/typedefs.hpp"
 | 
			
		||||
 | 
			
		||||
@ -28,7 +29,8 @@ class RestrictionCompressor
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    RestrictionCompressor(std::vector<TurnRestriction> &restrictions,
 | 
			
		||||
                          std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
 | 
			
		||||
                          std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
                          std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    // account for the compression of `from-via-to` into `from-to`
 | 
			
		||||
    void Compress(const NodeID from, const NodeID via, const NodeID to);
 | 
			
		||||
@ -40,6 +42,9 @@ class RestrictionCompressor
 | 
			
		||||
    // node-restrictions, so we can focus on them alone
 | 
			
		||||
    boost::unordered_multimap<NodeID, NodeRestriction *> starts;
 | 
			
		||||
    boost::unordered_multimap<NodeID, NodeRestriction *> ends;
 | 
			
		||||
 | 
			
		||||
    boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_starts;
 | 
			
		||||
    boost::unordered_multimap<NodeID, NodeBasedTurn *> maneuver_ends;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace extractor
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
#define SCRIPTING_ENVIRONMENT_HPP
 | 
			
		||||
 | 
			
		||||
#include "extractor/internal_extractor_edge.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/profile_properties.hpp"
 | 
			
		||||
#include "extractor/restriction.hpp"
 | 
			
		||||
 | 
			
		||||
@ -31,6 +32,7 @@ namespace extractor
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class RestrictionParser;
 | 
			
		||||
class ManeuverOverrideRelationParser;
 | 
			
		||||
class ExtractionRelationContainer;
 | 
			
		||||
struct ExtractionNode;
 | 
			
		||||
struct ExtractionWay;
 | 
			
		||||
@ -62,10 +64,12 @@ class ScriptingEnvironment
 | 
			
		||||
    virtual void
 | 
			
		||||
    ProcessElements(const osmium::memory::Buffer &buffer,
 | 
			
		||||
                    const RestrictionParser &restriction_parser,
 | 
			
		||||
                    const ManeuverOverrideRelationParser &maneuver_override_parser,
 | 
			
		||||
                    const ExtractionRelationContainer &relations,
 | 
			
		||||
                    std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
 | 
			
		||||
                    std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
 | 
			
		||||
                    std::vector<InputConditionalTurnRestriction> &resulting_restrictions) = 0;
 | 
			
		||||
                    std::vector<InputConditionalTurnRestriction> &resulting_restrictions,
 | 
			
		||||
                    std::vector<InputManeuverOverride> &resulting_maneuver_overrides) = 0;
 | 
			
		||||
 | 
			
		||||
    virtual bool HasLocationDependentData() const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -88,10 +88,12 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
 | 
			
		||||
    void
 | 
			
		||||
    ProcessElements(const osmium::memory::Buffer &buffer,
 | 
			
		||||
                    const RestrictionParser &restriction_parser,
 | 
			
		||||
                    const ManeuverOverrideRelationParser &maneuver_override_parser,
 | 
			
		||||
                    const ExtractionRelationContainer &relations,
 | 
			
		||||
                    std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
 | 
			
		||||
                    std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
 | 
			
		||||
                    std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
 | 
			
		||||
                    std::vector<InputConditionalTurnRestriction> &resulting_restrictions,
 | 
			
		||||
                    std::vector<InputManeuverOverride> &resulting_maneuver_overrides) override;
 | 
			
		||||
 | 
			
		||||
    bool HasLocationDependentData() const override { return !location_dependent_data.empty(); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
#include "conditional_turn_penalty.hpp"
 | 
			
		||||
#include "extractor/datasources.hpp"
 | 
			
		||||
#include "extractor/intersection_bearings_container.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/nbg_to_ebg.hpp"
 | 
			
		||||
#include "extractor/node_data_container.hpp"
 | 
			
		||||
#include "extractor/profile_properties.hpp"
 | 
			
		||||
@ -298,6 +299,16 @@ inline void read(storage::io::FileReader &reader,
 | 
			
		||||
    for (auto &penalty : conditional_penalties)
 | 
			
		||||
        read(reader, penalty);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void write(storage::io::FileWriter &writer,
 | 
			
		||||
                  const std::vector<StorageManeuverOverride> &maneuver_overrides,
 | 
			
		||||
                  const std::vector<NodeID> &node_sequences)
 | 
			
		||||
{
 | 
			
		||||
    writer.WriteElementCount64(maneuver_overrides.size());
 | 
			
		||||
    writer.WriteElementCount64(node_sequences.size());
 | 
			
		||||
    writer.WriteFrom(maneuver_overrides);
 | 
			
		||||
    writer.WriteFrom(node_sequences);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -321,7 +321,8 @@ const constexpr char *modifier_names[] = {"uturn",
 | 
			
		||||
                                          "straight",
 | 
			
		||||
                                          "slight left",
 | 
			
		||||
                                          "left",
 | 
			
		||||
                                          "sharp left"};
 | 
			
		||||
                                          "sharp left",
 | 
			
		||||
                                          "UNDEFINED"};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Human readable values for TurnType enum values
 | 
			
		||||
@ -363,13 +364,14 @@ const constexpr TurnTypeName turn_type_names[] = {
 | 
			
		||||
    {"roundabout turn", "roundabout turn"},
 | 
			
		||||
    {"exit roundabout", "exit roundabout turn"},
 | 
			
		||||
    {"invalid", "(stay on roundabout)"},
 | 
			
		||||
    {"invalid", "(sliproad)"}};
 | 
			
		||||
    {"invalid", "(sliproad)"},
 | 
			
		||||
    {"MAXVALUE", "MAXVALUE"}};
 | 
			
		||||
 | 
			
		||||
} // ns detail
 | 
			
		||||
 | 
			
		||||
inline std::string instructionTypeToString(const TurnType::Enum type)
 | 
			
		||||
{
 | 
			
		||||
    static_assert(sizeof(detail::turn_type_names) / sizeof(detail::turn_type_names[0]) >=
 | 
			
		||||
    static_assert((sizeof(detail::turn_type_names) + 1) / sizeof(detail::turn_type_names[0]) >=
 | 
			
		||||
                      TurnType::MaxTurnType,
 | 
			
		||||
                  "Some turn types have no string representation.");
 | 
			
		||||
    return detail::turn_type_names[static_cast<std::size_t>(type)].external_name;
 | 
			
		||||
@ -377,7 +379,7 @@ inline std::string instructionTypeToString(const TurnType::Enum type)
 | 
			
		||||
 | 
			
		||||
inline std::string internalInstructionTypeToString(const TurnType::Enum type)
 | 
			
		||||
{
 | 
			
		||||
    static_assert(sizeof(detail::turn_type_names) / sizeof(detail::turn_type_names[0]) >=
 | 
			
		||||
    static_assert((sizeof(detail::turn_type_names) + 1) / sizeof(detail::turn_type_names[0]) >=
 | 
			
		||||
                      TurnType::MaxTurnType,
 | 
			
		||||
                  "Some turn types have no string representation.");
 | 
			
		||||
    return detail::turn_type_names[static_cast<std::size_t>(type)].internal_name;
 | 
			
		||||
@ -385,7 +387,7 @@ inline std::string internalInstructionTypeToString(const TurnType::Enum type)
 | 
			
		||||
 | 
			
		||||
inline std::string instructionModifierToString(const DirectionModifier::Enum modifier)
 | 
			
		||||
{
 | 
			
		||||
    static_assert(sizeof(detail::modifier_names) / sizeof(detail::modifier_names[0]) >=
 | 
			
		||||
    static_assert((sizeof(detail::modifier_names) + 1) / sizeof(detail::modifier_names[0]) >=
 | 
			
		||||
                      DirectionModifier::MaxDirectionModifier,
 | 
			
		||||
                  "Some direction modifiers have no string representation.");
 | 
			
		||||
    return detail::modifier_names[static_cast<std::size_t>(modifier)];
 | 
			
		||||
 | 
			
		||||
@ -88,7 +88,9 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
 | 
			
		||||
                                            "MLD_CELL_LEVEL_OFFSETS",
 | 
			
		||||
                                            "MLD_GRAPH_NODE_LIST",
 | 
			
		||||
                                            "MLD_GRAPH_EDGE_LIST",
 | 
			
		||||
                                            "MLD_GRAPH_NODE_TO_OFFSET"};
 | 
			
		||||
                                            "MLD_GRAPH_NODE_TO_OFFSET",
 | 
			
		||||
                                            "MANEUVER_OVERRIDES",
 | 
			
		||||
                                            "MANEUVER_OVERRIDE_NODE_SEQUENCES"};
 | 
			
		||||
 | 
			
		||||
struct DataLayout
 | 
			
		||||
{
 | 
			
		||||
@ -165,6 +167,8 @@ struct DataLayout
 | 
			
		||||
        MLD_GRAPH_NODE_LIST,
 | 
			
		||||
        MLD_GRAPH_EDGE_LIST,
 | 
			
		||||
        MLD_GRAPH_NODE_TO_OFFSET,
 | 
			
		||||
        MANEUVER_OVERRIDES,
 | 
			
		||||
        MANEUVER_OVERRIDE_NODE_SEQUENCES,
 | 
			
		||||
        NUM_BLOCKS
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,8 @@ struct StorageConfig final : IOConfig
 | 
			
		||||
                    ".osrm.datasource_names",
 | 
			
		||||
                    ".osrm.names",
 | 
			
		||||
                    ".osrm.properties",
 | 
			
		||||
                    ".osrm.icd"},
 | 
			
		||||
                    ".osrm.icd",
 | 
			
		||||
                    ".osrm.maneuver_overrides"},
 | 
			
		||||
                   {".osrm.hsgr",
 | 
			
		||||
                    ".osrm.nbg_nodes",
 | 
			
		||||
                    ".osrm.ebg_nodes",
 | 
			
		||||
 | 
			
		||||
@ -566,6 +566,150 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
 | 
			
		||||
    return removeNoTurnInstructions(std::move(steps));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void applyOverrides(const datafacade::BaseDataFacade &facade,
 | 
			
		||||
                    std::vector<RouteStep> &steps,
 | 
			
		||||
                    const LegGeometry &leg_geometry)
 | 
			
		||||
{
 | 
			
		||||
    // Find overrides that match, and apply them
 | 
			
		||||
    // The +/-1 here are to remove the depart and arrive steps, which
 | 
			
		||||
    // we don't allow updates to
 | 
			
		||||
    for (auto current_step_it = steps.begin(); current_step_it != steps.end(); ++current_step_it)
 | 
			
		||||
    {
 | 
			
		||||
        util::Log(logDEBUG) << "Searching for " << current_step_it->from_id << std::endl;
 | 
			
		||||
        const auto overrides = facade.GetOverridesThatStartAt(current_step_it->from_id);
 | 
			
		||||
        if (overrides.empty())
 | 
			
		||||
            continue;
 | 
			
		||||
        util::Log(logDEBUG) << "~~~~ GOT A HIT, checking the rest ~~~" << std::endl;
 | 
			
		||||
        for (const extractor::ManeuverOverride &maneuver_relation : overrides)
 | 
			
		||||
        {
 | 
			
		||||
            util::Log(logDEBUG) << "Override sequence is ";
 | 
			
		||||
            for (auto &n : maneuver_relation.node_sequence)
 | 
			
		||||
            {
 | 
			
		||||
                util::Log(logDEBUG) << n << " ";
 | 
			
		||||
            }
 | 
			
		||||
            util::Log(logDEBUG) << std::endl;
 | 
			
		||||
            util::Log(logDEBUG) << "Override type is "
 | 
			
		||||
                                << osrm::guidance::internalInstructionTypeToString(
 | 
			
		||||
                                       maneuver_relation.override_type)
 | 
			
		||||
                                << std::endl;
 | 
			
		||||
            util::Log(logDEBUG) << "Override direction is "
 | 
			
		||||
                                << osrm::guidance::instructionModifierToString(
 | 
			
		||||
                                       maneuver_relation.direction)
 | 
			
		||||
                                << std::endl;
 | 
			
		||||
 | 
			
		||||
            util::Log(logDEBUG) << "Route sequence is ";
 | 
			
		||||
            for (auto it = current_step_it; it != steps.end(); ++it)
 | 
			
		||||
            {
 | 
			
		||||
                util::Log(logDEBUG) << it->from_id << " ";
 | 
			
		||||
            }
 | 
			
		||||
            util::Log(logDEBUG) << std::endl;
 | 
			
		||||
 | 
			
		||||
            auto search_iter = maneuver_relation.node_sequence.begin();
 | 
			
		||||
            auto route_iter = current_step_it;
 | 
			
		||||
            while (search_iter != maneuver_relation.node_sequence.end())
 | 
			
		||||
            {
 | 
			
		||||
                if (route_iter == steps.end())
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                if (*search_iter == route_iter->from_id)
 | 
			
		||||
                {
 | 
			
		||||
                    ++search_iter;
 | 
			
		||||
                    ++route_iter;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                // Skip over duplicated EBNs in the step array
 | 
			
		||||
                // EBNs are sometime duplicated because guidance code inserts
 | 
			
		||||
                // "fake" steps that it later removes.  This hasn't happened yet
 | 
			
		||||
                // at this point, but we can safely just skip past the dupes.
 | 
			
		||||
                if ((route_iter - 1)->from_id == route_iter->from_id)
 | 
			
		||||
                {
 | 
			
		||||
                    ++route_iter;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                // If we get here, the values got out of sync so it's not
 | 
			
		||||
                // a match.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // We got a match, update using the instruction_node
 | 
			
		||||
            if (search_iter == maneuver_relation.node_sequence.end())
 | 
			
		||||
            {
 | 
			
		||||
                util::Log(logDEBUG) << "Node sequence matched, looking for the step "
 | 
			
		||||
                                    << "that has the via node" << std::endl;
 | 
			
		||||
                const auto via_node_coords =
 | 
			
		||||
                    facade.GetCoordinateOfNode(maneuver_relation.instruction_node);
 | 
			
		||||
                // Find the step that has the instruction_node at the intersection point
 | 
			
		||||
                auto step_to_update = std::find_if(
 | 
			
		||||
                    current_step_it,
 | 
			
		||||
                    route_iter,
 | 
			
		||||
                    [&leg_geometry, &via_node_coords](const auto &step) {
 | 
			
		||||
                        util::Log(logDEBUG) << "Leg geom from " << step.geometry_begin << " to  "
 | 
			
		||||
                                            << step.geometry_end << std::endl;
 | 
			
		||||
 | 
			
		||||
                        // iterators over geometry of current step
 | 
			
		||||
                        auto begin = leg_geometry.locations.begin() + step.geometry_begin;
 | 
			
		||||
                        auto end = leg_geometry.locations.begin() + step.geometry_end;
 | 
			
		||||
                        auto via_match = std::find_if(begin, end, [&](const auto &location) {
 | 
			
		||||
                            return location == via_node_coords;
 | 
			
		||||
                        });
 | 
			
		||||
                        if (via_match != end)
 | 
			
		||||
                        {
 | 
			
		||||
                            util::Log(logDEBUG)
 | 
			
		||||
                                << "Found geometry match at "
 | 
			
		||||
                                << (std::distance(begin, end) - std::distance(via_match, end))
 | 
			
		||||
                                << std::endl;
 | 
			
		||||
                        }
 | 
			
		||||
                        util::Log(logDEBUG)
 | 
			
		||||
                            << ((*(leg_geometry.locations.begin() + step.geometry_begin) ==
 | 
			
		||||
                                 via_node_coords)
 | 
			
		||||
                                    ? "true"
 | 
			
		||||
                                    : "false")
 | 
			
		||||
                            << std::endl;
 | 
			
		||||
                        return *(leg_geometry.locations.begin() + step.geometry_begin) ==
 | 
			
		||||
                               via_node_coords;
 | 
			
		||||
                        // return via_match != end;
 | 
			
		||||
                    });
 | 
			
		||||
                // We found a step that had the intersection_node coordinate
 | 
			
		||||
                // in its geometry
 | 
			
		||||
                if (step_to_update != route_iter)
 | 
			
		||||
                {
 | 
			
		||||
                    // Don't update the last step (it's an arrive instruction)
 | 
			
		||||
                    util::Log(logDEBUG) << "Updating step "
 | 
			
		||||
                                        << std::distance(steps.begin(), steps.end()) -
 | 
			
		||||
                                               std::distance(step_to_update, steps.end())
 | 
			
		||||
                                        << std::endl;
 | 
			
		||||
                    if (maneuver_relation.override_type != osrm::guidance::TurnType::MaxTurnType)
 | 
			
		||||
                    {
 | 
			
		||||
                        util::Log(logDEBUG) << "    instruction was "
 | 
			
		||||
                                            << osrm::guidance::internalInstructionTypeToString(
 | 
			
		||||
                                                   step_to_update->maneuver.instruction.type)
 | 
			
		||||
                                            << " now "
 | 
			
		||||
                                            << osrm::guidance::internalInstructionTypeToString(
 | 
			
		||||
                                                   maneuver_relation.override_type)
 | 
			
		||||
                                            << std::endl;
 | 
			
		||||
                        step_to_update->maneuver.instruction.type = maneuver_relation.override_type;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (maneuver_relation.direction !=
 | 
			
		||||
                        osrm::guidance::DirectionModifier::MaxDirectionModifier)
 | 
			
		||||
                    {
 | 
			
		||||
                        util::Log(logDEBUG)
 | 
			
		||||
                            << "    direction was "
 | 
			
		||||
                            << osrm::guidance::instructionModifierToString(
 | 
			
		||||
                                   step_to_update->maneuver.instruction.direction_modifier)
 | 
			
		||||
                            << " now " << osrm::guidance::instructionModifierToString(
 | 
			
		||||
                                              maneuver_relation.direction)
 | 
			
		||||
                            << std::endl;
 | 
			
		||||
                        step_to_update->maneuver.instruction.direction_modifier =
 | 
			
		||||
                            maneuver_relation.direction;
 | 
			
		||||
                    }
 | 
			
		||||
                    // step_to_update->is_overridden = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        util::Log(logDEBUG) << "Done tweaking steps" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace guidance
 | 
			
		||||
} // namespace engine
 | 
			
		||||
} // namespace osrm
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
#include <tbb/blocked_range.h>
 | 
			
		||||
@ -219,15 +220,18 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
 | 
			
		||||
    return NBGToEBG{node_u, node_v, nbe_to_ebn_mapping[edge_id_1], nbe_to_ebn_mapping[edge_id_2]};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                                const std::string &turn_weight_penalties_filename,
 | 
			
		||||
                                const std::string &turn_duration_penalties_filename,
 | 
			
		||||
                                const std::string &turn_penalties_index_filename,
 | 
			
		||||
                                const std::string &cnbg_ebg_mapping_path,
 | 
			
		||||
                                const std::string &conditional_penalties_filename,
 | 
			
		||||
                                const RestrictionMap &node_restriction_map,
 | 
			
		||||
                                const ConditionalRestrictionMap &conditional_node_restriction_map,
 | 
			
		||||
                                const WayRestrictionMap &way_restriction_map)
 | 
			
		||||
void EdgeBasedGraphFactory::Run(
 | 
			
		||||
    ScriptingEnvironment &scripting_environment,
 | 
			
		||||
    const std::string &turn_weight_penalties_filename,
 | 
			
		||||
    const std::string &turn_duration_penalties_filename,
 | 
			
		||||
    const std::string &turn_penalties_index_filename,
 | 
			
		||||
    const std::string &cnbg_ebg_mapping_path,
 | 
			
		||||
    const std::string &conditional_penalties_filename,
 | 
			
		||||
    const std::string &maneuver_overrides_filename,
 | 
			
		||||
    const RestrictionMap &node_restriction_map,
 | 
			
		||||
    const ConditionalRestrictionMap &conditional_node_restriction_map,
 | 
			
		||||
    const WayRestrictionMap &way_restriction_map,
 | 
			
		||||
    const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
 | 
			
		||||
{
 | 
			
		||||
    TIMER_START(renumber);
 | 
			
		||||
    m_number_of_edge_based_nodes =
 | 
			
		||||
@ -252,9 +256,11 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                              turn_duration_penalties_filename,
 | 
			
		||||
                              turn_penalties_index_filename,
 | 
			
		||||
                              conditional_penalties_filename,
 | 
			
		||||
                              maneuver_overrides_filename,
 | 
			
		||||
                              node_restriction_map,
 | 
			
		||||
                              conditional_node_restriction_map,
 | 
			
		||||
                              way_restriction_map);
 | 
			
		||||
                              way_restriction_map,
 | 
			
		||||
                              unresolved_maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    TIMER_STOP(generate_edges);
 | 
			
		||||
 | 
			
		||||
@ -407,9 +413,11 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
    const std::string &turn_duration_penalties_filename,
 | 
			
		||||
    const std::string &turn_penalties_index_filename,
 | 
			
		||||
    const std::string &conditional_penalties_filename,
 | 
			
		||||
    const std::string &maneuver_overrides_filename,
 | 
			
		||||
    const RestrictionMap &node_restriction_map,
 | 
			
		||||
    const ConditionalRestrictionMap &conditional_restriction_map,
 | 
			
		||||
    const WayRestrictionMap &way_restriction_map)
 | 
			
		||||
    const WayRestrictionMap &way_restriction_map,
 | 
			
		||||
    const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
 | 
			
		||||
{
 | 
			
		||||
    util::Log() << "Generating edge-expanded edges ";
 | 
			
		||||
 | 
			
		||||
@ -434,6 +442,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
    std::vector<TurnPenalty> turn_weight_penalties;
 | 
			
		||||
    std::vector<TurnPenalty> turn_duration_penalties;
 | 
			
		||||
 | 
			
		||||
    // Now, renumber all our maneuver overrides to use edge-based-nodes
 | 
			
		||||
    std::vector<StorageManeuverOverride> storage_maneuver_overrides;
 | 
			
		||||
    std::vector<NodeID> maneuver_override_sequences;
 | 
			
		||||
 | 
			
		||||
    const auto weight_multiplier =
 | 
			
		||||
        scripting_environment.GetProfileProperties().GetWeightMultiplier();
 | 
			
		||||
 | 
			
		||||
@ -482,12 +494,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
            std::vector<EdgeWithData> delayed_data;    // may need this
 | 
			
		||||
            std::vector<Conditional> conditionals;
 | 
			
		||||
 | 
			
		||||
            std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> turn_to_ebn_map;
 | 
			
		||||
 | 
			
		||||
            util::ConnectivityChecksum checksum;
 | 
			
		||||
        };
 | 
			
		||||
        using EdgesPipelineBufferPtr = std::shared_ptr<EdgesPipelineBuffer>;
 | 
			
		||||
 | 
			
		||||
        m_connectivity_checksum = 0;
 | 
			
		||||
 | 
			
		||||
        std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> global_turn_to_ebn_map;
 | 
			
		||||
 | 
			
		||||
        // going over all nodes (which form the center of an intersection), we compute all possible
 | 
			
		||||
        // turns along these intersections.
 | 
			
		||||
        NodeID current_node = 0;
 | 
			
		||||
@ -847,6 +863,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
                                m_node_based_graph.GetTarget(outgoing_edge.edge),
 | 
			
		||||
                                m_number_of_edge_based_nodes);
 | 
			
		||||
 | 
			
		||||
                            /***************************/
 | 
			
		||||
 | 
			
		||||
                            const auto edgetarget =
 | 
			
		||||
                                m_node_based_graph.GetTarget(outgoing_edge.edge);
 | 
			
		||||
 | 
			
		||||
                            // TODO: this loop is not optimized - once we have a few
 | 
			
		||||
                            //       overrides available, we should index this for faster
 | 
			
		||||
                            //       lookups
 | 
			
		||||
                            for (auto & override : unresolved_maneuver_overrides)
 | 
			
		||||
                            {
 | 
			
		||||
                                for (auto &turn : override.turn_sequence)
 | 
			
		||||
                                {
 | 
			
		||||
                                    if (turn.from == incoming_edge.node &&
 | 
			
		||||
                                        turn.via == intersection_node && turn.to == edgetarget)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        const auto &ebn_from =
 | 
			
		||||
                                            nbe_to_ebn_mapping[incoming_edge.edge];
 | 
			
		||||
                                        const auto &ebn_to = target_id;
 | 
			
		||||
                                        buffer->turn_to_ebn_map[turn] =
 | 
			
		||||
                                            std::make_pair(ebn_from, ebn_to);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            { // scope to forget edge_with_data after
 | 
			
		||||
                                const auto edge_with_data_and_condition =
 | 
			
		||||
                                    generate_edge(nbe_to_ebn_mapping[incoming_edge.edge],
 | 
			
		||||
@ -997,6 +1037,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
                // Copy via-way restrictions delayed data
 | 
			
		||||
                delayed_data.insert(
 | 
			
		||||
                    delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end());
 | 
			
		||||
 | 
			
		||||
                std::for_each(buffer->turn_to_ebn_map.begin(),
 | 
			
		||||
                              buffer->turn_to_ebn_map.end(),
 | 
			
		||||
                              [&global_turn_to_ebn_map](const auto &p) {
 | 
			
		||||
                                  // TODO: log conflicts here
 | 
			
		||||
                                  global_turn_to_ebn_map.insert(p);
 | 
			
		||||
                              });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // Now, execute the pipeline.  The value of "5" here was chosen by experimentation
 | 
			
		||||
@ -1010,6 +1057,39 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
        // NOTE: buffer.delayed_data and buffer.delayed_turn_data have the same index
 | 
			
		||||
        std::for_each(delayed_data.begin(), delayed_data.end(), transfer_data);
 | 
			
		||||
 | 
			
		||||
        // Now, replace node-based-node ID values in the `node_sequence` with
 | 
			
		||||
        // the edge-based-node values we found and stored in the `turn_to_ebn_map`
 | 
			
		||||
        for (auto &unresolved_override : unresolved_maneuver_overrides)
 | 
			
		||||
        {
 | 
			
		||||
            StorageManeuverOverride storage_override;
 | 
			
		||||
            storage_override.instruction_node = unresolved_override.instruction_node;
 | 
			
		||||
            storage_override.override_type = unresolved_override.override_type;
 | 
			
		||||
            storage_override.direction = unresolved_override.direction;
 | 
			
		||||
 | 
			
		||||
            std::vector<NodeID> node_sequence(unresolved_override.turn_sequence.size() + 1,
 | 
			
		||||
                                              SPECIAL_NODEID);
 | 
			
		||||
 | 
			
		||||
            for (std::int64_t i = unresolved_override.turn_sequence.size() - 1; i >= 0; --i)
 | 
			
		||||
            {
 | 
			
		||||
                const auto v = global_turn_to_ebn_map.find(unresolved_override.turn_sequence[i]);
 | 
			
		||||
                if (v != global_turn_to_ebn_map.end())
 | 
			
		||||
                {
 | 
			
		||||
                    node_sequence[i] = v->second.first;
 | 
			
		||||
                    node_sequence[i + 1] = v->second.second;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            storage_override.node_sequence_offset_begin = maneuver_override_sequences.size();
 | 
			
		||||
            storage_override.node_sequence_offset_end =
 | 
			
		||||
                maneuver_override_sequences.size() + node_sequence.size();
 | 
			
		||||
 | 
			
		||||
            storage_override.start_node = node_sequence.front();
 | 
			
		||||
 | 
			
		||||
            maneuver_override_sequences.insert(
 | 
			
		||||
                maneuver_override_sequences.end(), node_sequence.begin(), node_sequence.end());
 | 
			
		||||
 | 
			
		||||
            storage_maneuver_overrides.push_back(storage_override);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Flush the turn_indexes_write_buffer if it's not empty
 | 
			
		||||
        if (!turn_indexes_write_buffer.empty())
 | 
			
		||||
        {
 | 
			
		||||
@ -1018,6 +1098,20 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
            turn_indexes_write_buffer.clear();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        util::Log() << "Sorting and writing " << storage_maneuver_overrides.size()
 | 
			
		||||
                    << " maneuver overrides...";
 | 
			
		||||
 | 
			
		||||
        // Sort by `from_node`, so that later lookups can be done with a binary search.
 | 
			
		||||
        std::sort(storage_maneuver_overrides.begin(),
 | 
			
		||||
                  storage_maneuver_overrides.end(),
 | 
			
		||||
                  [](const auto &a, const auto &b) { return a.start_node < b.start_node; });
 | 
			
		||||
        // write conditional turn penalties into the restrictions file
 | 
			
		||||
        storage::io::FileWriter writer(maneuver_overrides_filename,
 | 
			
		||||
                                       storage::io::FileWriter::GenerateFingerprint);
 | 
			
		||||
        extractor::serialization::write(
 | 
			
		||||
            writer, storage_maneuver_overrides, maneuver_override_sequences);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    util::Log() << "done.";
 | 
			
		||||
    util::Log() << "Renumbering turns";
 | 
			
		||||
 | 
			
		||||
@ -141,6 +141,19 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
 | 
			
		||||
    WriteEdges(file_out);
 | 
			
		||||
    WriteMetadata(file_out);
 | 
			
		||||
 | 
			
		||||
    /* Sort these so that searching is a bit faster later on */
 | 
			
		||||
    {
 | 
			
		||||
        util::UnbufferedLog log;
 | 
			
		||||
        log << "Sorting used ways         ... ";
 | 
			
		||||
        TIMER_START(sort_ways);
 | 
			
		||||
        tbb::parallel_sort(way_start_end_id_list.begin(),
 | 
			
		||||
                           way_start_end_id_list.end(),
 | 
			
		||||
                           FirstAndLastSegmentOfWayCompare());
 | 
			
		||||
        TIMER_STOP(sort_ways);
 | 
			
		||||
        log << "ok, after " << TIMER_SEC(sort_ways) << "s";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PrepareManeuverOverrides();
 | 
			
		||||
    PrepareRestrictions();
 | 
			
		||||
    WriteCharData(name_file_name);
 | 
			
		||||
}
 | 
			
		||||
@ -651,20 +664,262 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
 | 
			
		||||
    util::Log() << "Processed " << max_internal_node_id << " nodes";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtractionContainers::PrepareRestrictions()
 | 
			
		||||
void ExtractionContainers::PrepareManeuverOverrides()
 | 
			
		||||
{
 | 
			
		||||
    std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways;
 | 
			
		||||
 | 
			
		||||
    // prepare for extracting source/destination nodes for all maneuvers
 | 
			
		||||
    {
 | 
			
		||||
        util::UnbufferedLog log;
 | 
			
		||||
        log << "Sorting used ways         ... ";
 | 
			
		||||
        TIMER_START(sort_ways);
 | 
			
		||||
        tbb::parallel_sort(way_start_end_id_list.begin(),
 | 
			
		||||
                           way_start_end_id_list.end(),
 | 
			
		||||
                           FirstAndLastSegmentOfWayCompare());
 | 
			
		||||
        TIMER_STOP(sort_ways);
 | 
			
		||||
        log << "ok, after " << TIMER_SEC(sort_ways) << "s";
 | 
			
		||||
        log << "Collecting start/end information on " << external_maneuver_overrides_list.size()
 | 
			
		||||
            << " maneuver overrides...";
 | 
			
		||||
        TIMER_START(prepare_maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
        const auto mark_ids = [&](auto const &external_maneuver_override) {
 | 
			
		||||
            FirstAndLastSegmentOfWay dummy_segment{
 | 
			
		||||
                MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
 | 
			
		||||
            std::for_each(external_maneuver_override.via_ways.begin(),
 | 
			
		||||
                          external_maneuver_override.via_ways.end(),
 | 
			
		||||
                          [&referenced_ways, dummy_segment](const auto &element) {
 | 
			
		||||
                              referenced_ways[element] = dummy_segment;
 | 
			
		||||
                          });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // First, make an empty hashtable keyed by the ways referenced
 | 
			
		||||
        // by the maneuver overrides
 | 
			
		||||
        std::for_each(external_maneuver_overrides_list.begin(),
 | 
			
		||||
                      external_maneuver_overrides_list.end(),
 | 
			
		||||
                      mark_ids);
 | 
			
		||||
 | 
			
		||||
        const auto set_ids = [&](auto const &start_end) {
 | 
			
		||||
            auto itr = referenced_ways.find(start_end.way_id);
 | 
			
		||||
            if (itr != referenced_ways.end())
 | 
			
		||||
                itr->second = start_end;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Then, populate the values in that hashtable for only the ways
 | 
			
		||||
        // referenced
 | 
			
		||||
        std::for_each(way_start_end_id_list.cbegin(), way_start_end_id_list.cend(), set_ids);
 | 
			
		||||
 | 
			
		||||
        TIMER_STOP(prepare_maneuver_overrides);
 | 
			
		||||
        log << "ok, after " << TIMER_SEC(prepare_maneuver_overrides) << "s";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto const osm_node_to_internal_nbn = [&](auto const osm_node) {
 | 
			
		||||
        auto internal = mapExternalToInternalNodeID(
 | 
			
		||||
            used_node_id_list.begin(), used_node_id_list.end(), osm_node);
 | 
			
		||||
        if (internal == SPECIAL_NODEID)
 | 
			
		||||
        {
 | 
			
		||||
            util::Log(logDEBUG) << "Maneuver override references invalid node: " << osm_node;
 | 
			
		||||
        }
 | 
			
		||||
        return internal;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Given
 | 
			
		||||
    // a -- b - ????????? - c -- d as via segment
 | 
			
		||||
    // and either
 | 
			
		||||
    // d -- e - ????????? - f -- g or
 | 
			
		||||
    // h -- i - ????????? - j -- a
 | 
			
		||||
    // return
 | 
			
		||||
    // (d,e) or (j,a) as entry-segment
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *   Here's what these properties represent on the node-based-graph
 | 
			
		||||
     *       way "ABCD"                         way "AB"
 | 
			
		||||
     *  -----------------------------------------------------------------
 | 
			
		||||
     *     ⬇   A  first_segment_source_id
 | 
			
		||||
     *     ⬇   |
 | 
			
		||||
     *     ⬇︎   B  first_segment_target_id      A  first_segment_source_id
 | 
			
		||||
     *     ⬇︎   |                            ⬇ |  last_segment_source_id
 | 
			
		||||
     *     ⬇︎   |                            ⬇ |
 | 
			
		||||
     *     ⬇︎   |                               B  first_segment_target_id
 | 
			
		||||
     *     ⬇︎   C  last_segment_source_id          last_segment_target_id
 | 
			
		||||
     *     ⬇︎   |
 | 
			
		||||
     *     ⬇︎   D  last_segment_target_id
 | 
			
		||||
     *
 | 
			
		||||
     * Finds the point where two ways connect at the end, and returns the 3
 | 
			
		||||
     * node-based nodes that describe the turn (the node just before, the
 | 
			
		||||
     * node at the turn, and the next node after the turn)
 | 
			
		||||
     **/
 | 
			
		||||
    auto const find_turn_from_way_tofrom_nodes = [&](auto const &from_segment,
 | 
			
		||||
                                                     auto const &to_segment) {
 | 
			
		||||
 | 
			
		||||
        if (from_segment.first_segment_source_id == to_segment.first_segment_source_id)
 | 
			
		||||
        {
 | 
			
		||||
            return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(from_segment.first_segment_source_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(to_segment.first_segment_target_id)};
 | 
			
		||||
        }
 | 
			
		||||
        else if (from_segment.first_segment_source_id == to_segment.last_segment_target_id)
 | 
			
		||||
        {
 | 
			
		||||
            return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(from_segment.first_segment_source_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(to_segment.last_segment_source_id)};
 | 
			
		||||
        }
 | 
			
		||||
        else if (from_segment.last_segment_target_id == to_segment.first_segment_source_id)
 | 
			
		||||
        {
 | 
			
		||||
            return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.last_segment_source_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(from_segment.last_segment_target_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(to_segment.first_segment_target_id)};
 | 
			
		||||
        }
 | 
			
		||||
        else if (from_segment.last_segment_target_id == to_segment.last_segment_target_id)
 | 
			
		||||
        {
 | 
			
		||||
            return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.last_segment_source_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(from_segment.last_segment_target_id),
 | 
			
		||||
                                 osm_node_to_internal_nbn(to_segment.last_segment_source_id)};
 | 
			
		||||
        }
 | 
			
		||||
        util::Log(logDEBUG) << "Maneuver override ways " << from_segment.way_id << " and "
 | 
			
		||||
                            << to_segment.way_id << " are not connected";
 | 
			
		||||
        return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    auto const get_turn_from_way_pair = [&](const OSMWayID &from_id, const OSMWayID &to_id) {
 | 
			
		||||
        auto const from_segment_itr = referenced_ways.find(from_id);
 | 
			
		||||
        if (from_segment_itr->second.way_id != from_id)
 | 
			
		||||
        {
 | 
			
		||||
            util::Log(logDEBUG) << "Override references invalid way: " << from_id;
 | 
			
		||||
            return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto const to_segment_itr = referenced_ways.find(to_id);
 | 
			
		||||
        if (to_segment_itr->second.way_id != to_id)
 | 
			
		||||
        {
 | 
			
		||||
            util::Log(logDEBUG) << "Override references invalid way: " << to_id;
 | 
			
		||||
            return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto result =
 | 
			
		||||
            find_turn_from_way_tofrom_nodes(from_segment_itr->second, to_segment_itr->second);
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto strings_to_turn_type_and_direction = [](const std::string &turn_string,
 | 
			
		||||
                                                       const std::string &direction_string) {
 | 
			
		||||
        auto result = std::make_pair(guidance::TurnType::MaxTurnType,
 | 
			
		||||
                                     guidance::DirectionModifier::MaxDirectionModifier);
 | 
			
		||||
 | 
			
		||||
        if (turn_string == "uturn")
 | 
			
		||||
        {
 | 
			
		||||
            result.first = guidance::TurnType::Turn;
 | 
			
		||||
            result.second = guidance::DirectionModifier::UTurn;
 | 
			
		||||
        }
 | 
			
		||||
        else if (turn_string == "continue")
 | 
			
		||||
        {
 | 
			
		||||
            result.first = guidance::TurnType::Continue;
 | 
			
		||||
        }
 | 
			
		||||
        else if (turn_string == "turn")
 | 
			
		||||
        {
 | 
			
		||||
            result.first = guidance::TurnType::Turn;
 | 
			
		||||
        }
 | 
			
		||||
        else if (turn_string == "fork")
 | 
			
		||||
        {
 | 
			
		||||
            result.first = guidance::TurnType::Fork;
 | 
			
		||||
        }
 | 
			
		||||
        else if (turn_string == "suppress")
 | 
			
		||||
        {
 | 
			
		||||
            result.first = guidance::TurnType::Suppressed;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Directions
 | 
			
		||||
        if (direction_string == "left")
 | 
			
		||||
        {
 | 
			
		||||
            result.second = guidance::DirectionModifier::Left;
 | 
			
		||||
        }
 | 
			
		||||
        else if (direction_string == "slight_left")
 | 
			
		||||
        {
 | 
			
		||||
            result.second = guidance::DirectionModifier::SlightLeft;
 | 
			
		||||
        }
 | 
			
		||||
        else if (direction_string == "sharp_left")
 | 
			
		||||
        {
 | 
			
		||||
            result.second = guidance::DirectionModifier::SharpLeft;
 | 
			
		||||
        }
 | 
			
		||||
        else if (direction_string == "sharp_right")
 | 
			
		||||
        {
 | 
			
		||||
            result.second = guidance::DirectionModifier::SharpRight;
 | 
			
		||||
        }
 | 
			
		||||
        else if (direction_string == "slight_right")
 | 
			
		||||
        {
 | 
			
		||||
            result.second = guidance::DirectionModifier::SlightRight;
 | 
			
		||||
        }
 | 
			
		||||
        else if (direction_string == "right")
 | 
			
		||||
        {
 | 
			
		||||
            result.second = guidance::DirectionModifier::Right;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Transform an InternalManeuverOverride (based on WayIDs) into an OSRM override (base on
 | 
			
		||||
    // NodeIDs).
 | 
			
		||||
    // Returns true on successful transformation, false in case of invalid references.
 | 
			
		||||
    // Later, the UnresolvedManeuverOverride will be converted into a final ManeuverOverride
 | 
			
		||||
    // once the edge-based-node IDs are generated by the edge-based-graph-factory
 | 
			
		||||
    const auto transform = [&](const auto &external, auto &internal) {
 | 
			
		||||
 | 
			
		||||
        // Create a stub override
 | 
			
		||||
        auto maneuver_override =
 | 
			
		||||
            UnresolvedManeuverOverride{{},
 | 
			
		||||
                                       osm_node_to_internal_nbn(external.via_node),
 | 
			
		||||
                                       guidance::TurnType::Invalid,
 | 
			
		||||
                                       guidance::DirectionModifier::MaxDirectionModifier};
 | 
			
		||||
 | 
			
		||||
        // Convert Way IDs into node-based-node IDs
 | 
			
		||||
        // We iterate from back to front here because the first node in the node_sequence
 | 
			
		||||
        // must eventually be a source node, but all the others must be targets.
 | 
			
		||||
        // the get_internal_pairs_from_ways returns (source,target), so if we
 | 
			
		||||
        // iterate backwards, we will end up with source,target,target,target,target
 | 
			
		||||
        // in a sequence, which is what we want
 | 
			
		||||
        for (auto i = 0ul; i < external.via_ways.size() - 1; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            // returns the two far ends of the referenced ways
 | 
			
		||||
            auto turn = get_turn_from_way_pair(external.via_ways[i], external.via_ways[i + 1]);
 | 
			
		||||
 | 
			
		||||
            maneuver_override.turn_sequence.push_back(turn);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // check if we were able to resolve all the involved ways
 | 
			
		||||
        // auto maneuver_override =
 | 
			
		||||
        //    get_maneuver_override_from_OSM_ids(external.from, external.to,
 | 
			
		||||
        //    external.via_node);
 | 
			
		||||
 | 
			
		||||
        std::tie(maneuver_override.override_type, maneuver_override.direction) =
 | 
			
		||||
            strings_to_turn_type_and_direction(external.maneuver, external.direction);
 | 
			
		||||
 | 
			
		||||
        if (!maneuver_override.Valid())
 | 
			
		||||
        {
 | 
			
		||||
            util::Log(logDEBUG) << "Override is invalid";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal = std::move(maneuver_override);
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto transform_into_internal_types =
 | 
			
		||||
        [&](const InputManeuverOverride &external_maneuver_override) {
 | 
			
		||||
            UnresolvedManeuverOverride internal_maneuver_override;
 | 
			
		||||
            if (transform(external_maneuver_override, internal_maneuver_override))
 | 
			
		||||
                internal_maneuver_overrides.push_back(std::move(internal_maneuver_override));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    // Transforming the overrides into the dedicated internal types
 | 
			
		||||
    {
 | 
			
		||||
        util::UnbufferedLog log;
 | 
			
		||||
        log << "Collecting start/end information on " << external_maneuver_overrides_list.size()
 | 
			
		||||
            << " maneuver overrides...";
 | 
			
		||||
        TIMER_START(transform);
 | 
			
		||||
        std::for_each(external_maneuver_overrides_list.begin(),
 | 
			
		||||
                      external_maneuver_overrides_list.end(),
 | 
			
		||||
                      transform_into_internal_types);
 | 
			
		||||
        TIMER_STOP(transform);
 | 
			
		||||
        log << "ok, after " << TIMER_SEC(transform) << "s";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtractionContainers::PrepareRestrictions()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    // contain the start/end nodes of each way that is part of an restriction
 | 
			
		||||
    std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways;
 | 
			
		||||
 | 
			
		||||
@ -729,9 +984,16 @@ void ExtractionContainers::PrepareRestrictions()
 | 
			
		||||
    // (d,e) or (j,a) as entry-segment
 | 
			
		||||
    auto const find_node_restriction =
 | 
			
		||||
        [&](auto const &segment, auto const &via_segment, auto const via_node) {
 | 
			
		||||
            // In case of way-restrictions, via-node will be set to MAX_OSM_NODEID to signal that
 | 
			
		||||
            // In case of way-restrictions, via-node will be set to MAX_OSM_NODEID to signal
 | 
			
		||||
            // that
 | 
			
		||||
            // the node is not present.
 | 
			
		||||
            // connected at the front of the segment
 | 
			
		||||
            // Turn restrictions are described as a restriction between the two segments closest
 | 
			
		||||
            // to
 | 
			
		||||
            // the shared via-node on the from and to ways. Graph compression will later
 | 
			
		||||
            // renumber
 | 
			
		||||
            // the from and to internal node IDs as nodes are plucked out of the node-based
 | 
			
		||||
            // graph.
 | 
			
		||||
            if (via_node == MAX_OSM_NODEID || segment.first_segment_source_id == via_node)
 | 
			
		||||
            {
 | 
			
		||||
                if (segment.first_segment_source_id == via_segment.first_segment_source_id)
 | 
			
		||||
@ -770,7 +1032,8 @@ void ExtractionContainers::PrepareRestrictions()
 | 
			
		||||
            return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    // translate the turn from one segment onto another into a node restriction (the ways can only
 | 
			
		||||
    // translate the turn from one segment onto another into a node restriction (the ways can
 | 
			
		||||
    // only
 | 
			
		||||
    // be connected at a single location)
 | 
			
		||||
    auto const get_node_restriction_from_OSM_ids = [&](
 | 
			
		||||
        auto const from_id, auto const to_id, const OSMNodeID via_node) {
 | 
			
		||||
@ -792,7 +1055,8 @@ void ExtractionContainers::PrepareRestrictions()
 | 
			
		||||
 | 
			
		||||
    // Transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs).
 | 
			
		||||
    // Returns true on successful transformation, false in case of invalid references.
 | 
			
		||||
    // Based on the auto type deduction, this transfor handles both conditional and unconditional
 | 
			
		||||
    // Based on the auto type deduction, this transfor handles both conditional and
 | 
			
		||||
    // unconditional
 | 
			
		||||
    // turn restrictions.
 | 
			
		||||
    const auto transform = [&](const auto &external_type, auto &internal_type) {
 | 
			
		||||
        if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
 | 
			
		||||
@ -808,7 +1072,8 @@ void ExtractionContainers::PrepareRestrictions()
 | 
			
		||||
            if (!from_restriction.Valid() || !to_restriction.Valid())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            // point located at both via and segment is alway on `second`, to FSSF is the order we
 | 
			
		||||
            // point located at both via and segment is alway on `second`, to FSSF is the order
 | 
			
		||||
            // we
 | 
			
		||||
            // need
 | 
			
		||||
            WayRestriction way_restriction{from_restriction, to_restriction};
 | 
			
		||||
            internal_type.node_or_way = std::move(way_restriction);
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
#include "extractor/extraction_way.hpp"
 | 
			
		||||
#include "extractor/extractor_callbacks.hpp"
 | 
			
		||||
#include "extractor/files.hpp"
 | 
			
		||||
#include "extractor/maneuver_override_relation_parser.hpp"
 | 
			
		||||
#include "extractor/node_based_graph_factory.hpp"
 | 
			
		||||
#include "extractor/raster_source.hpp"
 | 
			
		||||
#include "extractor/restriction_filter.hpp"
 | 
			
		||||
@ -202,7 +203,11 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
 | 
			
		||||
    LaneDescriptionMap turn_lane_map;
 | 
			
		||||
    std::vector<TurnRestriction> turn_restrictions;
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
 | 
			
		||||
    std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides;
 | 
			
		||||
    std::tie(turn_lane_map,
 | 
			
		||||
             turn_restrictions,
 | 
			
		||||
             conditional_turn_restrictions,
 | 
			
		||||
             unresolved_maneuver_overrides) =
 | 
			
		||||
        ParseOSMData(scripting_environment, number_of_threads);
 | 
			
		||||
 | 
			
		||||
    // Transform the node-based graph that OSM is based on into an edge-based graph
 | 
			
		||||
@ -223,7 +228,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
 | 
			
		||||
    NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
 | 
			
		||||
                                                   scripting_environment,
 | 
			
		||||
                                                   turn_restrictions,
 | 
			
		||||
                                                   conditional_turn_restrictions);
 | 
			
		||||
                                                   conditional_turn_restrictions,
 | 
			
		||||
                                                   unresolved_maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
 | 
			
		||||
    TIMER_START(segregated);
 | 
			
		||||
@ -290,6 +296,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
 | 
			
		||||
                               conditional_turn_restrictions,
 | 
			
		||||
                               segregated_edges,
 | 
			
		||||
                               name_table,
 | 
			
		||||
                               unresolved_maneuver_overrides,
 | 
			
		||||
                               turn_lane_map,
 | 
			
		||||
                               scripting_environment,
 | 
			
		||||
                               edge_based_nodes_container,
 | 
			
		||||
@ -367,7 +374,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
 | 
			
		||||
 | 
			
		||||
std::tuple<LaneDescriptionMap,
 | 
			
		||||
           std::vector<TurnRestriction>,
 | 
			
		||||
           std::vector<ConditionalTurnRestriction>>
 | 
			
		||||
           std::vector<ConditionalTurnRestriction>,
 | 
			
		||||
           std::vector<UnresolvedManeuverOverride>>
 | 
			
		||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
                        const unsigned number_of_threads)
 | 
			
		||||
{
 | 
			
		||||
@ -432,6 +440,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
        config.parse_conditionals,
 | 
			
		||||
        restrictions);
 | 
			
		||||
 | 
			
		||||
    const ManeuverOverrideRelationParser maneuver_override_parser;
 | 
			
		||||
 | 
			
		||||
    // OSM data reader
 | 
			
		||||
    using SharedBuffer = std::shared_ptr<osmium::memory::Buffer>;
 | 
			
		||||
    struct ParsedBuffer
 | 
			
		||||
@ -441,6 +451,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
        std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
 | 
			
		||||
        std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> resulting_relations;
 | 
			
		||||
        std::vector<InputConditionalTurnRestriction> resulting_restrictions;
 | 
			
		||||
        std::vector<InputManeuverOverride> resulting_maneuver_overrides;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ExtractionRelationContainer relations;
 | 
			
		||||
@ -482,10 +493,12 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
            parsed_buffer.buffer = buffer;
 | 
			
		||||
            scripting_environment.ProcessElements(*buffer,
 | 
			
		||||
                                                  restriction_parser,
 | 
			
		||||
                                                  maneuver_override_parser,
 | 
			
		||||
                                                  relations,
 | 
			
		||||
                                                  parsed_buffer.resulting_nodes,
 | 
			
		||||
                                                  parsed_buffer.resulting_ways,
 | 
			
		||||
                                                  parsed_buffer.resulting_restrictions);
 | 
			
		||||
                                                  parsed_buffer.resulting_restrictions,
 | 
			
		||||
                                                  parsed_buffer.resulting_maneuver_overrides);
 | 
			
		||||
            return parsed_buffer;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -493,6 +506,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
    unsigned number_of_nodes = 0;
 | 
			
		||||
    unsigned number_of_ways = 0;
 | 
			
		||||
    unsigned number_of_restrictions = 0;
 | 
			
		||||
    unsigned number_of_maneuver_overrides = 0;
 | 
			
		||||
    tbb::filter_t<ParsedBuffer, void> buffer_storage(
 | 
			
		||||
        tbb::filter::serial_in_order, [&](const ParsedBuffer &parsed_buffer) {
 | 
			
		||||
 | 
			
		||||
@ -513,6 +527,13 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
            {
 | 
			
		||||
                extractor_callbacks->ProcessRestriction(result);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            number_of_maneuver_overrides = parsed_buffer.resulting_maneuver_overrides.size();
 | 
			
		||||
            for (const auto &result : parsed_buffer.resulting_maneuver_overrides)
 | 
			
		||||
            {
 | 
			
		||||
                extractor_callbacks->ProcessManeuverOverride(result);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    tbb::filter_t<SharedBuffer, std::shared_ptr<ExtractionRelationContainer>> buffer_relation_cache(
 | 
			
		||||
@ -617,7 +638,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
 | 
			
		||||
 | 
			
		||||
    return std::make_tuple(std::move(turn_lane_map),
 | 
			
		||||
                           std::move(extraction_containers.unconditional_turn_restrictions),
 | 
			
		||||
                           std::move(extraction_containers.conditional_turn_restrictions));
 | 
			
		||||
                           std::move(extraction_containers.conditional_turn_restrictions),
 | 
			
		||||
                           std::move(extraction_containers.internal_maneuver_overrides));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Extractor::FindComponents(unsigned number_of_edge_based_nodes,
 | 
			
		||||
@ -693,6 +715,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
 | 
			
		||||
    const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
    const std::unordered_set<EdgeID> &segregated_edges,
 | 
			
		||||
    const util::NameTable &name_table,
 | 
			
		||||
    const std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
 | 
			
		||||
    const LaneDescriptionMap &turn_lane_map,
 | 
			
		||||
    // for calculating turn penalties
 | 
			
		||||
    ScriptingEnvironment &scripting_environment,
 | 
			
		||||
@ -736,9 +759,11 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
 | 
			
		||||
                                     config.GetPath(".osrm.turn_penalties_index").string(),
 | 
			
		||||
                                     config.GetPath(".osrm.cnbg_to_ebg").string(),
 | 
			
		||||
                                     config.GetPath(".osrm.restrictions").string(),
 | 
			
		||||
                                     config.GetPath(".osrm.maneuver_overrides").string(),
 | 
			
		||||
                                     via_node_restriction_map,
 | 
			
		||||
                                     conditional_node_restriction_map,
 | 
			
		||||
                                     via_way_restriction_map);
 | 
			
		||||
                                     via_way_restriction_map,
 | 
			
		||||
                                     maneuver_overrides);
 | 
			
		||||
        return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,11 @@ void ExtractorCallbacks::ProcessRestriction(const InputConditionalTurnRestrictio
 | 
			
		||||
    // util::Log() << restriction.toString();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ExtractorCallbacks::ProcessManeuverOverride(const InputManeuverOverride & override)
 | 
			
		||||
{
 | 
			
		||||
    external_memory.external_maneuver_overrides_list.push_back(override);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Takes the geometry contained in the ```input_way``` and the tags computed
 | 
			
		||||
 * by the lua profile inside ```parsed_way``` and computes all edge segments.
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ void GraphCompressor::Compress(
 | 
			
		||||
    ScriptingEnvironment &scripting_environment,
 | 
			
		||||
    std::vector<TurnRestriction> &turn_restrictions,
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
 | 
			
		||||
    util::NodeBasedDynamicGraph &graph,
 | 
			
		||||
    const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
 | 
			
		||||
    CompressedEdgeContainer &geometry_compressor)
 | 
			
		||||
@ -33,7 +34,8 @@ void GraphCompressor::Compress(
 | 
			
		||||
    const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
 | 
			
		||||
    const unsigned original_number_of_edges = graph.GetNumberOfEdges();
 | 
			
		||||
 | 
			
		||||
    RestrictionCompressor restriction_compressor(turn_restrictions, conditional_turn_restrictions);
 | 
			
		||||
    RestrictionCompressor restriction_compressor(
 | 
			
		||||
        turn_restrictions, conditional_turn_restrictions, maneuver_overrides);
 | 
			
		||||
 | 
			
		||||
    // we do not compress turn restrictions on degree two nodes. These nodes are usually used to
 | 
			
		||||
    // indicated `directed` barriers
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										126
									
								
								src/extractor/maneuver_override_relation_parser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/extractor/maneuver_override_relation_parser.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
#include "extractor/maneuver_override_relation_parser.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
 | 
			
		||||
#include "util/log.hpp"
 | 
			
		||||
 | 
			
		||||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
#include <boost/algorithm/string/predicate.hpp>
 | 
			
		||||
#include <boost/algorithm/string/regex.hpp>
 | 
			
		||||
#include <boost/optional/optional.hpp>
 | 
			
		||||
#include <boost/ref.hpp>
 | 
			
		||||
#include <boost/regex.hpp>
 | 
			
		||||
 | 
			
		||||
#include <osmium/osm.hpp>
 | 
			
		||||
#include <osmium/tags/regex_filter.hpp>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
 | 
			
		||||
namespace osrm
 | 
			
		||||
{
 | 
			
		||||
namespace extractor
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
ManeuverOverrideRelationParser::ManeuverOverrideRelationParser() {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Parses the `type=maneuver` relation.  Reads the fields, and puts data
 | 
			
		||||
 * into an InputManeuverOverride object, if the relation is considered
 | 
			
		||||
 * valid (i.e. has the minimum tags we expect).
 | 
			
		||||
 */
 | 
			
		||||
boost::optional<InputManeuverOverride>
 | 
			
		||||
ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const
 | 
			
		||||
{
 | 
			
		||||
    osmium::tags::KeyFilter filter(false);
 | 
			
		||||
    filter.add(true, "maneuver");
 | 
			
		||||
 | 
			
		||||
    const osmium::TagList &tag_list = relation.tags();
 | 
			
		||||
 | 
			
		||||
    osmium::tags::KeyFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
 | 
			
		||||
    osmium::tags::KeyFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
 | 
			
		||||
 | 
			
		||||
    // if it's not a maneuver, continue;
 | 
			
		||||
    if (std::distance(fi_begin, fi_end) == 0)
 | 
			
		||||
    {
 | 
			
		||||
        return boost::none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // we pretend every restriction is a conditional restriction. If we do not find any restriction,
 | 
			
		||||
    // we can trim away the vector after parsing
 | 
			
		||||
    InputManeuverOverride maneuver_override;
 | 
			
		||||
 | 
			
		||||
    maneuver_override.maneuver = relation.tags().get_value_by_key("maneuver", "");
 | 
			
		||||
    maneuver_override.direction = relation.tags().get_value_by_key("direction", "");
 | 
			
		||||
 | 
			
		||||
    boost::optional<std::uint64_t> from = boost::none, via = boost::none, to = boost::none;
 | 
			
		||||
    std::vector<std::uint64_t> via_ways;
 | 
			
		||||
 | 
			
		||||
    for (const auto &member : relation.members())
 | 
			
		||||
    {
 | 
			
		||||
        const char *role = member.role();
 | 
			
		||||
        if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
 | 
			
		||||
        {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (member.type())
 | 
			
		||||
        {
 | 
			
		||||
        case osmium::item_type::node:
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            // Make sure nodes appear only in the role if a via node
 | 
			
		||||
            if (0 == strcmp("from", role) || 0 == strcmp("to", role))
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            BOOST_ASSERT(0 == strcmp("via", role));
 | 
			
		||||
            via = static_cast<std::uint64_t>(member.ref());
 | 
			
		||||
            // set via node id
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case osmium::item_type::way:
 | 
			
		||||
            BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
 | 
			
		||||
                         0 == strcmp("via", role));
 | 
			
		||||
            if (0 == strcmp("from", role))
 | 
			
		||||
            {
 | 
			
		||||
                from = static_cast<std::uint64_t>(member.ref());
 | 
			
		||||
            }
 | 
			
		||||
            else if (0 == strcmp("to", role))
 | 
			
		||||
            {
 | 
			
		||||
                to = static_cast<std::uint64_t>(member.ref());
 | 
			
		||||
            }
 | 
			
		||||
            else if (0 == strcmp("via", role))
 | 
			
		||||
            {
 | 
			
		||||
                via_ways.push_back(static_cast<std::uint64_t>(member.ref()));
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case osmium::item_type::relation:
 | 
			
		||||
            // not yet supported, but who knows what the future holds...
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            // shouldn't ever happen
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (from && (via || via_ways.size() > 0) && to)
 | 
			
		||||
    {
 | 
			
		||||
        via_ways.insert(via_ways.begin(), *from);
 | 
			
		||||
        via_ways.push_back(*to);
 | 
			
		||||
        if (via)
 | 
			
		||||
        {
 | 
			
		||||
            maneuver_override.via_node = {*via};
 | 
			
		||||
        }
 | 
			
		||||
        for (const auto &n : via_ways)
 | 
			
		||||
        {
 | 
			
		||||
            maneuver_override.via_ways.push_back(OSMWayID{n});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return boost::none;
 | 
			
		||||
    }
 | 
			
		||||
    return maneuver_override;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@ -19,10 +19,14 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
 | 
			
		||||
    const boost::filesystem::path &input_file,
 | 
			
		||||
    ScriptingEnvironment &scripting_environment,
 | 
			
		||||
    std::vector<TurnRestriction> &turn_restrictions,
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
 | 
			
		||||
{
 | 
			
		||||
    LoadDataFromFile(input_file);
 | 
			
		||||
    Compress(scripting_environment, turn_restrictions, conditional_turn_restrictions);
 | 
			
		||||
    Compress(scripting_environment,
 | 
			
		||||
             turn_restrictions,
 | 
			
		||||
             conditional_turn_restrictions,
 | 
			
		||||
             maneuver_overrides);
 | 
			
		||||
    CompressGeometry();
 | 
			
		||||
    CompressAnnotationData();
 | 
			
		||||
}
 | 
			
		||||
@ -84,7 +88,8 @@ void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &inpu
 | 
			
		||||
void NodeBasedGraphFactory::Compress(
 | 
			
		||||
    ScriptingEnvironment &scripting_environment,
 | 
			
		||||
    std::vector<TurnRestriction> &turn_restrictions,
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
 | 
			
		||||
{
 | 
			
		||||
    GraphCompressor graph_compressor;
 | 
			
		||||
    graph_compressor.Compress(barriers,
 | 
			
		||||
@ -92,6 +97,7 @@ void NodeBasedGraphFactory::Compress(
 | 
			
		||||
                              scripting_environment,
 | 
			
		||||
                              turn_restrictions,
 | 
			
		||||
                              conditional_turn_restrictions,
 | 
			
		||||
                              maneuver_overrides,
 | 
			
		||||
                              compressed_output_graph,
 | 
			
		||||
                              annotation_data,
 | 
			
		||||
                              compressed_edge_container);
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,8 @@ namespace extractor
 | 
			
		||||
 | 
			
		||||
RestrictionCompressor::RestrictionCompressor(
 | 
			
		||||
    std::vector<TurnRestriction> &restrictions,
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
 | 
			
		||||
{
 | 
			
		||||
    // add a node restriction ptr to the starts/ends maps, needs to be a reference!
 | 
			
		||||
    auto index = [&](auto &element) {
 | 
			
		||||
@ -40,10 +41,23 @@ RestrictionCompressor::RestrictionCompressor(
 | 
			
		||||
    std::for_each(conditional_turn_restrictions.begin(),
 | 
			
		||||
                  conditional_turn_restrictions.end(),
 | 
			
		||||
                  index_starts_and_ends);
 | 
			
		||||
 | 
			
		||||
    auto index_maneuver = [&](auto &maneuver) {
 | 
			
		||||
        for (auto &turn : maneuver.turn_sequence)
 | 
			
		||||
        {
 | 
			
		||||
            maneuver_starts.insert(std::make_pair(turn.from, &turn));
 | 
			
		||||
            maneuver_ends.insert(std::make_pair(turn.to, &turn));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    // !needs to be reference, so we can get the correct address
 | 
			
		||||
    std::for_each(maneuver_overrides.begin(), maneuver_overrides.end(), [&](auto &maneuver) {
 | 
			
		||||
        index_maneuver(maneuver);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
 | 
			
		||||
{
 | 
			
		||||
    // handle turn restrictions
 | 
			
		||||
    // extract all startptrs and move them from via to from.
 | 
			
		||||
    auto all_starts_range = starts.equal_range(via);
 | 
			
		||||
    std::vector<NodeRestriction *> start_ptrs;
 | 
			
		||||
@ -104,6 +118,75 @@ void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const
 | 
			
		||||
 | 
			
		||||
    const auto reinsert_end = [&](auto ptr) { ends.insert(std::make_pair(ptr->to, ptr)); };
 | 
			
		||||
    std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
 | 
			
		||||
 | 
			
		||||
    /**********************************************************************************************/
 | 
			
		||||
 | 
			
		||||
    // handle maneuver overrides from nodes
 | 
			
		||||
    // extract all startptrs
 | 
			
		||||
    auto maneuver_starts_range = maneuver_starts.equal_range(via);
 | 
			
		||||
    std::vector<NodeBasedTurn *> mnv_start_ptrs;
 | 
			
		||||
    std::transform(maneuver_starts_range.first,
 | 
			
		||||
                   maneuver_starts_range.second,
 | 
			
		||||
                   std::back_inserter(mnv_start_ptrs),
 | 
			
		||||
                   [](const auto pair) { return pair.second; });
 | 
			
		||||
 | 
			
		||||
    // update from nodes of maneuver overrides
 | 
			
		||||
    const auto update_start_mnv = [&](auto ptr) {
 | 
			
		||||
        // ____ | from - p.from | via - p.via | to - p.to | ____
 | 
			
		||||
        BOOST_ASSERT(ptr->from == via);
 | 
			
		||||
        if (ptr->via == to)
 | 
			
		||||
        {
 | 
			
		||||
            ptr->from = from;
 | 
			
		||||
        }
 | 
			
		||||
        // ____ | to - p.from | via - p.via | from - p.to | ____
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(ptr->via == from);
 | 
			
		||||
            ptr->from = to;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), update_start_mnv);
 | 
			
		||||
 | 
			
		||||
    // update the ptrs in our mapping
 | 
			
		||||
    maneuver_starts.erase(via);
 | 
			
		||||
    const auto reinsert_start_mnv = [&](auto ptr) {
 | 
			
		||||
        maneuver_starts.insert(std::make_pair(ptr->from, ptr));
 | 
			
		||||
    };
 | 
			
		||||
    std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), reinsert_start_mnv);
 | 
			
		||||
 | 
			
		||||
    /**********************************************************************************************/
 | 
			
		||||
    // handle maneuver override to nodes
 | 
			
		||||
    // extract all end ptrs and move them from via to to
 | 
			
		||||
    auto maneuver_ends_range = maneuver_ends.equal_range(via);
 | 
			
		||||
    std::vector<NodeBasedTurn *> mnv_end_ptrs;
 | 
			
		||||
    std::transform(maneuver_ends_range.first,
 | 
			
		||||
                   maneuver_ends_range.second,
 | 
			
		||||
                   std::back_inserter(mnv_end_ptrs),
 | 
			
		||||
                   [](const auto pair) { return pair.second; });
 | 
			
		||||
 | 
			
		||||
    const auto update_end_mnv = [&](auto ptr) {
 | 
			
		||||
        BOOST_ASSERT(ptr->to == via);
 | 
			
		||||
        // p.from | ____ - p.via | from - p.to | via - ____ | to
 | 
			
		||||
        if (ptr->via == from)
 | 
			
		||||
        {
 | 
			
		||||
            ptr->to = to;
 | 
			
		||||
        }
 | 
			
		||||
        // p.from | ____ - p.via | to - p.to | via - ____ | from
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(ptr->via == to);
 | 
			
		||||
            ptr->to = from;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), update_end_mnv);
 | 
			
		||||
 | 
			
		||||
    // update end ptrs in mapping
 | 
			
		||||
    maneuver_ends.erase(via);
 | 
			
		||||
 | 
			
		||||
    const auto reinsert_end_mnvs = [&](auto ptr) {
 | 
			
		||||
        maneuver_ends.insert(std::make_pair(ptr->to, ptr));
 | 
			
		||||
    };
 | 
			
		||||
    std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), reinsert_end_mnvs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace extractor
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
#include "extractor/extraction_turn.hpp"
 | 
			
		||||
#include "extractor/extraction_way.hpp"
 | 
			
		||||
#include "extractor/internal_extractor_edge.hpp"
 | 
			
		||||
#include "extractor/maneuver_override_relation_parser.hpp"
 | 
			
		||||
#include "extractor/profile_properties.hpp"
 | 
			
		||||
#include "extractor/query_node.hpp"
 | 
			
		||||
#include "extractor/raster_source.hpp"
 | 
			
		||||
@ -842,10 +843,12 @@ LuaScriptingContext &Sol2ScriptingEnvironment::GetSol2Context()
 | 
			
		||||
void Sol2ScriptingEnvironment::ProcessElements(
 | 
			
		||||
    const osmium::memory::Buffer &buffer,
 | 
			
		||||
    const RestrictionParser &restriction_parser,
 | 
			
		||||
    const ManeuverOverrideRelationParser &maneuver_override_parser,
 | 
			
		||||
    const ExtractionRelationContainer &relations,
 | 
			
		||||
    std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
 | 
			
		||||
    std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
 | 
			
		||||
    std::vector<InputConditionalTurnRestriction> &resulting_restrictions)
 | 
			
		||||
    std::vector<InputConditionalTurnRestriction> &resulting_restrictions,
 | 
			
		||||
    std::vector<InputManeuverOverride> &resulting_maneuver_overrides)
 | 
			
		||||
{
 | 
			
		||||
    ExtractionNode result_node;
 | 
			
		||||
    ExtractionWay result_way;
 | 
			
		||||
@ -885,6 +888,10 @@ void Sol2ScriptingEnvironment::ProcessElements(
 | 
			
		||||
            {
 | 
			
		||||
                resulting_restrictions.push_back(*result_res);
 | 
			
		||||
            }
 | 
			
		||||
            else if (auto result_res = maneuver_override_parser.TryParse(relation))
 | 
			
		||||
            {
 | 
			
		||||
                resulting_maneuver_overrides.push_back(*result_res);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
        default:
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@
 | 
			
		||||
#include "extractor/edge_based_edge.hpp"
 | 
			
		||||
#include "extractor/edge_based_node.hpp"
 | 
			
		||||
#include "extractor/files.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/packed_osm_ids.hpp"
 | 
			
		||||
#include "extractor/profile_properties.hpp"
 | 
			
		||||
#include "extractor/query_node.hpp"
 | 
			
		||||
@ -440,6 +441,17 @@ void Storage::PopulateLayout(DataLayout &layout)
 | 
			
		||||
                                                             lane_tuple_count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // load maneuver overrides
 | 
			
		||||
    {
 | 
			
		||||
        io::FileReader maneuver_overrides_file(config.GetPath(".osrm.maneuver_overrides"),
 | 
			
		||||
                                               io::FileReader::VerifyFingerprint);
 | 
			
		||||
        const auto number_of_overrides = maneuver_overrides_file.ReadElementCount64();
 | 
			
		||||
        layout.SetBlockSize<extractor::StorageManeuverOverride>(DataLayout::MANEUVER_OVERRIDES,
 | 
			
		||||
                                                                number_of_overrides);
 | 
			
		||||
        const auto number_of_nodes = maneuver_overrides_file.ReadElementCount64();
 | 
			
		||||
        layout.SetBlockSize<NodeID>(DataLayout::MANEUVER_OVERRIDE_NODE_SEQUENCES, number_of_nodes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        // Loading MLD Data
 | 
			
		||||
        if (boost::filesystem::exists(config.GetPath(".osrm.partition")))
 | 
			
		||||
@ -1074,6 +1086,22 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
 | 
			
		||||
                    " in " + config.GetPath(".osrm.edges").string());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // load maneuver overrides
 | 
			
		||||
        {
 | 
			
		||||
            io::FileReader maneuver_overrides_file(config.GetPath(".osrm.maneuver_overrides"),
 | 
			
		||||
                                                   io::FileReader::VerifyFingerprint);
 | 
			
		||||
            const auto number_of_overrides = maneuver_overrides_file.ReadElementCount64();
 | 
			
		||||
            const auto number_of_nodes = maneuver_overrides_file.ReadElementCount64();
 | 
			
		||||
            const auto maneuver_overrides_ptr =
 | 
			
		||||
                layout.GetBlockPtr<extractor::StorageManeuverOverride, true>(
 | 
			
		||||
                    memory_ptr, DataLayout::MANEUVER_OVERRIDES);
 | 
			
		||||
            maneuver_overrides_file.ReadInto(maneuver_overrides_ptr, number_of_overrides);
 | 
			
		||||
 | 
			
		||||
            const auto maneuver_override_node_sequences_ptr = layout.GetBlockPtr<NodeID, true>(
 | 
			
		||||
                memory_ptr, DataLayout::MANEUVER_OVERRIDE_NODE_SEQUENCES);
 | 
			
		||||
            maneuver_overrides_file.ReadInto(maneuver_override_node_sequences_ptr, number_of_nodes);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -20,8 +20,8 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
 | 
			
		||||
    PhantomNode target;
 | 
			
		||||
    source.forward_segment_id = {1, true};
 | 
			
		||||
    target.forward_segment_id = {6, true};
 | 
			
		||||
    PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    InternalRouteResult one_leg_result;
 | 
			
		||||
    one_leg_result.unpacked_path_segments = {{pathy, kathy}};
 | 
			
		||||
    one_leg_result.segment_end_coordinates = {PhantomNodes{source, target}};
 | 
			
		||||
@ -38,9 +38,9 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(two_legs_to_one_leg)
 | 
			
		||||
{
 | 
			
		||||
    PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData cathy{3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PhantomNode node_1;
 | 
			
		||||
    PhantomNode node_2;
 | 
			
		||||
    PhantomNode node_3;
 | 
			
		||||
@ -69,11 +69,11 @@ BOOST_AUTO_TEST_CASE(two_legs_to_one_leg)
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(three_legs_to_two_legs)
 | 
			
		||||
{
 | 
			
		||||
    PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData qathy{5, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData cathy{3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData mathy{4, 18, false, 8, 9, 13, 4, 2, {}, 4, 2, {}, 2, {3.0}, {1.0}, false};
 | 
			
		||||
    PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData qathy{0, 5, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData mathy{0, 4, 18, false, 8, 9, 13, 4, 2, {}, 4, 2, {}, 2, {3.0}, {1.0}, false};
 | 
			
		||||
    PhantomNode node_1;
 | 
			
		||||
    PhantomNode node_2;
 | 
			
		||||
    PhantomNode node_3;
 | 
			
		||||
@ -112,9 +112,9 @@ BOOST_AUTO_TEST_CASE(three_legs_to_two_legs)
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(two_legs_to_two_legs)
 | 
			
		||||
{
 | 
			
		||||
    PathData pathy{2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData cathy{3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
 | 
			
		||||
    PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
 | 
			
		||||
    PhantomNode node_1;
 | 
			
		||||
    PhantomNode node_2;
 | 
			
		||||
    PhantomNode node_3;
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,8 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
 | 
			
		||||
                                           {}};
 | 
			
		||||
 | 
			
		||||
    // Check that duplicated coordinate in the end is removed
 | 
			
		||||
    std::vector<RouteStep> steps = {{324,
 | 
			
		||||
    std::vector<RouteStep> steps = {{0,
 | 
			
		||||
                                     324,
 | 
			
		||||
                                     false,
 | 
			
		||||
                                     "Central Park West",
 | 
			
		||||
                                     "",
 | 
			
		||||
@ -61,7 +62,8 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
 | 
			
		||||
                                     3,
 | 
			
		||||
                                     {intersection1},
 | 
			
		||||
                                     false},
 | 
			
		||||
                                    {324,
 | 
			
		||||
                                    {0,
 | 
			
		||||
                                     324,
 | 
			
		||||
                                     false,
 | 
			
		||||
                                     "Central Park West",
 | 
			
		||||
                                     "",
 | 
			
		||||
 | 
			
		||||
@ -366,6 +366,12 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
 | 
			
		||||
    util::guidance::EntryClass GetEntryClass(const EdgeID /*turn_id*/) const override { return {}; }
 | 
			
		||||
    bool IsLeftHandDriving(const NodeID /*id*/) const override { return false; }
 | 
			
		||||
    bool IsSegregated(const NodeID /*id*/) const override { return false; }
 | 
			
		||||
 | 
			
		||||
    std::vector<extractor::ManeuverOverride>
 | 
			
		||||
    GetOverridesThatStartAt(const NodeID /* edge_based_node_id */) const override
 | 
			
		||||
    {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // datafacade
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
#include "extractor/graph_compressor.hpp"
 | 
			
		||||
#include "extractor/compressed_edge_container.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/restriction.hpp"
 | 
			
		||||
#include "util/node_based_graph.hpp"
 | 
			
		||||
#include "util/typedefs.hpp"
 | 
			
		||||
@ -71,6 +72,7 @@ BOOST_AUTO_TEST_CASE(long_road_test)
 | 
			
		||||
    std::vector<NodeBasedEdgeAnnotation> annotations(1);
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
 | 
			
		||||
                                    MakeUnitEdge(1, 0),
 | 
			
		||||
@ -91,6 +93,7 @@ BOOST_AUTO_TEST_CASE(long_road_test)
 | 
			
		||||
                        scripting_environment,
 | 
			
		||||
                        restrictions,
 | 
			
		||||
                        conditional_restrictions,
 | 
			
		||||
                        maneuver_overrides,
 | 
			
		||||
                        graph,
 | 
			
		||||
                        annotations,
 | 
			
		||||
                        container);
 | 
			
		||||
@ -117,6 +120,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    std::vector<NodeBasedEdgeAnnotation> annotations(1);
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
 | 
			
		||||
                                    MakeUnitEdge(0, 5),
 | 
			
		||||
@ -151,6 +155,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
 | 
			
		||||
                        scripting_environment,
 | 
			
		||||
                        restrictions,
 | 
			
		||||
                        conditional_restrictions,
 | 
			
		||||
                        maneuver_overrides,
 | 
			
		||||
                        graph,
 | 
			
		||||
                        annotations,
 | 
			
		||||
                        container);
 | 
			
		||||
@ -180,6 +185,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_restrictions;
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
 | 
			
		||||
                                    MakeUnitEdge(1, 0),
 | 
			
		||||
@ -200,6 +206,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
 | 
			
		||||
                        scripting_environment,
 | 
			
		||||
                        restrictions,
 | 
			
		||||
                        conditional_restrictions,
 | 
			
		||||
                        maneuver_overrides,
 | 
			
		||||
                        graph,
 | 
			
		||||
                        annotations,
 | 
			
		||||
                        container);
 | 
			
		||||
@ -223,6 +230,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_restrictions;
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    std::vector<InputEdge> edges = {
 | 
			
		||||
        MakeUnitEdge(0, 1), MakeUnitEdge(1, 0), MakeUnitEdge(1, 2), MakeUnitEdge(2, 1)};
 | 
			
		||||
@ -239,6 +247,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
 | 
			
		||||
                        scripting_environment,
 | 
			
		||||
                        restrictions,
 | 
			
		||||
                        conditional_restrictions,
 | 
			
		||||
                        maneuver_overrides,
 | 
			
		||||
                        graph,
 | 
			
		||||
                        annotations,
 | 
			
		||||
                        container);
 | 
			
		||||
@ -261,6 +270,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_restrictions;
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    std::vector<InputEdge> edges = {
 | 
			
		||||
        MakeUnitEdge(0, 1), MakeUnitEdge(1, 0), MakeUnitEdge(1, 2), MakeUnitEdge(2, 1)};
 | 
			
		||||
@ -273,6 +283,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
 | 
			
		||||
                        scripting_environment,
 | 
			
		||||
                        restrictions,
 | 
			
		||||
                        conditional_restrictions,
 | 
			
		||||
                        maneuver_overrides,
 | 
			
		||||
                        graph,
 | 
			
		||||
                        annotations,
 | 
			
		||||
                        container);
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_restrictions;
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    TurnLanesIndexedArray turn_lanes_data{{0, 0, 3},
 | 
			
		||||
                                          {TurnLaneType::uturn | TurnLaneType::left,
 | 
			
		||||
@ -90,6 +91,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
 | 
			
		||||
                               scripting_environment,
 | 
			
		||||
                               restrictions,
 | 
			
		||||
                               conditional_restrictions,
 | 
			
		||||
                               maneuver_overrides,
 | 
			
		||||
                               graph,
 | 
			
		||||
                               annotations,
 | 
			
		||||
                               container);
 | 
			
		||||
@ -157,6 +159,7 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_restrictions;
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    TurnLanesIndexedArray turn_lanes_data;
 | 
			
		||||
 | 
			
		||||
@ -211,6 +214,7 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
 | 
			
		||||
                               scripting_environment,
 | 
			
		||||
                               restrictions,
 | 
			
		||||
                               conditional_restrictions,
 | 
			
		||||
                               maneuver_overrides,
 | 
			
		||||
                               graph,
 | 
			
		||||
                               annotations,
 | 
			
		||||
                               container);
 | 
			
		||||
@ -261,6 +265,7 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes)
 | 
			
		||||
    std::vector<ConditionalTurnRestriction> conditional_restrictions;
 | 
			
		||||
    CompressedEdgeContainer container;
 | 
			
		||||
    test::MockScriptingEnvironment scripting_environment;
 | 
			
		||||
    std::vector<UnresolvedManeuverOverride> maneuver_overrides;
 | 
			
		||||
 | 
			
		||||
    TurnLanesIndexedArray turn_lanes_data;
 | 
			
		||||
 | 
			
		||||
@ -301,6 +306,7 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes)
 | 
			
		||||
                               scripting_environment,
 | 
			
		||||
                               restrictions,
 | 
			
		||||
                               conditional_restrictions,
 | 
			
		||||
                               maneuver_overrides,
 | 
			
		||||
                               graph,
 | 
			
		||||
                               annotations,
 | 
			
		||||
                               container);
 | 
			
		||||
 | 
			
		||||
@ -5,10 +5,12 @@
 | 
			
		||||
 | 
			
		||||
#include "contractor/query_edge.hpp"
 | 
			
		||||
#include "extractor/class_data.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/travel_mode.hpp"
 | 
			
		||||
#include "extractor/turn_lane_types.hpp"
 | 
			
		||||
#include "guidance/turn_bearing.hpp"
 | 
			
		||||
#include "guidance/turn_instruction.hpp"
 | 
			
		||||
#include "guidance/turn_instruction.hpp"
 | 
			
		||||
 | 
			
		||||
#include "engine/algorithm.hpp"
 | 
			
		||||
#include "engine/datafacade/algorithm_datafacade.hpp"
 | 
			
		||||
@ -264,6 +266,12 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
 | 
			
		||||
        result.activate(3);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<extractor::ManeuverOverride>
 | 
			
		||||
    GetOverridesThatStartAt(const NodeID /* edge_based_node_id */) const override
 | 
			
		||||
    {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename AlgorithmT> class MockAlgorithmDataFacade;
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include "extractor/extraction_segment.hpp"
 | 
			
		||||
#include "extractor/extraction_turn.hpp"
 | 
			
		||||
#include "extractor/maneuver_override.hpp"
 | 
			
		||||
#include "extractor/profile_properties.hpp"
 | 
			
		||||
#include "extractor/scripting_environment.hpp"
 | 
			
		||||
 | 
			
		||||
@ -37,10 +38,12 @@ class MockScriptingEnvironment : public extractor::ScriptingEnvironment
 | 
			
		||||
 | 
			
		||||
    void ProcessElements(const osmium::memory::Buffer &,
 | 
			
		||||
                         const extractor::RestrictionParser &,
 | 
			
		||||
                         const extractor::ManeuverOverrideRelationParser &,
 | 
			
		||||
                         const extractor::ExtractionRelationContainer &,
 | 
			
		||||
                         std::vector<std::pair<const osmium::Node &, extractor::ExtractionNode>> &,
 | 
			
		||||
                         std::vector<std::pair<const osmium::Way &, extractor::ExtractionWay>> &,
 | 
			
		||||
                         std::vector<extractor::InputConditionalTurnRestriction> &) override final
 | 
			
		||||
                         std::vector<extractor::InputConditionalTurnRestriction> &,
 | 
			
		||||
                         std::vector<extractor::InputManeuverOverride> &) override final
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user