diff --git a/CMakeLists.txt b/CMakeLists.txt index 489930566..9db6c510a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/include/util/version.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/include/util/version.hpp ) -file(GLOB UtilGlob src/util/*.cpp) +file(GLOB UtilGlob src/util/*.cpp src/util/*/*.cpp) file(GLOB ExtractorGlob src/extractor/*.cpp src/extractor/*/*.cpp) file(GLOB ContractorGlob src/contractor/*.cpp) file(GLOB StorageGlob src/storage/*.cpp) diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index 039b3a964..d54dec1ed 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -3,13 +3,15 @@ // Exposes all data access interfaces to the algorithms via base class ptr -#include "extractor/edge_based_node.hpp" -#include "extractor/external_memory_node.hpp" #include "contractor/query_edge.hpp" #include "engine/phantom_node.hpp" +#include "extractor/edge_based_node.hpp" +#include "extractor/external_memory_node.hpp" #include "extractor/guidance/turn_instruction.hpp" -#include "util/integer_range.hpp" #include "util/exception.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" +#include "util/integer_range.hpp" #include "util/string_util.hpp" #include "util/typedefs.hpp" @@ -17,9 +19,9 @@ #include -#include -#include #include +#include +#include namespace osrm { @@ -145,6 +147,15 @@ class BaseDataFacade virtual std::string GetTimestamp() const = 0; virtual bool GetContinueStraightDefault() const = 0; + + virtual BearingClassID GetBearingClassID(const NodeID id) const = 0; + + virtual util::guidance::BearingClass + GetBearingClass(const BearingClassID bearing_class_id) const = 0; + + virtual EntryClassID GetEntryClassID(const EdgeID eid) const = 0; + + virtual util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const = 0; }; } } diff --git a/include/engine/datafacade/internal_datafacade.hpp b/include/engine/datafacade/internal_datafacade.hpp index ff9d4adfe..e1e8c4ef0 100644 --- a/include/engine/datafacade/internal_datafacade.hpp +++ b/include/engine/datafacade/internal_datafacade.hpp @@ -6,21 +6,23 @@ #include "engine/datafacade/datafacade_base.hpp" #include "extractor/guidance/turn_instruction.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" #include "storage/storage_config.hpp" #include "engine/geospatial_query.hpp" +#include "extractor/compressed_edge_container.hpp" #include "extractor/original_edge_data.hpp" #include "extractor/profile_properties.hpp" #include "extractor/query_node.hpp" -#include "contractor/query_edge.hpp" +#include "util/graph_loader.hpp" +#include "util/io.hpp" +#include "util/range_table.hpp" +#include "util/rectangle.hpp" #include "util/shared_memory_vector_wrapper.hpp" +#include "util/simple_logger.hpp" #include "util/static_graph.hpp" #include "util/static_rtree.hpp" -#include "util/range_table.hpp" -#include "util/graph_loader.hpp" -#include "util/simple_logger.hpp" -#include "util/rectangle.hpp" -#include "extractor/compressed_edge_container.hpp" #include "osrm/coordinate.hpp" @@ -89,6 +91,17 @@ class InternalDataFacade final : public BaseDataFacade boost::filesystem::path file_index_path; util::RangeTable<16, false> m_name_table; + // bearing classes by node based node + util::ShM::vector m_bearing_class_id_table; + // entry class IDs by edge based egde + util::ShM::vector m_entry_class_id_list; + // the look-up table for entry classes. An entry class lists the possibility of entry for all + // available turns. For every turn, there is an associated entry class. + util::ShM::vector m_entry_class_table; + // the look-up table for distinct bearing classes. A bearing class lists the available bearings + // at an intersection + util::ShM::vector m_bearing_class_table; + void LoadProfileProperties(const boost::filesystem::path &properties_path) { boost::filesystem::ifstream in_stream(properties_path); @@ -97,7 +110,8 @@ class InternalDataFacade final : public BaseDataFacade throw util::exception("Could not open " + properties_path.string() + " for reading."); } - in_stream.read(reinterpret_cast(&m_profile_properties), sizeof(m_profile_properties)); + in_stream.read(reinterpret_cast(&m_profile_properties), + sizeof(m_profile_properties)); } void LoadTimestamp(const boost::filesystem::path ×tamp_path) @@ -154,6 +168,7 @@ class InternalDataFacade final : public BaseDataFacade m_name_ID_list.resize(number_of_edges); m_turn_instruction_list.resize(number_of_edges); m_travel_mode_list.resize(number_of_edges); + m_entry_class_id_list.resize(number_of_edges); extractor::OriginalEdgeData current_edge_data; for (unsigned i = 0; i < number_of_edges; ++i) @@ -164,6 +179,7 @@ class InternalDataFacade final : public BaseDataFacade m_name_ID_list[i] = current_edge_data.name_id; m_turn_instruction_list[i] = current_edge_data.turn_instruction; m_travel_mode_list[i] = current_edge_data.travel_mode; + m_entry_class_id_list[i] = current_edge_data.entry_classid; } } @@ -224,7 +240,8 @@ class InternalDataFacade final : public BaseDataFacade boost::filesystem::ifstream datasources_stream(datasource_indexes_file, std::ios::binary); if (!datasources_stream) { - throw util::exception("Could not open " + datasource_indexes_file.string() + " for reading!"); + throw util::exception("Could not open " + datasource_indexes_file.string() + + " for reading!"); } BOOST_ASSERT(datasources_stream); @@ -241,7 +258,8 @@ class InternalDataFacade final : public BaseDataFacade boost::filesystem::ifstream datasourcenames_stream(datasource_names_file, std::ios::binary); if (!datasourcenames_stream) { - throw util::exception("Could not open " + datasource_names_file.string() + " for reading!"); + throw util::exception("Could not open " + datasource_names_file.string() + + " for reading!"); } BOOST_ASSERT(datasourcenames_stream); std::string name; @@ -277,6 +295,43 @@ class InternalDataFacade final : public BaseDataFacade } } + void LoadIntersectionClasses(const boost::filesystem::path &intersection_class_file) + { + std::ifstream intersection_stream(intersection_class_file.string(), std::ios::binary); + if (!intersection_stream) + util::SimpleLogger().Write(logWARNING) << "Failed to open " << intersection_class_file + << " for reading."; + if (!util::readAndCheckFingerprint(intersection_stream)) + { + util::SimpleLogger().Write(logWARNING) + << "Fingerprint does not match or reading failed"; + exit(-1); + } + + { + util::SimpleLogger().Write(logINFO) << "Loading Bearing Class IDs"; + std::vector bearing_class_id; + util::deserializeVector(intersection_stream, bearing_class_id); + m_bearing_class_id_table.resize(bearing_class_id.size()); + std::copy(bearing_class_id.begin(), bearing_class_id.end(), + &m_bearing_class_id_table[0]); + } + { + util::SimpleLogger().Write(logINFO) << "Loading Bearing Classes"; + std::vector bearing_classes; + util::deserializeVector(intersection_stream, bearing_classes); + m_bearing_class_table.resize(bearing_classes.size()); + std::copy(bearing_classes.begin(), bearing_classes.end(), &m_bearing_class_table[0]); + } + { + util::SimpleLogger().Write(logINFO) << "Loading Entry Classes"; + std::vector entry_classes; + util::deserializeVector(intersection_stream, entry_classes); + m_entry_class_table.resize(entry_classes.size()); + std::copy(entry_classes.begin(), entry_classes.end(), &m_entry_class_table[0]); + } + } + public: virtual ~InternalDataFacade() { @@ -284,7 +339,7 @@ class InternalDataFacade final : public BaseDataFacade m_geospatial_query.reset(); } - explicit InternalDataFacade(const storage::StorageConfig& config) + explicit InternalDataFacade(const storage::StorageConfig &config) { ram_index_path = config.ram_index_path; file_index_path = config.file_index_path; @@ -302,8 +357,7 @@ class InternalDataFacade final : public BaseDataFacade LoadGeometries(config.geometries_path); util::SimpleLogger().Write() << "loading datasource info"; - LoadDatasourceInfo(config.datasource_names_path, - config.datasource_indexes_path); + LoadDatasourceInfo(config.datasource_names_path, config.datasource_indexes_path); util::SimpleLogger().Write() << "loading timestamp"; LoadTimestamp(config.timestamp_path); @@ -316,6 +370,9 @@ class InternalDataFacade final : public BaseDataFacade util::SimpleLogger().Write() << "loading rtree"; LoadRTree(); + + util::SimpleLogger().Write() << "loading intersection class data"; + LoadIntersectionClasses(config.intersection_class_path); } // search graph access @@ -548,8 +605,7 @@ class InternalDataFacade final : public BaseDataFacade result_nodes.clear(); result_nodes.reserve(end - begin); std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end, - [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) - { + [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) { result_nodes.emplace_back(edge.node_id); }); } @@ -564,8 +620,7 @@ class InternalDataFacade final : public BaseDataFacade result_weights.clear(); result_weights.reserve(end - begin); std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end, - [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) - { + [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) { result_weights.emplace_back(edge.weight); }); } @@ -592,11 +647,9 @@ class InternalDataFacade final : public BaseDataFacade } else { - std::for_each(m_datasource_list.begin() + begin, m_datasource_list.begin() + end, - [&](const uint8_t &datasource_id) - { - result_datasources.push_back(datasource_id); - }); + std::for_each( + m_datasource_list.begin() + begin, m_datasource_list.begin() + end, + [&](const uint8_t &datasource_id) { result_datasources.push_back(datasource_id); }); } } @@ -609,7 +662,33 @@ class InternalDataFacade final : public BaseDataFacade std::string GetTimestamp() const override final { return m_timestamp; } - bool GetContinueStraightDefault() const override final { return m_profile_properties.continue_straight_at_waypoint; } + bool GetContinueStraightDefault() const override final + { + return m_profile_properties.continue_straight_at_waypoint; + } + + BearingClassID GetBearingClassID(const NodeID nid) const override final + { + return m_bearing_class_id_table.at(nid); + } + + util::guidance::BearingClass + GetBearingClass(const BearingClassID bearing_class_id) const override final + { + BOOST_ASSERT(bearing_class_id != INVALID_BEARING_CLASSID); + return m_bearing_class_table.at(bearing_class_id); + } + + EntryClassID GetEntryClassID(const EdgeID eid) const override final + { + return m_entry_class_id_list.at(eid); + } + + util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const override final + { + BOOST_ASSERT(entry_class_id != INVALID_ENTRY_CLASSID); + return m_entry_class_table.at(entry_class_id); + } }; } } diff --git a/include/engine/datafacade/shared_datafacade.hpp b/include/engine/datafacade/shared_datafacade.hpp index 97e1ea257..12070a499 100644 --- a/include/engine/datafacade/shared_datafacade.hpp +++ b/include/engine/datafacade/shared_datafacade.hpp @@ -10,14 +10,16 @@ #include "extractor/guidance/turn_instruction.hpp" #include "extractor/profile_properties.hpp" #include "extractor/compressed_edge_container.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" #include "engine/geospatial_query.hpp" +#include "util/make_unique.hpp" #include "util/range_table.hpp" +#include "util/rectangle.hpp" +#include "util/simple_logger.hpp" #include "util/static_graph.hpp" #include "util/static_rtree.hpp" -#include "util/make_unique.hpp" -#include "util/simple_logger.hpp" -#include "util/rectangle.hpp" #include @@ -30,9 +32,9 @@ #include #include -#include -#include #include +#include +#include namespace osrm { @@ -94,6 +96,17 @@ class SharedDataFacade final : public BaseDataFacade std::shared_ptr> m_name_table; + // bearing classes by node based node + util::ShM::vector m_bearing_class_id_table; + // entry class IDs + util::ShM::vector m_entry_class_id_list; + // the look-up table for entry classes. An entry class lists the possibility of entry for all + // available turns. Such a class id is stored with every edge. + util::ShM::vector m_entry_class_table; + // the look-up table for distinct bearing classes. A bearing class lists the available bearings + // at an intersection + util::ShM::vector m_bearing_class_table; + void LoadChecksum() { m_check_sum = *data_layout->GetBlockPtr(shared_memory, @@ -171,6 +184,13 @@ class SharedDataFacade final : public BaseDataFacade util::ShM::vector name_id_list( name_id_list_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_ID_LIST]); m_name_ID_list = std::move(name_id_list); + + auto entry_class_id_list_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::ENTRY_CLASSID); + typename util::ShM::vector entry_class_id_list( + entry_class_id_list_ptr, + data_layout->num_entries[storage::SharedDataLayout::ENTRY_CLASSID]); + m_entry_class_id_list = std::move(entry_class_id_list); } void LoadViaNodeList() @@ -263,6 +283,28 @@ class SharedDataFacade final : public BaseDataFacade m_datasource_name_lengths = std::move(datasource_name_lengths); } + void LoadIntersecionClasses() + { + auto bearing_class_id_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::BEARING_CLASSID); + typename util::ShM::vector bearing_class_id_table( + bearing_class_id_ptr, + data_layout->num_entries[storage::SharedDataLayout::BEARING_CLASSID]); + m_bearing_class_id_table = std::move(bearing_class_id_table); + + auto bearing_class_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::BEARING_CLASS); + typename util::ShM::vector bearing_class_table( + bearing_class_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_CLASS]); + m_bearing_class_table = std::move(bearing_class_table); + + auto entry_class_ptr = data_layout->GetBlockPtr( + shared_memory, storage::SharedDataLayout::ENTRY_CLASS); + typename util::ShM::vector entry_class_table( + entry_class_ptr, data_layout->num_entries[storage::SharedDataLayout::ENTRY_CLASS]); + m_entry_class_table = std::move(entry_class_table); + } + public: virtual ~SharedDataFacade() {} @@ -350,6 +392,7 @@ class SharedDataFacade final : public BaseDataFacade LoadCoreInformation(); LoadProfileProperties(); LoadRTree(); + LoadIntersecionClasses(); util::SimpleLogger().Write() << "number of geometries: " << m_coordinate_list.size(); @@ -420,8 +463,7 @@ class SharedDataFacade final : public BaseDataFacade result_nodes.clear(); result_nodes.reserve(end - begin); std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end, - [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) - { + [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) { result_nodes.emplace_back(edge.node_id); }); } @@ -436,8 +478,7 @@ class SharedDataFacade final : public BaseDataFacade result_weights.clear(); result_weights.reserve(end - begin); std::for_each(m_geometry_list.begin() + begin, m_geometry_list.begin() + end, - [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) - { + [&](const osrm::extractor::CompressedEdgeContainer::CompressedEdge &edge) { result_weights.emplace_back(edge.weight); }); } @@ -634,11 +675,9 @@ class SharedDataFacade final : public BaseDataFacade } else { - std::for_each(m_datasource_list.begin() + begin, m_datasource_list.begin() + end, - [&](const uint8_t &datasource_id) - { - result_datasources.push_back(datasource_id); - }); + std::for_each( + m_datasource_list.begin() + begin, m_datasource_list.begin() + end, + [&](const uint8_t &datasource_id) { result_datasources.push_back(datasource_id); }); } } @@ -663,6 +702,32 @@ class SharedDataFacade final : public BaseDataFacade { return m_profile_properties->continue_straight_at_waypoint; } +<<<<<<< HEAD +======= + + BearingClassID GetBearingClassID(const NodeID id) const override final + { + return m_bearing_class_id_table.at(id); + } + + util::guidance::BearingClass + GetBearingClass(const BearingClassID bearing_class_id) const override final + { + BOOST_ASSERT(bearing_class_id != INVALID_BEARING_CLASSID); + return m_bearing_class_table.at(bearing_class_id); + } + + EntryClassID GetEntryClassID(const EdgeID eid) const override final + { + return m_entry_class_id_list.at(eid); + } + + util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const override final + { + BOOST_ASSERT(entry_class_id != INVALID_ENTRY_CLASSID); + return m_entry_class_table.at(entry_class_id); + } +>>>>>>> a5cb6a1... initial version of intersection classification }; } } diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index d798f04ad..68ab41c94 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -12,6 +12,9 @@ #include "util/bearing.hpp" #include "util/coordinate.hpp" #include "util/coordinate_calculation.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" +#include "util/typedefs.hpp" #include #include @@ -27,12 +30,13 @@ namespace detail { StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction, const LegGeometry &leg_geometry, - const std::size_t segment_index); + const std::size_t segment_index, + util::guidance::EntryClass entry_class, + util::guidance::BearingClass bearing_class); StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction, const WaypointType waypoint_type, const LegGeometry &leg_geometry); - } // ns detail template @@ -100,8 +104,10 @@ std::vector assembleSteps(const DataFacadeT &facade, } else { step_name_id = target_node.name_id; } - maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction, - leg_geometry, segment_index); + maneuver = detail::stepManeuverFromGeometry( + path_point.turn_instruction, leg_geometry, segment_index, + facade.GetEntryClass(path_point.entry_classid), + facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node))); segment_index++; segment_duration = 0; } diff --git a/include/engine/guidance/step_maneuver.hpp b/include/engine/guidance/step_maneuver.hpp index 084a9991a..c72efa7e1 100644 --- a/include/engine/guidance/step_maneuver.hpp +++ b/include/engine/guidance/step_maneuver.hpp @@ -3,6 +3,8 @@ #include "extractor/guidance/turn_instruction.hpp" #include "util/coordinate.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" #include #include @@ -27,6 +29,8 @@ struct IntermediateIntersection double duration; double distance; util::Coordinate location; + util::guidance::EntryClass entry_class; + util::guidance::BearingClass bearing_class; }; struct StepManeuver @@ -37,6 +41,8 @@ struct StepManeuver extractor::guidance::TurnInstruction instruction; WaypointType waypoint_type; unsigned exit; + util::guidance::EntryClass entry_class; + util::guidance::BearingClass bearing_class; std::vector intersections; }; diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index d1666e164..c3536cc48 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -2,8 +2,8 @@ #define RAW_ROUTE_DATA_H #include "engine/phantom_node.hpp" -#include "extractor/travel_mode.hpp" #include "extractor/guidance/turn_instruction.hpp" +#include "extractor/travel_mode.hpp" #include "util/typedefs.hpp" #include "osrm/coordinate.hpp" @@ -29,6 +29,8 @@ struct PathData extractor::guidance::TurnInstruction turn_instruction; // travel mode of the street that leads to the turn extractor::TravelMode travel_mode : 4; + // entry class of the turn, indicating possibility of turns + EntryClassID entry_classid; }; struct InternalRouteResult diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index deeec646a..3b7ec4450 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -1,10 +1,10 @@ #ifndef ROUTING_BASE_HPP #define ROUTING_BASE_HPP -#include "util/coordinate_calculation.hpp" #include "engine/internal_route_result.hpp" #include "engine/search_engine_data.hpp" #include "extractor/guidance/turn_instruction.hpp" +#include "util/coordinate_calculation.hpp" #include "util/typedefs.hpp" #include @@ -14,10 +14,10 @@ #include #include +#include +#include #include #include -#include -#include namespace osrm { @@ -317,13 +317,12 @@ template class BasicRoutingInterface for (std::size_t i = start_index; i < end_index; ++i) { unpacked_path.push_back( - PathData{id_vector[i], - name_index, - weight_vector[i], - extractor::guidance::TurnInstruction::NO_TURN(), - travel_mode}); + PathData{id_vector[i], name_index, weight_vector[i], + extractor::guidance::TurnInstruction::NO_TURN(), travel_mode, + INVALID_ENTRY_CLASSID}); } BOOST_ASSERT(unpacked_path.size() > 0); + unpacked_path.back().entry_classid = facade->GetEntryClassID(ed.id); unpacked_path.back().turn_instruction = turn_instruction; unpacked_path.back().duration_until_turn += (ed.distance - total_weight); } @@ -376,14 +375,12 @@ template class BasicRoutingInterface { BOOST_ASSERT(i < id_vector.size()); BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0); - unpacked_path.push_back( - PathData{id_vector[i], - phantom_node_pair.target_phantom.name_id, - weight_vector[i], - extractor::guidance::TurnInstruction::NO_TURN(), - target_traversed_in_reverse - ? phantom_node_pair.target_phantom.backward_travel_mode - : phantom_node_pair.target_phantom.forward_travel_mode}); + unpacked_path.push_back(PathData{ + id_vector[i], phantom_node_pair.target_phantom.name_id, weight_vector[i], + extractor::guidance::TurnInstruction::NO_TURN(), + target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode + : phantom_node_pair.target_phantom.forward_travel_mode, + INVALID_ENTRY_CLASSID}); } if (unpacked_path.size() > 0) @@ -641,9 +638,8 @@ template class BasicRoutingInterface } // TODO check if unordered_set might be faster // sort by id and increasing by distance - auto entry_point_comparator = - [](const std::pair &lhs, const std::pair &rhs) - { + auto entry_point_comparator = [](const std::pair &lhs, + const std::pair &rhs) { return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second); }; std::sort(forward_entry_points.begin(), forward_entry_points.end(), entry_point_comparator); diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 1aff3908f..8f6b24441 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -3,33 +3,35 @@ #ifndef EDGE_BASED_GRAPH_FACTORY_HPP_ #define EDGE_BASED_GRAPH_FACTORY_HPP_ -#include "extractor/edge_based_edge.hpp" -#include "extractor/profile_properties.hpp" -#include "extractor/restriction_map.hpp" #include "extractor/compressed_edge_container.hpp" +#include "extractor/edge_based_edge.hpp" #include "extractor/edge_based_node.hpp" #include "extractor/original_edge_data.hpp" +#include "extractor/profile_properties.hpp" #include "extractor/query_node.hpp" -#include "extractor/guidance/turn_analysis.hpp" +#include "extractor/restriction_map.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" +#include "extractor/guidance/turn_analysis.hpp" #include "extractor/guidance/turn_instruction.hpp" -#include "util/node_based_graph.hpp" -#include "util/typedefs.hpp" #include "util/deallocating_vector.hpp" #include "util/name_table.hpp" +#include "util/node_based_graph.hpp" +#include "util/typedefs.hpp" #include -#include #include +#include #include #include #include #include +#include #include #include #include -#include #include @@ -67,6 +69,12 @@ 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; + unsigned GetHighestEdgeID(); // Basic analysis of a turn (u --(e1)-- v --(e2)-- w) @@ -127,6 +135,10 @@ class EdgeBasedGraphFactory std::size_t restricted_turns_counter; std::size_t skipped_uturns_counter; std::size_t skipped_barrier_turns_counter; + + std::unordered_map bearing_class_hash; + std::vector bearing_class_by_node_based_node; + std::unordered_map entry_class_hash; }; } // namespace extractor } // namespace osrm diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index 1b61513c1..b92952334 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -29,10 +29,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define EXTRACTOR_HPP #include "extractor/edge_based_edge.hpp" -#include "extractor/extractor_config.hpp" #include "extractor/edge_based_graph_factory.hpp" +#include "extractor/extractor_config.hpp" #include "extractor/graph_compressor.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" + #include "util/typedefs.hpp" namespace osrm @@ -52,14 +55,16 @@ class Extractor ExtractorConfig config; std::pair - BuildEdgeExpandedGraph(lua_State* lua_state, - const ProfileProperties& profile_properties, + BuildEdgeExpandedGraph(lua_State *lua_state, + const ProfileProperties &profile_properties, std::vector &internal_to_external_node_map, std::vector &node_based_edge_list, std::vector &node_is_startpoint, std::vector &edge_based_node_weights, - util::DeallocatingVector &edge_based_edge_list); - void WriteProfileProperties(const std::string& output_path, const ProfileProperties& properties) const; + util::DeallocatingVector &edge_based_edge_list, + const std::string &intersection_class_output_file); + void WriteProfileProperties(const std::string &output_path, + const ProfileProperties &properties) const; void WriteNodeMapping(const std::vector &internal_to_external_node_map); void FindComponents(unsigned max_edge_id, const util::DeallocatingVector &edges, @@ -76,6 +81,12 @@ class Extractor void WriteEdgeBasedGraph(const std::string &output_file_filename, const size_t max_edge_id, util::DeallocatingVector const &edge_based_edge_list); + + void WriteIntersectionClassificationData( + const std::string &output_file_name, + const std::vector &node_based_intersection_classes, + const std::vector &bearing_classes, + const std::vector &entry_classes) const; }; } } diff --git a/include/extractor/extractor_config.hpp b/include/extractor/extractor_config.hpp index 80196db87..243b36570 100644 --- a/include/extractor/extractor_config.hpp +++ b/include/extractor/extractor_config.hpp @@ -72,6 +72,7 @@ struct ExtractorConfig edge_penalty_path = basepath + ".osrm.edge_penalties"; edge_based_node_weights_output_path = basepath + ".osrm.enw"; profile_properties_output_path = basepath + ".osrm.properties"; + intersection_class_data_output_path = basepath + ".osrm.icd"; } boost::filesystem::path config_file_path; @@ -90,6 +91,7 @@ struct ExtractorConfig std::string rtree_nodes_output_path; std::string rtree_leafs_output_path; std::string profile_properties_output_path; + std::string intersection_class_data_output_path; unsigned requested_num_threads; unsigned small_component_size; diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp index f7d0f614a..b1f702258 100644 --- a/include/extractor/guidance/toolkit.hpp +++ b/include/extractor/guidance/toolkit.hpp @@ -41,7 +41,8 @@ const constexpr bool shiftable_ccw[] = {false, true, true, false, false, true, t const constexpr bool shiftable_cw[] = {false, false, true, true, false, false, true, true}; const constexpr std::uint8_t modifier_bounds[detail::num_direction_modifiers] = { 0, 36, 93, 121, 136, 163, 220, 255}; -const constexpr double discrete_angle_step_size = 360. / 256.; + +const constexpr double discrete_angle_step_size = 360. / 24; template util::Coordinate @@ -246,12 +247,12 @@ inline bool isConflict(const TurnInstruction first, const TurnInstruction second inline DiscreteAngle discretizeAngle(const double angle) { BOOST_ASSERT(angle >= 0. && angle <= 360.); - return DiscreteAngle(static_cast(angle / detail::discrete_angle_step_size)); + return DiscreteAngle(static_cast((angle + 0.5 *detail::discrete_angle_step_size) / detail::discrete_angle_step_size)); } inline double angleFromDiscreteAngle(const DiscreteAngle angle) { - return static_cast(angle) * detail::discrete_angle_step_size; + return static_cast(angle) * detail::discrete_angle_step_size + 0.5 * detail::discrete_angle_step_size; } inline double getAngularPenalty(const double angle, DirectionModifier modifier) diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index 3f202f3dd..7d700a3ed 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -46,6 +46,9 @@ class TurnAnalysis // the entry into the turn analysis std::vector getTurns(const NodeID from_node, const EdgeID via_eid) const; + // access to the intersection representation for classification purposes + Intersection getIntersection(const NodeID from_node, const EdgeID via_eid) const; + private: const util::NodeBasedDynamicGraph &node_based_graph; const IntersectionGenerator intersection_generator; diff --git a/include/extractor/guidance/turn_classification.hpp b/include/extractor/guidance/turn_classification.hpp index 6cf7a080e..968ea2159 100644 --- a/include/extractor/guidance/turn_classification.hpp +++ b/include/extractor/guidance/turn_classification.hpp @@ -1,18 +1,23 @@ #ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_ #define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_ +#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/toolkit.hpp" +#include "extractor/compressed_edge_container.hpp" +#include "extractor/query_node.hpp" +#include "util/guidance/entry_class.hpp" +#include "util/guidance/bearing_class.hpp" #include "util/coordinate.hpp" #include "util/node_based_graph.hpp" #include "util/typedefs.hpp" -#include "extractor/compressed_edge_container.hpp" -#include "extractor/query_node.hpp" + #include #include #include +#include namespace osrm { @@ -21,99 +26,12 @@ namespace extractor namespace guidance { -struct TurnPossibility -{ - TurnPossibility(DiscreteAngle angle, EdgeID edge_id) - : angle(std::move(angle)), edge_id(std::move(edge_id)) - { - } - - TurnPossibility() : angle(0), edge_id(SPECIAL_EDGEID) {} - - DiscreteAngle angle; - EdgeID edge_id; -}; - -struct CompareTurnPossibilities -{ - bool operator()(const std::vector &left, - const std::vector &right) const - { - if (left.size() < right.size()) - return true; - if (left.size() > right.size()) - return false; - for (std::size_t i = 0; i < left.size(); ++i) - { - if ((((int)left[i].angle + 16) % 256) / 32 < (((int)right[i].angle + 16) % 256) / 32) - return true; - if ((((int)left[i].angle + 16) % 256) / 32 > (((int)right[i].angle + 16) % 256) / 32) - return false; - } - return false; - } -}; - -inline std::vector +std::pair classifyIntersection(NodeID nid, - const util::NodeBasedDynamicGraph &graph, + const Intersection &intersection, + const util::NodeBasedDynamicGraph &node_based_graph, const extractor::CompressedEdgeContainer &compressed_geometries, - const std::vector &query_nodes) -{ - - std::vector turns; - - if (graph.BeginEdges(nid) == graph.EndEdges(nid)) - return std::vector(); - - const EdgeID base_id = graph.BeginEdges(nid); - const auto base_coordinate = getRepresentativeCoordinate(nid, graph.GetTarget(base_id), base_id, - graph.GetEdgeData(base_id).reversed, - compressed_geometries, query_nodes); - const auto node_coordinate = util::Coordinate(query_nodes[nid].lon, query_nodes[nid].lat); - - // generate a list of all turn angles between a base edge, the node and a current edge - for (const EdgeID eid : graph.GetAdjacentEdgeRange(nid)) - { - const auto edge_coordinate = getRepresentativeCoordinate( - nid, graph.GetTarget(eid), eid, false, compressed_geometries, query_nodes); - - double angle = util::coordinate_calculation::computeAngle(base_coordinate, node_coordinate, - edge_coordinate); - turns.emplace_back(discretizeAngle(angle), eid); - } - - std::sort(turns.begin(), turns.end(), - [](const TurnPossibility left, const TurnPossibility right) { - return left.angle < right.angle; - }); - - turns.push_back(turns.front()); // sentinel - for (std::size_t turn_nr = 0; turn_nr + 1 < turns.size(); ++turn_nr) - { - turns[turn_nr].angle = (256 + static_cast(turns[turn_nr + 1].angle) - - static_cast(turns[turn_nr].angle)) % - 256; // calculate the difference to the right - } - turns.pop_back(); // remove sentinel again - - // find largest: - std::size_t best_id = 0; - DiscreteAngle largest_turn_angle = turns.front().angle; - for (std::size_t current_turn_id = 1; current_turn_id < turns.size(); ++current_turn_id) - { - if (turns[current_turn_id].angle > largest_turn_angle) - { - largest_turn_angle = turns[current_turn_id].angle; - best_id = current_turn_id; - } - } - - // rotate all angles so the largest angle comes first - std::rotate(turns.begin(), turns.begin() + best_id, turns.end()); - - return turns; -} + const std::vector &query_nodes); } // namespace guidance } // namespace extractor diff --git a/include/extractor/original_edge_data.hpp b/include/extractor/original_edge_data.hpp index 17d234af9..f77afc7dd 100644 --- a/include/extractor/original_edge_data.hpp +++ b/include/extractor/original_edge_data.hpp @@ -1,10 +1,11 @@ #ifndef ORIGINAL_EDGE_DATA_HPP #define ORIGINAL_EDGE_DATA_HPP -#include "extractor/travel_mode.hpp" #include "extractor/guidance/turn_instruction.hpp" +#include "extractor/travel_mode.hpp" #include "util/typedefs.hpp" +#include #include namespace osrm @@ -17,9 +18,10 @@ struct OriginalEdgeData explicit OriginalEdgeData(NodeID via_node, unsigned name_id, guidance::TurnInstruction turn_instruction, + EntryClassID entry_classid, TravelMode travel_mode) : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction), - travel_mode(travel_mode) + entry_classid(entry_classid), travel_mode(travel_mode) { } @@ -27,6 +29,7 @@ struct OriginalEdgeData : via_node(std::numeric_limits::max()), name_id(std::numeric_limits::max()), turn_instruction(guidance::TurnInstruction::INVALID()), + entry_classid(INVALID_ENTRY_CLASSID), travel_mode(TRAVEL_MODE_INACCESSIBLE) { } @@ -34,6 +37,7 @@ struct OriginalEdgeData NodeID via_node; unsigned name_id; guidance::TurnInstruction turn_instruction; + EntryClassID entry_classid; TravelMode travel_mode; }; } diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index ec1033a0d..8a0d7458f 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -29,6 +29,7 @@ struct SharedDataLayout GRAPH_EDGE_LIST, COORDINATE_LIST, TURN_INSTRUCTION, + ENTRY_CLASSID, TRAVEL_MODE, R_SEARCH_TREE, GEOMETRIES_INDEX, @@ -42,6 +43,9 @@ struct SharedDataLayout DATASOURCE_NAME_OFFSETS, DATASOURCE_NAME_LENGTHS, PROPERTIES, + BEARING_CLASSID, + ENTRY_CLASS, + BEARING_CLASS, NUM_BLOCKS }; diff --git a/include/storage/storage_config.hpp b/include/storage/storage_config.hpp index 62f2fddd5..94e6e01b0 100644 --- a/include/storage/storage_config.hpp +++ b/include/storage/storage_config.hpp @@ -64,6 +64,7 @@ struct StorageConfig final boost::filesystem::path datasource_indexes_path; boost::filesystem::path names_data_path; boost::filesystem::path properties_path; + boost::filesystem::path intersection_class_path; }; } } diff --git a/include/util/guidance/bearing_class.hpp b/include/util/guidance/bearing_class.hpp new file mode 100644 index 000000000..a5424ba4b --- /dev/null +++ b/include/util/guidance/bearing_class.hpp @@ -0,0 +1,87 @@ +#ifndef OSRM_UTIL_GUIDANCE_BEARING_CLASS_HPP_ +#define OSRM_UTIL_GUIDANCE_BEARING_CLASS_HPP_ + +#include +#include +#include +#include + +namespace osrm +{ +namespace util +{ +namespace guidance +{ +class BearingClass; +} // namespace guidance +} // namespace util +} // namespace osrm + +namespace std +{ +template <> struct hash<::osrm::util::guidance::BearingClass> +{ + inline std::size_t operator()(const ::osrm::util::guidance::BearingClass &bearing_class) const; +}; +} // namespace std + +namespace osrm +{ +namespace util +{ +namespace guidance +{ + +class BearingClass +{ + public: + using FlagBaseType = std::uint32_t; + const static constexpr double discrete_angle_step_size = 360. / 24; + + BearingClass(); + + // add a continuous angle to the, returns true if no item existed that uses the same discrete + // angle + bool addContinuous(const double bearing); + // add a discrete ID, returns true if no item existed that uses the same discrete angle + bool addDiscreteID(const std::uint8_t id); + + // hashing + bool operator==(const BearingClass &other) const; + + // sorting + bool operator<(const BearingClass &other) const; + + std::vector getAvailableBearings() const; + + // get a discrete representation of an angle. Required to map a bearing/angle to the discrete + // ones stored within the class + static std::uint8_t discreteBearingID(double angle); + + // we are hiding the access to the flags behind a protection wall, to make sure the bit logic + // isn't tempered with + private: + // given a list of possible discrete angles, the available angles flag indicates the presence of + // a given turn at the intersection + FlagBaseType available_bearings_mask; + + // allow hash access to internal representation + friend std::size_t std::hash::operator()(const BearingClass &) const; +}; + +} // namespace guidance +} // namespace util +} // namespace osrm + +// make Bearing Class hasbable +namespace std +{ +inline size_t hash<::osrm::util::guidance::BearingClass>:: +operator()(const ::osrm::util::guidance::BearingClass &bearing_class) const +{ + return hash<::osrm::util::guidance::BearingClass::FlagBaseType>()( + bearing_class.available_bearings_mask); +} +} // namespace std + +#endif /* OSRM_UTIL_GUIDANCE_BEARING_CLASS_HPP_ */ diff --git a/include/util/guidance/entry_class.hpp b/include/util/guidance/entry_class.hpp new file mode 100644 index 000000000..2bb76d1b6 --- /dev/null +++ b/include/util/guidance/entry_class.hpp @@ -0,0 +1,78 @@ +#ifndef OSRM_UTIL_GUIDANCE_ENTRY_CLASS_HPP_ +#define OSRM_UTIL_GUIDANCE_ENTRY_CLASS_HPP_ + +#include +#include +#include + +namespace osrm +{ +namespace util +{ +namespace guidance +{ +class EntryClass; +} // namespace guidance +} // namespace util +} // namespace osrm + +namespace std +{ +template <> struct hash<::osrm::util::guidance::EntryClass> +{ + inline std::size_t operator()(const ::osrm::util::guidance::EntryClass &entry_class) const; +}; +} // namespace std + +namespace osrm +{ +namespace util +{ +namespace guidance +{ + +class EntryClass +{ + using FlagBaseType = std::uint32_t; + + public: + EntryClass(); + + // we are hiding the access to the flags behind a protection wall, to make sure the bit logic + // isn't tempered with. zero based indexing + void activate(std::uint32_t index); + + // check whether a certain turn allows entry + bool allowsEntry(std::uint32_t index) const; + + // required for hashing + bool operator==(const EntryClass &) const; + + // sorting + bool operator<(const EntryClass &) const; + + private: + // given a list of possible discrete angles, the available angles flag indicates the presence of + // a given turn at the intersection + FlagBaseType enabled_entries_flags; + + // allow hash access to internal representation + friend std::size_t std::hash::operator()(const EntryClass &) const; +}; + +} // namespace guidance +} // namespace utilr +} // namespace osrm + +// make Entry Class hasbable +namespace std +{ +inline size_t hash<::osrm::util::guidance::EntryClass>:: +operator()(const ::osrm::util::guidance::EntryClass &entry_class) const +{ + return hash<::osrm::util::guidance::EntryClass::FlagBaseType>()( + entry_class.enabled_entries_flags); +} +} // namespace std + +#endif /* OSRM_UTIL_GUIDANCE_ENTRY_CLASS_HPP_ */ diff --git a/include/util/guidance/toolkit.hpp b/include/util/guidance/toolkit.hpp index 24072a85b..ff226b7f2 100644 --- a/include/util/guidance/toolkit.hpp +++ b/include/util/guidance/toolkit.hpp @@ -4,6 +4,12 @@ /* A set of tools required for guidance in both pre and post-processing */ #include "extractor/guidance/turn_instruction.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" +#include "util/simple_logger.hpp" + +#include +#include namespace osrm { @@ -41,8 +47,76 @@ inline extractor::guidance::DirectionModifier getTurnDirection(const double angl return extractor::guidance::DirectionModifier::UTurn; } -} /* namespace guidance */ -} /* namespace util */ -} /* namespace osrm */ +inline double getMatchingDiscreteBearing(const bool requires_entry, + const double bearing, + const EntryClass entry_class, + const std::vector existing_bearings) +{ + if (existing_bearings.empty()) + return 0; + + const double discrete_bearing = + BearingClass::discreteBearingID(bearing) * BearingClass::discrete_angle_step_size; + // it they are very close to the turn, the discrete bearing should be fine + if (std::abs(bearing - discrete_bearing) < 0.25 * BearingClass::discrete_angle_step_size) + { + const auto isValidEntry = [&]() { + const auto bound = std::upper_bound(existing_bearings.begin(), existing_bearings.end(), + (discrete_bearing - 0.001)); + const auto index = bound == existing_bearings.end() + ? 0 + : std::distance(existing_bearings.begin(), bound); + + return entry_class.allowsEntry(index); + }; + BOOST_ASSERT(!requires_entry || isValidEntry()); + return discrete_bearing; + } + else + { + // the next larger bearing or first if we are wrapping around at zero + const auto next_index = + std::distance(existing_bearings.begin(), + std::lower_bound(existing_bearings.begin(), existing_bearings.end(), + discrete_bearing)) % + existing_bearings.size(); + + // next smaller bearing or last if we are wrapping around at zero + const auto previous_index = + (next_index + existing_bearings.size() - 1) % existing_bearings.size(); + + const auto difference = [](const double first, const double second) { + return std::min(std::abs(first - second), 360.0 - std::abs(first - second)); + }; + + const auto next_bearing = existing_bearings[next_index]; + const auto previous_bearing = existing_bearings[previous_index]; + + const auto decideOnBearing = [&]( + const std::size_t preferred_index, const double preferred_bearing, + const std::size_t alternative_index, const double alternative_bearing) { + if (!requires_entry || entry_class.allowsEntry(preferred_index)) + return preferred_bearing; + else if (entry_class.allowsEntry(alternative_index)) + return alternative_bearing; + else + { + SimpleLogger().Write(logDEBUG) + << "Cannot find a valid entry for a discrete Bearing in Turn Classificiation"; + return 0.; + } + }; + + if (difference(bearing, next_bearing) < difference(bearing, previous_index)) + return decideOnBearing(next_index, next_bearing, previous_index, previous_bearing); + else + return decideOnBearing(previous_index, previous_bearing, next_index, next_bearing); + } + + return 0; +} +} // namespace guidance +} // namespace util +} // namespace osrm #endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */ diff --git a/include/util/io.hpp b/include/util/io.hpp index 70ab64a1b..2f3177fb3 100644 --- a/include/util/io.hpp +++ b/include/util/io.hpp @@ -8,8 +8,8 @@ #include #include -#include #include +#include #include #include "util/fingerprint.hpp" @@ -51,6 +51,16 @@ bool serializeVector(const std::string &filename, const std::vector return static_cast(stream); } +template +bool serializeVector(std::ostream &stream, const std::vector &data) +{ + std::uint64_t count = data.size(); + stream.write(reinterpret_cast(&count), sizeof(count)); + if (!data.empty()) + stream.write(reinterpret_cast(&data[0]), sizeof(simple_type) * count); + return static_cast(stream); +} + template bool deserializeVector(const std::string &filename, std::vector &data) { @@ -67,6 +77,17 @@ bool deserializeVector(const std::string &filename, std::vector &da return static_cast(stream); } +template +bool deserializeVector(std::istream &stream, std::vector &data) +{ + std::uint64_t count = 0; + stream.read(reinterpret_cast(&count), sizeof(count)); + data.resize(count); + if (count) + stream.read(reinterpret_cast(&data[0]), sizeof(simple_type) * count); + return static_cast(stream); +} + inline bool serializeFlags(const boost::filesystem::path &path, const std::vector &flags) { // TODO this should be replaced with a FILE-based write using error checking diff --git a/include/util/typedefs.hpp b/include/util/typedefs.hpp index f36a241ee..1a9e055b0 100644 --- a/include/util/typedefs.hpp +++ b/include/util/typedefs.hpp @@ -34,13 +34,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include // OpenStreetMap node ids are higher than 2^32 -OSRM_STRONG_TYPEDEF(uint64_t, OSMNodeID) -OSRM_STRONG_TYPEDEF_HASHABLE(uint64_t, OSMNodeID) +OSRM_STRONG_TYPEDEF(std::uint64_t, OSMNodeID) +OSRM_STRONG_TYPEDEF_HASHABLE(std::uint64_t, OSMNodeID) -OSRM_STRONG_TYPEDEF(uint32_t, OSMWayID) -OSRM_STRONG_TYPEDEF_HASHABLE(uint32_t, OSMWayID) +OSRM_STRONG_TYPEDEF(std::uint32_t, OSMWayID) +OSRM_STRONG_TYPEDEF_HASHABLE(std::uint32_t, OSMWayID) static const OSMNodeID SPECIAL_OSM_NODEID = OSMNodeID(std::numeric_limits::max()); static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID(std::numeric_limits::max()); @@ -57,6 +58,12 @@ using NodeID = unsigned int; using EdgeID = unsigned int; using EdgeWeight = int; +using BearingClassID = std::uint32_t; +static const BearingClassID INVALID_BEARING_CLASSID = std::numeric_limits::max(); + +using EntryClassID = std::uint16_t; +static const EntryClassID INVALID_ENTRY_CLASSID = std::numeric_limits::max(); + static const NodeID SPECIAL_NODEID = std::numeric_limits::max(); static const NodeID SPECIAL_SEGMENTID = std::numeric_limits::max(); static const EdgeID SPECIAL_EDGEID = std::numeric_limits::max(); diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index c23ca9c4b..8bd9c7755 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -4,6 +4,10 @@ #include "engine/polyline_compressor.hpp" #include "util/integer_range.hpp" +#include "util/guidance/bearing_class.hpp" +#include "util/guidance/entry_class.hpp" +#include "util/guidance/toolkit.hpp" + #include #include @@ -93,6 +97,47 @@ util::json::Array coordinateToLonLat(const util::Coordinate coordinate) return array; } +util::json::Object getConnection(const bool entry_allowed, const double bearing) +{ + util::json::Object result; + result.values["entry_allowed"] = entry_allowed ? "true" : "false"; + result.values["bearing"] = bearing; + return result; +} + +util::json::Array getConnections(const util::guidance::EntryClass entry_class, + const util::guidance::BearingClass bearing_class) +{ + util::json::Array result; + const auto bearings = bearing_class.getAvailableBearings(); + for (size_t connection = 0; connection < bearings.size(); ++connection) + { + result.values.push_back( + getConnection(entry_class.allowsEntry(connection), bearings[connection])); + } + return result; +} + +util::json::Object getIntersection(const guidance::StepManeuver maneuver) +{ + util::json::Object result; + // bearings are oriented in the direction of driving. For the in-bearing, we actually need to + // find the bearing from the view of the intersection. This means we have to rotate the bearing + // by 180 degree. + const auto rotated_bearing_before = (maneuver.bearing_before >= 180.0) + ? (maneuver.bearing_before - 180.0) + : (maneuver.bearing_before + 180.0); + result.values["from_bearing"] = + getMatchingDiscreteBearing(false, rotated_bearing_before, maneuver.entry_class, + maneuver.bearing_class.getAvailableBearings()); + result.values["to_bearing"] = + getMatchingDiscreteBearing(true, maneuver.bearing_after, maneuver.entry_class, + maneuver.bearing_class.getAvailableBearings()); + + result.values["connections"] = getConnections(maneuver.entry_class, maneuver.bearing_class); + return result; +} + // FIXME this actually needs to be configurable from the profiles std::string modeToString(const extractor::TravelMode mode) { @@ -150,6 +195,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) if (maneuver.waypoint_type == guidance::WaypointType::None) { step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type); + step_maneuver.values["intersection"] = detail::getIntersection(maneuver); } else step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type); @@ -169,6 +215,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) // actually compute the correct locations of the intersections if (!maneuver.intersections.empty() && maneuver.exit == 0) step_maneuver.values["exit"] = maneuver.intersections.size(); + return step_maneuver; } diff --git a/src/engine/guidance/assemble_steps.cpp b/src/engine/guidance/assemble_steps.cpp index 207a6d287..17b5211a4 100644 --- a/src/engine/guidance/assemble_steps.cpp +++ b/src/engine/guidance/assemble_steps.cpp @@ -37,20 +37,23 @@ StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instr pre_turn_bearing = util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate); } - return StepManeuver{ - std::move(turn_coordinate), - pre_turn_bearing, - post_turn_bearing, - std::move(instruction), - waypoint_type, - INVALID_EXIT_NR, - {} // no intermediate intersections - }; + return StepManeuver{std::move(turn_coordinate), + pre_turn_bearing, + post_turn_bearing, + std::move(instruction), + waypoint_type, + INVALID_EXIT_NR, + // BearingClass,EntryClass, and Intermediate intersections are unknown yet + {}, + {}, + {}}; } StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction, const LegGeometry &leg_geometry, - const std::size_t segment_index) + const std::size_t segment_index, + util::guidance::EntryClass entry_class, + util::guidance::BearingClass bearing_class) { auto turn_index = leg_geometry.BackIndex(segment_index); BOOST_ASSERT(turn_index > 0); @@ -66,15 +69,10 @@ StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instr const double post_turn_bearing = util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate); - return StepManeuver{ - std::move(turn_coordinate), - pre_turn_bearing, - post_turn_bearing, - std::move(instruction), - WaypointType::None, - INVALID_EXIT_NR, - {} // no intermediate intersections - }; + // add a step without intermediate intersections + return StepManeuver{std::move(turn_coordinate), pre_turn_bearing, post_turn_bearing, + std::move(instruction), WaypointType::None, INVALID_EXIT_NR, + std::move(entry_class), std::move(bearing_class), {}}; } } // ns detail } // ns engine diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index 18726d97a..0182be686 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -444,7 +444,8 @@ std::vector postProcess(std::vector steps) auto addIntersection = [](RouteStep into, const RouteStep &last_step, const RouteStep &intersection) { into.maneuver.intersections.push_back( - {last_step.duration, last_step.distance, intersection.maneuver.location}); + {last_step.duration, last_step.distance, intersection.maneuver.location, + intersection.maneuver.entry_class, intersection.maneuver.bearing_class}); return forwardInto(std::move(into), intersection); }; diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 51f67d510..c6abb2f1e 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -11,6 +11,7 @@ #include "extractor/suffix_table.hpp" #include "extractor/guidance/toolkit.hpp" +#include "extractor/guidance/turn_analysis.hpp" #include #include @@ -22,6 +23,7 @@ #include #include #include +#include namespace osrm { @@ -326,6 +328,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( guidance::TurnAnalysis turn_analysis(*m_node_based_graph, m_node_info_list, *m_restriction_map, m_barrier_nodes, m_compressed_edge_container, name_table, street_name_suffix_table); + + bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(), + std::numeric_limits::max()); + for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) { progress.PrintStatus(node_u); @@ -340,6 +346,40 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( auto possible_turns = turn_analysis.getTurns(node_u, edge_from_u); const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u); + + // the entry class depends on the turn, so we have to classify the interesction for + // every edge + const auto turn_classification = classifyIntersection( + node_v, turn_analysis.getIntersection(node_u, edge_from_u), *m_node_based_graph, + m_compressed_edge_container, m_node_info_list); + + const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) { + if (0 == entry_class_hash.count(entry_class)) + { + const auto id = static_cast(entry_class_hash.size()); + entry_class_hash[entry_class] = id; + return id; + } + else + { + return entry_class_hash.find(entry_class)->second; + } + }(turn_classification.first); + + const auto bearing_class_id = [&](const util::guidance::BearingClass bearing_class) { + if (0 == bearing_class_hash.count(bearing_class)) + { + const auto id = static_cast(bearing_class_hash.size()); + bearing_class_hash[bearing_class] = id; + return id; + } + else + { + return bearing_class_hash.find(bearing_class)->second; + } + }(turn_classification.second); + bearing_class_by_node_based_node[node_v] = bearing_class_id; + for (const auto turn : possible_turns) { const double turn_angle = turn.angle; @@ -373,7 +413,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_from_u)); original_edge_data_vector.emplace_back( m_compressed_edge_container.GetPositionForID(edge_from_u), edge_data1.name_id, - turn_instruction, edge_data1.travel_mode); + turn_instruction, entry_class_id, edge_data1.travel_mode); ++original_edges_counter; @@ -469,6 +509,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( } } + util::SimpleLogger().Write() << "Created " << entry_class_hash.size() << " entry classes and " + << bearing_class_hash.size() << " Bearing Classes"; + FlushVectorToStream(edge_data_file, original_edge_data_vector); // Finally jump back to the empty space at the beginning and write length prefix @@ -493,6 +536,38 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( << " turns over barriers"; } +std::vector EdgeBasedGraphFactory::GetBearingClasses() const +{ + std::vector result(bearing_class_hash.size()); + for (const auto &pair : bearing_class_hash) + { + 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.size()); + for (const auto &pair : entry_class_hash) + { + BOOST_ASSERT(pair.second < result.size()); + result[pair.second] = pair.first; + } + return result; +} + int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const { BOOST_ASSERT(lua_state != nullptr); diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index c744c38f4..c0579491c 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -9,20 +9,18 @@ #include "extractor/scripting_environment.hpp" #include "extractor/raster_source.hpp" +#include "util/graph_loader.hpp" #include "util/io.hpp" +#include "util/lua_util.hpp" #include "util/make_unique.hpp" +#include "util/name_table.hpp" #include "util/simple_logger.hpp" #include "util/timing_util.hpp" -#include "util/lua_util.hpp" -#include "util/graph_loader.hpp" -#include "util/name_table.hpp" -#include "util/typedefs.hpp" - -#include "util/static_graph.hpp" -#include "util/static_rtree.hpp" #include "extractor/compressed_edge_container.hpp" #include "extractor/restriction_map.hpp" +#include "util/static_graph.hpp" +#include "util/static_rtree.hpp" #include "extractor/tarjan_scc.hpp" @@ -41,14 +39,14 @@ #include #include +#include +#include #include #include #include #include #include #include -#include -#include namespace osrm { @@ -159,8 +157,7 @@ int Extractor::run() // parse OSM entities in parallel, store in resulting vectors tbb::parallel_for( tbb::blocked_range(0, osm_elements.size()), - [&](const tbb::blocked_range &range) - { + [&](const tbb::blocked_range &range) { ExtractionNode result_node; ExtractionWay result_way; auto &local_context = scripting_environment.GetContex(); @@ -269,10 +266,10 @@ int Extractor::run() std::vector node_is_startpoint; std::vector edge_based_node_weights; std::vector internal_to_external_node_map; - auto graph_size = BuildEdgeExpandedGraph(main_context.state, main_context.properties, - internal_to_external_node_map, - edge_based_node_list, node_is_startpoint, - edge_based_node_weights, edge_based_edge_list); + auto graph_size = BuildEdgeExpandedGraph( + main_context.state, main_context.properties, internal_to_external_node_map, + edge_based_node_list, node_is_startpoint, edge_based_node_weights, edge_based_edge_list, + config.intersection_class_data_output_path); auto number_of_node_based_nodes = graph_size.first; auto max_edge_id = graph_size.second; @@ -474,7 +471,8 @@ Extractor::BuildEdgeExpandedGraph(lua_State *lua_state, std::vector &node_based_edge_list, std::vector &node_is_startpoint, std::vector &edge_based_node_weights, - util::DeallocatingVector &edge_based_edge_list) + util::DeallocatingVector &edge_based_edge_list, + const std::string &intersection_class_output_file) { std::unordered_set barrier_nodes; std::unordered_set traffic_lights; @@ -508,6 +506,11 @@ Extractor::BuildEdgeExpandedGraph(lua_State *lua_state, auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID(); const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes(); + + WriteIntersectionClassificationData( + intersection_class_output_file, edge_based_graph_factory.GetBearingClassIds(), + edge_based_graph_factory.GetBearingClasses(), edge_based_graph_factory.GetEntryClasses()); + return std::make_pair(number_of_node_based_nodes, max_edge_id); } @@ -601,5 +604,40 @@ void Extractor::WriteEdgeBasedGraph( util::SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges"; } + +void Extractor::WriteIntersectionClassificationData( + const std::string &output_file_name, + const std::vector &node_based_intersection_classes, + const std::vector &bearing_classes, + const std::vector &entry_classes) const +{ + std::ofstream file_out_stream(output_file_name.c_str(), std::ios::binary); + if (!file_out_stream) + { + util::SimpleLogger().Write(logWARNING) << "Failed to open " << output_file_name + << " for writing"; + return; + } + + util::SimpleLogger().Write() << "Writing Intersection Classification Data"; + TIMER_START(write_edges); + util::writeFingerprint(file_out_stream); + util::serializeVector(file_out_stream, node_based_intersection_classes); + + static_assert(std::is_trivially_copyable::value, + "BearingClass Serialization requires trivial copyable bearing classes"); + + util::serializeVector(file_out_stream, bearing_classes); + + static_assert(std::is_trivially_copyable::value, + "EntryClass Serialization requires trivial copyable entry classes"); + + util::serializeVector(file_out_stream, entry_classes); + TIMER_STOP(write_edges); + util::SimpleLogger().Write() << "ok, after " << TIMER_SEC(write_edges) << "s for " + << node_based_intersection_classes.size() << " Indices into " + << bearing_classes.size() << " bearing classes and " + << entry_classes.size() << " entry classes"; +} } } diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index a573194ab..38359cdb4 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include using osrm::util::guidance::getTurnDirection; @@ -79,6 +81,11 @@ std::vector TurnAnalysis::getTurns(const NodeID from_nid, const E return turns; } +Intersection TurnAnalysis::getIntersection(const NodeID from_nid, const EdgeID via_eid) const +{ + return intersection_generator(from_nid, via_eid); +} + // Sets basic turn types as fallback for otherwise unhandled turns Intersection TurnAnalysis::setTurnTypes(const NodeID from_nid, const EdgeID, Intersection intersection) const diff --git a/src/extractor/guidance/turn_classification.cpp b/src/extractor/guidance/turn_classification.cpp new file mode 100644 index 000000000..8a69c4c7b --- /dev/null +++ b/src/extractor/guidance/turn_classification.cpp @@ -0,0 +1,97 @@ +#include "extractor/guidance/turn_classification.hpp" + +#include "util/simple_logger.hpp" + +namespace osrm +{ +namespace extractor +{ +namespace guidance +{ + +struct TurnPossibility +{ + TurnPossibility(bool entry_allowed, double bearing) + : entry_allowed(entry_allowed), bearing(std::move(bearing)) + { + } + + TurnPossibility() : entry_allowed(false), bearing(0) {} + + bool entry_allowed; + double bearing; +}; + +std::pair +classifyIntersection(NodeID nid, + const Intersection &intersection, + const util::NodeBasedDynamicGraph &node_based_graph, + const extractor::CompressedEdgeContainer &compressed_geometries, + const std::vector &query_nodes) +{ + + std::vector turns; + + const auto node_coordinate = util::Coordinate(query_nodes[nid].lon, query_nodes[nid].lat); + + // generate a list of all turn angles between a base edge, the node and a current edge + for (const auto &road : intersection) + { + const auto eid = road.turn.eid; + const auto edge_coordinate = getRepresentativeCoordinate( + nid, node_based_graph.GetTarget(eid), eid, false, compressed_geometries, query_nodes); + + const double bearing = + util::coordinate_calculation::bearing(node_coordinate, edge_coordinate); + turns.push_back({road.entry_allowed, bearing}); + } + + if (turns.empty()) + return {}; + + std::sort(turns.begin(), turns.end(), + [](const TurnPossibility left, const TurnPossibility right) { + return left.bearing < right.bearing; + }); + + util::guidance::EntryClass entry_class; + util::guidance::BearingClass bearing_class; + + std::size_t turn_index = 0; + for (std::size_t i = 0; i < turns.size(); ++i) + { + if (turns[i].entry_allowed) + entry_class.activate(turn_index); + if (bearing_class.addContinuous(turns[i].bearing)) + ++turn_index; + } + + if (turn_index != turns.size()) + { + util::SimpleLogger().Write(logDEBUG) + << "Failed to provide full turn list for intersection: " << turn_index << " roads of " + << turns.size() << " mapped."; + for (auto turn : turns) + std::cout << " " << (int)turn.bearing << " (" + << (int)util::guidance::BearingClass::discreteBearingID(turn.bearing) << ")"; + std::cout << std::endl; + for (const auto &road : intersection) + { + const auto eid = road.turn.eid; + const auto edge_coordinate = + getRepresentativeCoordinate(nid, node_based_graph.GetTarget(eid), eid, false, + compressed_geometries, query_nodes); + + const double bearing = + util::coordinate_calculation::bearing(node_coordinate, edge_coordinate); + std::cout << " " << bearing; + } + std::cout << std::endl; + } + + return std::make_pair(entry_class, bearing_class); +} + +} // namespace guidance +} // namespace extractor +} // namespace osrm diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index 43967dc37..e0c016a9d 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -1,24 +1,25 @@ -#include "extractor/original_edge_data.hpp" -#include "util/range_table.hpp" #include "contractor/query_edge.hpp" -#include "extractor/query_node.hpp" -#include "extractor/profile_properties.hpp" +#include "engine/datafacade/datafacade_base.hpp" #include "extractor/compressed_edge_container.hpp" +#include "extractor/guidance/turn_instruction.hpp" +#include "extractor/original_edge_data.hpp" +#include "extractor/profile_properties.hpp" +#include "extractor/query_node.hpp" +#include "extractor/travel_mode.hpp" +#include "storage/shared_barriers.hpp" +#include "storage/shared_datatype.hpp" +#include "storage/shared_memory.hpp" +#include "storage/storage.hpp" +#include "util/coordinate.hpp" +#include "util/exception.hpp" +#include "util/fingerprint.hpp" +#include "util/io.hpp" +#include "util/range_table.hpp" #include "util/shared_memory_vector_wrapper.hpp" +#include "util/simple_logger.hpp" #include "util/static_graph.hpp" #include "util/static_rtree.hpp" -#include "engine/datafacade/datafacade_base.hpp" -#include "extractor/travel_mode.hpp" -#include "extractor/guidance/turn_instruction.hpp" -#include "storage/storage.hpp" -#include "storage/shared_datatype.hpp" -#include "storage/shared_barriers.hpp" -#include "storage/shared_memory.hpp" -#include "util/fingerprint.hpp" -#include "util/exception.hpp" -#include "util/simple_logger.hpp" #include "util/typedefs.hpp" -#include "util/coordinate.hpp" #ifdef __linux__ #include @@ -49,8 +50,7 @@ void deleteRegion(const SharedDataType region) { if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region)) { - const std::string name = [&] - { + const std::string name = [&] { switch (region) { case CURRENT_REGIONS: @@ -105,20 +105,14 @@ int Storage::Run() // determine segment to use bool segment2_in_use = SharedMemory::RegionExists(LAYOUT_2); - const storage::SharedDataType layout_region = [&] - { + const storage::SharedDataType layout_region = [&] { return segment2_in_use ? LAYOUT_1 : LAYOUT_2; }(); - const storage::SharedDataType data_region = [&] - { - return segment2_in_use ? DATA_1 : DATA_2; - }(); - const storage::SharedDataType previous_layout_region = [&] - { + const storage::SharedDataType data_region = [&] { return segment2_in_use ? DATA_1 : DATA_2; }(); + const storage::SharedDataType previous_layout_region = [&] { return segment2_in_use ? LAYOUT_2 : LAYOUT_1; }(); - const storage::SharedDataType previous_data_region = [&] - { + const storage::SharedDataType previous_data_region = [&] { return segment2_in_use ? DATA_2 : DATA_1; }(); @@ -136,7 +130,8 @@ int Storage::Run() boost::filesystem::ifstream name_stream(config.names_data_path, std::ios::binary); if (!name_stream) { - throw util::exception("Could not open " + config.names_data_path.string() + " for reading."); + throw util::exception("Could not open " + config.names_data_path.string() + + " for reading."); } unsigned name_blocks = 0; name_stream.read((char *)&name_blocks, sizeof(unsigned)); @@ -154,7 +149,8 @@ int Storage::Run() boost::filesystem::ifstream edges_input_stream(config.edges_data_path, std::ios::binary); if (!edges_input_stream) { - throw util::exception("Could not open " + config.edges_data_path.string() + " for reading."); + throw util::exception("Could not open " + config.edges_data_path.string() + + " for reading."); } unsigned number_of_original_edges = 0; edges_input_stream.read((char *)&number_of_original_edges, sizeof(unsigned)); @@ -168,6 +164,8 @@ int Storage::Run() number_of_original_edges); shared_layout_ptr->SetBlockSize( SharedDataLayout::TURN_INSTRUCTION, number_of_original_edges); + shared_layout_ptr->SetBlockSize(SharedDataLayout::ENTRY_CLASSID, + number_of_original_edges); boost::filesystem::ifstream hsgr_input_stream(config.hsgr_data_path, std::ios::binary); if (!hsgr_input_stream) @@ -250,7 +248,8 @@ int Storage::Run() boost::filesystem::ifstream geometry_input_stream(config.geometries_path, std::ios::binary); if (!geometry_input_stream) { - throw util::exception("Could not open " + config.geometries_path.string() + " for reading."); + throw util::exception("Could not open " + config.geometries_path.string() + + " for reading."); } unsigned number_of_geometries_indices = 0; unsigned number_of_compressed_geometries = 0; @@ -270,7 +269,8 @@ int Storage::Run() std::ios::binary); if (!geometry_datasource_input_stream) { - throw util::exception("Could not open " + config.datasource_indexes_path.string() + " for reading."); + throw util::exception("Could not open " + config.datasource_indexes_path.string() + + " for reading."); } std::size_t number_of_compressed_datasources = 0; if (geometry_datasource_input_stream) @@ -287,7 +287,8 @@ int Storage::Run() std::ios::binary); if (!datasource_names_input_stream) { - throw util::exception("Could not open " + config.datasource_names_path.string() + " for reading."); + throw util::exception("Could not open " + config.datasource_names_path.string() + + " for reading."); } std::vector m_datasource_name_data; std::vector m_datasource_name_offsets; @@ -331,7 +332,8 @@ int Storage::Run() file_index_path_ptr + shared_layout_ptr->GetBlockSize(SharedDataLayout::FILE_INDEX_PATH), 0); - std::copy(absolute_file_index_path.string().begin(), absolute_file_index_path.string().end(), file_index_path_ptr); + std::copy(absolute_file_index_path.string().begin(), absolute_file_index_path.string().end(), + file_index_path_ptr); // Loading street names unsigned *name_offsets_ptr = shared_layout_ptr->GetBlockPtr( @@ -382,6 +384,9 @@ int Storage::Run() shared_layout_ptr->GetBlockPtr( shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION); + EntryClassID *entry_class_id_ptr = shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::ENTRY_CLASSID); + extractor::OriginalEdgeData current_edge_data; for (unsigned i = 0; i < number_of_original_edges; ++i) { @@ -390,6 +395,7 @@ int Storage::Run() name_id_ptr[i] = current_edge_data.name_id; travel_mode_ptr[i] = current_edge_data.travel_mode; turn_instructions_ptr[i] = current_edge_data.turn_instruction; + entry_class_id_ptr[i] = current_edge_data.entry_classid; } edges_input_stream.close(); @@ -503,8 +509,7 @@ int Storage::Run() { const unsigned bucket = i / 32; const unsigned offset = i % 32; - const unsigned value = [&] - { + const unsigned value = [&] { unsigned return_value = 0; if (0 != offset) { @@ -539,13 +544,16 @@ int Storage::Run() hsgr_input_stream.close(); // load profile properties - auto profile_properties_ptr = shared_layout_ptr->GetBlockPtr(shared_memory_ptr, SharedDataLayout::PROPERTIES); + auto profile_properties_ptr = + shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::PROPERTIES); boost::filesystem::ifstream profile_properties_stream(config.properties_path); if (!profile_properties_stream) { util::exception("Could not open " + config.properties_path.string() + " for reading!"); } - profile_properties_stream.read(reinterpret_cast(profile_properties_ptr), sizeof(extractor::ProfileProperties)); + profile_properties_stream.read(reinterpret_cast(profile_properties_ptr), + sizeof(extractor::ProfileProperties)); // acquire lock SharedMemory *data_type_memory = @@ -562,6 +570,43 @@ int Storage::Run() barrier.no_running_queries_condition.wait(query_lock); } + // load intersection classes + { + boost::filesystem::ifstream intersection_stream(config.intersection_class_path, + std::ios::binary); + if (!util::readAndCheckFingerprint(intersection_stream)) + { + util::SimpleLogger().Write(logWARNING) + << "Fingerprint does not match or reading failed"; + } + + std::vector bearing_class_id_table; + util::deserializeVector(intersection_stream, bearing_class_id_table); + shared_layout_ptr->SetBlockSize(SharedDataLayout::BEARING_CLASSID, + bearing_class_id_table.size()); + auto bearing_id_ptr = shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::BEARING_CLASSID); + std::copy(bearing_class_id_table.begin(), bearing_class_id_table.end(), bearing_id_ptr); + + auto bearing_class_ptr = + shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::BEARING_CLASS); + std::vector bearing_class_table; + util::deserializeVector(intersection_stream, bearing_class_table); + shared_layout_ptr->SetBlockSize( + SharedDataLayout::BEARING_CLASS, bearing_class_table.size()); + std::copy(bearing_class_table.begin(), bearing_class_table.end(), bearing_class_ptr); + + auto entry_class_ptr = + shared_layout_ptr->GetBlockPtr( + shared_memory_ptr, SharedDataLayout::ENTRY_CLASS); + std::vector entry_class_table; + util::deserializeVector(intersection_stream, entry_class_table); + shared_layout_ptr->SetBlockSize( + SharedDataLayout::ENTRY_CLASS, entry_class_table.size()); + std::copy(entry_class_table.begin(), entry_class_table.end(), entry_class_ptr); + } + data_timestamp_ptr->layout = layout_region; data_timestamp_ptr->data = data_region; data_timestamp_ptr->timestamp += 1; diff --git a/src/storage/storage_config.cpp b/src/storage/storage_config.cpp index 6ade34a0c..768473b26 100644 --- a/src/storage/storage_config.cpp +++ b/src/storage/storage_config.cpp @@ -14,8 +14,8 @@ StorageConfig::StorageConfig(const boost::filesystem::path &base) geometries_path{base.string() + ".geometry"}, timestamp_path{base.string() + ".timestamp"}, datasource_names_path{base.string() + ".datasource_names"}, datasource_indexes_path{base.string() + ".datasource_indexes"}, - names_data_path{base.string() + ".names"}, - properties_path{base.string() + ".properties"} + names_data_path{base.string() + ".names"}, properties_path{base.string() + ".properties"}, + intersection_class_path{base.string() + ".icd"} { } @@ -32,7 +32,8 @@ bool StorageConfig::IsValid() const boost::filesystem::is_regular_file(datasource_names_path) && boost::filesystem::is_regular_file(datasource_indexes_path) && boost::filesystem::is_regular_file(names_data_path) && - boost::filesystem::is_regular_file(properties_path); + boost::filesystem::is_regular_file(properties_path) && + boost::filesystem::is_regular_file(intersection_class_path); } } } diff --git a/src/util/guidance/bearing_class.cpp b/src/util/guidance/bearing_class.cpp new file mode 100644 index 000000000..b2d7892a1 --- /dev/null +++ b/src/util/guidance/bearing_class.cpp @@ -0,0 +1,68 @@ +#include "extractor/guidance/discrete_angle.hpp" +#include "util/guidance/bearing_class.hpp" + +#include + +namespace osrm +{ +namespace util +{ +namespace guidance +{ + +static_assert( + 360 / BearingClass::discrete_angle_step_size <= 8 * sizeof(BearingClass::FlagBaseType), + "The number of expressable bearings does not fit into the datatype used for storage."); + +std::uint8_t BearingClass::discreteBearingID(double angle) +{ + BOOST_ASSERT(angle >= 0. && angle <= 360.); + // shift angle by half the step size to have the class be located around the center + angle = (angle + 0.5 * BearingClass::discrete_angle_step_size); + if (angle > 360) + angle -= 360; + + return std::uint8_t(angle / BearingClass::discrete_angle_step_size); +} + +BearingClass::BearingClass() : available_bearings_mask(0) {} + +bool BearingClass::operator==(const BearingClass &other) const +{ + return other.available_bearings_mask == available_bearings_mask; +} + +bool BearingClass::operator<(const BearingClass &other) const +{ + return available_bearings_mask < other.available_bearings_mask; +} + +bool BearingClass::addContinuous(const double angle) +{ + return addDiscreteID(discreteBearingID(angle)); +} + +bool BearingClass::addDiscreteID(const std::uint8_t discrete_id) +{ + const auto mask = (1 << discrete_id); + const auto is_new = (0 == (available_bearings_mask & mask)); + available_bearings_mask |= mask; + return is_new; +} + +std::vector BearingClass::getAvailableBearings() const +{ + std::vector result; + // account for some basic inaccuracries of double + for (std::size_t discrete_id = 0; discrete_id * discrete_angle_step_size <= 361; ++discrete_id) + { + // ervery set bit indicates a bearing + if (available_bearings_mask & (1 << discrete_id)) + result.push_back(discrete_id * discrete_angle_step_size); + } + return result; +} + +} // namespace guidance +} // namespace extractor +} // namespace osrm diff --git a/src/util/guidance/entry_class.cpp b/src/util/guidance/entry_class.cpp new file mode 100644 index 000000000..9140eb020 --- /dev/null +++ b/src/util/guidance/entry_class.cpp @@ -0,0 +1,38 @@ +#include "util/guidance/entry_class.hpp" + +#include + +namespace osrm +{ +namespace util +{ +namespace guidance +{ + +EntryClass::EntryClass() : enabled_entries_flags(0) {} + +void EntryClass::activate(std::uint32_t index) +{ + BOOST_ASSERT(index < 8 * sizeof(FlagBaseType)); + enabled_entries_flags |= (1 << index); +} + +bool EntryClass::allowsEntry(std::uint32_t index) const +{ + BOOST_ASSERT(index < 8 * sizeof(FlagBaseType)); + return 0 != (enabled_entries_flags & (1 << index)); +} + +bool EntryClass::operator==(const EntryClass &other) const +{ + return enabled_entries_flags == other.enabled_entries_flags; +} + +bool EntryClass::operator<(const EntryClass &other) const +{ + return enabled_entries_flags < other.enabled_entries_flags; +} + +} // namespace guidance +} // namespace extractor +} // namespace osrm