From 3d4b69402eccde7fcc8fde9520dee04c49cfbd05 Mon Sep 17 00:00:00 2001 From: Michael Krasnyk Date: Mon, 8 Jan 2018 19:12:06 +0100 Subject: [PATCH] Move guidance turn generation out of EBGF --- CMakeLists.txt | 2 +- features/support/cache.js | 5 +- features/support/env.js | 3 +- .../contiguous_internalmem_datafacade.hpp | 15 +- include/engine/datafacade/datafacade_base.hpp | 7 +- include/engine/internal_route_result.hpp | 7 +- .../routing_algorithms/routing_base.hpp | 10 +- .../extractor/edge_based_graph_factory.hpp | 21 +- include/extractor/extractor.hpp | 22 +- .../intersection/mergable_road_detector.hpp | 2 +- .../intersection/node_based_graph_walker.hpp | 2 +- include/extractor/turn_data_container.hpp.tbd | 123 ------- include/guidance/guidance_processing.hpp | 49 +++ ...segregated_intersection_classification.hpp | 4 +- include/guidance/turn_bearing.hpp | 38 ++ include/guidance/turn_data_container.hpp | 30 +- include/util/guidance/turn_bearing.hpp | 30 -- src/extractor/edge_based_graph_factory.cpp | 330 +----------------- src/extractor/extractor.cpp | 147 ++++++-- .../intersection/coordinate_extractor.cpp | 2 +- .../intersection/mergable_road_detector.cpp | 2 +- src/guidance/guidance_processing.cpp | 330 ++++++++++++++++++ ...segregated_intersection_classification.cpp | 14 +- src/storage/storage.cpp | 16 +- src/util/guidance/bearing_class.cpp | 2 +- src/util/guidance/entry_class.cpp | 2 +- src/util/guidance/turn_bearing.cpp | 25 -- unit_tests/engine/offline_facade.cpp | 8 +- unit_tests/mocks/mock_datafacade.hpp | 10 +- 29 files changed, 630 insertions(+), 628 deletions(-) delete mode 100644 include/extractor/turn_data_container.hpp.tbd create mode 100644 include/guidance/guidance_processing.hpp create mode 100644 include/guidance/turn_bearing.hpp delete mode 100644 include/util/guidance/turn_bearing.hpp create mode 100644 src/guidance/guidance_processing.cpp delete mode 100644 src/util/guidance/turn_bearing.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f3f8b65c7fa..875d191b03d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,7 @@ configure_file( ) file(GLOB UtilGlob src/util/*.cpp src/util/*/*.cpp) file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp) -file(GLOB GuidanceGlob src/guidance/*.cpp) +file(GLOB GuidanceGlob src/guidance/*.cpp src/extractor/intersection/*.cpp) file(GLOB PartitionerGlob src/partitioner/*.cpp) file(GLOB CustomizerGlob src/customize/*.cpp) file(GLOB ContractorGlob src/contractor/*.cpp) diff --git a/features/support/cache.js b/features/support/cache.js index c30f66a0088..b9634d9b3e1 100644 --- a/features/support/cache.js +++ b/features/support/cache.js @@ -36,8 +36,8 @@ module.exports = function() { // shorten uri to be realtive to 'features/' let featurePath = path.relative(path.resolve('./features'), uri); // bicycle/bollards/{HASH}/ - let featureID = path.join(featurePath, hash); - + let featureID = path.join(featurePath, hash); + let featureCacheDirectory = this.getFeatureCacheDirectory(featureID); let featureProcessedCacheDirectory = this.getFeatureProcessedCacheDirectory(featureCacheDirectory, this.osrmHash); this.featureIDs[uri] = featureID; @@ -115,6 +115,7 @@ module.exports = function() { this.OSRM_EXTRACT_PATH, this.OSRM_CONTRACT_PATH, this.LIB_OSRM_EXTRACT_PATH, + this.LIB_OSRM_GUIDANCE_PATH, this.LIB_OSRM_CONTRACT_PATH ]; diff --git a/features/support/env.js b/features/support/env.js index 979507f6841..93bfdc6351f 100644 --- a/features/support/env.js +++ b/features/support/env.js @@ -44,7 +44,7 @@ module.exports = function () { this.OSRM_PORT = process.env.OSRM_PORT && parseInt(process.env.OSRM_PORT) || 5000; this.HOST = 'http://127.0.0.1:' + this.OSRM_PORT; - + this.OSRM_PROFILE = process.env.OSRM_PROFILE; if (this.PLATFORM_WINDOWS) { @@ -72,6 +72,7 @@ module.exports = function () { this.OSRM_CONTRACT_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-contract', this.EXE)); this.OSRM_ROUTED_PATH = path.resolve(util.format('%s/%s%s', this.BIN_PATH, 'osrm-routed', this.EXE)); this.LIB_OSRM_EXTRACT_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_extract'), + this.LIB_OSRM_GUIDANCE_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_guidance'), this.LIB_OSRM_CONTRACT_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm_contract'), this.LIB_OSRM_PATH = util.format('%s/' + this.LIB, this.BIN_PATH, 'osrm'); diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 4c982643b33..8b434c9c14e 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -19,6 +19,8 @@ #include "extractor/profile_properties.hpp" #include "extractor/segment_data_container.hpp" #include "extractor/turn_lane_types.hpp" + +#include "guidance/turn_bearing.hpp" #include "guidance/turn_data_container.hpp" #include "guidance/turn_instruction.hpp" @@ -35,7 +37,6 @@ #include "util/filtered_graph.hpp" #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/guidance/turn_lanes.hpp" #include "util/log.hpp" #include "util/name_table.hpp" @@ -328,14 +329,14 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade util::vector_view entry_class_ids( entry_class_id_list_ptr, layout.num_entries[storage::DataLayout::ENTRY_CLASSID]); - const auto pre_turn_bearing_ptr = layout.GetBlockPtr( + const auto pre_turn_bearing_ptr = layout.GetBlockPtr( memory_ptr, storage::DataLayout::PRE_TURN_BEARING); - util::vector_view pre_turn_bearings( + util::vector_view pre_turn_bearings( pre_turn_bearing_ptr, layout.num_entries[storage::DataLayout::PRE_TURN_BEARING]); - const auto post_turn_bearing_ptr = layout.GetBlockPtr( + const auto post_turn_bearing_ptr = layout.GetBlockPtr( memory_ptr, storage::DataLayout::POST_TURN_BEARING); - util::vector_view post_turn_bearings( + util::vector_view post_turn_bearings( post_turn_bearing_ptr, layout.num_entries[storage::DataLayout::POST_TURN_BEARING]); turn_data = guidance::TurnDataView(std::move(turn_instructions), @@ -844,11 +845,11 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade return intersection_bearings_view.GetBearingClass(node); } - util::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const override final + guidance::TurnBearing PreTurnBearing(const EdgeID eid) const override final { return turn_data.GetPreTurnBearing(eid); } - util::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const override final + guidance::TurnBearing PostTurnBearing(const EdgeID eid) const override final { return turn_data.GetPostTurnBearing(eid); } diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 8eb42686120..de1ab10c5f2 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -13,12 +13,13 @@ #include "extractor/query_node.hpp" #include "extractor/travel_mode.hpp" #include "extractor/turn_lane_types.hpp" + +#include "guidance/turn_bearing.hpp" #include "guidance/turn_instruction.hpp" #include "util/exception.hpp" #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/guidance/turn_lanes.hpp" #include "util/integer_range.hpp" #include "util/string_util.hpp" @@ -181,8 +182,8 @@ class BaseDataFacade virtual double GetWeightMultiplier() const = 0; - virtual util::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const = 0; - virtual util::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const = 0; + virtual osrm::guidance::TurnBearing PreTurnBearing(const EdgeID eid) const = 0; + virtual osrm::guidance::TurnBearing PostTurnBearing(const EdgeID eid) const = 0; virtual util::guidance::BearingClass GetBearingClass(const NodeID node) const = 0; diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index bf30032293f..f3cdf7100bf 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -3,13 +3,14 @@ #include "extractor/class_data.hpp" #include "extractor/travel_mode.hpp" + +#include "guidance/turn_bearing.hpp" #include "guidance/turn_instruction.hpp" #include "engine/phantom_node.hpp" #include "util/coordinate.hpp" #include "util/guidance/entry_class.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/guidance/turn_lanes.hpp" #include "util/integer_range.hpp" #include "util/typedefs.hpp" @@ -56,9 +57,9 @@ struct PathData DatasourceID datasource_id; // bearing (as seen from the intersection) pre-turn - util::guidance::TurnBearing pre_turn_bearing; + osrm::guidance::TurnBearing pre_turn_bearing; // bearing (as seen from the intersection) post-turn - util::guidance::TurnBearing post_turn_bearing; + osrm::guidance::TurnBearing post_turn_bearing; // Driving side of the turn bool is_left_hand_driving; diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 087a8e98fed..b9fa5425ffe 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -1,6 +1,7 @@ #ifndef OSRM_ENGINE_ROUTING_BASE_HPP #define OSRM_ENGINE_ROUTING_BASE_HPP +#include "guidance/turn_bearing.hpp" #include "guidance/turn_instruction.hpp" #include "engine/algorithm.hpp" @@ -10,7 +11,6 @@ #include "engine/search_engine_data.hpp" #include "util/coordinate_calculation.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/typedefs.hpp" #include @@ -205,8 +205,8 @@ void annotatePath(const FacadeT &facade, classes, EMPTY_ENTRY_CLASS, datasource_vector[segment_idx], - util::guidance::TurnBearing(0), - util::guidance::TurnBearing(0), + osrm::guidance::TurnBearing(0), + osrm::guidance::TurnBearing(0), is_left_hand_driving}); } BOOST_ASSERT(unpacked_path.size() > 0); @@ -279,8 +279,8 @@ void annotatePath(const FacadeT &facade, facade.GetClassData(target_node_id), EMPTY_ENTRY_CLASS, datasource_vector[segment_idx], - util::guidance::TurnBearing(0), - util::guidance::TurnBearing(0), + guidance::TurnBearing(0), + guidance::TurnBearing(0), is_target_left_hand_driving}); } diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 733a8ebc6e4..53bb93434ac 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -75,11 +75,9 @@ class EdgeBasedGraphFactory const std::vector &coordinates, const util::NameTable &name_table, const std::unordered_set &segregated_edges, - LaneDescriptionMap &lane_description_map); + const LaneDescriptionMap &lane_description_map); void Run(ScriptingEnvironment &scripting_environment, - const std::string &turn_data_filename, - const std::string &turn_lane_data_filename, const std::string &turn_weight_penalties_filename, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, @@ -95,12 +93,6 @@ class EdgeBasedGraphFactory void GetStartPointMarkers(std::vector &node_is_startpoint); void GetEdgeBasedNodeWeights(std::vector &output_node_weights); - // These access functions don't destroy the content - const std::vector &GetBearingClassIds() const; - std::vector &GetBearingClassIds(); - std::vector GetBearingClasses() const; - std::vector GetEntryClasses() const; - std::uint64_t GetNumberOfEdgeBasedNodes() const; // Basic analysis of a turn (u --(e1)-- v --(e2)-- w) @@ -158,7 +150,7 @@ class EdgeBasedGraphFactory const util::NameTable &name_table; const std::unordered_set &segregated_edges; - LaneDescriptionMap &lane_description_map; + const LaneDescriptionMap &lane_description_map; // In the edge based graph, any traversable (non reversed) edge of the node-based graph forms a // node of the edge-based graph. To be able to name these nodes, we loop over the node-based @@ -175,8 +167,6 @@ 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 &original_edge_data_filename, - const std::string &turn_lane_data_filename, const std::string &turn_weight_penalties_filename, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, @@ -187,15 +177,8 @@ class EdgeBasedGraphFactory NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v); - std::size_t restricted_turns_counter; - std::size_t skipped_uturns_counter; - std::size_t skipped_barrier_turns_counter; - // mapping of node-based edges to edge-based nodes std::vector nbe_to_ebn_mapping; - util::ConcurrentIDMap bearing_class_hash; - std::vector bearing_class_by_node_based_node; - util::ConcurrentIDMap entry_class_hash; }; } // namespace extractor } // namespace osrm diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index d5354b44de5..2a1764ba07d 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -34,6 +34,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "extractor/graph_compressor.hpp" #include "extractor/packed_osm_ids.hpp" +#include "guidance/guidance_processing.hpp" +#include "guidance/turn_data_container.hpp" + #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" #include "util/guidance/turn_lanes.hpp" @@ -72,8 +75,8 @@ class Extractor const std::vector &turn_restrictions, const std::vector &conditional_turn_restrictions, const std::unordered_set &segregated_edges, - // might have to be updated to add new lane combinations - LaneDescriptionMap &turn_lane_map, + const util::NameTable &name_table, + const LaneDescriptionMap &turn_lane_map, // for calculating turn penalties ScriptingEnvironment &scripting_environment, // output data @@ -81,8 +84,7 @@ class Extractor std::vector &edge_based_node_segments, std::vector &node_is_startpoint, std::vector &edge_based_node_weights, - util::DeallocatingVector &edge_based_edge_list, - const std::string &intersection_class_output_file); + util::DeallocatingVector &edge_based_edge_list); void FindComponents(unsigned max_edge_id, const util::DeallocatingVector &input_edge_list, @@ -101,6 +103,18 @@ class Extractor void WriteConditionalRestrictions( const std::string &path, std::vector &conditional_turn_restrictions); + + void ProcessGuidanceTurns( + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &edge_based_node_container, + const std::vector &node_coordinates, + const CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const std::vector &turn_restrictions, + const std::vector &conditional_turn_restrictions, + const util::NameTable &name_table, + LaneDescriptionMap lane_description_map, + ScriptingEnvironment &scripting_environment); }; } } diff --git a/include/extractor/intersection/mergable_road_detector.hpp b/include/extractor/intersection/mergable_road_detector.hpp index 69d9f7fe535..b53bf635870 100644 --- a/include/extractor/intersection/mergable_road_detector.hpp +++ b/include/extractor/intersection/mergable_road_detector.hpp @@ -177,7 +177,7 @@ class MergableRoadDetector const static double constexpr distance_to_extract = 120; }; -} // namespace guidance +} // namespace intersection } // namespace extractor } // namespace osrm diff --git a/include/extractor/intersection/node_based_graph_walker.hpp b/include/extractor/intersection/node_based_graph_walker.hpp index 0fe03ebeb51..64f6a0b80ba 100644 --- a/include/extractor/intersection/node_based_graph_walker.hpp +++ b/include/extractor/intersection/node_based_graph_walker.hpp @@ -311,7 +311,7 @@ struct DistanceToNextIntersectionAccumulator double distance = 0.; }; -} // namespace guidance +} // namespace intersection } // namespace extractor } // namespace osrm diff --git a/include/extractor/turn_data_container.hpp.tbd b/include/extractor/turn_data_container.hpp.tbd deleted file mode 100644 index 1545097e6da..00000000000 --- a/include/extractor/turn_data_container.hpp.tbd +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef OSRM_EXTRACTOR_TURN_DATA_CONTAINER_HPP -#define OSRM_EXTRACTOR_TURN_DATA_CONTAINER_HPP - -#include "extractor/travel_mode.hpp" -#include "guidance/turn_instruction.hpp" - -#include "storage/io_fwd.hpp" -#include "storage/shared_memory_ownership.hpp" - -#include "util/guidance/turn_bearing.hpp" -#include "util/vector_view.hpp" - -#include "util/typedefs.hpp" - -namespace osrm -{ -namespace extractor -{ -namespace detail -{ -template class TurnDataContainerImpl; -} - -namespace serialization -{ -template -void read(storage::io::FileReader &reader, detail::TurnDataContainerImpl &turn_data); - -template -void write(storage::io::FileWriter &writer, - const detail::TurnDataContainerImpl &turn_data); -} - -struct TurnData -{ - extractor::guidance::TurnInstruction turn_instruction; - LaneDataID lane_data_id; - EntryClassID entry_class_id; - util::guidance::TurnBearing pre_turn_bearing; - util::guidance::TurnBearing post_turn_bearing; -}; - -namespace detail -{ -template class TurnDataContainerImpl -{ - template using Vector = util::ViewOrVector; - - public: - TurnDataContainerImpl() = default; - - TurnDataContainerImpl(Vector turn_instructions, - Vector lane_data_ids, - Vector entry_class_ids, - Vector pre_turn_bearings, - Vector post_turn_bearings) - : turn_instructions(std::move(turn_instructions)), lane_data_ids(std::move(lane_data_ids)), - entry_class_ids(std::move(entry_class_ids)), - pre_turn_bearings(std::move(pre_turn_bearings)), - post_turn_bearings(std::move(post_turn_bearings)) - { - } - - EntryClassID GetEntryClassID(const EdgeID id) const { return entry_class_ids[id]; } - - util::guidance::TurnBearing GetPreTurnBearing(const EdgeID id) const - { - return pre_turn_bearings[id]; - } - - util::guidance::TurnBearing GetPostTurnBearing(const EdgeID id) const - { - return post_turn_bearings[id]; - } - - LaneDataID GetLaneDataID(const EdgeID id) const { return lane_data_ids[id]; } - - bool HasLaneData(const EdgeID id) const { return INVALID_LANE_DATAID != lane_data_ids[id]; } - - extractor::guidance::TurnInstruction GetTurnInstruction(const EdgeID id) const - { - return turn_instructions[id]; - } - - // Used by EdgeBasedGraphFactory to fill data structure - template > - void push_back(const TurnData &data) - { - turn_instructions.push_back(data.turn_instruction); - lane_data_ids.push_back(data.lane_data_id); - entry_class_ids.push_back(data.entry_class_id); - pre_turn_bearings.push_back(data.pre_turn_bearing); - post_turn_bearings.push_back(data.post_turn_bearing); - } - - template > - void append(const std::vector &others) - { - std::for_each( - others.begin(), others.end(), [this](const TurnData &other) { push_back(other); }); - } - - friend void serialization::read(storage::io::FileReader &reader, - TurnDataContainerImpl &turn_data_container); - friend void serialization::write(storage::io::FileWriter &writer, - const TurnDataContainerImpl &turn_data_container); - - private: - Vector turn_instructions; - Vector lane_data_ids; - Vector entry_class_ids; - Vector pre_turn_bearings; - Vector post_turn_bearings; -}; -} - -using TurnDataExternalContainer = detail::TurnDataContainerImpl; -using TurnDataContainer = detail::TurnDataContainerImpl; -using TurnDataView = detail::TurnDataContainerImpl; -} -} - -#endif diff --git a/include/guidance/guidance_processing.hpp b/include/guidance/guidance_processing.hpp new file mode 100644 index 00000000000..192a580b41e --- /dev/null +++ b/include/guidance/guidance_processing.hpp @@ -0,0 +1,49 @@ +#ifndef OSRM_GUIDANCE_GUIDANCE_RUNNER_HPP +#define OSRM_GUIDANCE_GUIDANCE_RUNNER_HPP + +#include "guidance/turn_data_container.hpp" + +#include "extractor/compressed_edge_container.hpp" +#include "extractor/node_data_container.hpp" +#include "extractor/suffix_table.hpp" +#include "extractor/turn_lane_types.hpp" +#include "extractor/way_restriction_map.hpp" + +#include "util/coordinate.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" +#include "util/guidance/turn_lanes.hpp" +#include "util/name_table.hpp" +#include "util/node_based_graph.hpp" + +#include + +namespace osrm +{ +namespace guidance +{ +using BearingClassesVector = std::vector; +using BearingClassesMap = util::ConcurrentIDMap; +using EntryClassesMap = util::ConcurrentIDMap; + +void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, + const extractor::EdgeBasedNodeDataContainer &edge_based_node_container, + const std::vector &node_coordinates, + const extractor::CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const extractor::RestrictionMap &node_restriction_map, + const extractor::WayRestrictionMap &way_restriction_map, + const util::NameTable &name_table, + const extractor::SuffixTable &suffix_table, + const extractor::TurnLanesIndexedArray &turn_lanes_data, + extractor::LaneDescriptionMap &lane_description_map, + util::guidance::LaneDataIdMap &lane_data_map, + guidance::TurnDataExternalContainer &turn_data_container, + BearingClassesVector &bearing_class_by_node_based_node, + BearingClassesMap &bearing_class_hash, + EntryClassesMap &entry_class_hash); + +} // namespace customizer +} // namespace osrm + +#endif diff --git a/include/guidance/segregated_intersection_classification.hpp b/include/guidance/segregated_intersection_classification.hpp index 8007ca53e06..25d39d929f9 100644 --- a/include/guidance/segregated_intersection_classification.hpp +++ b/include/guidance/segregated_intersection_classification.hpp @@ -12,6 +12,7 @@ class NameTable; namespace extractor { class NodeBasedGraphFactory; +} namespace guidance { @@ -20,8 +21,7 @@ namespace guidance // - middle edges between two osm ways in one logic road (U-turn) // - staggered intersections (X-cross) // - square/circle intersections -std::unordered_set findSegregatedNodes(const NodeBasedGraphFactory &factory, +std::unordered_set findSegregatedNodes(const extractor::NodeBasedGraphFactory &factory, const util::NameTable &names); } } -} diff --git a/include/guidance/turn_bearing.hpp b/include/guidance/turn_bearing.hpp new file mode 100644 index 00000000000..ad6e3ac1afb --- /dev/null +++ b/include/guidance/turn_bearing.hpp @@ -0,0 +1,38 @@ +#ifndef OSRM_INCLUDE_GUIDANCE_TURN_BEARING_HPP_ +#define OSRM_INCLUDE_GUIDANCE_TURN_BEARING_HPP_ + +#include + +#include + +namespace osrm +{ +namespace guidance +{ +namespace +{ +const double bearing_scale = 360.0 / 256.0; +} + +#pragma pack(push, 1) +class TurnBearing +{ + public: + // discretizes a bearing into distinct units of 1.4 degrees + TurnBearing(const double value = 0) : bearing(value / bearing_scale) + { + BOOST_ASSERT_MSG(value >= 0 && value < 360.0, + "Bearing value needs to be between 0 and 360 (exclusive)"); + } + + double Get() const { return bearing * bearing_scale; } + + private: + std::uint8_t bearing; +}; +#pragma pack(pop) + +} // namespace guidance +} // namespace osrm + +#endif /* OSRM_INCLUDE_GUIDANCE_TURN_BEARING_HPP_ */ diff --git a/include/guidance/turn_data_container.hpp b/include/guidance/turn_data_container.hpp index 8f77eb2df43..91261f3f3b8 100644 --- a/include/guidance/turn_data_container.hpp +++ b/include/guidance/turn_data_container.hpp @@ -2,12 +2,12 @@ #define OSRM_GUIDANCE_TURN_DATA_CONTAINER_HPP #include "extractor/travel_mode.hpp" +#include "guidance/turn_bearing.hpp" #include "guidance/turn_instruction.hpp" #include "storage/io_fwd.hpp" #include "storage/shared_memory_ownership.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/vector_view.hpp" #include "util/typedefs.hpp" @@ -33,11 +33,11 @@ void write(storage::io::FileWriter &writer, struct TurnData { - guidance::TurnInstruction turn_instruction; + TurnInstruction turn_instruction; LaneDataID lane_data_id; EntryClassID entry_class_id; - util::guidance::TurnBearing pre_turn_bearing; - util::guidance::TurnBearing post_turn_bearing; + TurnBearing pre_turn_bearing; + TurnBearing post_turn_bearing; }; namespace detail @@ -49,11 +49,11 @@ template class TurnDataContainerImpl public: TurnDataContainerImpl() = default; - TurnDataContainerImpl(Vector turn_instructions, + TurnDataContainerImpl(Vector turn_instructions, Vector lane_data_ids, Vector entry_class_ids, - Vector pre_turn_bearings, - Vector post_turn_bearings) + Vector pre_turn_bearings, + Vector post_turn_bearings) : turn_instructions(std::move(turn_instructions)), lane_data_ids(std::move(lane_data_ids)), entry_class_ids(std::move(entry_class_ids)), pre_turn_bearings(std::move(pre_turn_bearings)), @@ -63,15 +63,9 @@ template class TurnDataContainerImpl EntryClassID GetEntryClassID(const EdgeID id) const { return entry_class_ids[id]; } - util::guidance::TurnBearing GetPreTurnBearing(const EdgeID id) const - { - return pre_turn_bearings[id]; - } + TurnBearing GetPreTurnBearing(const EdgeID id) const { return pre_turn_bearings[id]; } - util::guidance::TurnBearing GetPostTurnBearing(const EdgeID id) const - { - return post_turn_bearings[id]; - } + TurnBearing GetPostTurnBearing(const EdgeID id) const { return post_turn_bearings[id]; } LaneDataID GetLaneDataID(const EdgeID id) const { return lane_data_ids[id]; } @@ -106,11 +100,11 @@ template class TurnDataContainerImpl const TurnDataContainerImpl &turn_data_container); private: - Vector turn_instructions; + Vector turn_instructions; Vector lane_data_ids; Vector entry_class_ids; - Vector pre_turn_bearings; - Vector post_turn_bearings; + Vector pre_turn_bearings; + Vector post_turn_bearings; }; } diff --git a/include/util/guidance/turn_bearing.hpp b/include/util/guidance/turn_bearing.hpp deleted file mode 100644 index 87b4f2a3bdb..00000000000 --- a/include/util/guidance/turn_bearing.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef OSRM_INCLUDE_UTIL_TURN_BEARING_HPP_ -#define OSRM_INCLUDE_UTIL_TURN_BEARING_HPP_ - -#include - -namespace osrm -{ -namespace util -{ -namespace guidance -{ - -#pragma pack(push, 1) -class TurnBearing -{ - public: - TurnBearing(const double value = 0); - - double Get() const; - - private: - std::uint8_t bearing; -}; -#pragma pack(pop) - -} // namespace guidance -} // namespace util -} // namespace osrm - -#endif /* OSRM_INCLUDE_UTIL_TURN_BEARING_HPP_ */ diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 90cfa90f8d5..edf548925d6 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -7,11 +7,6 @@ #include "extractor/serialization.hpp" #include "extractor/suffix_table.hpp" -#include "guidance/files.hpp" -#include "guidance/turn_analysis.hpp" -#include "guidance/turn_data_container.hpp" -#include "guidance/turn_lane_handler.hpp" - #include "storage/io.hpp" #include "util/assert.hpp" @@ -19,7 +14,6 @@ #include "util/coordinate.hpp" #include "util/coordinate_calculation.hpp" #include "util/exception.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/integer_range.hpp" #include "util/log.hpp" #include "util/percent.hpp" @@ -75,7 +69,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( const std::vector &coordinates, const util::NameTable &name_table, const std::unordered_set &segregated_edges, - extractor::LaneDescriptionMap &lane_description_map) + const extractor::LaneDescriptionMap &lane_description_map) : m_edge_based_node_container(node_data_container), m_number_of_edge_based_nodes(0), m_coordinates(coordinates), m_node_based_graph(std::move(node_based_graph)), m_barrier_nodes(barrier_nodes), m_traffic_lights(traffic_lights), @@ -219,8 +213,6 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N } void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, - const std::string &turn_data_filename, - const std::string &turn_lane_data_filename, const std::string &turn_weight_penalties_filename, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, @@ -249,8 +241,6 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, TIMER_START(generate_edges); GenerateEdgeExpandedEdges(scripting_environment, - turn_data_filename, - turn_lane_data_filename, turn_weight_penalties_filename, turn_duration_penalties_filename, turn_penalties_index_filename, @@ -406,8 +396,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re /// Actually it also generates turn data and serializes them... void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( ScriptingEnvironment &scripting_environment, - const std::string &turn_data_filename, - const std::string &turn_lane_data_filename, const std::string &turn_weight_penalties_filename, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, @@ -419,15 +407,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( util::Log() << "Generating edge-expanded edges "; std::size_t node_based_edge_counter = 0; - restricted_turns_counter = 0; - skipped_uturns_counter = 0; - skipped_barrier_turns_counter = 0; storage::io::FileWriter turn_penalties_index_file(turn_penalties_index_filename, storage::io::FileWriter::HasNoFingerprint); - guidance::TurnDataExternalContainer turn_data_container; - SuffixTable street_name_suffix_table(scripting_environment); const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map); intersection::MergableRoadDetector mergable_road_detector(m_node_based_graph, @@ -440,34 +423,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( name_table, street_name_suffix_table); - // Loop over all turns and generate new set of edges. - // Three nested loop look super-linear, but we are dealing with a (kind of) - // linear number of turns only. - guidance::TurnAnalysis turn_analysis(m_node_based_graph, - m_edge_based_node_container, - m_coordinates, - m_compressed_edge_container, - node_restriction_map, - m_barrier_nodes, - turn_lanes_data, - name_table, - street_name_suffix_table); - - util::guidance::LaneDataIdMap lane_data_map; - guidance::lanes::TurnLaneHandler turn_lane_handler(m_node_based_graph, - m_edge_based_node_container, - m_coordinates, - m_compressed_edge_container, - node_restriction_map, - m_barrier_nodes, - turn_lanes_data, - lane_description_map, - turn_analysis, - lane_data_map); - - bearing_class_by_node_based_node.resize(m_node_based_graph.GetNumberOfNodes(), - std::numeric_limits::max()); - // FIXME these need to be tuned in pre-allocated size std::vector turn_weight_penalties; std::vector turn_duration_penalties; @@ -484,8 +439,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // created them in (tbb::filter::serial_in_order creates this guarantee). The order needs to be // maintained because we depend on it later in the processing pipeline. { - util::UnbufferedLog log; - const NodeID node_count = m_node_based_graph.GetNumberOfNodes(); // Because we write TurnIndexBlock data as we go, we'll @@ -524,18 +477,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( }; using EdgesPipelineBufferPtr = std::shared_ptr; - struct TurnsPipelineBuffer - { - std::size_t nodes_processed = 0; - - std::vector continuous_turn_data; // populate answers from guidance - std::vector delayed_turn_data; // populate answers from guidance - }; - using TurnsPipelineBufferPtr = std::shared_ptr; - // going over all nodes (which form the center of an intersection), we compute all possible // turns along these intersections. - NodeID current_node = 0; // Handle intersections in sets of 100. The pipeline below has a serial bottleneck during @@ -764,10 +707,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const auto turning_off_via_way = way_restriction_map.IsViaWay(incoming_edge.node, intersection_node); - // Save reversed incoming bearing to compute turn angles - const auto incoming_bearing = - findEdgeBearing(edge_geometries, incoming_edge.edge); - for (const auto &outgoing_edge : outgoing_edges) { if (!intersection::isTurnAllowed(m_node_based_graph, @@ -1006,177 +945,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( return buffer; }); - // - // Guidance stage - // - tbb::filter_t, TurnsPipelineBufferPtr> guidance_stage( - tbb::filter::parallel, [&](const tbb::blocked_range &intersection_node_range) { - - auto buffer = std::make_shared(); - buffer->nodes_processed = intersection_node_range.size(); - - for (auto intersection_node = intersection_node_range.begin(), - end = intersection_node_range.end(); - intersection_node < end; - ++intersection_node) - { - // We capture the thread-local work in these objects, then flush - // them in a controlled manner at the end of the parallel range - const auto &incoming_edges = - intersection::getIncomingEdges(m_node_based_graph, intersection_node); - const auto &outgoing_edges = - intersection::getOutgoingEdges(m_node_based_graph, intersection_node); - const auto &edge_geometries_and_merged_edges = - intersection::getIntersectionGeometries(m_node_based_graph, - m_compressed_edge_container, - m_coordinates, - mergable_road_detector, - intersection_node); - const auto &edge_geometries = edge_geometries_and_merged_edges.first; - const auto &merged_edge_ids = edge_geometries_and_merged_edges.second; - - // all nodes in the graph are connected in both directions. We check all - // outgoing nodes to find the incoming edge. This is a larger search overhead, - // but the cost we need to pay to generate edges here is worth the additional - // search overhead. - // - // a -> b <-> c - // | - // v - // d - // - // will have: - // a: b,rev=0 - // b: a,rev=1 c,rev=0 d,rev=0 - // c: b,rev=0 - // - // From the flags alone, we cannot determine which nodes are connected to - // `b` by an outgoing edge. Therefore, we have to search all connected edges for - // edges entering `b` - - for (const auto &incoming_edge : incoming_edges) - { - const auto intersection_view = - convertToIntersectionView(m_node_based_graph, - m_edge_based_node_container, - node_restriction_map, - m_barrier_nodes, - edge_geometries, - turn_lanes_data, - incoming_edge, - outgoing_edges, - merged_edge_ids); - - auto intersection = turn_analysis.AssignTurnTypes( - incoming_edge.node, incoming_edge.edge, intersection_view); - - OSRM_ASSERT(intersection.valid(), m_coordinates[intersection_node]); - intersection = turn_lane_handler.assignTurnLanes( - incoming_edge.node, incoming_edge.edge, std::move(intersection)); - - // the entry class depends on the turn, so we have to classify the - // interesction for every edge - const auto turn_classification = - classifyIntersection(intersection, m_coordinates[intersection_node]); - - const auto entry_class_id = - entry_class_hash.ConcurrentFindOrAdd(turn_classification.first); - - const auto bearing_class_id = - bearing_class_hash.ConcurrentFindOrAdd(turn_classification.second); - - // Note - this is strictly speaking not thread safe, but we know we - // should never be touching the same element twice, so we should - // be fine. - bearing_class_by_node_based_node[intersection_node] = bearing_class_id; - - // check if we are turning off a via way - const auto turning_off_via_way = - way_restriction_map.IsViaWay(incoming_edge.node, intersection_node); - - for (const auto &outgoing_edge : outgoing_edges) - { - if (!intersection::isTurnAllowed(m_node_based_graph, - m_edge_based_node_container, - node_restriction_map, - m_barrier_nodes, - edge_geometries, - turn_lanes_data, - incoming_edge, - outgoing_edge)) - continue; - - const auto turn = - std::find_if(intersection.begin(), - intersection.end(), - [edge = outgoing_edge.edge](const auto &road) { - return road.eid == edge; - }); - - OSRM_ASSERT(turn != intersection.end(), - m_coordinates[intersection_node]); - - buffer->continuous_turn_data.push_back(guidance::TurnData{ - turn->instruction, - turn->lane_data_id, - entry_class_id, - util::guidance::TurnBearing(intersection[0].bearing), - util::guidance::TurnBearing(turn->bearing)}); - - // when turning off a a via-way turn restriction, we need to not only - // handle the normal edges for the way, but also add turns for every - // duplicated node. This process is integrated here to avoid doing the - // turn analysis multiple times. - if (turning_off_via_way) - { - const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs( - incoming_edge.node, intersection_node); - - // next to the normal restrictions tracked in `entry_allowed`, via - // ways might introduce additional restrictions. These are handled - // here when turning off a via-way - for (auto duplicated_node_id : duplicated_nodes) - { - auto const node_at_end_of_turn = - m_node_based_graph.GetTarget(outgoing_edge.edge); - - const auto is_way_restricted = way_restriction_map.IsRestricted( - duplicated_node_id, node_at_end_of_turn); - - if (is_way_restricted) - { - auto const restriction = way_restriction_map.GetRestriction( - duplicated_node_id, node_at_end_of_turn); - - if (restriction.condition.empty()) - continue; - - buffer->delayed_turn_data.push_back(guidance::TurnData{ - turn->instruction, - turn->lane_data_id, - entry_class_id, - util::guidance::TurnBearing(intersection[0].bearing), - util::guidance::TurnBearing(turn->bearing)}); - } - else - { - buffer->delayed_turn_data.push_back(guidance::TurnData{ - turn->instruction, - turn->lane_data_id, - entry_class_id, - util::guidance::TurnBearing(intersection[0].bearing), - util::guidance::TurnBearing(turn->bearing)}); - } - } - } - } - } - } - - return buffer; - }); - // Last part of the pipeline puts all the calculated data into the serial buffers + util::UnbufferedLog log; util::Percent routing_progress(log, node_count); std::vector delayed_data; tbb::filter_t output_stage( @@ -1206,51 +976,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end()); }); - // Last part of the pipeline puts all the calculated data into the serial buffers - util::Percent guidance_progress(log, node_count); - std::vector delayed_turn_data; - - tbb::filter_t guidance_output_stage( - tbb::filter::serial_in_order, [&](auto buffer) { - - guidance_progress.PrintAddition(buffer->nodes_processed); - - // Guidance data - std::for_each(buffer->continuous_turn_data.begin(), - buffer->continuous_turn_data.end(), - [&turn_data_container](const auto &turn_data) { - turn_data_container.push_back(turn_data); - }); - - // Copy via-way restrictions delayed data - delayed_turn_data.insert(delayed_turn_data.end(), - buffer->delayed_turn_data.begin(), - buffer->delayed_turn_data.end()); - }); - // Now, execute the pipeline. The value of "5" here was chosen by experimentation // on a 16-CPU machine and seemed to give the best performance. This value needs // to be balanced with the GRAINSIZE above - ideally, the pipeline puts as much work // as possible in the `intersection_handler` step so that those parallel workers don't // get blocked too much by the slower (io-performing) `buffer_storage` - util::Log() << "Generating edge-expanded edges "; - current_node = 0; tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5, generator_stage & processor_stage & output_stage); - log << std::endl; - - util::Log() << "Generating guidance turns "; - current_node = 0; - tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5, - generator_stage & guidance_stage & guidance_output_stage); // NOTE: buffer.delayed_data and buffer.delayed_turn_data have the same index std::for_each(delayed_data.begin(), delayed_data.end(), transfer_data); - std::for_each(delayed_turn_data.begin(), - delayed_turn_data.end(), - [&turn_data_container](const auto &turn_data) { - turn_data_container.push_back(turn_data); - }); // Flush the turn_indexes_write_buffer if it's not empty if (!turn_indexes_write_buffer.empty()) @@ -1261,7 +996,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( } } - util::Log() << "Reunmbering turns"; + util::Log() << "done."; + util::Log() << "Renumbering turns"; // Now, update the turn_id property on every EdgeBasedEdge - it will equal the position in the // m_edge_based_edge_list array for each object. tbb::parallel_for(tbb::blocked_range(0, m_edge_based_edge_list.size()), @@ -1272,7 +1008,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( } }); - // re-hash conditionals to ocnnect to their respective edge-based edges. Due to the ordering, we + // re-hash conditionals to connect to their respective edge-based edges. Due to the ordering, we // do not really have a choice but to index the conditional penalties and walk over all // edge-based-edges to find the ID of the edge auto const indexed_conditionals = IndexConditionals(std::move(conditionals)); @@ -1299,34 +1035,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( storage::serialization::write(writer, turn_duration_penalties); } - util::Log() << "Created " << entry_class_hash.data.size() << " entry classes and " - << bearing_class_hash.data.size() << " Bearing Classes"; - - util::Log() << "Writing Turn Lane Data to File..."; - { - storage::io::FileWriter writer(turn_lane_data_filename, - storage::io::FileWriter::GenerateFingerprint); - - std::vector lane_data(lane_data_map.data.size()); - // extract lane data sorted by ID - for (auto itr : lane_data_map.data) - lane_data[itr.second] = itr.first; - - storage::serialization::write(writer, lane_data); - } - util::Log() << "done."; - - guidance::files::writeTurnData(turn_data_filename, turn_data_container); - util::Log() << "Generated " << m_edge_based_node_segments.size() << " edge based node segments"; util::Log() << "Node-based graph contains " << node_based_edge_counter << " edges"; util::Log() << "Edge-expanded graph ..."; util::Log() << " contains " << m_edge_based_edge_list.size() << " edges"; - util::Log() << " skips " << restricted_turns_counter << " turns, " - "defined by " - << node_restriction_map.Size() << " restrictions"; - util::Log() << " skips " << skipped_uturns_counter << " U turns"; - util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers"; } std::vector @@ -1354,37 +1066,5 @@ EdgeBasedGraphFactory::IndexConditionals(std::vector &&conditionals return indexed_restrictions; } -std::vector EdgeBasedGraphFactory::GetBearingClasses() const -{ - std::vector result(bearing_class_hash.data.size()); - for (const auto &pair : bearing_class_hash.data) - { - BOOST_ASSERT(pair.second < result.size()); - result[pair.second] = pair.first; - } - return result; -} - -const std::vector &EdgeBasedGraphFactory::GetBearingClassIds() const -{ - return bearing_class_by_node_based_node; -} - -std::vector &EdgeBasedGraphFactory::GetBearingClassIds() -{ - return bearing_class_by_node_based_node; -} - -std::vector EdgeBasedGraphFactory::GetEntryClasses() const -{ - std::vector result(entry_class_hash.data.size()); - for (const auto &pair : entry_class_hash.data) - { - BOOST_ASSERT(pair.second < result.size()); - result[pair.second] = pair.first; - } - return result; -} - } // namespace extractor } // namespace osrm diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 220b92367e1..206dcd765d9 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -13,7 +13,10 @@ #include "extractor/restriction_parser.hpp" #include "extractor/scripting_environment.hpp" +#include "guidance/files.hpp" +#include "guidance/guidance_processing.hpp" #include "guidance/segregated_intersection_classification.hpp" +#include "guidance/turn_data_container.hpp" #include "storage/io.hpp" @@ -274,6 +277,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes(); + const util::NameTable name_table(config.GetPath(".osrm.names").string()); + const auto number_of_edge_based_nodes = BuildEdgeExpandedGraph(node_based_graph, coordinates, @@ -283,14 +288,25 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) turn_restrictions, conditional_turn_restrictions, segregated_edges, + name_table, turn_lane_map, scripting_environment, edge_based_nodes_container, edge_based_node_segments, node_is_startpoint, edge_based_node_weights, - edge_based_edge_list, - config.GetPath(".osrm.icd").string()); + edge_based_edge_list); + + ProcessGuidanceTurns(node_based_graph, + edge_based_nodes_container, + coordinates, + node_based_graph_factory.GetCompressedEdges(), + barrier_nodes, + turn_restrictions, + conditional_turn_restrictions, + name_table, + std::move(turn_lane_map), + scripting_environment); TIMER_STOP(expansion); @@ -672,8 +688,8 @@ EdgeID Extractor::BuildEdgeExpandedGraph( const std::vector &turn_restrictions, const std::vector &conditional_turn_restrictions, const std::unordered_set &segregated_edges, - // might have to be updated to add new lane combinations - LaneDescriptionMap &turn_lane_map, + const util::NameTable &name_table, + const LaneDescriptionMap &turn_lane_map, // for calculating turn penalties ScriptingEnvironment &scripting_environment, // output data @@ -681,11 +697,8 @@ EdgeID Extractor::BuildEdgeExpandedGraph( std::vector &edge_based_node_segments, std::vector &node_is_startpoint, std::vector &edge_based_node_weights, - util::DeallocatingVector &edge_based_edge_list, - const std::string &intersection_class_output_file) + util::DeallocatingVector &edge_based_edge_list) { - util::NameTable name_table(config.GetPath(".osrm.names").string()); - EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph, edge_based_nodes_container, compressed_edge_container, @@ -712,10 +725,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph( WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions); ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions, IndexNodeByFromAndVia()); - edge_based_graph_factory.Run(scripting_environment, - config.GetPath(".osrm.edges").string(), - config.GetPath(".osrm.tld").string(), config.GetPath(".osrm.turn_weight_penalties").string(), config.GetPath(".osrm.turn_duration_penalties").string(), config.GetPath(".osrm.turn_penalties_index").string(), @@ -729,30 +739,11 @@ EdgeID Extractor::BuildEdgeExpandedGraph( const auto number_of_edge_based_nodes = create_edge_based_edges(); - { - std::vector turn_lane_offsets; - std::vector turn_lane_masks; - std::tie(turn_lane_offsets, turn_lane_masks) = - transformTurnLaneMapIntoArrays(turn_lane_map); - files::writeTurnLaneDescriptions( - config.GetPath(".osrm.tls"), turn_lane_offsets, turn_lane_masks); - } - edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list); edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments); edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint); edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights); - util::Log() << "Writing Intersection Classification Data"; - TIMER_START(write_intersections); - files::writeIntersections( - intersection_class_output_file, - IntersectionBearingsContainer{edge_based_graph_factory.GetBearingClassIds(), - edge_based_graph_factory.GetBearingClasses()}, - edge_based_graph_factory.GetEntryClasses()); - TIMER_STOP(write_intersections); - util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s"; - return number_of_edge_based_nodes; } @@ -844,5 +835,101 @@ void Extractor::WriteCompressedNodeBasedGraph(const std::string &path, } } +template auto convertIDMapToVector(const Map &map) +{ + std::vector result(map.size()); + for (const auto &pair : map) + { + BOOST_ASSERT(pair.second < map.size()); + result[pair.second] = pair.first; + } + return result; +} + +void Extractor::ProcessGuidanceTurns( + const util::NodeBasedDynamicGraph &node_based_graph, + const extractor::EdgeBasedNodeDataContainer &edge_based_node_container, + const std::vector &node_coordinates, + const CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const std::vector &turn_restrictions, + const std::vector &conditional_turn_restrictions, + const util::NameTable &name_table, + LaneDescriptionMap lane_description_map, + ScriptingEnvironment &scripting_environment) +{ + // Output data + osrm::guidance::TurnDataExternalContainer turn_data_container; + util::guidance::LaneDataIdMap lane_data_map; + osrm::guidance::BearingClassesVector bearing_class_by_node_based_node; + osrm::guidance::BearingClassesMap bearing_class_hash; + osrm::guidance::EntryClassesMap entry_class_hash; + + TIMER_START(turn_annotations); + + { + SuffixTable street_name_suffix_table(scripting_environment); + const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map); + + std::vector node_restrictions; + for (auto const &t : turn_restrictions) + if (t.Type() == RestrictionType::NODE_RESTRICTION) + node_restrictions.push_back(t); + + RestrictionMap node_restriction_map(node_restrictions, IndexNodeByFromAndVia()); + WayRestrictionMap way_restriction_map(conditional_turn_restrictions); + + osrm::guidance::annotateTurns(node_based_graph, + edge_based_node_container, + node_coordinates, + compressed_edge_container, + barrier_nodes, + node_restriction_map, + way_restriction_map, + name_table, + street_name_suffix_table, + turn_lanes_data, + lane_description_map, + lane_data_map, + turn_data_container, + bearing_class_by_node_based_node, + bearing_class_hash, + entry_class_hash); + } + + TIMER_STOP(turn_annotations); + util::Log() << "Guidance turn annotations took " << TIMER_SEC(turn_annotations) << "s"; + + util::Log() << "Writing Intersection Classification Data"; + TIMER_START(write_intersections); + files::writeIntersections( + config.GetPath(".osrm.icd").string(), + IntersectionBearingsContainer{bearing_class_by_node_based_node, + convertIDMapToVector(bearing_class_hash.data)}, + convertIDMapToVector(entry_class_hash.data)); + TIMER_STOP(write_intersections); + util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s"; + + util::Log() << "Writing Turns and Lane Data..."; + TIMER_START(write_guidance_data); + storage::io::FileWriter writer(config.GetPath(".osrm.tld").string(), + storage::io::FileWriter::GenerateFingerprint); + storage::serialization::write(writer, convertIDMapToVector(lane_data_map.data)); + + { // Turn lanes handler modifies lane_description_map, so another transformation is needed + std::vector turn_lane_offsets; + std::vector turn_lane_masks; + std::tie(turn_lane_offsets, turn_lane_masks) = + transformTurnLaneMapIntoArrays(lane_description_map); + files::writeTurnLaneDescriptions( + config.GetPath(".osrm.tls"), turn_lane_offsets, turn_lane_masks); + } + + osrm::guidance::files::writeTurnData(config.GetPath(".osrm.edges").string(), + turn_data_container); + TIMER_STOP(write_guidance_data); + util::Log() << "ok, after " << TIMER_SEC(write_guidance_data) << "s"; +} + } // namespace extractor } // namespace osrm diff --git a/src/extractor/intersection/coordinate_extractor.cpp b/src/extractor/intersection/coordinate_extractor.cpp index f8c96dcd01f..389271b15e4 100644 --- a/src/extractor/intersection/coordinate_extractor.cpp +++ b/src/extractor/intersection/coordinate_extractor.cpp @@ -1174,6 +1174,6 @@ CoordinateExtractor::RegressionLine(const std::vector &coordin return {coord_between_front, coord_between_back}; } -} // namespace guidance +} // namespace intersection } // namespace extractor } // namespace osrm diff --git a/src/extractor/intersection/mergable_road_detector.cpp b/src/extractor/intersection/mergable_road_detector.cpp index 8c3610aed70..1d0e828934e 100644 --- a/src/extractor/intersection/mergable_road_detector.cpp +++ b/src/extractor/intersection/mergable_road_detector.cpp @@ -615,6 +615,6 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node, .annotation_data)); } -} // namespace guidance +} // namespace intersection } // namespace extractor } // namespace osrm diff --git a/src/guidance/guidance_processing.cpp b/src/guidance/guidance_processing.cpp new file mode 100644 index 00000000000..7137a933ee5 --- /dev/null +++ b/src/guidance/guidance_processing.cpp @@ -0,0 +1,330 @@ +#include "guidance/guidance_processing.hpp" +#include "guidance/turn_analysis.hpp" +#include "guidance/turn_lane_handler.hpp" + +#include "extractor/intersection/intersection_analysis.hpp" + +#include "util/assert.hpp" +#include "util/percent.hpp" + +#include +#include +#include + +namespace osrm +{ +namespace guidance +{ + +void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, + const extractor::EdgeBasedNodeDataContainer &edge_based_node_container, + const std::vector &node_coordinates, + const extractor::CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const extractor::RestrictionMap &node_restriction_map, + const extractor::WayRestrictionMap &way_restriction_map, + const util::NameTable &name_table, + const extractor::SuffixTable &suffix_table, + const extractor::TurnLanesIndexedArray &turn_lanes_data, + extractor::LaneDescriptionMap &lane_description_map, + util::guidance::LaneDataIdMap &lane_data_map, + guidance::TurnDataExternalContainer &turn_data_container, + BearingClassesVector &bearing_class_by_node_based_node, + BearingClassesMap &bearing_class_hash, + EntryClassesMap &entry_class_hash) +{ + util::Log() << "Generating guidance turns "; + + extractor::intersection::MergableRoadDetector mergable_road_detector(node_based_graph, + edge_based_node_container, + node_coordinates, + compressed_edge_container, + node_restriction_map, + barrier_nodes, + turn_lanes_data, + name_table, + suffix_table); + + guidance::TurnAnalysis turn_analysis(node_based_graph, + edge_based_node_container, + node_coordinates, + compressed_edge_container, + node_restriction_map, + barrier_nodes, + turn_lanes_data, + name_table, + suffix_table); + + guidance::lanes::TurnLaneHandler turn_lane_handler(node_based_graph, + edge_based_node_container, + node_coordinates, + compressed_edge_container, + node_restriction_map, + barrier_nodes, + turn_lanes_data, + lane_description_map, + turn_analysis, + lane_data_map); + + bearing_class_by_node_based_node.resize(node_based_graph.GetNumberOfNodes(), + std::numeric_limits::max()); + + struct TurnsPipelineBuffer + { + std::size_t nodes_processed = 0; + + std::vector continuous_turn_data; // populate answers from guidance + std::vector delayed_turn_data; // populate answers from guidance + }; + using TurnsPipelineBufferPtr = std::shared_ptr; + + // going over all nodes (which form the center of an intersection), we compute all + // possible turns along these intersections. + { + const NodeID node_count = node_based_graph.GetNumberOfNodes(); + NodeID current_node = 0; + + // Handle intersections in sets of 100. The pipeline below has a serial bottleneck + // during the writing phase, so we want to make the parallel workers do more work + // to give the serial final stage time to complete its tasks. + const constexpr unsigned GRAINSIZE = 100; + + // First part of the pipeline generates iterator ranges of IDs in sets of GRAINSIZE + tbb::filter_t> generator_stage( + tbb::filter::serial_in_order, [&](tbb::flow_control &fc) { + if (current_node < node_count) + { + auto next_node = std::min(current_node + GRAINSIZE, node_count); + auto result = tbb::blocked_range(current_node, next_node); + current_node = next_node; + return result; + } + else + { + fc.stop(); + return tbb::blocked_range(node_count, node_count); + } + }); + + // + // Guidance stage + // + tbb::filter_t, TurnsPipelineBufferPtr> guidance_stage( + tbb::filter::parallel, [&](const tbb::blocked_range &intersection_node_range) { + + auto buffer = std::make_shared(); + buffer->nodes_processed = intersection_node_range.size(); + + for (auto intersection_node = intersection_node_range.begin(), + end = intersection_node_range.end(); + intersection_node < end; + ++intersection_node) + { + // We capture the thread-local work in these objects, then flush + // them in a controlled manner at the end of the parallel range + const auto &incoming_edges = extractor::intersection::getIncomingEdges( + node_based_graph, intersection_node); + const auto &outgoing_edges = extractor::intersection::getOutgoingEdges( + node_based_graph, intersection_node); + const auto &edge_geometries_and_merged_edges = + extractor::intersection::getIntersectionGeometries( + node_based_graph, + compressed_edge_container, + node_coordinates, + mergable_road_detector, + intersection_node); + const auto &edge_geometries = edge_geometries_and_merged_edges.first; + const auto &merged_edge_ids = edge_geometries_and_merged_edges.second; + + // all nodes in the graph are connected in both directions. We check all + // outgoing nodes to find the incoming edge. This is a larger search overhead, + // but the cost we need to pay to generate edges here is worth the additional + // search overhead. + // + // a -> b <-> c + // | + // v + // d + // + // will have: + // a: b,rev=0 + // b: a,rev=1 c,rev=0 d,rev=0 + // c: b,rev=0 + // + // From the flags alone, we cannot determine which nodes are connected to + // `b` by an outgoing edge. Therefore, we have to search all connected edges for + // edges entering `b` + + for (const auto &incoming_edge : incoming_edges) + { + const auto intersection_view = + extractor::intersection::convertToIntersectionView( + node_based_graph, + edge_based_node_container, + node_restriction_map, + barrier_nodes, + edge_geometries, + turn_lanes_data, + incoming_edge, + outgoing_edges, + merged_edge_ids); + + auto intersection = turn_analysis.AssignTurnTypes( + incoming_edge.node, incoming_edge.edge, intersection_view); + + OSRM_ASSERT(intersection.valid(), node_coordinates[intersection_node]); + intersection = turn_lane_handler.assignTurnLanes( + incoming_edge.node, incoming_edge.edge, std::move(intersection)); + + // the entry class depends on the turn, so we have to classify the + // interesction for every edge + const auto turn_classification = + classifyIntersection(intersection, node_coordinates[intersection_node]); + + const auto entry_class_id = + entry_class_hash.ConcurrentFindOrAdd(turn_classification.first); + + const auto bearing_class_id = + bearing_class_hash.ConcurrentFindOrAdd(turn_classification.second); + + // Note - this is strictly speaking not thread safe, but we know we + // should never be touching the same element twice, so we should + // be fine. + bearing_class_by_node_based_node[intersection_node] = bearing_class_id; + + // check if we are turning off a via way + const auto turning_off_via_way = + way_restriction_map.IsViaWay(incoming_edge.node, intersection_node); + + for (const auto &outgoing_edge : outgoing_edges) + { + auto is_turn_allowed = + extractor::intersection::isTurnAllowed(node_based_graph, + edge_based_node_container, + node_restriction_map, + barrier_nodes, + edge_geometries, + turn_lanes_data, + incoming_edge, + outgoing_edge); + + if (!is_turn_allowed) + continue; + + const auto turn = + std::find_if(intersection.begin(), + intersection.end(), + [edge = outgoing_edge.edge](const auto &road) { + return road.eid == edge; + }); + + OSRM_ASSERT(turn != intersection.end(), + node_coordinates[intersection_node]); + + buffer->continuous_turn_data.push_back( + guidance::TurnData{turn->instruction, + turn->lane_data_id, + entry_class_id, + guidance::TurnBearing(intersection[0].bearing), + guidance::TurnBearing(turn->bearing)}); + + // when turning off a a via-way turn restriction, we need to not only + // handle the normal edges for the way, but also add turns for every + // duplicated node. This process is integrated here to avoid doing the + // turn analysis multiple times. + if (turning_off_via_way) + { + const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs( + incoming_edge.node, intersection_node); + + // next to the normal restrictions tracked in `entry_allowed`, via + // ways might introduce additional restrictions. These are handled + // here when turning off a via-way + for (auto duplicated_node_id : duplicated_nodes) + { + auto const node_at_end_of_turn = + node_based_graph.GetTarget(outgoing_edge.edge); + + const auto is_way_restricted = way_restriction_map.IsRestricted( + duplicated_node_id, node_at_end_of_turn); + + if (is_way_restricted) + { + auto const restriction = way_restriction_map.GetRestriction( + duplicated_node_id, node_at_end_of_turn); + + if (restriction.condition.empty()) + continue; + + buffer->delayed_turn_data.push_back(guidance::TurnData{ + turn->instruction, + turn->lane_data_id, + entry_class_id, + guidance::TurnBearing(intersection[0].bearing), + guidance::TurnBearing(turn->bearing)}); + } + else + { + buffer->delayed_turn_data.push_back(guidance::TurnData{ + turn->instruction, + turn->lane_data_id, + entry_class_id, + guidance::TurnBearing(intersection[0].bearing), + guidance::TurnBearing(turn->bearing)}); + } + } + } + } + } + } + + return buffer; + }); + + // Last part of the pipeline puts all the calculated data into the serial buffers + util::UnbufferedLog log; + util::Percent guidance_progress(log, node_count); + std::vector delayed_turn_data; + + tbb::filter_t guidance_output_stage( + tbb::filter::serial_in_order, [&](auto buffer) { + + guidance_progress.PrintAddition(buffer->nodes_processed); + + // Guidance data + std::for_each(buffer->continuous_turn_data.begin(), + buffer->continuous_turn_data.end(), + [&turn_data_container](const auto &turn_data) { + turn_data_container.push_back(turn_data); + }); + + // Copy via-way restrictions delayed data + delayed_turn_data.insert(delayed_turn_data.end(), + buffer->delayed_turn_data.begin(), + buffer->delayed_turn_data.end()); + }); + + // Now, execute the pipeline. The value of "5" here was chosen by experimentation + // on a 16-CPU machine and seemed to give the best performance. This value needs + // to be balanced with the GRAINSIZE above - ideally, the pipeline puts as much work + // as possible in the `intersection_handler` step so that those parallel workers don't + // get blocked too much by the slower (io-performing) `buffer_storage` + tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5, + generator_stage & guidance_stage & guidance_output_stage); + + // NOTE: EBG edges delayed_data and turns delayed_turn_data have the same index + std::for_each(delayed_turn_data.begin(), + delayed_turn_data.end(), + [&turn_data_container](const auto &turn_data) { + turn_data_container.push_back(turn_data); + }); + } + + util::Log() << "done."; + + util::Log() << "Created " << entry_class_hash.data.size() << " entry classes and " + << bearing_class_hash.data.size() << " Bearing Classes"; +} + +} // namespace guidance +} // namespace osrm diff --git a/src/guidance/segregated_intersection_classification.cpp b/src/guidance/segregated_intersection_classification.cpp index 64faeef0517..b7f891a7ba5 100644 --- a/src/guidance/segregated_intersection_classification.cpp +++ b/src/guidance/segregated_intersection_classification.cpp @@ -7,11 +7,11 @@ namespace osrm { -namespace extractor -{ namespace guidance { +namespace RoadPriorityClass = extractor::RoadPriorityClass; + struct EdgeInfo { NodeID node; @@ -21,7 +21,7 @@ struct EdgeInfo // 0 - outgoing (forward), 1 - incoming (reverse), 2 - both outgoing and incoming int direction; - ClassData road_class; + extractor::ClassData road_class; RoadPriorityClass::Enum road_priority_class; @@ -125,7 +125,7 @@ bool IsSegregated(std::vector v1, return edgeLength <= threshold; } -std::unordered_set findSegregatedNodes(const NodeBasedGraphFactory &factory, +std::unordered_set findSegregatedNodes(const extractor::NodeBasedGraphFactory &factory, const util::NameTable &names) { @@ -238,6 +238,6 @@ std::unordered_set findSegregatedNodes(const NodeBasedGraphFactory &fact return segregated_edges; } -} -} -} + +} // namespace guidance +} // namespace osrm diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index f900afb109e..e70cbbc154d 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -241,10 +241,10 @@ void Storage::PopulateLayout(DataLayout &layout) const auto number_of_original_edges = edges_file.ReadElementCount64(); // note: settings this all to the same size is correct, we extract them from the same struct - layout.SetBlockSize(DataLayout::PRE_TURN_BEARING, - number_of_original_edges); - layout.SetBlockSize(DataLayout::POST_TURN_BEARING, - number_of_original_edges); + layout.SetBlockSize(DataLayout::PRE_TURN_BEARING, + number_of_original_edges); + layout.SetBlockSize(DataLayout::POST_TURN_BEARING, + number_of_original_edges); layout.SetBlockSize(DataLayout::TURN_INSTRUCTION, number_of_original_edges); layout.SetBlockSize(DataLayout::LANE_DATA_ID, number_of_original_edges); @@ -708,14 +708,14 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr) util::vector_view entry_class_ids( entry_class_id_list_ptr, layout.num_entries[storage::DataLayout::ENTRY_CLASSID]); - const auto pre_turn_bearing_ptr = layout.GetBlockPtr( + const auto pre_turn_bearing_ptr = layout.GetBlockPtr( memory_ptr, storage::DataLayout::PRE_TURN_BEARING); - util::vector_view pre_turn_bearings( + util::vector_view pre_turn_bearings( pre_turn_bearing_ptr, layout.num_entries[storage::DataLayout::PRE_TURN_BEARING]); - const auto post_turn_bearing_ptr = layout.GetBlockPtr( + const auto post_turn_bearing_ptr = layout.GetBlockPtr( memory_ptr, storage::DataLayout::POST_TURN_BEARING); - util::vector_view post_turn_bearings( + util::vector_view post_turn_bearings( post_turn_bearing_ptr, layout.num_entries[storage::DataLayout::POST_TURN_BEARING]); guidance::TurnDataView turn_data(std::move(turn_instructions), diff --git a/src/util/guidance/bearing_class.cpp b/src/util/guidance/bearing_class.cpp index c2bdffa4f39..6e49466a586 100644 --- a/src/util/guidance/bearing_class.cpp +++ b/src/util/guidance/bearing_class.cpp @@ -78,5 +78,5 @@ std::size_t BearingClass::findMatchingBearing(const double bearing) const } } // namespace guidance -} // namespace extractor +} // namespace util } // namespace osrm diff --git a/src/util/guidance/entry_class.cpp b/src/util/guidance/entry_class.cpp index 68569ed161b..34232f2443c 100644 --- a/src/util/guidance/entry_class.cpp +++ b/src/util/guidance/entry_class.cpp @@ -37,5 +37,5 @@ bool EntryClass::operator<(const EntryClass &other) const } } // namespace guidance -} // namespace extractor +} // namespace util } // namespace osrm diff --git a/src/util/guidance/turn_bearing.cpp b/src/util/guidance/turn_bearing.cpp deleted file mode 100644 index 9f70a693105..00000000000 --- a/src/util/guidance/turn_bearing.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "util/guidance/turn_bearing.hpp" - -#include - -namespace osrm -{ -namespace util -{ -namespace guidance -{ - -constexpr double bearing_scale = 360.0 / 256.0; - -// discretizes a bearing into distinct units of 1.4 degrees -TurnBearing::TurnBearing(const double value) : bearing(value / bearing_scale) -{ - BOOST_ASSERT_MSG(value >= 0 && value < 360.0, - "Bearing value needs to be between 0 and 360 (exclusive)"); -} - -double TurnBearing::Get() const { return bearing * bearing_scale; } - -} // namespace guidance -} // namespace util -} // namespace osrm diff --git a/unit_tests/engine/offline_facade.cpp b/unit_tests/engine/offline_facade.cpp index 8d2b561216d..75c9cb4871c 100644 --- a/unit_tests/engine/offline_facade.cpp +++ b/unit_tests/engine/offline_facade.cpp @@ -341,14 +341,14 @@ class ContiguousInternalMemoryDataFacade ComponentID GetComponentID(NodeID) const override { return ComponentID{}; } bool ExcludeNode(const NodeID) const override { return false; } - util::guidance::TurnBearing PreTurnBearing(const EdgeID /*eid*/) const override + guidance::TurnBearing PreTurnBearing(const EdgeID /*eid*/) const override { - return util::guidance::TurnBearing(0); + return guidance::TurnBearing(0); } - util::guidance::TurnBearing PostTurnBearing(const EdgeID /*eid*/) const override + guidance::TurnBearing PostTurnBearing(const EdgeID /*eid*/) const override { - return util::guidance::TurnBearing(0); + return guidance::TurnBearing(0); } util::guidance::BearingClass diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index fd8d75e9512..47656c43085 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -7,6 +7,7 @@ #include "extractor/class_data.hpp" #include "extractor/travel_mode.hpp" #include "extractor/turn_lane_types.hpp" +#include "guidance/turn_bearing.hpp" #include "guidance/turn_instruction.hpp" #include "engine/algorithm.hpp" @@ -15,7 +16,6 @@ #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" -#include "util/guidance/turn_bearing.hpp" #include "util/typedefs.hpp" namespace osrm @@ -226,13 +226,13 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade bool IsLeftHandDriving(const NodeID /*id*/) const override { return false; } bool IsSegregated(const NodeID /*id*/) const override { return false; } - util::guidance::TurnBearing PreTurnBearing(const EdgeID /*eid*/) const override final + guidance::TurnBearing PreTurnBearing(const EdgeID /*eid*/) const override final { - return util::guidance::TurnBearing{0.0}; + return guidance::TurnBearing{0.0}; } - util::guidance::TurnBearing PostTurnBearing(const EdgeID /*eid*/) const override final + guidance::TurnBearing PostTurnBearing(const EdgeID /*eid*/) const override final { - return util::guidance::TurnBearing{0.0}; + return guidance::TurnBearing{0.0}; } bool HasLaneData(const EdgeID /*id*/) const override final { return true; };