diff --git a/CHANGELOG.md b/CHANGELOG.md index 846ec5373..bd4c11ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Exposes `use_threads_number=Number` parameter of `EngineConfig` to limit a number of threads in a TBB internal pool - Internals - MLD uses a unidirectional Dijkstra for 1-to-N and N-to-1 matrices + - BREAKING: Internal file formats have changed, requiring a new pre-processing run - Guidance - Fixed some cases of sliproads pre-processing (https://github.com/Project-OSRM/osrm-backend/issues/4348) - don't suppress name announcements via sliproad handler diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index cc2aaf18b..795b1ca3b 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -12,6 +12,7 @@ #include "customizer/edge_based_graph.hpp" #include "extractor/datasources.hpp" +#include "extractor/edge_based_node.hpp" #include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_lane_types.hpp" #include "extractor/intersection_bearings_container.hpp" @@ -337,43 +338,21 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade void InitializeEdgeBasedNodeDataInformationPointers(storage::DataLayout &layout, char *memory_ptr) { - const auto via_geometry_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::GEOMETRY_ID_LIST); - util::vector_view geometry_ids( - via_geometry_list_ptr, layout.num_entries[storage::DataLayout::GEOMETRY_ID_LIST]); + const auto edge_based_node_list_ptr = layout.GetBlockPtr( + memory_ptr, storage::DataLayout::EDGE_BASED_NODE_DATA_LIST); + util::vector_view edge_based_node_data_list( + edge_based_node_list_ptr, + layout.num_entries[storage::DataLayout::EDGE_BASED_NODE_DATA_LIST]); - const auto name_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::NAME_ID_LIST); - util::vector_view name_ids(name_id_list_ptr, - layout.num_entries[storage::DataLayout::NAME_ID_LIST]); + const auto annotation_data_list_ptr = + layout.GetBlockPtr( + memory_ptr, storage::DataLayout::ANNOTATION_DATA_LIST); + util::vector_view annotation_data( + annotation_data_list_ptr, + layout.num_entries[storage::DataLayout::ANNOTATION_DATA_LIST]); - const auto component_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::COMPONENT_ID_LIST); - util::vector_view component_ids( - component_id_list_ptr, layout.num_entries[storage::DataLayout::COMPONENT_ID_LIST]); - - const auto travel_mode_list_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::TRAVEL_MODE_LIST); - util::vector_view travel_modes( - travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]); - - const auto classes_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::CLASSES_LIST); - util::vector_view classes( - classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]); - - auto is_left_hand_driving_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST); - util::vector_view is_left_hand_driving( - is_left_hand_driving_ptr, - layout.num_entries[storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST]); - - edge_based_node_data = extractor::EdgeBasedNodeDataView(std::move(geometry_ids), - std::move(name_ids), - std::move(component_ids), - std::move(travel_modes), - std::move(classes), - std::move(is_left_hand_driving)); + edge_based_node_data = extractor::EdgeBasedNodeDataView( + std::move(edge_based_node_data_list), std::move(annotation_data)); } void InitializeEdgeInformationPointers(storage::DataLayout &layout, char *memory_ptr) @@ -465,7 +444,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade geometries_index_ptr, data_layout.num_entries[storage::DataLayout::GEOMETRIES_INDEX]); auto num_entries = data_layout.num_entries[storage::DataLayout::GEOMETRIES_NODE_LIST]; - auto geometries_node_list_ptr = data_layout.GetBlockPtr( memory_block, storage::DataLayout::GEOMETRIES_NODE_LIST); util::vector_view geometry_node_list(geometries_node_list_ptr, num_entries); diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 8abf3efbe..9f24bee75 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -14,8 +14,6 @@ #include "extractor/nbg_to_ebg.hpp" #include "extractor/node_data_container.hpp" #include "extractor/original_edge_data.hpp" -#include "extractor/packed_osm_ids.hpp" -#include "extractor/profile_properties.hpp" #include "extractor/query_node.hpp" #include "extractor/restriction_index.hpp" #include "extractor/way_restriction_map.hpp" @@ -26,7 +24,6 @@ #include "util/guidance/entry_class.hpp" #include "util/name_table.hpp" #include "util/node_based_graph.hpp" -#include "util/packed_vector.hpp" #include "util/typedefs.hpp" #include "storage/io.hpp" @@ -71,13 +68,12 @@ class EdgeBasedGraphFactory EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete; EdgeBasedGraphFactory &operator=(const EdgeBasedGraphFactory &) = delete; - explicit EdgeBasedGraphFactory(std::shared_ptr node_based_graph, - CompressedEdgeContainer &compressed_edge_container, + explicit EdgeBasedGraphFactory(const util::NodeBasedDynamicGraph &node_based_graph, + EdgeBasedNodeDataContainer &node_data_container, + const CompressedEdgeContainer &compressed_edge_container, const std::unordered_set &barrier_nodes, const std::unordered_set &traffic_lights, const std::vector &coordinates, - const extractor::PackedOSMIDs &osm_node_ids, - ProfileProperties profile_properties, const util::NameTable &name_table, guidance::LaneDescriptionMap &lane_description_map); @@ -95,7 +91,6 @@ class EdgeBasedGraphFactory // The following get access functions destroy the content in the factory void GetEdgeBasedEdges(util::DeallocatingVector &edges); - void GetEdgeBasedNodes(EdgeBasedNodeDataContainer &data_container); void GetEdgeBasedNodeSegments(std::vector &nodes); void GetStartPointMarkers(std::vector &node_is_startpoint); void GetEdgeBasedNodeWeights(std::vector &output_node_weights); @@ -144,7 +139,7 @@ class EdgeBasedGraphFactory //! list of edge based nodes (compressed segments) std::vector m_edge_based_node_segments; - EdgeBasedNodeDataContainer m_edge_based_node_container; + EdgeBasedNodeDataContainer &m_edge_based_node_container; util::DeallocatingVector m_edge_based_edge_list; // The number of edge-based nodes is mostly made up out of the edges in the node-based graph. @@ -155,19 +150,20 @@ class EdgeBasedGraphFactory std::uint64_t m_number_of_edge_based_nodes; const std::vector &m_coordinates; - const extractor::PackedOSMIDs &m_osm_node_ids; - std::shared_ptr m_node_based_graph; + const util::NodeBasedDynamicGraph &m_node_based_graph; const std::unordered_set &m_barrier_nodes; const std::unordered_set &m_traffic_lights; - CompressedEdgeContainer &m_compressed_edge_container; - - ProfileProperties profile_properties; + const CompressedEdgeContainer &m_compressed_edge_container; const util::NameTable &name_table; guidance::LaneDescriptionMap &lane_description_map; - unsigned RenumberEdges(); + // 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 + // graph and create a mapping from edges (node-based) to nodes (edge-based). The mapping is + // essentially a prefix-sum over all previous non-reversed edges of the node-based graph. + unsigned LabelEdgeBasedNodes(); // During the generation of the edge-expanded nodes, we need to also generate duplicates that // represent state during via-way restrictions (see @@ -194,6 +190,8 @@ class EdgeBasedGraphFactory 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; diff --git a/include/extractor/edge_based_node.hpp b/include/extractor/edge_based_node.hpp new file mode 100644 index 000000000..011f3b338 --- /dev/null +++ b/include/extractor/edge_based_node.hpp @@ -0,0 +1,21 @@ +#ifndef OSRM_EXTRACTOR_EDGE_BASED_NODE_HPP_ +#define OSRM_EXTRACTOR_EDGE_BASED_NODE_HPP_ + +#include "util/typedefs.hpp" + +namespace osrm +{ +namespace extractor +{ + +struct EdgeBasedNode +{ + GeometryID geometry_id; + ComponentID component_id; + AnnotationID annotation_id; +}; + +} // namespace extractor +} // namespace osrm + +#endif // OSRM_EXTRACTOR_EDGE_BASED_NODE_HPP_ diff --git a/include/extractor/extraction_containers.hpp b/include/extractor/extraction_containers.hpp index 0fb3f5a7b..55c6bd498 100644 --- a/include/extractor/extraction_containers.hpp +++ b/include/extractor/extraction_containers.hpp @@ -28,12 +28,14 @@ class ExtractionContainers void WriteNodes(storage::io::FileWriter &file_out) const; void WriteEdges(storage::io::FileWriter &file_out) const; + void WriteMetadata(storage::io::FileWriter &file_out) const; void WriteCharData(const std::string &file_name); public: using NodeIDVector = std::vector; using NodeVector = std::vector; using EdgeVector = std::vector; + using AnnotationDataVector = std::vector; using WayIDStartEndVector = std::vector; using NameCharData = std::vector; using NameOffsets = std::vector; @@ -43,6 +45,7 @@ class ExtractionContainers NodeIDVector used_node_id_list; NodeVector all_nodes_list; EdgeVector all_edges_list; + AnnotationDataVector all_edges_annotation_data_list; NameCharData name_char_data; NameOffsets name_offsets; // an adjacency array containing all turn lane masks diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index 13a46abb7..c28b82a3d 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "extractor/edge_based_graph_factory.hpp" #include "extractor/extractor_config.hpp" #include "extractor/graph_compressor.hpp" +#include "extractor/packed_osm_ids.hpp" #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" @@ -61,19 +62,27 @@ class Extractor std::vector> ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads); - std::pair - BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, - std::vector &coordinates, - extractor::PackedOSMIDs &osm_node_ids, - EdgeBasedNodeDataContainer &edge_based_nodes_container, - 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, - std::vector &turn_restrictions, - std::vector &conditional_turn_restrictions, - guidance::LaneDescriptionMap &turn_lane_map); + EdgeID BuildEdgeExpandedGraph( + // input data + const util::NodeBasedDynamicGraph &node_based_graph, + const std::vector &coordinates, + const CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const std::unordered_set &traffic_lights, + const std::vector &turn_restrictions, + const std::vector &conditional_turn_restrictions, + // might have to be updated to add new lane combinations + guidance::LaneDescriptionMap &turn_lane_map, + // for calculating turn penalties + ScriptingEnvironment &scripting_environment, + // output data + EdgeBasedNodeDataContainer &edge_based_nodes_container, + 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); + void FindComponents(unsigned max_edge_id, const util::DeallocatingVector &input_edge_list, const std::vector &input_node_segments, @@ -82,11 +91,6 @@ class Extractor std::vector node_is_startpoint, const std::vector &coordinates); std::shared_ptr LoadRestrictionMap(); - std::shared_ptr - LoadNodeBasedGraph(std::unordered_set &barrier_nodes, - std::unordered_set &traffic_lights, - std::vector &coordinates, - extractor::PackedOSMIDs &osm_node_ids); // Writes compressed node based graph and its embedding into a file for osrm-partition to use. static void WriteCompressedNodeBasedGraph(const std::string &path, diff --git a/include/extractor/files.hpp b/include/extractor/files.hpp index e28740110..f6d6e5f12 100644 --- a/include/extractor/files.hpp +++ b/include/extractor/files.hpp @@ -78,27 +78,27 @@ inline void writeProfileProperties(const boost::filesystem::path &path, template void writeEdgeBasedGraph(const boost::filesystem::path &path, - EdgeID const max_edge_id, + EdgeID const number_of_edge_based_nodes, const EdgeBasedEdgeVector &edge_based_edge_list) { static_assert(std::is_same::value, ""); storage::io::FileWriter writer(path, storage::io::FileWriter::GenerateFingerprint); - writer.WriteElementCount64(max_edge_id); + writer.WriteElementCount64(number_of_edge_based_nodes); storage::serialization::write(writer, edge_based_edge_list); } template void readEdgeBasedGraph(const boost::filesystem::path &path, - EdgeID &max_edge_id, + EdgeID &number_of_edge_based_nodes, EdgeBasedEdgeVector &edge_based_edge_list) { static_assert(std::is_same::value, ""); storage::io::FileReader reader(path, storage::io::FileReader::VerifyFingerprint); - max_edge_id = reader.ReadElementCount64(); + number_of_edge_based_nodes = reader.ReadElementCount64(); storage::serialization::read(reader, edge_based_edge_list); } diff --git a/include/extractor/graph_compressor.hpp b/include/extractor/graph_compressor.hpp index 2cb6c1f8a..e2418badf 100644 --- a/include/extractor/graph_compressor.hpp +++ b/include/extractor/graph_compressor.hpp @@ -29,6 +29,7 @@ class GraphCompressor std::vector &turn_restrictions, std::vector &conditional_turn_restrictions, util::NodeBasedDynamicGraph &graph, + const std::vector &node_data_container, CompressedEdgeContainer &geometry_compressor); private: diff --git a/include/extractor/guidance/coordinate_extractor.hpp b/include/extractor/guidance/coordinate_extractor.hpp index 808f169cb..9ba96e7f6 100644 --- a/include/extractor/guidance/coordinate_extractor.hpp +++ b/include/extractor/guidance/coordinate_extractor.hpp @@ -225,7 +225,7 @@ class CoordinateExtractor const std::vector &segment_distances, const double segment_length, const double considered_lane_width, - const util::NodeBasedEdgeData &edge_data) const; + const extractor::NodeBasedEdgeClassification &edge_data) const; /* * If the very first coordinate is within lane offsets and the rest offers a near straight line, diff --git a/include/extractor/guidance/driveway_handler.hpp b/include/extractor/guidance/driveway_handler.hpp index 1bbdb81d3..7fb1a24c5 100644 --- a/include/extractor/guidance/driveway_handler.hpp +++ b/include/extractor/guidance/driveway_handler.hpp @@ -16,6 +16,7 @@ class DrivewayHandler final : public IntersectionHandler public: DrivewayHandler(const IntersectionGenerator &intersection_generator, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table); diff --git a/include/extractor/guidance/intersection_generator.hpp b/include/extractor/guidance/intersection_generator.hpp index d012c81d8..e0f8c671b 100644 --- a/include/extractor/guidance/intersection_generator.hpp +++ b/include/extractor/guidance/intersection_generator.hpp @@ -38,6 +38,7 @@ class IntersectionGenerator { public: IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, const std::vector &coordinates, @@ -110,6 +111,7 @@ class IntersectionGenerator private: const util::NodeBasedDynamicGraph &node_based_graph; + const EdgeBasedNodeDataContainer &node_data_container; const RestrictionMap &restriction_map; const std::unordered_set &barrier_nodes; const std::vector &coordinates; diff --git a/include/extractor/guidance/intersection_handler.hpp b/include/extractor/guidance/intersection_handler.hpp index 69ce1ef34..9c63825c9 100644 --- a/include/extractor/guidance/intersection_handler.hpp +++ b/include/extractor/guidance/intersection_handler.hpp @@ -33,6 +33,7 @@ class IntersectionHandler { public: IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, @@ -50,6 +51,7 @@ class IntersectionHandler protected: const util::NodeBasedDynamicGraph &node_based_graph; + const EdgeBasedNodeDataContainer &node_data_container; const std::vector &coordinates; const util::NameTable &name_table; const SuffixTable &street_name_suffix_table; @@ -124,7 +126,6 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const { using Road = typename IntersectionType::value_type; - using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData; using osrm::util::angularDeviation; // no obvious road @@ -135,7 +136,8 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, if (intersection.size() == 2) return 1; - const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge); + const auto &in_way_edge = node_based_graph.GetEdgeData(via_edge); + const auto &in_way_data = node_data_container.GetAnnotation(in_way_edge.annotation_data); // the strategy for picking the most obvious turn involves deciding between // an overall best candidate and a best candidate that shares the same name @@ -146,35 +148,35 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, double best_continue_deviation = 180; /* helper functions */ - const auto IsContinueRoad = [&](const EdgeData &way_data) { + const auto IsContinueRoad = [&](const NodeBasedEdgeAnnotation &way_data) { return !util::guidance::requiresNameAnnounced( in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table); }; - auto sameOrHigherPriority = [&in_way_data](const auto &way_data) { - return way_data.road_classification.GetPriority() <= - in_way_data.road_classification.GetPriority(); + auto sameOrHigherPriority = [&](const auto &way_data) { + return way_data.flags.road_classification.GetPriority() <= + in_way_edge.flags.road_classification.GetPriority(); }; auto IsLowPriority = [](const auto &way_data) { - return way_data.road_classification.IsLowPriorityRoadClass(); + return way_data.flags.road_classification.IsLowPriorityRoadClass(); }; // These two Compare functions are used for sifting out best option and continue // candidates by evaluating all the ways in an intersection by what they share // with the in way. Ideal candidates are of similar road class with the in way // and are require relatively straight turns. const auto RoadCompare = [&](const auto &lhs, const auto &rhs) { - const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid); - const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid); + const auto &lhs_edge = node_based_graph.GetEdgeData(lhs.eid); + const auto &rhs_edge = node_based_graph.GetEdgeData(rhs.eid); const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE); const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE); const bool rhs_same_classification = - rhs_data.road_classification == in_way_data.road_classification; + rhs_edge.flags.road_classification == in_way_edge.flags.road_classification; const bool lhs_same_classification = - lhs_data.road_classification == in_way_data.road_classification; - const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data); - const bool rhs_low_priority = IsLowPriority(rhs_data); - const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data); - const bool lhs_low_priority = IsLowPriority(lhs_data); + lhs_edge.flags.road_classification == in_way_edge.flags.road_classification; + const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_edge); + const bool rhs_low_priority = IsLowPriority(rhs_edge); + const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_edge); + const bool lhs_low_priority = IsLowPriority(lhs_edge); auto left_tie = std::tie(lhs.entry_allowed, lhs_same_or_higher_priority, rhs_low_priority, @@ -188,8 +190,10 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, return left_tie > right_tie; }; const auto RoadCompareSameName = [&](const auto &lhs, const auto &rhs) { - const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid); - const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid); + const auto &lhs_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(lhs.eid).annotation_data); + const auto &rhs_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(rhs.eid).annotation_data); const auto lhs_continues = IsContinueRoad(lhs_data); const auto rhs_continues = IsContinueRoad(rhs_data); const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues); @@ -204,12 +208,14 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, best_option = std::distance(begin(intersection), best_option_it); best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE); - const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid); + const auto &best_option_edge = node_based_graph.GetEdgeData(intersection[best_option].eid); + const auto &best_option_data = + node_data_container.GetAnnotation(best_option_edge.annotation_data); // Unless the in way is also low priority, it is generally undesirable to // indicate that a low priority road is obvious - if (IsLowPriority(best_option_data) && - best_option_data.road_classification != in_way_data.road_classification) + if (IsLowPriority(best_option_edge) && + best_option_edge.flags.road_classification != in_way_edge.flags.road_classification) { best_option = 0; best_option_deviation = 180; @@ -219,13 +225,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE); if (straightest != best_option_it) { - const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid); + const auto &straightest_edge = node_based_graph.GetEdgeData(straightest->eid); double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE); const auto deviation_diff = std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE; - const auto not_ramp_class = !straightest_data.road_classification.IsRampClass(); - const auto not_link_class = !straightest_data.road_classification.IsLinkClass(); - if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class && + const auto not_ramp_class = !straightest_edge.flags.road_classification.IsRampClass(); + const auto not_link_class = !straightest_edge.flags.road_classification.IsLinkClass(); + if (deviation_diff && !IsLowPriority(straightest_edge) && not_ramp_class && not_link_class && !IsContinueRoad(best_option_data)) { best_option = std::distance(begin(intersection), straightest); @@ -240,7 +246,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, auto best_continue_it = std::min_element(begin(intersection), end(intersection), RoadCompareSameName); - const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid); + const auto best_continue_edge = node_based_graph.GetEdgeData(best_continue_it->eid); + const auto best_continue_data = + node_data_container.GetAnnotation(best_continue_edge.annotation_data); if (IsContinueRoad(best_continue_data) || (in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID)) { @@ -252,8 +260,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, // if the best angle is going straight but the road is turning, declare no obvious turn if (0 != best_continue && best_option != best_continue && best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION && - node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification == - best_option_data.road_classification) + best_continue_edge.flags.road_classification == best_option_edge.flags.road_classification) { return 0; } @@ -262,17 +269,21 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, // continue instruction because they share a name with the approaching way const std::int64_t continue_count = count_if(++begin(intersection), end(intersection), [&](const auto &way) { - return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)); + return IsContinueRoad(node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(way.eid).annotation_data)); }); const std::int64_t continue_count_valid = count_if(++begin(intersection), end(intersection), [&](const auto &way) { - return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed; + return IsContinueRoad(node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(way.eid).annotation_data)) && + way.entry_allowed; }); // checks if continue candidates are sharp turns const bool all_continues_are_narrow = [&]() { return std::count_if(begin(intersection), end(intersection), [&](const Road &road) { - const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid); + const auto &road_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(road.eid).annotation_data); const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE); return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE); }) == continue_count; @@ -296,32 +307,32 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, return true; // continue data now most certainly exists - const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid); + const auto &continue_edge = node_based_graph.GetEdgeData(intersection[best_continue].eid); // best_continue is obvious by road class - if (obviousByRoadClass(in_way_data.road_classification, - continue_data.road_classification, - best_option_data.road_classification)) + if (obviousByRoadClass(in_way_edge.flags.road_classification, + continue_edge.flags.road_classification, + best_option_edge.flags.road_classification)) return false; // best_option is obvious by road class - if (obviousByRoadClass(in_way_data.road_classification, - best_option_data.road_classification, - continue_data.road_classification)) + if (obviousByRoadClass(in_way_edge.flags.road_classification, + best_option_edge.flags.road_classification, + continue_edge.flags.road_classification)) return true; // the best_option deviation is very straight and not a ramp if (best_option_deviation < best_continue_deviation && best_option_deviation < FUZZY_ANGLE_DIFFERENCE && - !best_option_data.road_classification.IsRampClass()) + !best_option_edge.flags.road_classification.IsRampClass()) return true; // the continue road is of a lower priority, while the road continues on the same priority // with a better angle if (best_option_deviation < best_continue_deviation && - in_way_data.road_classification == best_option_data.road_classification && - continue_data.road_classification.GetPriority() > - best_option_data.road_classification.GetPriority()) + in_way_edge.flags.road_classification == best_option_edge.flags.road_classification && + continue_edge.flags.road_classification.GetPriority() > + best_option_edge.flags.road_classification.GetPriority()) return true; return false; @@ -335,24 +346,25 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, const auto in_through_candidate = intersection.FindClosestBearing(util::bearing::reverse(road.bearing)); - const auto &in_data = node_based_graph.GetEdgeData(in_through_candidate->eid); - const auto &out_data = node_based_graph.GetEdgeData(road.eid); + const auto &in_edge = node_based_graph.GetEdgeData(in_through_candidate->eid); + const auto &out_edge = node_based_graph.GetEdgeData(road.eid); // by asking for the same class, we ensure that we do not overrule obvious by road-class // decisions - const auto same_class = in_data.road_classification == out_data.road_classification; + const auto same_class = + in_edge.flags.road_classification == out_edge.flags.road_classification; // only if the entry is allowed for one of the two, but not the other, we need to check. // Otherwise other handlers do it better const bool is_oneway = !in_through_candidate->entry_allowed && road.entry_allowed; - const bool not_roundabout = - !(in_data.roundabout || in_data.circular || out_data.roundabout || out_data.circular); + const bool not_roundabout = !(in_edge.flags.roundabout || in_edge.flags.circular || + out_edge.flags.roundabout || out_edge.flags.circular); // for the purpose of this check, we do not care about low-priority roads (parking lots, // mostly). Since we postulate both classes to be the same, checking one of the two is // enough - const bool not_low_priority = !in_data.road_classification.IsLowPriorityRoadClass(); + const bool not_low_priority = !in_edge.flags.road_classification.IsLowPriorityRoadClass(); const auto in_deviation = angularDeviation(in_through_candidate->angle, STRAIGHT_ANGLE); const auto out_deviaiton = angularDeviation(road.angle, STRAIGHT_ANGLE); @@ -371,11 +383,11 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, const auto index_candidate = (best_option + 1) % intersection.size(); if (index_candidate == 0) return index_candidate; - const auto &candidate_data = + const auto &candidate_edge = node_based_graph.GetEdgeData(intersection[index_candidate].eid); - if (obviousByRoadClass(in_way_data.road_classification, - best_option_data.road_classification, - candidate_data.road_classification)) + if (obviousByRoadClass(in_way_edge.flags.road_classification, + best_option_edge.flags.road_classification, + candidate_edge.flags.road_classification)) return (index_candidate + 1) % intersection.size(); else return index_candidate; @@ -386,11 +398,11 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, const auto index_candidate = best_option - 1; if (index_candidate == 0) return index_candidate; - const auto candidate_data = + const auto &candidate_edge = node_based_graph.GetEdgeData(intersection[index_candidate].eid); - if (obviousByRoadClass(in_way_data.road_classification, - best_option_data.road_classification, - candidate_data.road_classification)) + if (obviousByRoadClass(in_way_edge.flags.road_classification, + best_option_edge.flags.road_classification, + candidate_edge.flags.road_classification)) return index_candidate - 1; else return index_candidate; @@ -407,17 +419,17 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE) return best_option; - const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid); - const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid); + const auto &left_edge = node_based_graph.GetEdgeData(intersection[left_index].eid); + const auto &right_edge = node_based_graph.GetEdgeData(intersection[right_index].eid); const bool obvious_to_left = - left_index == 0 || obviousByRoadClass(in_way_data.road_classification, - best_option_data.road_classification, - left_data.road_classification); + left_index == 0 || obviousByRoadClass(in_way_edge.flags.road_classification, + best_option_edge.flags.road_classification, + left_edge.flags.road_classification); const bool obvious_to_right = - right_index == 0 || obviousByRoadClass(in_way_data.road_classification, - best_option_data.road_classification, - right_data.road_classification); + right_index == 0 || obviousByRoadClass(in_way_edge.flags.road_classification, + best_option_edge.flags.road_classification, + right_edge.flags.road_classification); // if the best_option turn isn't narrow, but there is a nearly straight turn, we don't // consider the turn obvious @@ -447,14 +459,15 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, distinction rate. If the road category is smaller, its also adjusted. Only roads of the same priority require the full distinction ratio. */ - const auto &best_option_data = + const auto &best_option_edge = node_based_graph.GetEdgeData(intersection[best_option].eid); const auto adjusted_distinction_ratio = [&]() { // obviousness by road classes - if (in_way_data.road_classification == best_option_data.road_classification && - best_option_data.road_classification.GetPriority() < + if (in_way_edge.flags.road_classification == + best_option_edge.flags.road_classification && + best_option_edge.flags.road_classification.GetPriority() < node_based_graph.GetEdgeData(intersection[index].eid) - .road_classification.GetPriority()) + .flags.road_classification.GetPriority()) return 0.8 * DISTINCTION_RATIO; // if road classes are the same, we use the full ratio else @@ -472,7 +485,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, } else { - const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid); + const auto &continue_edge = node_based_graph.GetEdgeData(intersection[best_continue].eid); + const auto &continue_data = + node_data_container.GetAnnotation(continue_edge.annotation_data); if (std::abs(best_continue_deviation) < 1) return best_continue; @@ -488,11 +503,12 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, if (i == best_continue || !intersection[i].entry_allowed) continue; - const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid); + const auto &turn_edge = node_based_graph.GetEdgeData(intersection[i].eid); + const auto &turn_data = node_data_container.GetAnnotation(turn_edge.annotation_data); const bool is_obvious_by_road_class = - obviousByRoadClass(in_way_data.road_classification, - continue_data.road_classification, - turn_data.road_classification); + obviousByRoadClass(in_way_edge.flags.road_classification, + continue_edge.flags.road_classification, + turn_edge.flags.road_classification); // if the main road is obvious by class, we ignore the current road as a potential // prevention of obviousness @@ -500,9 +516,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, continue; // continuation could be grouped with a straight turn and the turning road is a ramp - if (turn_data.road_classification.IsRampClass() && + if (turn_edge.flags.road_classification.IsRampClass() && best_continue_deviation < GROUP_ANGLE && - !continue_data.road_classification.IsRampClass()) + !continue_edge.flags.road_classification.IsRampClass()) continue; // perfectly straight turns prevent obviousness @@ -567,11 +583,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, // actually represents a near 180 degree different in bearings between the two // roads. So if there is a road that is enterable in the opposite direction just // prior, a turn is not obvious - const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid); + const auto &turn_edge_data = node_based_graph.GetEdgeData(comparison_road.eid); + const auto &turn_data = + node_data_container.GetAnnotation(turn_edge_data.annotation_data); if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE && angularDeviation(comparison_road.angle, continue_road.angle) < FUZZY_ANGLE_DIFFERENCE && - !turn_data.reversed && continue_data.CanCombineWith(turn_data)) + !turn_edge_data.reversed && continue_data.CanCombineWith(turn_data)) return 0; } } diff --git a/include/extractor/guidance/intersection_normalizer.hpp b/include/extractor/guidance/intersection_normalizer.hpp index 41359a604..95c07f393 100644 --- a/include/extractor/guidance/intersection_normalizer.hpp +++ b/include/extractor/guidance/intersection_normalizer.hpp @@ -43,6 +43,7 @@ class IntersectionNormalizer std::vector performed_merges; }; IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &node_coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, diff --git a/include/extractor/guidance/mergable_road_detector.hpp b/include/extractor/guidance/mergable_road_detector.hpp index a5c661c66..d230bc385 100644 --- a/include/extractor/guidance/mergable_road_detector.hpp +++ b/include/extractor/guidance/mergable_road_detector.hpp @@ -37,6 +37,7 @@ class MergableRoadDetector using MergableRoadData = IntersectionShapeData; MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &node_coordinates, const IntersectionGenerator &intersection_generator, const CoordinateExtractor &coordinate_extractor, @@ -77,8 +78,10 @@ class MergableRoadDetector // When it comes to merging roads, we need to find out if two ways actually represent the // same road. This check tries to identify roads which are the same road in opposite directions - bool EdgeDataSupportsMerge(const util::NodeBasedEdgeData &lhs_edge_data, - const util::NodeBasedEdgeData &rhs_edge_data) const; + bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags, + const NodeBasedEdgeClassification &rhs_flags, + const NodeBasedEdgeAnnotation &lhs_edge_annotation, + const NodeBasedEdgeAnnotation &rhs_edge_annotation) const; // Detect traffic loops. // Since OSRM cannot handle loop edges, we cannot directly see a connection between a node and @@ -138,6 +141,7 @@ class MergableRoadDetector bool IsLinkRoad(const NodeID intersection_node, const MergableRoadData &road) const; const util::NodeBasedDynamicGraph &node_based_graph; + const EdgeBasedNodeDataContainer &node_data_container; const std::vector &node_coordinates; const IntersectionGenerator &intersection_generator; const CoordinateExtractor &coordinate_extractor; diff --git a/include/extractor/guidance/motorway_handler.hpp b/include/extractor/guidance/motorway_handler.hpp index b3d7ccfc0..036395dd4 100644 --- a/include/extractor/guidance/motorway_handler.hpp +++ b/include/extractor/guidance/motorway_handler.hpp @@ -24,6 +24,7 @@ class MotorwayHandler : public IntersectionHandler { public: MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, diff --git a/include/extractor/guidance/node_based_graph_walker.hpp b/include/extractor/guidance/node_based_graph_walker.hpp index d157a83de..bed1edac2 100644 --- a/include/extractor/guidance/node_based_graph_walker.hpp +++ b/include/extractor/guidance/node_based_graph_walker.hpp @@ -28,6 +28,7 @@ class NodeBasedGraphWalker { public: NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const IntersectionGenerator &intersection_generator); /* @@ -46,6 +47,7 @@ class NodeBasedGraphWalker private: const util::NodeBasedDynamicGraph &node_based_graph; + const EdgeBasedNodeDataContainer &node_data_container; const IntersectionGenerator &intersection_generator; }; @@ -106,7 +108,8 @@ struct SelectRoadByNameOnlyChoiceAndStraightness boost::optional operator()(const NodeID nid, const EdgeID via_edge_id, const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &node_based_graph) const; + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container) const; private: const NameID desired_name_id; @@ -131,7 +134,8 @@ struct SelectStraightmostRoadByNameAndOnlyChoice boost::optional operator()(const NodeID nid, const EdgeID via_edge_id, const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &node_based_graph) const; + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container) const; private: const NameID desired_name_id; @@ -201,8 +205,11 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id, if (next_intersection.size() <= 1) return {}; - auto next_edge_id = - selector(current_node_id, current_edge_id, next_intersection, node_based_graph); + auto next_edge_id = selector(current_node_id, + current_edge_id, + next_intersection, + node_based_graph, + node_data_container); if (!next_edge_id) return {}; @@ -224,7 +231,8 @@ struct SkipTrafficSignalBarrierRoadSelector boost::optional operator()(const NodeID, const EdgeID, const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &) const + const util::NodeBasedDynamicGraph &, + const EdgeBasedNodeDataContainer &) const { if (intersection.isTrafficSignalOrBarrier()) { diff --git a/include/extractor/guidance/roundabout_handler.hpp b/include/extractor/guidance/roundabout_handler.hpp index 61ca6b824..72779b12e 100644 --- a/include/extractor/guidance/roundabout_handler.hpp +++ b/include/extractor/guidance/roundabout_handler.hpp @@ -7,7 +7,6 @@ #include "extractor/guidance/intersection_generator.hpp" #include "extractor/guidance/intersection_handler.hpp" #include "extractor/guidance/roundabout_type.hpp" -#include "extractor/profile_properties.hpp" #include "extractor/query_node.hpp" #include "util/name_table.hpp" @@ -41,11 +40,11 @@ class RoundaboutHandler : public IntersectionHandler { public: RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, - const ProfileProperties &profile_properties, const IntersectionGenerator &intersection_generator); ~RoundaboutHandler() override final = default; @@ -86,8 +85,6 @@ class RoundaboutHandler : public IntersectionHandler qualifiesAsRoundaboutIntersection(const std::unordered_set &roundabout_nodes) const; const CompressedEdgeContainer &compressed_edge_container; - const ProfileProperties &profile_properties; - const CoordinateExtractor coordinate_extractor; }; diff --git a/include/extractor/guidance/sliproad_handler.hpp b/include/extractor/guidance/sliproad_handler.hpp index eed194dc9..8dfa5d3ea 100644 --- a/include/extractor/guidance/sliproad_handler.hpp +++ b/include/extractor/guidance/sliproad_handler.hpp @@ -26,6 +26,7 @@ class SliproadHandler final : public IntersectionHandler public: SliproadHandler(const IntersectionGenerator &intersection_generator, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table); diff --git a/include/extractor/guidance/suppress_mode_handler.hpp b/include/extractor/guidance/suppress_mode_handler.hpp index 6a5237ed7..7b3eb458c 100644 --- a/include/extractor/guidance/suppress_mode_handler.hpp +++ b/include/extractor/guidance/suppress_mode_handler.hpp @@ -23,6 +23,7 @@ class SuppressModeHandler final : public IntersectionHandler public: SuppressModeHandler(const IntersectionGenerator &intersection_generator, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table); diff --git a/include/extractor/guidance/turn_analysis.hpp b/include/extractor/guidance/turn_analysis.hpp index 41b56107f..48c163f99 100644 --- a/include/extractor/guidance/turn_analysis.hpp +++ b/include/extractor/guidance/turn_analysis.hpp @@ -41,13 +41,13 @@ class TurnAnalysis { public: TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table, - const ProfileProperties &profile_properties); + const SuffixTable &street_name_suffix_table); /* Full Analysis Process for a single node/edge combination. Use with caution, as the process is * relatively expensive */ diff --git a/include/extractor/guidance/turn_handler.hpp b/include/extractor/guidance/turn_handler.hpp index 89ae3c6c9..b80edebad 100644 --- a/include/extractor/guidance/turn_handler.hpp +++ b/include/extractor/guidance/turn_handler.hpp @@ -28,6 +28,7 @@ class TurnHandler : public IntersectionHandler { public: TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, diff --git a/include/extractor/guidance/turn_lane_handler.hpp b/include/extractor/guidance/turn_lane_handler.hpp index 48cdf7598..4f19e163b 100644 --- a/include/extractor/guidance/turn_lane_handler.hpp +++ b/include/extractor/guidance/turn_lane_handler.hpp @@ -73,6 +73,7 @@ class TurnLaneHandler typedef std::vector LaneDataVector; TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, LaneDescriptionMap &lane_description_map, const TurnAnalysis &turn_analysis, util::guidance::LaneDataIdMap &id_map); @@ -88,6 +89,7 @@ class TurnLaneHandler // we need to be able to look at previous intersections to, in some cases, find the correct turn // lanes for a turn const util::NodeBasedDynamicGraph &node_based_graph; + const EdgeBasedNodeDataContainer &node_data_container; std::vector turn_lane_offsets; std::vector turn_lane_masks; LaneDescriptionMap &lane_description_map; diff --git a/include/extractor/internal_extractor_edge.hpp b/include/extractor/internal_extractor_edge.hpp index 4432bc5eb..67a38dd23 100644 --- a/include/extractor/internal_extractor_edge.hpp +++ b/include/extractor/internal_extractor_edge.hpp @@ -58,65 +58,24 @@ struct InternalExtractorEdge using WeightData = detail::ByEdgeOrByMeterValue; using DurationData = detail::ByEdgeOrByMeterValue; - explicit InternalExtractorEdge() - : result(MIN_OSM_NODEID, - MIN_OSM_NODEID, - SPECIAL_NODEID, - 0, - 0, - false, // forward - false, // backward - false, // roundabout - false, // circular - true, // can be startpoint - false, // local access only - false, // is_left_hand_driving - false, // split edge - TRAVEL_MODE_INACCESSIBLE, - 0, - guidance::TurnLaneType::empty, - guidance::RoadClassification()), - weight_data(), duration_data() - { - } + explicit InternalExtractorEdge() : weight_data(), duration_data() {} explicit InternalExtractorEdge(OSMNodeID source, OSMNodeID target, - NodeID name_id, WeightData weight_data, DurationData duration_data, - bool forward, - bool backward, - bool roundabout, - bool circular, - bool startpoint, - bool restricted, - bool is_left_hand_driving, - bool is_split, - TravelMode travel_mode, - ClassData classes, - LaneDescriptionID lane_description, - guidance::RoadClassification road_classification, util::Coordinate source_coordinate) - : result(source, - target, - name_id, - 0, - 0, - forward, - backward, - roundabout, - circular, - startpoint, - restricted, - is_left_hand_driving, - is_split, - travel_mode, - classes, - lane_description, - std::move(road_classification)), - weight_data(std::move(weight_data)), duration_data(std::move(duration_data)), - source_coordinate(std::move(source_coordinate)) + : result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)), + duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate)) + { + } + + explicit InternalExtractorEdge(NodeBasedEdgeWithOSM edge, + WeightData weight_data, + DurationData duration_data, + util::Coordinate source_coordinate) + : result(std::move(edge)), weight_data(weight_data), duration_data(duration_data), + source_coordinate(source_coordinate) { } @@ -132,45 +91,13 @@ struct InternalExtractorEdge // necessary static util functions for stxxl's sorting static InternalExtractorEdge min_osm_value() { - return InternalExtractorEdge(MIN_OSM_NODEID, - MIN_OSM_NODEID, - SPECIAL_NODEID, - WeightData(), - DurationData(), - false, // forward - false, // backward - false, // roundabout - false, // circular - true, // can be startpoint - false, // local access only - false, // is_left_hand_driving - false, // split edge - TRAVEL_MODE_INACCESSIBLE, - 0, - INVALID_LANE_DESCRIPTIONID, - guidance::RoadClassification(), - util::Coordinate()); + return InternalExtractorEdge( + MIN_OSM_NODEID, MIN_OSM_NODEID, WeightData(), DurationData(), util::Coordinate()); } static InternalExtractorEdge max_osm_value() { - return InternalExtractorEdge(MAX_OSM_NODEID, - MAX_OSM_NODEID, - SPECIAL_NODEID, - WeightData(), - DurationData(), - false, // forward - false, // backward - false, // roundabout - false, // circular - true, // can be startpoint - false, // local access only - false, // is_left_hand_driving - false, // split edge - TRAVEL_MODE_INACCESSIBLE, - 0, - INVALID_LANE_DESCRIPTIONID, - guidance::RoadClassification(), - util::Coordinate()); + return InternalExtractorEdge( + MAX_OSM_NODEID, MAX_OSM_NODEID, WeightData(), DurationData(), util::Coordinate()); } static InternalExtractorEdge min_internal_value() diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp index 22d62772d..40d95a973 100644 --- a/include/extractor/node_based_edge.hpp +++ b/include/extractor/node_based_edge.hpp @@ -1,6 +1,9 @@ #ifndef NODE_BASED_EDGE_HPP #define NODE_BASED_EDGE_HPP +#include +#include + #include "extractor/class_data.hpp" #include "extractor/travel_mode.hpp" #include "util/typedefs.hpp" @@ -12,68 +15,97 @@ namespace osrm namespace extractor { +// Flags describing the class of the road. This data is used during creation of graphs/guidance +// generation but is not available in annotation/navigation +struct NodeBasedEdgeClassification +{ + std::uint8_t forward : 1; // 1 + std::uint8_t backward : 1; // 1 + std::uint8_t is_split : 1; // 1 + std::uint8_t roundabout : 1; // 1 + std::uint8_t circular : 1; // 1 + std::uint8_t startpoint : 1; // 1 + std::uint8_t restricted : 1; // 1 + guidance::RoadClassification road_classification; // 16 2 + + NodeBasedEdgeClassification(); + + NodeBasedEdgeClassification(const bool forward, + const bool backward, + const bool is_split, + const bool roundabout, + const bool circular, + const bool startpoint, + const bool restricted, + guidance::RoadClassification road_classification) + : forward(forward), backward(backward), is_split(is_split), roundabout(roundabout), + circular(circular), startpoint(startpoint), restricted(restricted), + road_classification(road_classification) + { + } + + bool operator==(const NodeBasedEdgeClassification &other) const + { + return (road_classification == other.road_classification) && (forward == other.forward) && + (backward == other.backward) && (is_split) == (other.is_split) && + (roundabout == other.roundabout) && (circular == other.circular) && + (startpoint == other.startpoint) && (restricted == other.restricted); + } +}; + +// Annotative data, used in parts in guidance generation, in parts during navigation (classes) but +// mostly for annotation of edges. The entry can be shared between multiple edges and usually +// describes features present on OSM ways. This is the place to put specific data that you want to +// see as part of the API output but that does not influence navigation +struct NodeBasedEdgeAnnotation +{ + NameID name_id; // 32 4 + LaneDescriptionID lane_description_id; // 16 2 + ClassData classes; // 8 1 + TravelMode travel_mode : 4; // 4 + bool is_left_hand_driving : 1; // 1 + + bool CanCombineWith(const NodeBasedEdgeAnnotation &other) const + { + return (std::tie(name_id, classes, travel_mode, is_left_hand_driving) == + std::tie(other.name_id, other.classes, other.travel_mode, is_left_hand_driving)); + } +}; + struct NodeBasedEdge { NodeBasedEdge(); NodeBasedEdge(NodeID source, NodeID target, - NodeID name_id, EdgeWeight weight, EdgeDuration duration, - bool forward, - bool backward, - bool roundabout, - bool circular, - bool startpoint, - bool restricted, - bool is_left_hand_driving, - bool is_split, - TravelMode travel_mode, - ClassData classes, - const LaneDescriptionID lane_description_id, - guidance::RoadClassification road_classification); + GeometryID geometry_id, + AnnotationID annotation_data, + NodeBasedEdgeClassification flags); bool operator<(const NodeBasedEdge &other) const; - NodeID source; // 32 4 - NodeID target; // 32 4 - NodeID name_id; // 32 4 - EdgeWeight weight; // 32 4 - EdgeDuration duration; // 32 4 - std::uint8_t forward : 1; // 1 - std::uint8_t backward : 1; // 1 - std::uint8_t roundabout : 1; // 1 - std::uint8_t circular : 1; // 1 - std::uint8_t startpoint : 1; // 1 - std::uint8_t restricted : 1; // 1 - std::uint8_t is_left_hand_driving : 1; // 1 - std::uint8_t is_split : 1; // 1 - TravelMode travel_mode : 4; // 4 - ClassData classes; // 8 1 - LaneDescriptionID lane_description_id; // 16 2 - guidance::RoadClassification road_classification; // 16 2 + NodeID source; // 32 4 + NodeID target; // 32 4 + EdgeWeight weight; // 32 4 + EdgeDuration duration; // 32 4 + GeometryID geometry_id; // 32 4 + AnnotationID annotation_data; // 32 4 + NodeBasedEdgeClassification flags; // 32 4 }; struct NodeBasedEdgeWithOSM : NodeBasedEdge { + NodeBasedEdgeWithOSM(); + NodeBasedEdgeWithOSM(OSMNodeID source, OSMNodeID target, - NodeID name_id, EdgeWeight weight, EdgeDuration duration, - bool forward, - bool backward, - bool roundabout, - bool circular, - bool startpoint, - bool restricted, - bool is_left_hand_driving, - bool is_split, - TravelMode travel_mode, - ClassData classes, - const LaneDescriptionID lane_description_id, - guidance::RoadClassification road_classification); + GeometryID geometry_id, + AnnotationID annotation_data, + NodeBasedEdgeClassification flags); OSMNodeID osm_source_id; OSMNodeID osm_target_id; @@ -81,36 +113,26 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge // Impl. +inline NodeBasedEdgeClassification::NodeBasedEdgeClassification() + : forward(false), backward(false), is_split(false), roundabout(false), circular(false), + startpoint(false), restricted(false) +{ +} + inline NodeBasedEdge::NodeBasedEdge() - : source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), duration(0), - forward(false), backward(false), roundabout(false), circular(false), startpoint(true), - restricted(false), is_left_hand_driving(false), is_split(false), - travel_mode(TRAVEL_MODE_INACCESSIBLE), lane_description_id(INVALID_LANE_DESCRIPTIONID) + : source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1) { } inline NodeBasedEdge::NodeBasedEdge(NodeID source, NodeID target, - NodeID name_id, EdgeWeight weight, EdgeDuration duration, - bool forward, - bool backward, - bool roundabout, - bool circular, - bool startpoint, - bool restricted, - bool is_left_hand_driving, - bool is_split, - TravelMode travel_mode, - ClassData classes, - const LaneDescriptionID lane_description_id, - guidance::RoadClassification road_classification) - : source(source), target(target), name_id(name_id), weight(weight), duration(duration), - forward(forward), backward(backward), roundabout(roundabout), circular(circular), - startpoint(startpoint), restricted(restricted), is_left_hand_driving(is_left_hand_driving), - is_split(is_split), travel_mode(travel_mode), classes(classes), - lane_description_id(lane_description_id), road_classification(std::move(road_classification)) + GeometryID geometry_id, + AnnotationID annotation_data, + NodeBasedEdgeClassification flags) + : source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id), + annotation_data(annotation_data), flags(flags) { } @@ -122,7 +144,8 @@ inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const { if (weight == other.weight) { - return forward && backward && ((!other.forward) || (!other.backward)); + return flags.forward && flags.backward && + ((!other.flags.forward) || (!other.flags.backward)); } return weight < other.weight; } @@ -133,42 +156,22 @@ inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source, OSMNodeID target, - NodeID name_id, EdgeWeight weight, EdgeDuration duration, - bool forward, - bool backward, - bool roundabout, - bool circular, - bool startpoint, - bool restricted, - bool is_left_hand_driving, - bool is_split, - TravelMode travel_mode, - ClassData classes, - const LaneDescriptionID lane_description_id, - guidance::RoadClassification road_classification) - : NodeBasedEdge(SPECIAL_NODEID, - SPECIAL_NODEID, - name_id, - weight, - duration, - forward, - backward, - roundabout, - circular, - startpoint, - restricted, - is_left_hand_driving, - is_split, - travel_mode, - classes, - lane_description_id, - std::move(road_classification)), + GeometryID geometry_id, + AnnotationID annotation_data, + NodeBasedEdgeClassification flags) + : NodeBasedEdge( + SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags), osm_source_id(std::move(source)), osm_target_id(std::move(target)) { } +inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM() + : osm_source_id(MIN_OSM_NODEID), osm_target_id(MIN_OSM_NODEID) +{ +} + static_assert(sizeof(extractor::NodeBasedEdge) == 28, "Size of extractor::NodeBasedEdge type is " "bigger than expected. This will influence " diff --git a/include/extractor/node_based_graph_factory.hpp b/include/extractor/node_based_graph_factory.hpp new file mode 100644 index 000000000..aaadfb728 --- /dev/null +++ b/include/extractor/node_based_graph_factory.hpp @@ -0,0 +1,101 @@ +#ifndef OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_ +#define OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_ + +#include "extractor/compressed_edge_container.hpp" +#include "extractor/node_based_edge.hpp" +#include "extractor/node_data_container.hpp" +#include "extractor/packed_osm_ids.hpp" +#include "extractor/scripting_environment.hpp" + +#include "util/coordinate.hpp" +#include "util/node_based_graph.hpp" + +#include + +#include +#include +#include +#include + +namespace osrm +{ +namespace extractor +{ + +// Turn the output of the extraction process into a graph that represents junctions as nodes and +// ways as edges between these nodes. The graph forms the further input for OSRMs creation of the +// edge-based graph and is also the basic concept for annotating paths. All information from ways +// that is transferred into the API response is connected to the edges of the node-based graph. +// +// The input to the graph creation is the set of edges, traffic signals, barriers, meta-data,... +// which is generated during extraction and stored within the extraction containers. +class NodeBasedGraphFactory +{ + public: + // The node-based graph factory loads the *.osrm file and transforms the data within into the + // node-based graph to represent the OSM network. This includes geometry compression, annotation + // data optimisation and many other aspects. After this step, the edge-based graph factory can + // turn the graph into the routing graph to be used with the navigation algorithms. + NodeBasedGraphFactory(const boost::filesystem::path &input_file, + ScriptingEnvironment &scripting_environment, + std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions); + + auto const &GetGraph() const { return compressed_output_graph; } + auto const &GetBarriers() const { return barriers; } + auto const &GetTrafficSignals() const { return traffic_signals; } + auto &GetCompressedEdges() { return compressed_edge_container; } + auto &GetCoordinates() { return coordinates; } + auto &GetAnnotationData() { return annotation_data; } + auto &GetOsmNodes() { return osm_node_ids; } + + // to reduce the memory footprint, the node-based graph factory allows releasing memory after it + // might have been used for the last time: + void ReleaseOsmNodes(); + + private: + // Get the information from the *.osrm file (direct product of the extractor callback/extraction + // containers) and prepare the graph creation process + void LoadDataFromFile(const boost::filesystem::path &input_file); + + // Compress the node-based graph into a compact representation of itself. This removes storing a + // single edge for every part of the geometry and might also combine meta-data for multiple + // edges into a single representative form + void Compress(ScriptingEnvironment &scripting_environment, + std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions); + + // Most ways are bidirectional, making the geometry in forward and backward direction the same, + // except for reversal. We make use of this fact by keeping only one representation of the + // geometry around + void CompressGeometry(); + + // After graph compression, some of the annotation entries might not be referenced anymore. We + // compress the annotation data by relabeling the node-based graph references and removing all + // unreferenced entries + void CompressAnnotationData(); + + // After produce, this will contain a compresse version of the node-based graph + util::NodeBasedDynamicGraph compressed_output_graph; + // To store the meta-data for the graph that is purely annotative / not used for the navigation + // itself. Since the edges of a node-based graph form the nodes of the edge based graphs, we + // transform this data into the EdgeBasedNodeDataContainer as output storage. + std::vector annotation_data; + + // General Information about the graph, not used outside of extractor + std::unordered_set barriers; + std::unordered_set traffic_signals; + + std::vector coordinates; + + // data to keep in sync with the node-based graph + extractor::PackedOSMIDs osm_node_ids; + + // for the compressed geometry + extractor::CompressedEdgeContainer compressed_edge_container; +}; + +} // namespace extractor +} // namespace osrm + +#endif // OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_ diff --git a/include/extractor/node_data_container.hpp b/include/extractor/node_data_container.hpp index 611c73ac2..407db37a8 100644 --- a/include/extractor/node_data_container.hpp +++ b/include/extractor/node_data_container.hpp @@ -2,6 +2,8 @@ #define OSRM_EXTRACTOR_NODE_DATA_CONTAINER_HPP #include "extractor/class_data.hpp" +#include "extractor/edge_based_node.hpp" +#include "extractor/node_based_edge.hpp" #include "extractor/travel_mode.hpp" #include "storage/io_fwd.hpp" @@ -15,6 +17,10 @@ namespace osrm { namespace extractor { + +class Extractor; +class EdgeBasedGraphFactory; + namespace detail { template class EdgeBasedNodeDataContainerImpl; @@ -38,63 +44,47 @@ template class EdgeBasedNodeDataContainerImpl template using Vector = util::ViewOrVector; using TravelMode = extractor::TravelMode; + // to fill in data on edgeBasedNodes + friend class osrm::extractor::Extractor; + friend class osrm::extractor::EdgeBasedGraphFactory; + public: EdgeBasedNodeDataContainerImpl() = default; - EdgeBasedNodeDataContainerImpl(std::size_t size) - : geometry_ids(size), name_ids(size), component_ids(size), travel_modes(size), - classes(size), is_left_hand_driving(size) + EdgeBasedNodeDataContainerImpl(const NodeID number_of_edge_based_nodes, + const AnnotationID number_of_annotations) + : nodes(number_of_edge_based_nodes), annotation_data(number_of_annotations) { } - EdgeBasedNodeDataContainerImpl(Vector geometry_ids, - Vector name_ids, - Vector component_ids, - Vector travel_modes, - Vector classes, - Vector is_left_hand_driving) - : geometry_ids(std::move(geometry_ids)), name_ids(std::move(name_ids)), - component_ids(std::move(component_ids)), travel_modes(std::move(travel_modes)), - classes(std::move(classes)), is_left_hand_driving(std::move(is_left_hand_driving)) + EdgeBasedNodeDataContainerImpl(Vector nodes, + Vector annotation_data) + : nodes(std::move(nodes)), annotation_data(std::move(annotation_data)) { } - GeometryID GetGeometryID(const NodeID node_id) const { return geometry_ids[node_id]; } + GeometryID GetGeometryID(const NodeID node_id) const { return nodes[node_id].geometry_id; } - TravelMode GetTravelMode(const NodeID node_id) const { return travel_modes[node_id]; } + ComponentID GetComponentID(const NodeID node_id) const { return nodes[node_id].component_id; } - NameID GetNameID(const NodeID node_id) const { return name_ids[node_id]; } - - ComponentID GetComponentID(const NodeID node_id) const { return component_ids[node_id]; } - - ClassData GetClassData(const NodeID node_id) const { return classes[node_id]; } - - ClassData IsLeftHandDriving(const NodeID node_id) const + TravelMode GetTravelMode(const NodeID node_id) const { - return is_left_hand_driving[node_id]; + return annotation_data[nodes[node_id].annotation_id].travel_mode; } - // Used by EdgeBasedGraphFactory to fill data structure - template > - void SetData(NodeID node_id, - GeometryID geometry_id, - NameID name_id, - TravelMode travel_mode, - ClassData class_data, - bool is_left_hand_driving_flag) + bool IsLeftHandDriving(const NodeID node_id) const { - geometry_ids[node_id] = geometry_id; - name_ids[node_id] = name_id; - travel_modes[node_id] = travel_mode; - classes[node_id] = class_data; - is_left_hand_driving[node_id] = is_left_hand_driving_flag; + return annotation_data[nodes[node_id].annotation_id].is_left_hand_driving; } - // Used by EdgeBasedGraphFactory to fill data structure - template > - void SetComponentID(NodeID node_id, ComponentID component_id) + NameID GetNameID(const NodeID node_id) const { - component_ids[node_id] = component_id; + return annotation_data[nodes[node_id].annotation_id].name_id; + } + + ClassData GetClassData(const NodeID node_id) const + { + return annotation_data[nodes[node_id].annotation_id].classes; } friend void serialization::read(storage::io::FileReader &reader, @@ -106,33 +96,30 @@ template class EdgeBasedNodeDataContainerImpl template > void Renumber(const std::vector &permutation) { - util::inplacePermutation(geometry_ids.begin(), geometry_ids.end(), permutation); - util::inplacePermutation(name_ids.begin(), name_ids.end(), permutation); - util::inplacePermutation(component_ids.begin(), component_ids.end(), permutation); - util::inplacePermutation(travel_modes.begin(), travel_modes.end(), permutation); - util::inplacePermutation(classes.begin(), classes.end(), permutation); - util::inplacePermutation( - is_left_hand_driving.begin(), is_left_hand_driving.end(), permutation); + util::inplacePermutation(nodes.begin(), nodes.end(), permutation); } - // all containers have the exact same size - std::size_t Size() const + NodeID NumberOfNodes() const { return nodes.size(); } + + // the number of annotations differs from the number of nodes, since annotations can be shared + // between a large set of nodes + AnnotationID NumberOfAnnotations() const { return annotation_data.size(); } + + EdgeBasedNode &GetNode(const NodeID node_id) { return nodes[node_id]; } + EdgeBasedNode const &GetNode(const NodeID node_id) const { return nodes[node_id]; } + + NodeBasedEdgeAnnotation &GetAnnotation(const AnnotationID annotation) { - BOOST_ASSERT(geometry_ids.size() == name_ids.size()); - BOOST_ASSERT(geometry_ids.size() == component_ids.size()); - BOOST_ASSERT(geometry_ids.size() == travel_modes.size()); - BOOST_ASSERT(geometry_ids.size() == classes.size()); - BOOST_ASSERT(geometry_ids.size() == is_left_hand_driving.size()); - return geometry_ids.size(); + return annotation_data[annotation]; + } + NodeBasedEdgeAnnotation const &GetAnnotation(const AnnotationID annotation) const + { + return annotation_data[annotation]; } private: - Vector geometry_ids; - Vector name_ids; - Vector component_ids; - Vector travel_modes; - Vector classes; - Vector is_left_hand_driving; + Vector nodes; + Vector annotation_data; }; } @@ -141,7 +128,7 @@ using EdgeBasedNodeDataExternalContainer = using EdgeBasedNodeDataContainer = detail::EdgeBasedNodeDataContainerImpl; using EdgeBasedNodeDataView = detail::EdgeBasedNodeDataContainerImpl; -} -} +} // namespace extractor +} // namespace osrm #endif diff --git a/include/extractor/scripting_environment_lua.hpp b/include/extractor/scripting_environment_lua.hpp index 41dea0d99..8a00f2048 100644 --- a/include/extractor/scripting_environment_lua.hpp +++ b/include/extractor/scripting_environment_lua.hpp @@ -96,7 +96,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment std::vector> &resulting_relations, std::vector &resulting_restrictions) override; - bool HasLocationDependentData() const { return !location_dependent_data.empty(); } + bool HasLocationDependentData() const override { return !location_dependent_data.empty(); } private: LuaScriptingContext &GetSol2Context(); diff --git a/include/extractor/serialization.hpp b/include/extractor/serialization.hpp index 02b1e54a3..bfbd438d2 100644 --- a/include/extractor/serialization.hpp +++ b/include/extractor/serialization.hpp @@ -120,24 +120,22 @@ template inline void read(storage::io::FileReader &reader, detail::EdgeBasedNodeDataContainerImpl &node_data_container) { - storage::serialization::read(reader, node_data_container.geometry_ids); - storage::serialization::read(reader, node_data_container.name_ids); - storage::serialization::read(reader, node_data_container.component_ids); - storage::serialization::read(reader, node_data_container.travel_modes); - storage::serialization::read(reader, node_data_container.classes); - storage::serialization::read(reader, node_data_container.is_left_hand_driving); + // read header (separate sizes for both vectors) + reader.ReadElementCount64(); + reader.ReadElementCount64(); + // read actual data + storage::serialization::read(reader, node_data_container.nodes); + storage::serialization::read(reader, node_data_container.annotation_data); } template inline void write(storage::io::FileWriter &writer, const detail::EdgeBasedNodeDataContainerImpl &node_data_container) { - storage::serialization::write(writer, node_data_container.geometry_ids); - storage::serialization::write(writer, node_data_container.name_ids); - storage::serialization::write(writer, node_data_container.component_ids); - storage::serialization::write(writer, node_data_container.travel_modes); - storage::serialization::write(writer, node_data_container.classes); - storage::serialization::write(writer, node_data_container.is_left_hand_driving); + writer.WriteElementCount64(node_data_container.NumberOfNodes()); + writer.WriteElementCount64(node_data_container.NumberOfAnnotations()); + storage::serialization::write(writer, node_data_container.nodes); + storage::serialization::write(writer, node_data_container.annotation_data); } inline void read(storage::io::FileReader &reader, NodeRestriction &restriction) diff --git a/include/partition/edge_based_graph_reader.hpp b/include/partition/edge_based_graph_reader.hpp index ae71fbe1d..e2e88d5b6 100644 --- a/include/partition/edge_based_graph_reader.hpp +++ b/include/partition/edge_based_graph_reader.hpp @@ -184,14 +184,14 @@ graphToEdges(const DynamicEdgeBasedGraph &edge_based_graph) inline DynamicEdgeBasedGraph LoadEdgeBasedGraph(const boost::filesystem::path &path) { - EdgeID max_node_id; + EdgeID number_of_edge_based_nodes; std::vector edges; - extractor::files::readEdgeBasedGraph(path, max_node_id, edges); + extractor::files::readEdgeBasedGraph(path, number_of_edge_based_nodes, edges); auto directed = splitBidirectionalEdges(edges); auto tidied = prepareEdgesForUsageInGraph(std::move(directed)); - return DynamicEdgeBasedGraph(max_node_id + 1, std::move(tidied)); + return DynamicEdgeBasedGraph(number_of_edge_based_nodes, std::move(tidied)); } } // ns partition diff --git a/include/storage/shared_datatype.hpp b/include/storage/shared_datatype.hpp index a7c493714..ff88f8d0e 100644 --- a/include/storage/shared_datatype.hpp +++ b/include/storage/shared_datatype.hpp @@ -19,12 +19,8 @@ namespace storage const constexpr char CANARY[4] = {'O', 'S', 'R', 'M'}; const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA", - "GEOMETRY_ID_LIST", - "NAME_ID_LIST", - "COMPONENT_ID_LIST", - "TRAVEL_MODE_LIST", - "CLASSES_LIST", - "IS_LEFT_HAND_DRIVING_LIST", + "EDGE_BASED_NODE_DATA", + "ANNOTATION_DATA", "CH_GRAPH_NODE_LIST", "CH_GRAPH_EDGE_LIST", "CH_EDGE_FILTER_0", @@ -107,12 +103,8 @@ struct DataLayout enum BlockID { NAME_CHAR_DATA = 0, - GEOMETRY_ID_LIST, - NAME_ID_LIST, - COMPONENT_ID_LIST, - TRAVEL_MODE_LIST, - CLASSES_LIST, - IS_LEFT_HAND_DRIVING_LIST, + EDGE_BASED_NODE_DATA_LIST, + ANNOTATION_DATA_LIST, CH_GRAPH_NODE_LIST, CH_GRAPH_EDGE_LIST, CH_EDGE_FILTER_0, diff --git a/include/util/debug.hpp b/include/util/debug.hpp index 36486153a..e251fddfe 100644 --- a/include/util/debug.hpp +++ b/include/util/debug.hpp @@ -3,6 +3,7 @@ #include "extractor/guidance/intersection.hpp" #include "extractor/guidance/turn_lane_data.hpp" +#include "extractor/node_data_container.hpp" #include "extractor/query_node.hpp" #include "engine/guidance/route_step.hpp" #include "util/node_based_graph.hpp" @@ -77,7 +78,8 @@ inline void print(const NodeBasedDynamicGraph &node_based_graph, for (const auto &road : intersection) { std::cout << "\t" << toString(road) << "\n"; - std::cout << "\t\t" << node_based_graph.GetEdgeData(road.eid).road_classification.ToString() + std::cout << "\t\t" + << node_based_graph.GetEdgeData(road.eid).flags.road_classification.ToString() << "\n"; } std::cout << std::flush; diff --git a/include/util/dynamic_graph.hpp b/include/util/dynamic_graph.hpp index 522d2c12d..cfc661fe0 100644 --- a/include/util/dynamic_graph.hpp +++ b/include/util/dynamic_graph.hpp @@ -223,6 +223,7 @@ template class DynamicGraph unsigned GetNumberOfNodes() const { return number_of_nodes; } unsigned GetNumberOfEdges() const { return number_of_edges; } + auto GetEdgeCapacity() const { return edge_list.size(); } unsigned GetOutDegree(const NodeIterator n) const { return node_array[n].edges; } diff --git a/include/util/graph_loader.hpp b/include/util/graph_loader.hpp index 9c4032b5f..2eca54a9e 100644 --- a/include/util/graph_loader.hpp +++ b/include/util/graph_loader.hpp @@ -77,7 +77,7 @@ NodeID loadNodesFromFile(storage::io::FileReader &file_reader, /** * Reads a .osrm file and produces the edges. */ -inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader, +inline EdgeID loadEdgesFromFile(storage::io::FileReader &file_reader, std::vector &edge_list) { auto number_of_edges = file_reader.ReadElementCount64(); @@ -104,8 +104,7 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader, const auto &prev_edge = edge_list[i - 1]; BOOST_ASSERT_MSG(edge.weight > 0, "loaded null weight"); - BOOST_ASSERT_MSG(edge.forward, "edge must be oriented in forward direction"); - BOOST_ASSERT_MSG(edge.travel_mode != TRAVEL_MODE_INACCESSIBLE, "loaded non-accessible"); + BOOST_ASSERT_MSG(edge.flags.forward, "edge must be oriented in forward direction"); BOOST_ASSERT_MSG(edge.source != edge.target, "loaded edges contain a loop"); BOOST_ASSERT_MSG(edge.source != prev_edge.source || edge.target != prev_edge.target, @@ -117,6 +116,15 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader, return number_of_edges; } + +inline EdgeID loadAnnotationData(storage::io::FileReader &file_reader, + std::vector &metadata) +{ + auto const meta_data_count = file_reader.ReadElementCount64(); + metadata.resize(meta_data_count); + file_reader.ReadInto(metadata.data(), meta_data_count); + return meta_data_count; +} } } diff --git a/include/util/graph_utils.hpp b/include/util/graph_utils.hpp index c2165c5b6..e135873ab 100644 --- a/include/util/graph_utils.hpp +++ b/include/util/graph_utils.hpp @@ -74,7 +74,7 @@ std::vector directedEdgesFromCompressed(const std::vector directedEdgesFromCompressed(const std::vector #include +#include namespace osrm { @@ -19,70 +21,57 @@ namespace util struct NodeBasedEdgeData { NodeBasedEdgeData() - : weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID), - name_id(std::numeric_limits::max()), reversed(false), roundabout(false), - circular(false), startpoint(false), restricted(false), is_left_hand_driving(false), - travel_mode(TRAVEL_MODE_INACCESSIBLE), lane_description_id(INVALID_LANE_DESCRIPTIONID) + : weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}), + reversed(false), annotation_data(-1) { } NodeBasedEdgeData(EdgeWeight weight, EdgeWeight duration, - unsigned edge_id, - unsigned name_id, + GeometryID geometry_id, bool reversed, - bool roundabout, - bool circular, - bool startpoint, - bool restricted, - bool is_left_hand_driving, - extractor::TravelMode travel_mode, - extractor::ClassData classes, - const LaneDescriptionID lane_description_id) - : weight(weight), duration(duration), edge_id(edge_id), name_id(name_id), - reversed(reversed), roundabout(roundabout), circular(circular), startpoint(startpoint), - restricted(restricted), is_left_hand_driving(is_left_hand_driving), - travel_mode(travel_mode), classes(classes), lane_description_id(lane_description_id) + extractor::NodeBasedEdgeClassification flags, + AnnotationID annotation_data) + : weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed), + flags(flags), annotation_data(annotation_data) { } EdgeWeight weight; EdgeWeight duration; - unsigned edge_id; - unsigned name_id; + GeometryID geometry_id; bool reversed : 1; - bool roundabout : 1; - bool circular : 1; - bool startpoint : 1; - bool restricted : 1; - bool is_left_hand_driving : 1; - extractor::TravelMode travel_mode : 4; - extractor::ClassData classes; - LaneDescriptionID lane_description_id; - extractor::guidance::RoadClassification road_classification; - - bool IsCompatibleTo(const NodeBasedEdgeData &other) const - { - return (reversed == other.reversed) && (roundabout == other.roundabout) && - (circular == other.circular) && (startpoint == other.startpoint) && - (travel_mode == other.travel_mode) && (classes == other.classes) && - (road_classification == other.road_classification) && - (restricted == other.restricted) && - (is_left_hand_driving == other.is_left_hand_driving); - } - - bool CanCombineWith(const NodeBasedEdgeData &other) const - { - return (name_id == other.name_id) && IsCompatibleTo(other); - } + extractor::NodeBasedEdgeClassification flags; + AnnotationID annotation_data; }; +// Check if two edge data elements can be compressed into a single edge (i.e. match in terms of +// their meta-data). +inline bool CanBeCompressed(const NodeBasedEdgeData &lhs, + const NodeBasedEdgeData &rhs, + const extractor::EdgeBasedNodeDataContainer &node_data_container) +{ + if (!(lhs.flags == rhs.flags)) + return false; + + auto const &lhs_annotation = node_data_container.GetAnnotation(lhs.annotation_data); + auto const &rhs_annotation = node_data_container.GetAnnotation(rhs.annotation_data); + + if (lhs_annotation.is_left_hand_driving != rhs_annotation.is_left_hand_driving) + return false; + + if (lhs_annotation.travel_mode != rhs_annotation.travel_mode) + return false; + + return lhs_annotation.classes == rhs_annotation.classes; +} + using NodeBasedDynamicGraph = DynamicGraph; /// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges /// Since DynamicGraph expects directed edges, we need to insert /// two edges for undirected edges. -inline std::shared_ptr +inline NodeBasedDynamicGraph NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes, const std::vector &input_edge_list) { @@ -92,16 +81,8 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes, const extractor::NodeBasedEdge &input_edge) { output_edge.data.weight = input_edge.weight; output_edge.data.duration = input_edge.duration; - output_edge.data.roundabout = input_edge.roundabout; - output_edge.data.circular = input_edge.circular; - output_edge.data.name_id = input_edge.name_id; - output_edge.data.travel_mode = input_edge.travel_mode; - output_edge.data.classes = input_edge.classes; - output_edge.data.startpoint = input_edge.startpoint; - output_edge.data.restricted = input_edge.restricted; - output_edge.data.is_left_hand_driving = input_edge.is_left_hand_driving; - output_edge.data.road_classification = input_edge.road_classification; - output_edge.data.lane_description_id = input_edge.lane_description_id; + output_edge.data.flags = input_edge.flags; + output_edge.data.annotation_data = input_edge.annotation_data; BOOST_ASSERT(output_edge.data.weight > 0); BOOST_ASSERT(output_edge.data.duration > 0); @@ -109,9 +90,7 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes, tbb::parallel_sort(edges_list.begin(), edges_list.end()); - auto graph = std::make_shared(number_of_nodes, edges_list); - - return graph; + return NodeBasedDynamicGraph(number_of_nodes, edges_list); } } } diff --git a/include/util/packed_vector.hpp b/include/util/packed_vector.hpp index 25d26db44..196946c91 100644 --- a/include/util/packed_vector.hpp +++ b/include/util/packed_vector.hpp @@ -450,6 +450,11 @@ template class Pack friend void serialization::write(storage::io::FileWriter &writer, const PackedVector &vec); + inline void swap(PackedVector &other) noexcept + { + std::swap(vec, other.vec); + std::swap(num_elements, other.num_elements); + } private: void allocate_blocks(std::size_t num_blocks) diff --git a/include/util/typedefs.hpp b/include/util/typedefs.hpp index bb601bfbe..ede2ea3a9 100644 --- a/include/util/typedefs.hpp +++ b/include/util/typedefs.hpp @@ -72,6 +72,7 @@ static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits edge_based_edge_list; updater::Updater updater(config.updater_config); - EdgeID max_edge_id = updater.LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights); + EdgeID number_of_edge_based_nodes = + updater.LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights); // Contracting the edge-expanded graph @@ -82,7 +83,8 @@ int Contractor::Run() extractor::ProfileProperties properties; extractor::files::readProfileProperties(config.GetPath(".osrm.properties"), properties); - node_filters = util::excludeFlagsToNodeFilter(max_edge_id + 1, node_data, properties); + node_filters = + util::excludeFlagsToNodeFilter(number_of_edge_based_nodes, node_data, properties); } RangebasedCRC32 crc32_calculator; @@ -91,11 +93,11 @@ int Contractor::Run() QueryGraph query_graph; std::vector> edge_filters; std::vector> cores; - std::tie(query_graph, edge_filters, cores) = - contractExcludableGraph(toContractorGraph(max_edge_id + 1, std::move(edge_based_edge_list)), - std::move(node_weights), - std::move(node_filters), - config.core_factor); + std::tie(query_graph, edge_filters, cores) = contractExcludableGraph( + toContractorGraph(number_of_edge_based_nodes, std::move(edge_based_edge_list)), + std::move(node_weights), + std::move(node_filters), + config.core_factor); TIMER_STOP(contraction); util::Log() << "Contracted graph has " << query_graph.GetNumberOfEdges() << " edges."; util::Log() << "Contraction took " << TIMER_SEC(contraction) << " sec"; diff --git a/src/extractor/compressed_edge_container.cpp b/src/extractor/compressed_edge_container.cpp index 67b9024b1..c2ab11d66 100644 --- a/src/extractor/compressed_edge_container.cpp +++ b/src/extractor/compressed_edge_container.cpp @@ -264,6 +264,9 @@ void CompressedEdgeContainer::InitializeBothwayVector() unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID r_edge_id) { + if (!segment_data) + InitializeBothwayVector(); + const auto &forward_bucket = GetBucketReference(f_edge_id); const auto &reverse_bucket = GetBucketReference(r_edge_id); diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 968ffa665..ae395c4f4 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -60,19 +60,18 @@ namespace extractor // Configuration to find representative candidate for turn angle calculations EdgeBasedGraphFactory::EdgeBasedGraphFactory( - std::shared_ptr node_based_graph, - CompressedEdgeContainer &compressed_edge_container, + const util::NodeBasedDynamicGraph &node_based_graph, + EdgeBasedNodeDataContainer &node_data_container, + const CompressedEdgeContainer &compressed_edge_container, const std::unordered_set &barrier_nodes, const std::unordered_set &traffic_lights, const std::vector &coordinates, - const extractor::PackedOSMIDs &osm_node_ids, - ProfileProperties profile_properties, const util::NameTable &name_table, guidance::LaneDescriptionMap &lane_description_map) - : m_number_of_edge_based_nodes(0), m_coordinates(coordinates), m_osm_node_ids(osm_node_ids), - m_node_based_graph(std::move(node_based_graph)), m_barrier_nodes(barrier_nodes), - m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container), - profile_properties(std::move(profile_properties)), name_table(name_table), + : 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), + m_compressed_edge_container(compressed_edge_container), name_table(name_table), lane_description_map(lane_description_map) { } @@ -85,12 +84,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedEdges( swap(m_edge_based_edge_list, output_edge_list); } -void EdgeBasedGraphFactory::GetEdgeBasedNodes(EdgeBasedNodeDataContainer &data_container) -{ - using std::swap; // Koenig swap - swap(data_container, m_edge_based_node_container); -} - void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector &nodes) { using std::swap; // Koenig swap @@ -121,21 +114,23 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N BOOST_ASSERT(node_v != SPECIAL_NODEID); // find forward edge id and - const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v); + const EdgeID edge_id_1 = m_node_based_graph.FindEdge(node_u, node_v); BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID); - const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1); + const EdgeData &forward_data = m_node_based_graph.GetEdgeData(edge_id_1); // find reverse edge id and - const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u); + const EdgeID edge_id_2 = m_node_based_graph.FindEdge(node_v, node_u); BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID); - const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2); + const EdgeData &reverse_data = m_node_based_graph.GetEdgeData(edge_id_2); - BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID || reverse_data.edge_id != SPECIAL_NODEID); + BOOST_ASSERT(nbe_to_ebn_mapping[edge_id_1] != SPECIAL_NODEID || + nbe_to_ebn_mapping[edge_id_2] != SPECIAL_NODEID); - if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID) - m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT; + if (nbe_to_ebn_mapping[edge_id_1] != SPECIAL_NODEID && + nbe_to_ebn_mapping[edge_id_2] == SPECIAL_NODEID) + m_edge_based_node_weights[nbe_to_ebn_mapping[edge_id_1]] = INVALID_EDGE_WEIGHT; BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) == m_compressed_edge_container.HasEntryForID(edge_id_2)); @@ -149,7 +144,8 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N // There should always be some geometry BOOST_ASSERT(0 != segment_count); - const unsigned packed_geometry_id = m_compressed_edge_container.ZipEdges(edge_id_1, edge_id_2); + // const unsigned packed_geometry_id = m_compressed_edge_container.ZipEdges(edge_id_1, + // edge_id_2); NodeID current_edge_source_coordinate_id = node_u; @@ -163,23 +159,18 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N }; // Add edge-based node data for forward and reverse nodes indexed by edge_id - BOOST_ASSERT(forward_data.edge_id != SPECIAL_EDGEID); - m_edge_based_node_container.SetData(forward_data.edge_id, - GeometryID{packed_geometry_id, true}, - forward_data.name_id, - forward_data.travel_mode, - forward_data.classes, - forward_data.is_left_hand_driving); - if (reverse_data.edge_id != SPECIAL_EDGEID) + BOOST_ASSERT(nbe_to_ebn_mapping[edge_id_1] != SPECIAL_EDGEID); + m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].geometry_id = + forward_data.geometry_id; + m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].annotation_id = + forward_data.annotation_data; + if (nbe_to_ebn_mapping[edge_id_2] != SPECIAL_EDGEID) { - m_edge_based_node_container.SetData(reverse_data.edge_id, - GeometryID{packed_geometry_id, false}, - reverse_data.name_id, - reverse_data.travel_mode, - reverse_data.classes, - reverse_data.is_left_hand_driving); + m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].geometry_id = + reverse_data.geometry_id; + m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].annotation_id = + reverse_data.annotation_data; } - // Add segments of edge-based nodes for (const auto i : util::irange(std::size_t{0}, segment_count)) { @@ -196,20 +187,21 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id); // build edges - m_edge_based_node_segments.emplace_back(edge_id_to_segment_id(forward_data.edge_id), - edge_id_to_segment_id(reverse_data.edge_id), - current_edge_source_coordinate_id, - current_edge_target_coordinate_id, - i); + m_edge_based_node_segments.emplace_back( + edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_1]), + edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]), + current_edge_source_coordinate_id, + current_edge_target_coordinate_id, + i); - m_edge_based_node_is_startpoint.push_back( - (forward_data.startpoint || reverse_data.startpoint)); + m_edge_based_node_is_startpoint.push_back(forward_data.flags.startpoint || + reverse_data.flags.startpoint); current_edge_source_coordinate_id = current_edge_target_coordinate_id; } BOOST_ASSERT(current_edge_source_coordinate_id == node_v); - return NBGToEBG{node_u, node_v, forward_data.edge_id, reverse_data.edge_id}; + return NBGToEBG{node_u, node_v, nbe_to_ebn_mapping[edge_id_1], nbe_to_ebn_mapping[edge_id_2]}; } void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, @@ -225,9 +217,15 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, const WayRestrictionMap &way_restriction_map) { TIMER_START(renumber); - m_number_of_edge_based_nodes = RenumberEdges() + way_restriction_map.NumberOfDuplicatedNodes(); + m_number_of_edge_based_nodes = + LabelEdgeBasedNodes() + way_restriction_map.NumberOfDuplicatedNodes(); TIMER_STOP(renumber); + // Allocate memory for edge-based nodes + // In addition to the normal edges, allocate enough space for copied edges from + // via-way-restrictions, see calculation above + m_edge_based_node_container.nodes.resize(m_number_of_edge_based_nodes); + TIMER_START(generate_nodes); { auto mapping = GenerateEdgeExpandedNodes(way_restriction_map); @@ -258,19 +256,19 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, /// Renumbers all _forward_ edges and sets the edge_id. /// A specific numbering is not important. Any unique ID will do. /// Returns the number of edge-based nodes. -unsigned EdgeBasedGraphFactory::RenumberEdges() +unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes() { // heuristic: node-based graph node is a simple intersection with four edges (edge-based nodes) - m_edge_based_node_weights.reserve(4 * m_node_based_graph->GetNumberOfNodes()); + m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes()); + nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID); // renumber edge based node of outgoing edges unsigned numbered_edges_count = 0; - for (const auto current_node : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) + for (const auto current_node : util::irange(0u, m_node_based_graph.GetNumberOfNodes())) { - for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node)) + for (const auto current_edge : m_node_based_graph.GetAdjacentEdgeRange(current_node)) { - EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge); - + const EdgeData &edge_data = m_node_based_graph.GetEdgeData(current_edge); // only number incoming edges if (edge_data.reversed) { @@ -279,11 +277,9 @@ unsigned EdgeBasedGraphFactory::RenumberEdges() m_edge_based_node_weights.push_back(edge_data.weight); - BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges()); - edge_data.edge_id = numbered_edges_count; + BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges()); + nbe_to_ebn_mapping[current_edge] = numbered_edges_count; ++numbered_edges_count; - - BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id); } } @@ -296,31 +292,25 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re { std::vector mapping; - // Allocate memory for edge-based nodes - // In addition to the normal edges, allocate enough space for copied edges from - // via-way-restrictions - m_edge_based_node_container = EdgeBasedNodeDataContainer(m_number_of_edge_based_nodes); - util::Log() << "Generating edge expanded nodes ... "; // indicating a normal node within the edge-based graph. This node represents an edge in the // node-based graph { util::UnbufferedLog log; - util::Percent progress(log, m_node_based_graph->GetNumberOfNodes()); + util::Percent progress(log, m_node_based_graph.GetNumberOfNodes()); - m_compressed_edge_container.InitializeBothwayVector(); + // m_compressed_edge_container.InitializeBothwayVector(); // loop over all edges and generate new set of nodes - for (const auto nbg_node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) + for (const auto nbg_node_u : util::irange(0u, m_node_based_graph.GetNumberOfNodes())) { BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID); progress.PrintStatus(nbg_node_u); - for (EdgeID nbg_edge_id : m_node_based_graph->GetAdjacentEdgeRange(nbg_node_u)) + for (EdgeID nbg_edge_id : m_node_based_graph.GetAdjacentEdgeRange(nbg_node_u)) { BOOST_ASSERT(nbg_edge_id != SPECIAL_EDGEID); - const EdgeData &nbg_edge_data = m_node_based_graph->GetEdgeData(nbg_edge_id); - const NodeID nbg_node_v = m_node_based_graph->GetTarget(nbg_edge_id); + const NodeID nbg_node_v = m_node_based_graph.GetTarget(nbg_edge_id); BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID); BOOST_ASSERT(nbg_node_u != nbg_node_v); @@ -332,7 +322,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re } // if we found a non-forward edge reverse and try again - if (nbg_edge_data.edge_id == SPECIAL_NODEID) + if (nbe_to_ebn_mapping[nbg_edge_id] == SPECIAL_NODEID) { mapping.push_back(InsertEdgeBasedNode(nbg_node_v, nbg_node_u)); } @@ -360,28 +350,21 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re const auto node_u = way.from; const auto node_v = way.to; // we know that the edge exists as non-reversed edge - const auto eid = m_node_based_graph->FindEdge(node_u, node_v); + const auto eid = m_node_based_graph.FindEdge(node_u, node_v); - BOOST_ASSERT(m_node_based_graph->GetEdgeData(eid).edge_id != SPECIAL_NODEID); + BOOST_ASSERT(nbe_to_ebn_mapping[eid] != SPECIAL_NODEID); // merge edges together into one EdgeBasedNode BOOST_ASSERT(node_u != SPECIAL_NODEID); BOOST_ASSERT(node_v != SPECIAL_NODEID); // find node in the edge based graph, we only require one id: - const EdgeData &edge_data = m_node_based_graph->GetEdgeData(eid); - // what is this ID all about? :( - BOOST_ASSERT(edge_data.edge_id != SPECIAL_NODEID); - - BOOST_ASSERT(edge_data.edge_id < m_edge_based_node_container.Size()); - m_edge_based_node_container.SetData( - edge_based_node_id, - // fetch the known geometry ID - m_edge_based_node_container.GetGeometryID(static_cast(edge_data.edge_id)), - edge_data.name_id, - edge_data.travel_mode, - edge_data.classes, - edge_data.is_left_hand_driving); + const EdgeData &edge_data = m_node_based_graph.GetEdgeData(eid); + // BOOST_ASSERT(edge_data.edge_id < m_edge_based_node_container.Size()); + m_edge_based_node_container.nodes[edge_based_node_id].geometry_id = + edge_data.geometry_id; + m_edge_based_node_container.nodes[edge_based_node_id].annotation_id = + edge_data.annotation_data; m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]); @@ -431,20 +414,23 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // Three nested loop look super-linear, but we are dealing with a (kind of) // linear number of turns only. SuffixTable street_name_suffix_table(scripting_environment); - guidance::TurnAnalysis turn_analysis(*m_node_based_graph, + guidance::TurnAnalysis turn_analysis(m_node_based_graph, + m_edge_based_node_container, m_coordinates, node_restriction_map, m_barrier_nodes, m_compressed_edge_container, name_table, - street_name_suffix_table, - profile_properties); + street_name_suffix_table); util::guidance::LaneDataIdMap lane_data_map; - guidance::lanes::TurnLaneHandler turn_lane_handler( - *m_node_based_graph, lane_description_map, turn_analysis, lane_data_map); + guidance::lanes::TurnLaneHandler turn_lane_handler(m_node_based_graph, + m_edge_based_node_container, + lane_description_map, + turn_analysis, + lane_data_map); - bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(), + 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 @@ -467,7 +453,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( { util::UnbufferedLog log; - const NodeID node_count = m_node_based_graph->GetNumberOfNodes(); + const NodeID node_count = m_node_based_graph.GetNumberOfNodes(); util::Percent progress(log, node_count); // This counter is used to keep track of how far along we've made it std::uint64_t nodes_completed = 0; @@ -550,7 +536,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const auto node_restricted = isRestricted(node_along_road_entering, node_at_center_of_intersection, - m_node_based_graph->GetTarget(turn.eid), + m_node_based_graph.GetTarget(turn.eid), conditional_restriction_map); boost::optional conditional = boost::none; @@ -565,10 +551,11 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( conditions}}}; } - const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(node_based_edge_from); - const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(node_based_edge_to); + const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from); + const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to); - BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id); + BOOST_ASSERT(nbe_to_ebn_mapping[node_based_edge_from] != + nbe_to_ebn_mapping[node_based_edge_to]); BOOST_ASSERT(!edge_data1.reversed); BOOST_ASSERT(!edge_data2.reversed); @@ -581,11 +568,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // compute weight and duration penalties auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection); - ExtractionTurn extracted_turn(turn, - is_traffic_light, - edge_data1.restricted, - edge_data2.restricted, - edge_data1.is_left_hand_driving); + ExtractionTurn extracted_turn( + turn, + is_traffic_light, + edge_data1.flags.restricted, + edge_data2.flags.restricted, + m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data) + .is_left_hand_driving); scripting_environment.ProcessTurn(extracted_turn); // turn penalties are limited to [-2^15, 2^15) which roughly @@ -594,8 +583,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( boost::numeric_cast(extracted_turn.weight * weight_multiplier); auto duration_penalty = boost::numeric_cast(extracted_turn.duration * 10.); - BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id); - BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id); + BOOST_ASSERT(SPECIAL_NODEID != nbe_to_ebn_mapping[node_based_edge_from]); + BOOST_ASSERT(SPECIAL_NODEID != nbe_to_ebn_mapping[node_based_edge_to]); // auto turn_id = m_edge_based_edge_list.size(); auto weight = boost::numeric_cast(edge_data1.weight + weight_penalty); @@ -682,15 +671,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // `b` by an outgoing edge. Therefore, we have to search all connected edges for // edges entering `b` for (const EdgeID outgoing_edge : - m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_intersection)) + m_node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection)) { const NodeID node_along_road_entering = - m_node_based_graph->GetTarget(outgoing_edge); + m_node_based_graph.GetTarget(outgoing_edge); - const auto incoming_edge = m_node_based_graph->FindEdge( + const auto incoming_edge = m_node_based_graph.FindEdge( node_along_road_entering, node_at_center_of_intersection); - if (m_node_based_graph->GetEdgeData(incoming_edge).reversed) + if (m_node_based_graph.GetEdgeData(incoming_edge).reversed) continue; ++node_based_edge_counter; @@ -743,10 +732,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( if (!turn.entry_allowed) continue; - const EdgeData &edge_data1 = - m_node_based_graph->GetEdgeData(incoming_edge); - const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid); - // In case a way restriction starts at a given location, add a turn onto // every artificial node eminating here. // @@ -764,18 +749,19 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // artificial node, we simply have to find a single representative for // the turn. Here we check whether the turn in question is the start of // a via way restriction. If that should be the case, we switch - // edge_data2.edge_id to the ID of the duplicated node associated with - // the turn. (e.g. ab via bc switches bc to bc_dup) + // the id of the edge-based-node for the target to the ID of the + // duplicated node associated with the turn. (e.g. ab via bc switches bc + // to bc_dup) auto const target_id = way_restriction_map.RemapIfRestricted( - edge_data2.edge_id, + nbe_to_ebn_mapping[turn.eid], node_along_road_entering, node_at_center_of_intersection, - m_node_based_graph->GetTarget(turn.eid), + m_node_based_graph.GetTarget(turn.eid), m_number_of_edge_based_nodes); { // scope to forget edge_with_data after const auto edge_with_data_and_condition = - generate_edge(edge_data1.edge_id, + generate_edge(nbe_to_ebn_mapping[incoming_edge], target_id, node_along_road_entering, incoming_edge, @@ -822,14 +808,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( duplicated_node_id; auto const node_at_end_of_turn = - m_node_based_graph->GetTarget(turn.eid); + m_node_based_graph.GetTarget(turn.eid); 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); @@ -837,16 +822,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( continue; // add into delayed data - auto edge_with_data_and_condition = generate_edge( - NodeID(from_id), - m_node_based_graph->GetEdgeData(turn.eid).edge_id, - node_along_road_entering, - incoming_edge, - node_at_center_of_intersection, - turn.eid, - intersection, - turn, - entry_class_id); + auto edge_with_data_and_condition = + generate_edge(NodeID(from_id), + nbe_to_ebn_mapping[turn.eid], + node_along_road_entering, + incoming_edge, + node_at_center_of_intersection, + turn.eid, + intersection, + turn, + entry_class_id); buffer->delayed_data.push_back( std::move(edge_with_data_and_condition.first)); @@ -863,7 +848,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // add a new conditional for the edge we just created buffer->conditionals.push_back( {NodeID(from_id), - m_node_based_graph->GetEdgeData(turn.eid).edge_id, + nbe_to_ebn_mapping[turn.eid], {static_cast(-1), m_coordinates[node_at_center_of_intersection], restriction.condition}}); @@ -871,16 +856,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( } else { - auto edge_with_data_and_condition = generate_edge( - NodeID(from_id), - m_node_based_graph->GetEdgeData(turn.eid).edge_id, - node_along_road_entering, - incoming_edge, - node_at_center_of_intersection, - turn.eid, - intersection, - turn, - entry_class_id); + auto edge_with_data_and_condition = + generate_edge(NodeID(from_id), + nbe_to_ebn_mapping[turn.eid], + node_along_road_entering, + incoming_edge, + node_at_center_of_intersection, + turn.eid, + intersection, + turn, + entry_class_id); buffer->delayed_data.push_back( std::move(edge_with_data_and_condition.first)); diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 93d33507b..86e440fa0 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -67,23 +67,26 @@ struct CmpEdgeByInternalSourceTargetAndName if (lhs.result.target == SPECIAL_NODEID) return false; - if (lhs.result.name_id == rhs.result.name_id) + auto const lhs_name_id = edge_annotation_data[lhs.result.annotation_data].name_id; + auto const rhs_name_id = edge_annotation_data[rhs.result.annotation_data].name_id; + if (lhs_name_id == rhs_name_id) return false; - if (lhs.result.name_id == EMPTY_NAMEID) + if (lhs_name_id == EMPTY_NAMEID) return false; - if (rhs.result.name_id == EMPTY_NAMEID) + if (rhs_name_id == EMPTY_NAMEID) return true; BOOST_ASSERT(!name_offsets.empty() && name_offsets.back() == name_data.size()); const oe::ExtractionContainers::NameCharData::const_iterator data = name_data.begin(); - return std::lexicographical_compare(data + name_offsets[lhs.result.name_id], - data + name_offsets[lhs.result.name_id + 1], - data + name_offsets[rhs.result.name_id], - data + name_offsets[rhs.result.name_id + 1]); + return std::lexicographical_compare(data + name_offsets[lhs_name_id], + data + name_offsets[lhs_name_id + 1], + data + name_offsets[rhs_name_id], + data + name_offsets[rhs_name_id + 1]); } + const oe::ExtractionContainers::AnnotationDataVector &edge_annotation_data; const oe::ExtractionContainers::NameCharData &name_data; const oe::ExtractionContainers::NameOffsets &name_offsets; }; @@ -136,6 +139,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme all_nodes_list.clear(); // free all_nodes_list before allocation of normal_edges all_nodes_list.shrink_to_fit(); WriteEdges(file_out); + WriteMetadata(file_out); PrepareRestrictions(); WriteCharData(name_file_name); @@ -361,7 +365,7 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm util::Coordinate target_coord{node_iterator->lon, node_iterator->lat}; // flip source and target coordinates if segment is in backward direction only - if (!edge_iterator->result.forward && edge_iterator->result.backward) + if (!edge_iterator->result.flags.forward && edge_iterator->result.flags.backward) std::swap(source_coord, target_coord); const auto distance = @@ -389,9 +393,9 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm std::swap(edge.source, edge.target); // std::swap does not work with bit-fields - bool temp = edge.forward; - edge.forward = edge.backward; - edge.backward = temp; + bool temp = edge.flags.forward; + edge.flags.forward = edge.flags.backward; + edge.flags.backward = temp; } ++edge_iterator; } @@ -415,7 +419,8 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm std::mutex name_data_mutex; tbb::parallel_sort(all_edges_list.begin(), all_edges_list.end(), - CmpEdgeByInternalSourceTargetAndName{name_char_data, name_offsets}); + CmpEdgeByInternalSourceTargetAndName{ + all_edges_annotation_data_list, name_char_data, name_offsets}); TIMER_STOP(sort_edges_by_renumbered_start); log << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s"; } @@ -452,12 +457,12 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm { const auto &result = all_edges_list[i].result; const auto value = std::make_pair(result.weight, result.duration); - if (result.forward && value < min_forward) + if (result.flags.forward && value < min_forward) { min_forward_idx = i; min_forward = value; } - if (result.backward && value < min_backward) + if (result.flags.backward && value < min_backward) { min_backward_idx = i; min_backward = value; @@ -476,9 +481,9 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm if (min_backward_idx == min_forward_idx) { - all_edges_list[min_forward_idx].result.is_split = false; - all_edges_list[min_forward_idx].result.forward = true; - all_edges_list[min_forward_idx].result.backward = true; + all_edges_list[min_forward_idx].result.flags.is_split = false; + all_edges_list[min_forward_idx].result.flags.forward = true; + all_edges_list[min_forward_idx].result.flags.backward = true; } else { @@ -486,17 +491,17 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm bool has_backward = min_backward_idx != std::numeric_limits::max(); if (has_forward) { - all_edges_list[min_forward_idx].result.forward = true; - all_edges_list[min_forward_idx].result.backward = false; - all_edges_list[min_forward_idx].result.is_split = has_backward; + all_edges_list[min_forward_idx].result.flags.forward = true; + all_edges_list[min_forward_idx].result.flags.backward = false; + all_edges_list[min_forward_idx].result.flags.is_split = has_backward; } if (has_backward) { std::swap(all_edges_list[min_backward_idx].result.source, all_edges_list[min_backward_idx].result.target); - all_edges_list[min_backward_idx].result.forward = true; - all_edges_list[min_backward_idx].result.backward = false; - all_edges_list[min_backward_idx].result.is_split = has_forward; + all_edges_list[min_backward_idx].result.flags.forward = true; + all_edges_list[min_backward_idx].result.flags.backward = false; + all_edges_list[min_backward_idx].result.flags.is_split = has_forward; } } @@ -545,10 +550,25 @@ void ExtractionContainers::WriteEdges(storage::io::FileWriter &file_out) const TIMER_STOP(write_edges); log << "ok, after " << TIMER_SEC(write_edges) << "s"; - log << "Processed " << normal_edges.size() << " edges"; + log << " -- Processed " << normal_edges.size() << " edges"; } } +void ExtractionContainers::WriteMetadata(storage::io::FileWriter &file_out) const +{ + util::UnbufferedLog log; + log << "Writing way meta-data ... " << std::flush; + TIMER_START(write_meta_data); + + file_out.WriteElementCount64(all_edges_annotation_data_list.size()); + file_out.WriteFrom(all_edges_annotation_data_list.data(), + all_edges_annotation_data_list.size()); + + TIMER_STOP(write_meta_data); + log << "ok, after " << TIMER_SEC(write_meta_data) << "s"; + log << " -- Metadata contains << " << all_edges_annotation_data_list.size() << " entries."; +} + void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const { { diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index f34cb2a78..b12750d9b 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -7,6 +7,7 @@ #include "extractor/extraction_way.hpp" #include "extractor/extractor_callbacks.hpp" #include "extractor/files.hpp" +#include "extractor/node_based_graph_factory.hpp" #include "extractor/raster_source.hpp" #include "extractor/restriction_filter.hpp" #include "extractor/restriction_parser.hpp" @@ -209,27 +210,80 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) util::DeallocatingVector edge_based_edge_list; std::vector node_is_startpoint; std::vector edge_based_node_weights; - std::vector coordinates; - extractor::PackedOSMIDs osm_node_ids; - auto graph_size = BuildEdgeExpandedGraph(scripting_environment, - coordinates, - osm_node_ids, - edge_based_nodes_container, - edge_based_node_segments, - node_is_startpoint, - edge_based_node_weights, - edge_based_edge_list, - config.GetPath(".osrm.icd").string(), - turn_restrictions, - conditional_turn_restrictions, - turn_lane_map); + // Create a node-based graph from the OSRM file + NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"), + scripting_environment, + turn_restrictions, + conditional_turn_restrictions); - auto number_of_node_based_nodes = graph_size.first; - auto max_edge_id = graph_size.second - 1; + util::Log() << "Writing nodes for nodes-based and edges-based graphs ..."; + auto const &coordinates = node_based_graph_factory.GetCoordinates(); + files::writeNodes( + config.GetPath(".osrm.nbg_nodes"), coordinates, node_based_graph_factory.GetOsmNodes()); + node_based_graph_factory.ReleaseOsmNodes(); + + auto const &node_based_graph = node_based_graph_factory.GetGraph(); + + // The osrm-partition tool requires the compressed node based graph with an embedding. + // + // The `Run` function above re-numbers non-reverse compressed node based graph edges + // to a continuous range so that the nodes in the edge based graph are continuous. + // + // Luckily node based node ids still coincide with the coordinate array. + // That's the reason we can only here write out the final compressed node based graph. + + // Dumps to file asynchronously and makes sure we wait for its completion. + std::future compressed_node_based_graph_writing; + + BOOST_SCOPE_EXIT_ALL(&) + { + if (compressed_node_based_graph_writing.valid()) + compressed_node_based_graph_writing.wait(); + }; + + compressed_node_based_graph_writing = std::async(std::launch::async, [&] { + WriteCompressedNodeBasedGraph( + config.GetPath(".osrm.cnbg").string(), node_based_graph, coordinates); + }); + + node_based_graph_factory.GetCompressedEdges().PrintStatistics(); + + const auto &barrier_nodes = node_based_graph_factory.GetBarriers(); + const auto &traffic_signals = node_based_graph_factory.GetTrafficSignals(); + // stealing the annotation data from the node-based graph + edge_based_nodes_container = + EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData())); + + conditional_turn_restrictions = + removeInvalidRestrictions(std::move(conditional_turn_restrictions), node_based_graph); + + const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes(); + + const auto number_of_edge_based_nodes = + BuildEdgeExpandedGraph(node_based_graph, + coordinates, + node_based_graph_factory.GetCompressedEdges(), + barrier_nodes, + traffic_signals, + turn_restrictions, + conditional_turn_restrictions, + 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()); TIMER_STOP(expansion); + // output the geometry of the node-based graph, needs to be done after the last usage, since it + // destroys internal containers + files::writeSegmentData(config.GetPath(".osrm.geometry"), + *node_based_graph_factory.GetCompressedEdges().ToSegmentData()); + util::Log() << "Saving edge-based node weights to file."; TIMER_START(timer_write_node_weights); { @@ -241,8 +295,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")"; util::Log() << "Computing strictly connected components ..."; - FindComponents( - max_edge_id, edge_based_edge_list, edge_based_node_segments, edge_based_nodes_container); + FindComponents(number_of_edge_based_nodes, + edge_based_edge_list, + edge_based_node_segments, + edge_based_nodes_container); util::Log() << "Building r-tree ..."; TIMER_START(rtree); @@ -250,13 +306,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) TIMER_STOP(rtree); - util::Log() << "Writing nodes for nodes-based and edges-based graphs ..."; - files::writeNodes(config.GetPath(".osrm.nbg_nodes"), coordinates, osm_node_ids); files::writeNodeData(config.GetPath(".osrm.ebg_nodes"), edge_based_nodes_container); util::Log() << "Writing edge-based-graph edges ... " << std::flush; TIMER_START(write_edges); - files::writeEdgeBasedGraph(config.GetPath(".osrm.ebg"), max_edge_id, edge_based_edge_list); + files::writeEdgeBasedGraph( + config.GetPath(".osrm.ebg"), number_of_edge_based_nodes, edge_based_edge_list); TIMER_STOP(write_edges); util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s"; @@ -265,7 +320,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) const auto nodes_per_second = static_cast(number_of_node_based_nodes / TIMER_SEC(expansion)); const auto edges_per_second = - static_cast((max_edge_id + 1) / TIMER_SEC(expansion)); + static_cast((number_of_edge_based_nodes) / TIMER_SEC(expansion)); util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second << " edges/sec"; @@ -492,7 +547,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment, std::move(extraction_containers.conditional_turn_restrictions)); } -void Extractor::FindComponents(unsigned max_edge_id, +void Extractor::FindComponents(unsigned number_of_edge_based_nodes, const util::DeallocatingVector &input_edge_list, const std::vector &input_node_segments, EdgeBasedNodeDataContainer &nodes_container) const @@ -506,8 +561,8 @@ void Extractor::FindComponents(unsigned max_edge_id, { BOOST_ASSERT_MSG(static_cast(std::max(edge.data.weight, 1)) > 0, "edge distance < 1"); - BOOST_ASSERT(edge.source <= max_edge_id); - BOOST_ASSERT(edge.target <= max_edge_id); + BOOST_ASSERT(edge.source < number_of_edge_based_nodes); + BOOST_ASSERT(edge.target < number_of_edge_based_nodes); if (edge.data.forward) { edges.push_back({edge.source, edge.target}); @@ -525,8 +580,8 @@ void Extractor::FindComponents(unsigned max_edge_id, { if (segment.reverse_segment_id.enabled) { - BOOST_ASSERT(segment.forward_segment_id.id <= max_edge_id); - BOOST_ASSERT(segment.reverse_segment_id.id <= max_edge_id); + BOOST_ASSERT(segment.forward_segment_id.id < number_of_edge_based_nodes); + BOOST_ASSERT(segment.reverse_segment_id.id < number_of_edge_based_nodes); edges.push_back({segment.forward_segment_id.id, segment.reverse_segment_id.id}); edges.push_back({segment.reverse_segment_id.id, segment.forward_segment_id.id}); } @@ -535,98 +590,54 @@ void Extractor::FindComponents(unsigned max_edge_id, tbb::parallel_sort(edges.begin(), edges.end()); edges.erase(std::unique(edges.begin(), edges.end()), edges.end()); - auto uncontracted_graph = UncontractedGraph(max_edge_id + 1, edges); + auto uncontracted_graph = UncontractedGraph(number_of_edge_based_nodes, edges); TarjanSCC component_search(uncontracted_graph); component_search.Run(); - for (NodeID node_id = 0; node_id <= max_edge_id; ++node_id) + for (NodeID node_id = 0; node_id < number_of_edge_based_nodes; ++node_id) { const auto forward_component = component_search.GetComponentID(node_id); const auto component_size = component_search.GetComponentSize(forward_component); const auto is_tiny = component_size < config.small_component_size; - nodes_container.SetComponentID(node_id, {1 + forward_component, is_tiny}); + BOOST_ASSERT(node_id < nodes_container.NumberOfNodes()); + nodes_container.nodes[node_id].component_id = {1 + forward_component, is_tiny}; } } -/** - \brief Load node based graph from .osrm file - */ -std::shared_ptr -Extractor::LoadNodeBasedGraph(std::unordered_set &barriers, - std::unordered_set &traffic_signals, - std::vector &coordiantes, - extractor::PackedOSMIDs &osm_node_ids) -{ - storage::io::FileReader file_reader(config.GetPath(".osrm"), - storage::io::FileReader::VerifyFingerprint); - - auto barriers_iter = inserter(barriers, end(barriers)); - auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals)); - - NodeID number_of_node_based_nodes = util::loadNodesFromFile( - file_reader, barriers_iter, traffic_signals_iter, coordiantes, osm_node_ids); - - util::Log() << " - " << barriers.size() << " bollard nodes, " << traffic_signals.size() - << " traffic lights"; - - std::vector edge_list; - util::loadEdgesFromFile(file_reader, edge_list); - - if (edge_list.empty()) - { - throw util::exception("Node-based-graph (" + config.GetPath(".osrm").string() + - ") contains no edges." + SOURCE_REF); - } - - return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list); -} - /** \brief Building an edge-expanded graph from node-based input and turn restrictions */ -std::pair Extractor::BuildEdgeExpandedGraph( + +EdgeID Extractor::BuildEdgeExpandedGraph( + // input data + const util::NodeBasedDynamicGraph &node_based_graph, + const std::vector &coordinates, + const CompressedEdgeContainer &compressed_edge_container, + const std::unordered_set &barrier_nodes, + const std::unordered_set &traffic_signals, + const std::vector &turn_restrictions, + const std::vector &conditional_turn_restrictions, + // might have to be updated to add new lane combinations + guidance::LaneDescriptionMap &turn_lane_map, + // for calculating turn penalties ScriptingEnvironment &scripting_environment, - std::vector &coordinates, - extractor::PackedOSMIDs &osm_node_ids, + // output data EdgeBasedNodeDataContainer &edge_based_nodes_container, 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, - std::vector &turn_restrictions, - std::vector &conditional_turn_restrictions, - guidance::LaneDescriptionMap &turn_lane_map) + const std::string &intersection_class_output_file) { - std::unordered_set barrier_nodes; - std::unordered_set traffic_signals; - - auto node_based_graph = - LoadNodeBasedGraph(barrier_nodes, traffic_signals, coordinates, osm_node_ids); - - CompressedEdgeContainer compressed_edge_container; - GraphCompressor graph_compressor; - graph_compressor.Compress(barrier_nodes, - traffic_signals, - scripting_environment, - turn_restrictions, - conditional_turn_restrictions, - *node_based_graph, - compressed_edge_container); - - conditional_turn_restrictions = - removeInvalidRestrictions(std::move(conditional_turn_restrictions), *node_based_graph); - util::NameTable name_table(config.GetPath(".osrm.names").string()); EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph, + edge_based_nodes_container, compressed_edge_container, barrier_nodes, traffic_signals, coordinates, - osm_node_ids, - scripting_environment.GetProfileProperties(), name_table, turn_lane_map); @@ -646,8 +657,6 @@ std::pair Extractor::BuildEdgeExpandedGraph( WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions); ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions, IndexNodeByFromAndVia()); - turn_restrictions.clear(); - turn_restrictions.shrink_to_fit(); edge_based_graph_factory.Run(scripting_environment, config.GetPath(".osrm.edges").string(), @@ -664,29 +673,6 @@ std::pair Extractor::BuildEdgeExpandedGraph( }; const auto number_of_edge_based_nodes = create_edge_based_edges(); - compressed_edge_container.PrintStatistics(); - - // The osrm-partition tool requires the compressed node based graph with an embedding. - // - // The `Run` function above re-numbers non-reverse compressed node based graph edges - // to a continuous range so that the nodes in the edge based graph are continuous. - // - // Luckily node based node ids still coincide with the coordinate array. - // That's the reason we can only here write out the final compressed node based graph. - - // Dumps to file asynchronously and makes sure we wait for its completion. - std::future compressed_node_based_graph_writing; - - BOOST_SCOPE_EXIT_ALL(&) - { - if (compressed_node_based_graph_writing.valid()) - compressed_node_based_graph_writing.wait(); - }; - - compressed_node_based_graph_writing = std::async(std::launch::async, [&] { - WriteCompressedNodeBasedGraph( - config.GetPath(".osrm.cnbg").string(), *node_based_graph, coordinates); - }); { std::vector turn_lane_offsets; @@ -696,17 +682,12 @@ std::pair Extractor::BuildEdgeExpandedGraph( files::writeTurnLaneDescriptions( config.GetPath(".osrm.tls"), turn_lane_offsets, turn_lane_masks); } - files::writeSegmentData(config.GetPath(".osrm.geometry"), - *compressed_edge_container.ToSegmentData()); edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list); - edge_based_graph_factory.GetEdgeBasedNodes(edge_based_nodes_container); 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); - const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes(); - util::Log() << "Writing Intersection Classification Data"; TIMER_START(write_intersections); files::writeIntersections( @@ -717,7 +698,7 @@ std::pair Extractor::BuildEdgeExpandedGraph( TIMER_STOP(write_intersections); util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s"; - return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes); + return number_of_edge_based_nodes; } /** diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 6c14da86d..1527db8b7 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -390,57 +390,67 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti if (in_forward_direction) { // add (forward) segments or (forward,backward) for non-split edges in backward direction + const auto annotation_data_id = external_memory.all_edges_annotation_data_list.size(); + external_memory.all_edges_annotation_data_list.push_back({name_id, + turn_lane_id_forward, + forward_classes, + parsed_way.forward_travel_mode, + parsed_way.is_left_hand_driving}); util::for_each_pair( nodes.cbegin(), nodes.cend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { - external_memory.all_edges_list.push_back( - InternalExtractorEdge(OSMNodeID{static_cast(first_node.ref())}, - OSMNodeID{static_cast(last_node.ref())}, - name_id, - forward_weight_data, - forward_duration_data, - true, - in_backward_direction && !split_edge, - parsed_way.roundabout, - parsed_way.circular, - parsed_way.is_startpoint, - parsed_way.forward_restricted, - parsed_way.is_left_hand_driving, - split_edge, - parsed_way.forward_travel_mode, - forward_classes, - turn_lane_id_forward, - road_classification, - {})); + NodeBasedEdgeWithOSM edge = { + OSMNodeID{static_cast(first_node.ref())}, + OSMNodeID{static_cast(last_node.ref())}, + 0, // weight + 0, // duration + {}, // geometry id + static_cast(annotation_data_id), + {true, + in_backward_direction && !split_edge, + split_edge, + parsed_way.roundabout, + parsed_way.circular, + parsed_way.is_startpoint, + parsed_way.forward_restricted, + road_classification}}; + + external_memory.all_edges_list.push_back(InternalExtractorEdge( + std::move(edge), forward_weight_data, forward_duration_data, {})); }); } if (in_backward_direction && (!in_forward_direction || split_edge)) { // add (backward) segments for split edges or not in forward direction + const auto annotation_data_id = external_memory.all_edges_annotation_data_list.size(); + external_memory.all_edges_annotation_data_list.push_back({name_id, + turn_lane_id_backward, + backward_classes, + parsed_way.backward_travel_mode, + parsed_way.is_left_hand_driving}); util::for_each_pair( nodes.cbegin(), nodes.cend(), [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) { - external_memory.all_edges_list.push_back( - InternalExtractorEdge(OSMNodeID{static_cast(first_node.ref())}, - OSMNodeID{static_cast(last_node.ref())}, - name_id, - backward_weight_data, - backward_duration_data, - false, - true, - parsed_way.roundabout, - parsed_way.circular, - parsed_way.is_startpoint, - parsed_way.backward_restricted, - parsed_way.is_left_hand_driving, - split_edge, - parsed_way.backward_travel_mode, - backward_classes, - turn_lane_id_backward, - road_classification, - {})); + NodeBasedEdgeWithOSM edge = { + OSMNodeID{static_cast(first_node.ref())}, + OSMNodeID{static_cast(last_node.ref())}, + 0, // weight + 0, // duration + {}, // geometry id + static_cast(annotation_data_id), + {false, + true, + split_edge, + parsed_way.roundabout, + parsed_way.circular, + parsed_way.is_startpoint, + parsed_way.backward_restricted, + road_classification}}; + + external_memory.all_edges_list.push_back(InternalExtractorEdge( + std::move(edge), backward_weight_data, backward_duration_data, {})); }); } diff --git a/src/extractor/graph_compressor.cpp b/src/extractor/graph_compressor.cpp index cab2ae4cd..4b2691e36 100644 --- a/src/extractor/graph_compressor.cpp +++ b/src/extractor/graph_compressor.cpp @@ -27,6 +27,7 @@ void GraphCompressor::Compress( std::vector &turn_restrictions, std::vector &conditional_turn_restrictions, util::NodeBasedDynamicGraph &graph, + const std::vector &node_data_container, CompressedEdgeContainer &geometry_compressor) { const unsigned original_number_of_nodes = graph.GetNumberOfNodes(); @@ -104,6 +105,7 @@ void GraphCompressor::Compress( BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && forward_e2 < graph.EndEdges(node_v)); const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order; + BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2); BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) && reverse_e2 < graph.EndEdges(node_v)); @@ -127,6 +129,10 @@ void GraphCompressor::Compress( const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1); const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1); + const auto fwd_annotation_data1 = node_data_container[fwd_edge_data1.annotation_data]; + const auto fwd_annotation_data2 = node_data_container[fwd_edge_data2.annotation_data]; + const auto rev_annotation_data1 = node_data_container[rev_edge_data1.annotation_data]; + const auto rev_annotation_data2 = node_data_container[rev_edge_data2.annotation_data]; if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID) { @@ -134,20 +140,22 @@ void GraphCompressor::Compress( } // this case can happen if two ways with different names overlap - if (fwd_edge_data1.name_id != rev_edge_data1.name_id || - fwd_edge_data2.name_id != rev_edge_data2.name_id) + if ((fwd_annotation_data1.name_id != rev_annotation_data1.name_id) || + (fwd_annotation_data2.name_id != rev_annotation_data2.name_id)) { continue; } - if (fwd_edge_data1.CanCombineWith(fwd_edge_data2) && - rev_edge_data1.CanCombineWith(rev_edge_data2)) + if ((fwd_edge_data1.flags == fwd_edge_data2.flags) && + (rev_edge_data1.flags == rev_edge_data2.flags) && + (fwd_edge_data1.reversed == fwd_edge_data2.reversed) && + (rev_edge_data1.reversed == rev_edge_data2.reversed) && + // annotations need to match, except for the lane-id which can differ + fwd_annotation_data1.CanCombineWith(fwd_annotation_data2) && + rev_annotation_data1.CanCombineWith(rev_annotation_data2)) { - BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id == - graph.GetEdgeData(reverse_e1).name_id); - BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id == - graph.GetEdgeData(reverse_e2).name_id); - + BOOST_ASSERT(!(graph.GetEdgeData(forward_e1).reversed && + graph.GetEdgeData(reverse_e1).reversed)); /* * Remember Lane Data for compressed parts. This handles scenarios where lane-data * is @@ -175,24 +183,26 @@ void GraphCompressor::Compress( * just * like a barrier. */ - const auto selectLaneID = [](const LaneDescriptionID front, - const LaneDescriptionID back) { + const auto selectAnnotation = [&node_data_container]( + const AnnotationID front_annotation, const AnnotationID back_annotation) { // A lane has tags: u - (front) - v - (back) - w // During contraction, we keep only one of the tags. Usually the one closer to - // the - // intersection is preferred. If its empty, however, we keep the non-empty one - if (back == INVALID_LANE_DESCRIPTIONID) - return front; - return back; + // the intersection is preferred. If its empty, however, we keep the non-empty + // one + if (node_data_container[back_annotation].lane_description_id == + INVALID_LANE_DESCRIPTIONID) + return front_annotation; + return back_annotation; }; - graph.GetEdgeData(forward_e1).lane_description_id = selectLaneID( - fwd_edge_data1.lane_description_id, fwd_edge_data2.lane_description_id); - graph.GetEdgeData(reverse_e1).lane_description_id = selectLaneID( - rev_edge_data1.lane_description_id, rev_edge_data2.lane_description_id); - graph.GetEdgeData(forward_e2).lane_description_id = selectLaneID( - fwd_edge_data2.lane_description_id, fwd_edge_data1.lane_description_id); - graph.GetEdgeData(reverse_e2).lane_description_id = selectLaneID( - rev_edge_data2.lane_description_id, rev_edge_data1.lane_description_id); + + graph.GetEdgeData(forward_e1).annotation_data = selectAnnotation( + fwd_edge_data1.annotation_data, fwd_edge_data2.annotation_data); + graph.GetEdgeData(reverse_e1).annotation_data = selectAnnotation( + rev_edge_data1.annotation_data, rev_edge_data2.annotation_data); + graph.GetEdgeData(forward_e2).annotation_data = selectAnnotation( + fwd_edge_data2.annotation_data, fwd_edge_data1.annotation_data); + graph.GetEdgeData(reverse_e2).annotation_data = selectAnnotation( + rev_edge_data2.annotation_data, rev_edge_data1.annotation_data); /* // Do not compress edge if it crosses a traffic signal. @@ -206,14 +216,15 @@ void GraphCompressor::Compress( if (has_node_penalty) { // we cannot handle this as node penalty, if it depends on turn direction - if (fwd_edge_data1.restricted != fwd_edge_data2.restricted) + if (fwd_edge_data1.flags.restricted != fwd_edge_data2.flags.restricted) continue; // generate an artifical turn for the turn penalty generation - ExtractionTurn extraction_turn(true, - fwd_edge_data1.restricted, - fwd_edge_data2.restricted, - fwd_edge_data1.is_left_hand_driving); + ExtractionTurn extraction_turn( + true, + fwd_edge_data1.flags.restricted, + fwd_edge_data2.flags.restricted, + node_data_container[fwd_edge_data1.annotation_data].is_left_hand_driving); scripting_environment.ProcessTurn(extraction_turn); node_duration_penalty = extraction_turn.duration * 10; diff --git a/src/extractor/guidance/coordinate_extractor.cpp b/src/extractor/guidance/coordinate_extractor.cpp index 9b146ab98..85a368f35 100644 --- a/src/extractor/guidance/coordinate_extractor.cpp +++ b/src/extractor/guidance/coordinate_extractor.cpp @@ -122,7 +122,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate( // coordinate set to add a small level of fault tolerance const constexpr double skipping_inaccuracies_distance = 2; - const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge); + const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge).flags; // roundabouts, check early to avoid other costly checks if (turn_edge_data.roundabout || turn_edge_data.circular) @@ -175,7 +175,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate( // the lane count might not always be set. We need to assume a positive number, though. Here we // select the number of lanes to operate on const auto considered_lanes = - GetOffsetCorrectionFactor(node_based_graph.GetEdgeData(turn_edge).road_classification) * + GetOffsetCorrectionFactor(turn_edge_data.road_classification) * ((intersection_lanes == 0) ? ASSUMED_LANE_COUNT : intersection_lanes); /* if the very first coordinate along the road is reasonably far away from the road, we assume @@ -644,7 +644,7 @@ bool CoordinateExtractor::IsCurve(const std::vector &coordinat const std::vector &segment_distances, const double segment_length, const double considered_lane_width, - const util::NodeBasedEdgeData &edge_data) const + const extractor::NodeBasedEdgeClassification &edge_data) const { BOOST_ASSERT(coordinates.size() > 2); diff --git a/src/extractor/guidance/driveway_handler.cpp b/src/extractor/guidance/driveway_handler.cpp index 83bab82a9..3b1f0bac1 100644 --- a/src/extractor/guidance/driveway_handler.cpp +++ b/src/extractor/guidance/driveway_handler.cpp @@ -14,10 +14,12 @@ namespace guidance DrivewayHandler::DrivewayHandler(const IntersectionGenerator &intersection_generator, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table) : IntersectionHandler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, @@ -38,13 +40,13 @@ bool DrivewayHandler::canProcess(const NodeID /*nid*/, const auto from_eid = intersection.getUTurnRoad().eid; if (intersection.size() <= 2 || - node_based_graph.GetEdgeData(from_eid).road_classification.IsLowPriorityRoadClass()) + node_based_graph.GetEdgeData(from_eid).flags.road_classification.IsLowPriorityRoadClass()) return false; auto low_priority_count = std::count_if(intersection.begin(), intersection.end(), [this](const auto &road) { return node_based_graph.GetEdgeData(road.eid) - .road_classification.IsLowPriorityRoadClass(); + .flags.road_classification.IsLowPriorityRoadClass(); }); // Process intersection if it has two edges with normal priority and one is the entry edge, @@ -58,7 +60,7 @@ operator()(const NodeID nid, const EdgeID source_edge_id, Intersection intersect auto road = std::find_if(intersection.begin() + 1, intersection.end(), [this](const auto &road) { return !node_based_graph.GetEdgeData(road.eid) - .road_classification.IsLowPriorityRoadClass(); + .flags.road_classification.IsLowPriorityRoadClass(); }); (void)nid; diff --git a/src/extractor/guidance/intersection_generator.cpp b/src/extractor/guidance/intersection_generator.cpp index 21421f17b..d1d6e2075 100644 --- a/src/extractor/guidance/intersection_generator.cpp +++ b/src/extractor/guidance/intersection_generator.cpp @@ -33,12 +33,13 @@ const constexpr bool USE_HIGH_PRECISION_MODE = !USE_LOW_PRECISION_MODE; IntersectionGenerator::IntersectionGenerator( const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, const std::vector &coordinates, const CompressedEdgeContainer &compressed_edge_container) - : node_based_graph(node_based_graph), restriction_map(restriction_map), - barrier_nodes(barrier_nodes), coordinates(coordinates), + : node_based_graph(node_based_graph), node_data_container(node_data_container), + restriction_map(restriction_map), barrier_nodes(barrier_nodes), coordinates(coordinates), coordinate_extractor(node_based_graph, compressed_edge_container, coordinates) { } @@ -69,15 +70,15 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i // number of lanes at the intersection changes how far we look down the road const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection); - const auto max_lanes_intersection = std::accumulate( - edge_range.begin(), - edge_range.end(), - std::uint8_t{0}, - [this](const auto current_max, const auto current_eid) { - return std::max( - current_max, - node_based_graph.GetEdgeData(current_eid).road_classification.GetNumberOfLanes()); - }); + const auto max_lanes_intersection = + std::accumulate(edge_range.begin(), + edge_range.end(), + std::uint8_t{0}, + [this](const auto current_max, const auto current_eid) { + return std::max(current_max, + node_based_graph.GetEdgeData(current_eid) + .flags.road_classification.GetNumberOfLanes()); + }); for (const EdgeID edge_connected_to_intersection : node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection)) @@ -265,9 +266,11 @@ IntersectionGenerator::SkipDegreeTwoNodes(const NodeID starting_node, const Edge query_node = next_node; query_edge = next_edge; - if (!node_based_graph.GetEdgeData(query_edge) - .IsCompatibleTo(node_based_graph.GetEdgeData(next_edge)) || - node_based_graph.GetTarget(next_edge) == starting_node) + // check if there is a relevant change in the graph + if (!CanBeCompressed(node_based_graph.GetEdgeData(query_edge), + node_based_graph.GetEdgeData(next_edge), + node_data_container) || + (node_based_graph.GetTarget(next_edge) == starting_node)) break; } diff --git a/src/extractor/guidance/intersection_handler.cpp b/src/extractor/guidance/intersection_handler.cpp index 3b760709b..dd43a4ba2 100644 --- a/src/extractor/guidance/intersection_handler.cpp +++ b/src/extractor/guidance/intersection_handler.cpp @@ -24,21 +24,38 @@ namespace guidance namespace detail { -inline bool requiresAnnouncement(const EdgeData &from, const EdgeData &to) +// TODO check flags! +inline bool requiresAnnouncement(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, + const EdgeID from, + const EdgeID to) { - return !from.CanCombineWith(to); -} + const auto &from_edge = node_based_graph.GetEdgeData(from); + const auto &to_edge = node_based_graph.GetEdgeData(to); + + if (from_edge.reversed != to_edge.reversed) + return true; + + if (!(from_edge.flags == to_edge.flags)) + return true; + + const auto &annotation_from = node_data_container.GetAnnotation(from_edge.annotation_data); + const auto &annotation_to = node_data_container.GetAnnotation(to_edge.annotation_data); + return !annotation_from.CanCombineWith(annotation_to); } +} // namespace detail IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, const IntersectionGenerator &intersection_generator) - : node_based_graph(node_based_graph), coordinates(coordinates), name_table(name_table), + : node_based_graph(node_based_graph), node_data_container(node_data_container), + coordinates(coordinates), name_table(name_table), street_name_suffix_table(street_name_suffix_table), intersection_generator(intersection_generator), - graph_walker(node_based_graph, intersection_generator) + graph_walker(node_based_graph, node_data_container, intersection_generator) { } @@ -48,20 +65,23 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &road) const { - const auto &in_data = node_based_graph.GetEdgeData(via_edge); - const auto &out_data = node_based_graph.GetEdgeData(road.eid); - - bool on_ramp = in_data.road_classification.IsRampClass(); - - bool onto_ramp = out_data.road_classification.IsRampClass(); + bool on_ramp = node_based_graph.GetEdgeData(via_edge).flags.road_classification.IsRampClass(); + bool onto_ramp = node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsRampClass(); if (!on_ramp && onto_ramp) return TurnType::OnRamp; - const auto same_name = !util::guidance::requiresNameAnnounced( - in_data.name_id, out_data.name_id, name_table, street_name_suffix_table); + const auto &in_name = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data) + .name_id; + const auto &out_name = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .name_id; - if (in_data.name_id != EMPTY_NAMEID && out_data.name_id != EMPTY_NAMEID && same_name) + const auto same_name = !util::guidance::requiresNameAnnounced( + in_name, out_name, name_table, street_name_suffix_table); + + if (in_name != EMPTY_NAMEID && out_name != EMPTY_NAMEID && same_name) { return TurnType::Continue; } @@ -86,14 +106,22 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t } // handle travel modes: - const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode; - const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode; + const auto in_mode = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data) + .travel_mode; + const auto out_mode = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .travel_mode; const auto needs_notification = in_mode != out_mode; if (type == TurnType::Turn) { - const auto &in_data = node_based_graph.GetEdgeData(via_edge); - const auto &out_data = node_based_graph.GetEdgeData(road.eid); + const auto &in_classification = node_based_graph.GetEdgeData(via_edge).flags; + const auto &in_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(via_edge).annotation_data); + const auto &out_classification = node_based_graph.GetEdgeData(road.eid).flags; + const auto &out_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(road.eid).annotation_data); if (util::guidance::requiresNameAnnounced( in_data.name_id, out_data.name_id, name_table, street_name_suffix_table)) @@ -104,12 +132,12 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t // We reserve merges for motorway types. All others are considered for simply going // straight onto a road. This avoids confusion about merge directions on streets // that could potentially also offer different choices - if (out_data.road_classification.IsMotorwayClass()) + if (out_classification.road_classification.IsMotorwayClass()) return {TurnType::Merge, road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightRight : DirectionModifier::SlightLeft}; - else if (in_data.road_classification.IsRampClass() && - out_data.road_classification.IsRampClass()) + else if (in_classification.road_classification.IsRampClass() && + out_classification.road_classification.IsRampClass()) { // This check is more a precaution than anything else. Our current travel modes // cannot reach this, since all ramps are exposing the same travel type. But we @@ -177,15 +205,20 @@ void IntersectionHandler::assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const { - const auto &in_data = node_based_graph.GetEdgeData(via_edge); - const bool low_priority_left = - node_based_graph.GetEdgeData(left.eid).road_classification.IsLowPriorityRoadClass(); - const bool low_priority_right = - node_based_graph.GetEdgeData(right.eid).road_classification.IsLowPriorityRoadClass(); - const auto same_mode_left = - in_data.travel_mode == node_based_graph.GetEdgeData(left.eid).travel_mode; - const auto same_mode_right = - in_data.travel_mode == node_based_graph.GetEdgeData(right.eid).travel_mode; + const auto &in_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data); + const auto &lhs_classification = + node_based_graph.GetEdgeData(left.eid).flags.road_classification; + const auto &lhs_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(left.eid).annotation_data); + const auto &rhs_classification = + node_based_graph.GetEdgeData(right.eid).flags.road_classification; + const auto &rhs_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(right.eid).annotation_data); + const bool low_priority_left = lhs_classification.IsLowPriorityRoadClass(); + const bool low_priority_right = rhs_classification.IsLowPriorityRoadClass(); + const auto same_mode_left = in_data.travel_mode == lhs_data.travel_mode; + const auto same_mode_right = in_data.travel_mode == rhs_data.travel_mode; const auto suppressed_left_type = same_mode_left ? TurnType::Suppressed : TurnType::Notification; const auto suppressed_right_type = @@ -194,8 +227,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge, angularDeviation(right.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)) { // left side is actually straight - const auto &out_data = node_based_graph.GetEdgeData(left.eid); - if (detail::requiresAnnouncement(in_data, out_data)) + if (detail::requiresAnnouncement(node_based_graph, node_data_container, via_edge, left.eid)) { if (low_priority_right && !low_priority_left) { @@ -230,11 +262,11 @@ void IntersectionHandler::assignFork(const EdgeID via_edge, angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE) { // right side is actually straight - const auto &out_data = node_based_graph.GetEdgeData(right.eid); if (angularDeviation(right.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION && angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE) { - if (detail::requiresAnnouncement(in_data, out_data)) + if (detail::requiresAnnouncement( + node_based_graph, node_data_container, via_edge, right.eid)) { if (low_priority_left && !low_priority_right) { @@ -304,8 +336,14 @@ void IntersectionHandler::assignFork(const EdgeID via_edge, { // TODO handle low priority road classes in a reasonable way const auto suppressed_type = [&](const ConnectedRoad &road) { - const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode; - const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode; + const auto in_mode = + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data) + .travel_mode; + const auto out_mode = + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .travel_mode; return in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification; }; @@ -314,9 +352,8 @@ void IntersectionHandler::assignFork(const EdgeID via_edge, left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft}; if (angularDeviation(center.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION) { - const auto &in_data = node_based_graph.GetEdgeData(via_edge); - const auto &out_data = node_based_graph.GetEdgeData(center.eid); - if (detail::requiresAnnouncement(in_data, out_data)) + if (detail::requiresAnnouncement( + node_based_graph, node_data_container, via_edge, center.eid)) { center.instruction = {TurnType::Fork, DirectionModifier::Straight}; } @@ -371,7 +408,8 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid, bool IntersectionHandler::isThroughStreet(const std::size_t index, const Intersection &intersection) const { - const auto &data_at_index = node_based_graph.GetEdgeData(intersection[index].eid); + const auto &data_at_index = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(intersection[index].eid).annotation_data); if (data_at_index.name_id == EMPTY_NAMEID) return false; @@ -383,7 +421,8 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index, continue; const auto &road = intersection[road_index]; - const auto &road_data = node_based_graph.GetEdgeData(road.eid); + const auto &road_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(road.eid).annotation_data); // roads have a near straight angle (180 degree) const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) > @@ -395,7 +434,8 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index, data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table); const bool have_same_category = - data_at_index.road_classification == road_data.road_classification; + node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification == + node_based_graph.GetEdgeData(road.eid).flags.road_classification; if (is_nearly_straight && have_same_name && have_same_category) return true; @@ -443,8 +483,10 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons bool IntersectionHandler::isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const { - const auto &source_edge_data = node_based_graph.GetEdgeData(source_edge_id); - const auto &target_edge_data = node_based_graph.GetEdgeData(target_edge_id); + const auto &source_edge_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(source_edge_id).annotation_data); + const auto &target_edge_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(target_edge_id).annotation_data); return source_edge_data.name_id != EMPTY_NAMEID && // target_edge_data.name_id != EMPTY_NAMEID && // diff --git a/src/extractor/guidance/intersection_normalizer.cpp b/src/extractor/guidance/intersection_normalizer.cpp index fffa32645..7b7e9fa3a 100644 --- a/src/extractor/guidance/intersection_normalizer.cpp +++ b/src/extractor/guidance/intersection_normalizer.cpp @@ -14,13 +14,16 @@ namespace extractor namespace guidance { -IntersectionNormalizer::IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph, - const std::vector &coordinates, - const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table, - const IntersectionGenerator &intersection_generator) +IntersectionNormalizer::IntersectionNormalizer( + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, + const std::vector &coordinates, + const util::NameTable &name_table, + const SuffixTable &street_name_suffix_table, + const IntersectionGenerator &intersection_generator) : node_based_graph(node_based_graph), intersection_generator(intersection_generator), mergable_road_detector(node_based_graph, + node_data_container, coordinates, intersection_generator, intersection_generator.GetCoordinateExtractor(), diff --git a/src/extractor/guidance/mergable_road_detector.cpp b/src/extractor/guidance/mergable_road_detector.cpp index 14b16e157..1248b2870 100644 --- a/src/extractor/guidance/mergable_road_detector.cpp +++ b/src/extractor/guidance/mergable_road_detector.cpp @@ -25,13 +25,17 @@ namespace // check a connected road for equality of a name inline auto makeCheckRoadForName(const NameID name_id, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const util::NameTable &name_table, const SuffixTable &suffix_table) { - return [name_id, &node_based_graph, &name_table, &suffix_table]( + return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table]( const MergableRoadDetector::MergableRoadData &road) { // since we filter here, we don't want any other name than the one we are looking for - const auto road_name = node_based_graph.GetEdgeData(road.eid).name_id; + const auto road_name = + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .name_id; if (name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID) return true; const auto requires_announcement = @@ -44,14 +48,16 @@ inline auto makeCheckRoadForName(const NameID name_id, } MergableRoadDetector::MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &node_coordinates, const IntersectionGenerator &intersection_generator, const CoordinateExtractor &coordinate_extractor, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table) - : node_based_graph(node_based_graph), node_coordinates(node_coordinates), - intersection_generator(intersection_generator), coordinate_extractor(coordinate_extractor), - name_table(name_table), street_name_suffix_table(street_name_suffix_table) + : node_based_graph(node_based_graph), node_data_container(node_data_container), + node_coordinates(node_coordinates), intersection_generator(intersection_generator), + coordinate_extractor(coordinate_extractor), name_table(name_table), + street_name_suffix_table(street_name_suffix_table) { } @@ -63,11 +69,14 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node, if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE) return false; - const auto &lhs_edge_data = node_based_graph.GetEdgeData(lhs.eid); - const auto &rhs_edge_data = node_based_graph.GetEdgeData(rhs.eid); + const auto &lhs_edge = node_based_graph.GetEdgeData(lhs.eid); + const auto &rhs_edge = node_based_graph.GetEdgeData(rhs.eid); + const auto &lhs_edge_data = node_data_container.GetAnnotation(lhs_edge.annotation_data); + const auto &rhs_edge_data = node_data_container.GetAnnotation(rhs_edge.annotation_data); // and they need to describe the same road - if (!EdgeDataSupportsMerge(lhs_edge_data, rhs_edge_data)) + if ((lhs_edge.reversed == rhs_edge.reversed) || + !EdgeDataSupportsMerge(lhs_edge.flags, rhs_edge.flags, lhs_edge_data, rhs_edge_data)) return false; /* don't use any circular links, since they mess up detection we jump out early. @@ -120,36 +129,36 @@ bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs, if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE) return true; else // or it cannot have the same name - return !HaveIdenticalNames(node_based_graph.GetEdgeData(lhs.eid).name_id, - node_based_graph.GetEdgeData(rhs.eid).name_id); + return !HaveIdenticalNames( + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data) + .name_id, + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data) + .name_id); } -bool MergableRoadDetector::EdgeDataSupportsMerge(const util::NodeBasedEdgeData &lhs_edge_data, - const util::NodeBasedEdgeData &rhs_edge_data) const +bool MergableRoadDetector::EdgeDataSupportsMerge( + const NodeBasedEdgeClassification &lhs_flags, + const NodeBasedEdgeClassification &rhs_flags, + const NodeBasedEdgeAnnotation &lhs_annotation, + const NodeBasedEdgeAnnotation &rhs_annotation) const { // roundabouts are special, simply don't hurt them. We might not want to bear the // consequences - if (lhs_edge_data.roundabout || rhs_edge_data.roundabout) - return false; - - /* to describe the same road, but in opposite directions (which is what we require for a - * merge), the roads have to feature one reversed and one non-reversed edge - */ - if (lhs_edge_data.reversed == rhs_edge_data.reversed) + if (lhs_flags.roundabout || rhs_flags.roundabout) return false; /* The travel mode should be the same for both roads. If we were to merge different travel * modes, we would hide information/run the risk of loosing valid choices (e.g. short period * of pushing) */ - if (lhs_edge_data.travel_mode != rhs_edge_data.travel_mode) + if (lhs_annotation.travel_mode != rhs_annotation.travel_mode) return false; // we require valid names - if (!HaveIdenticalNames(lhs_edge_data.name_id, rhs_edge_data.name_id)) + if (!HaveIdenticalNames(lhs_annotation.name_id, rhs_annotation.name_id)) return false; - return lhs_edge_data.road_classification == rhs_edge_data.road_classification; + return lhs_flags.road_classification == rhs_flags.road_classification; } bool MergableRoadDetector::IsTrafficLoop(const NodeID intersection_node, @@ -172,9 +181,13 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node, * Since both items have the same id, we can `select` based on any setup */ SelectStraightmostRoadByNameAndOnlyChoice selector( - node_based_graph.GetEdgeData(lhs.eid).name_id, lhs.bearing, /*requires entry=*/false); + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data) + .name_id, + lhs.bearing, + /*requires entry=*/false); - NodeBasedGraphWalker graph_walker(node_based_graph, intersection_generator); + NodeBasedGraphWalker graph_walker( + node_based_graph, node_data_container, intersection_generator); graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector); /* if the intersection does not have a right turn, we continue onto the next one once * (skipping over a single small side street) @@ -231,7 +244,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node, const auto num_lanes = [this](const MergableRoadData &road) { return std::max( - node_based_graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes(), 1); + node_based_graph.GetEdgeData(road.eid).flags.road_classification.GetNumberOfLanes(), 1); }; // the width we can bridge at the intersection @@ -265,11 +278,15 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node, return false; // Find a coordinate following a road that is far away - NodeBasedGraphWalker graph_walker(node_based_graph, intersection_generator); + NodeBasedGraphWalker graph_walker( + node_based_graph, node_data_container, intersection_generator); const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) { LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length); SelectStraightmostRoadByNameAndOnlyChoice selector( - node_based_graph.GetEdgeData(edge_id).name_id, lhs.bearing, /*requires_entry=*/false); + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data) + .name_id, + lhs.bearing, + /*requires_entry=*/false); graph_walker.TraverseRoad(intersection_node, edge_id, accumulator, selector); return std::make_pair(accumulator.accumulated_length, accumulator.coordinates); @@ -342,9 +359,9 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node, coordinates_to_the_right.end()); const auto lane_count_lhs = std::max( - 1, node_based_graph.GetEdgeData(lhs.eid).road_classification.GetNumberOfLanes()); + 1, node_based_graph.GetEdgeData(lhs.eid).flags.road_classification.GetNumberOfLanes()); const auto lane_count_rhs = std::max( - 1, node_based_graph.GetEdgeData(rhs.eid).road_classification.GetNumberOfLanes()); + 1, node_based_graph.GetEdgeData(rhs.eid).flags.road_classification.GetNumberOfLanes()); const auto combined_road_width = 0.5 * (lane_count_lhs + lane_count_rhs) * ASSUMED_LANE_WIDTH; const auto constexpr MAXIMAL_ALLOWED_SEPARATION_WIDTH = 8; @@ -380,10 +397,16 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node, // check if all items share a name const auto range = node_based_graph.GetAdjacentEdgeRange(nid); - const auto required_name_id = node_based_graph.GetEdgeData(range.front()).name_id; + const auto required_name_id = + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(range.front()).annotation_data) + .name_id; const auto has_required_name = [this, required_name_id](const auto edge_id) { - const auto road_name = node_based_graph.GetEdgeData(edge_id).name_id; + const auto road_name = + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data) + .name_id; if (required_name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID) return false; return !util::guidance::requiresNameAnnounced( @@ -428,14 +451,19 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node, const auto next_intersection_along_road = intersection_generator.GetConnectedRoads( next_intersection_parameters.nid, next_intersection_parameters.via_eid); const auto extract_name_id = [this](const MergableRoadData &road) { - return node_based_graph.GetEdgeData(road.eid).name_id; + return node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .name_id; }; const auto requested_name_id = extract_name_id(road); const auto next_road_along_path = next_intersection_along_road.findClosestTurn( STRAIGHT_ANGLE, - makeCheckRoadForName( - requested_name_id, node_based_graph, name_table, street_name_suffix_table)); + makeCheckRoadForName(requested_name_id, + node_based_graph, + node_data_container, + name_table, + street_name_suffix_table)); // we need to have a continuing road to successfully detect a link road if (next_road_along_path == next_intersection_along_road.end()) @@ -460,9 +488,16 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node, // near straight road that continues return angularDeviation(opposite_of_next_road_along_path->angle, next_road_along_path->angle) >= (STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE) && + (node_based_graph.GetEdgeData(next_road_along_path->eid).reversed == + node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid).reversed) && EdgeDataSupportsMerge( - node_based_graph.GetEdgeData(next_road_along_path->eid), - node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid)); + node_based_graph.GetEdgeData(next_road_along_path->eid).flags, + node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid).flags, + node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(next_road_along_path->eid).annotation_data), + node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid) + .annotation_data)); } } // namespace guidance diff --git a/src/extractor/guidance/motorway_handler.cpp b/src/extractor/guidance/motorway_handler.cpp index 18cafcd04..04da12c47 100644 --- a/src/extractor/guidance/motorway_handler.cpp +++ b/src/extractor/guidance/motorway_handler.cpp @@ -24,27 +24,29 @@ namespace inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph) { - return node_based_graph.GetEdgeData(eid).road_classification.IsMotorwayClass(); + return node_based_graph.GetEdgeData(eid).flags.road_classification.IsMotorwayClass(); } inline RoadClassification roadClass(const ConnectedRoad &road, const util::NodeBasedDynamicGraph &graph) { - return graph.GetEdgeData(road.eid).road_classification; + return graph.GetEdgeData(road.eid).flags.road_classification; } inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph) { - return node_based_graph.GetEdgeData(eid).road_classification.IsRampClass(); + return node_based_graph.GetEdgeData(eid).flags.road_classification.IsRampClass(); } } // namespace MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, const IntersectionGenerator &intersection_generator) : IntersectionHandler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, @@ -101,7 +103,8 @@ operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection intersection) const { - const auto &in_data = node_based_graph.GetEdgeData(via_eid); + const auto &in_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_eid).annotation_data); BOOST_ASSERT(isMotorwayClass(via_eid, node_based_graph)); const auto countExitingMotorways = [this](const Intersection &intersection) { @@ -121,7 +124,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in if (!road.entry_allowed) continue; - const auto &out_data = node_based_graph.GetEdgeData(road.eid); + const auto &out_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(road.eid).annotation_data); const auto same_name = !util::guidance::requiresNameAnnounced( in_data.name_id, out_data.name_id, name_table, street_name_suffix_table); @@ -353,8 +357,10 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters } else if (intersection.size() == 3) { - const auto &second_intersection_data = node_based_graph.GetEdgeData(intersection[2].eid); - const auto &first_intersection_data = node_based_graph.GetEdgeData(intersection[1].eid); + const auto &second_intersection_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(intersection[2].eid).annotation_data); + const auto &first_intersection_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(intersection[1].eid).annotation_data); const auto first_second_same_name = !util::guidance::requiresNameAnnounced(second_intersection_data.name_id, first_intersection_data.name_id, diff --git a/src/extractor/guidance/node_based_graph_walker.cpp b/src/extractor/guidance/node_based_graph_walker.cpp index 8b3df93ae..179c8de34 100644 --- a/src/extractor/guidance/node_based_graph_walker.cpp +++ b/src/extractor/guidance/node_based_graph_walker.cpp @@ -15,8 +15,10 @@ namespace guidance // --------------------------------------------------------------------------------- NodeBasedGraphWalker::NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const IntersectionGenerator &intersection_generator) - : node_based_graph(node_based_graph), intersection_generator(intersection_generator) + : node_based_graph(node_based_graph), node_data_container(node_data_container), + intersection_generator(intersection_generator) { } @@ -64,21 +66,24 @@ boost::optional SelectRoadByNameOnlyChoiceAndStraightness:: operator()(const NodeID /*nid*/, const EdgeID /*via_edge_id*/, const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &node_based_graph) const + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container) const { BOOST_ASSERT(!intersection.empty()); - const auto comparator = [this, &node_based_graph](const IntersectionViewData &lhs, - const IntersectionViewData &rhs) { + const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) { // the score of an elemnt results in an ranking preferring valid entries, if required over // invalid requested name_ids over non-requested narrow deviations over non-narrow - const auto score = [this, &node_based_graph](const IntersectionViewData &road) { + const auto score = [&](const IntersectionViewData &road) { double result_score = 0; // since angular deviation is limited by 0-180, we add 360 for invalid if (requires_entry && !road.entry_allowed) result_score += 360.; // 180 for undesired name-ids - if (desired_name_id != node_based_graph.GetEdgeData(road.eid).name_id) + if (desired_name_id != + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .name_id) result_score += 180; return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE); @@ -108,24 +113,27 @@ boost::optional SelectStraightmostRoadByNameAndOnlyChoice:: operator()(const NodeID /*nid*/, const EdgeID /*via_edge_id*/, const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &node_based_graph) const + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container) const { BOOST_ASSERT(!intersection.empty()); if (intersection.size() == 1) return {}; - const auto comparator = [this, &node_based_graph](const IntersectionViewData &lhs, - const IntersectionViewData &rhs) { + const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) { // the score of an elemnt results in an ranking preferring valid entries, if required over // invalid requested name_ids over non-requested narrow deviations over non-narrow - const auto score = [this, &node_based_graph](const IntersectionViewData &road) { + const auto score = [&](const IntersectionViewData &road) { double result_score = 0; // since angular deviation is limited by 0-180, we add 360 for invalid if (requires_entry && !road.entry_allowed) result_score += 360.; // 180 for undesired name-ids - if (desired_name_id != node_based_graph.GetEdgeData(road.eid).name_id) + if (desired_name_id != + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .name_id) result_score += 180; return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE); @@ -135,11 +143,11 @@ operator()(const NodeID /*nid*/, }; const auto count_desired_name = - std::count_if(std::begin(intersection), - std::end(intersection), - [this, &node_based_graph](const auto &road) { - return node_based_graph.GetEdgeData(road.eid).name_id == desired_name_id; - }); + std::count_if(std::begin(intersection), std::end(intersection), [&](const auto &road) { + return node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .name_id == desired_name_id; + }); if (count_desired_name > 2) return {}; @@ -149,7 +157,9 @@ operator()(const NodeID /*nid*/, const auto is_valid_choice = !requires_entry || min_element->entry_allowed; const auto is_only_choice_with_same_name = count_desired_name <= 2 && // <= in case we come from a bridge - node_based_graph.GetEdgeData(min_element->eid).name_id == desired_name_id && + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(min_element->eid).annotation_data) + .name_id == desired_name_id && angularDeviation(min_element->angle, STRAIGHT_ANGLE) < 100; // don't do crazy turns const auto has_valid_angle = ((intersection.size() == 2 || diff --git a/src/extractor/guidance/roundabout_handler.cpp b/src/extractor/guidance/roundabout_handler.cpp index 36fb32bcf..1aa8f5951 100644 --- a/src/extractor/guidance/roundabout_handler.cpp +++ b/src/extractor/guidance/roundabout_handler.cpp @@ -24,18 +24,19 @@ namespace guidance { RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, - const ProfileProperties &profile_properties, const IntersectionGenerator &intersection_generator) : IntersectionHandler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, intersection_generator), - compressed_edge_container(compressed_edge_container), profile_properties(profile_properties), + compressed_edge_container(compressed_edge_container), coordinate_extractor(node_based_graph, compressed_edge_container, coordinates) { } @@ -70,22 +71,24 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags( const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const { const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid); - bool on_roundabout = in_edge_data.roundabout || in_edge_data.circular; + const auto &in_edge_class = in_edge_data.flags; + bool on_roundabout = in_edge_class.roundabout || in_edge_class.circular; bool can_enter_roundabout = false; bool can_exit_roundabout_separately = false; - const bool lhs = in_edge_data.is_left_hand_driving; + const bool lhs = + node_data_container.GetAnnotation(in_edge_data.annotation_data).is_left_hand_driving; const int step = lhs ? -1 : 1; for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; cnt < intersection.size(); ++cnt, idx += step) { const auto &road = intersection[idx]; - const auto &edge_data = node_based_graph.GetEdgeData(road.eid); + const auto &edge = node_based_graph.GetEdgeData(road.eid); // only check actual outgoing edges - if (edge_data.reversed || !road.entry_allowed) + if (edge.reversed || !road.entry_allowed) continue; - if (edge_data.roundabout || edge_data.circular) + if (edge.flags.roundabout || edge.flags.circular) { can_enter_roundabout = true; } @@ -108,8 +111,8 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, const EdgeID via_eid, Intersection &intersection) const { - const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid); - if (in_edge_data.roundabout || in_edge_data.circular) + const auto &in_edge_class = node_based_graph.GetEdgeData(via_eid).flags; + if (in_edge_class.roundabout || in_edge_class.circular) return; // Find range in which exits that must be invalidated (shaded areas): @@ -136,10 +139,10 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, auto invalidate_from = intersection.end(), invalidate_to = intersection.end(); for (auto road = intersection.begin(); road != intersection.end(); ++road) { - const auto &edge_data = node_based_graph.GetEdgeData(road->eid); - if (edge_data.roundabout || edge_data.circular) + const auto &edge = node_based_graph.GetEdgeData(road->eid); + if (edge.flags.roundabout || edge.flags.circular) { - if (edge_data.reversed) + if (edge.reversed) { if (roundabout_entry_first) { // invalidate turns in range exit..end @@ -166,8 +169,8 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid, // u-turn against the roundabout direction is invalidated. for (; invalidate_from != invalidate_to; ++invalidate_from) { - const auto &edge_data = node_based_graph.GetEdgeData(invalidate_from->eid); - if (!edge_data.roundabout && !edge_data.circular && + const auto &edge = node_based_graph.GetEdgeData(invalidate_from->eid); + if (!edge.flags.roundabout && !edge.flags.circular && node_based_graph.GetTarget(invalidate_from->eid) != from_nid) { invalidate_from->entry_allowed = false; @@ -207,8 +210,8 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection( // can only contain a single further road for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node)) { - const auto edge_data = node_based_graph.GetEdgeData(edge); - if (edge_data.roundabout || edge_data.circular) + const auto &edge_data = node_based_graph.GetEdgeData(edge); + if (edge_data.flags.roundabout || edge_data.flags.circular) continue; // there is a single non-roundabout edge @@ -222,7 +225,7 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection( [this](const auto current_max, const auto current_eid) { return std::max(current_max, node_based_graph.GetEdgeData(current_eid) - .road_classification.GetNumberOfLanes()); + .flags.road_classification.GetNumberOfLanes()); }); const auto next_coordinate = @@ -279,11 +282,12 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const const NodeID node, const bool roundabout, const bool circular) { BOOST_ASSERT(roundabout != circular); EdgeID continue_edge = SPECIAL_EDGEID; - for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node)) + for (const auto edge_id : node_based_graph.GetAdjacentEdgeRange(node)) { - const auto &edge_data = node_based_graph.GetEdgeData(edge); - if (!edge_data.reversed && (edge_data.circular == circular) && - (edge_data.roundabout == roundabout)) + const auto &edge = node_based_graph.GetEdgeData(edge_id); + const auto &edge_data = node_data_container.GetAnnotation(edge.annotation_data); + if (!edge.reversed && (edge.flags.circular == circular) && + (edge.flags.roundabout == roundabout)) { if (SPECIAL_EDGEID != continue_edge) { @@ -303,9 +307,9 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const roundabout_name_ids.insert(edge_data.name_id); } - continue_edge = edge; + continue_edge = edge_id; } - else if (!edge_data.roundabout && !edge_data.circular) + else if (!edge.flags.roundabout && !edge.flags.circular) { // remember all connected road names connected_names.insert(edge_data.name_id); @@ -322,7 +326,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const for (const auto edge : node_based_graph.GetAdjacentEdgeRange(at_node)) { const auto &edge_data = node_based_graph.GetEdgeData(edge); - if (edge_data.roundabout || edge_data.circular) + if (edge_data.flags.roundabout || edge_data.flags.circular) count++; } return count; @@ -353,7 +357,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const bool roundabout = false, circular = false; for (const auto eid : node_based_graph.GetAdjacentEdgeRange(nid)) { - const auto data = node_based_graph.GetEdgeData(eid); + const auto data = node_based_graph.GetEdgeData(eid).flags; roundabout |= data.roundabout; circular |= data.circular; } @@ -435,7 +439,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou NodeID node_at_center_of_intersection = node_based_graph.GetTarget(via_eid); const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid); - const bool lhs = in_edge_data.is_left_hand_driving; + const bool lhs = + node_data_container.GetAnnotation(in_edge_data.annotation_data).is_left_hand_driving; const int step = lhs ? -1 : 1; if (on_roundabout) @@ -448,7 +453,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou { auto &road = intersection[idx]; auto &turn = road; - const auto &out_data = node_based_graph.GetEdgeData(road.eid); + const auto &out_data = node_based_graph.GetEdgeData(road.eid).flags; + ; if (out_data.roundabout || out_data.circular) { // TODO can forks happen in roundabouts? E.g. required lane changes @@ -471,11 +477,10 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou for (const auto eid : node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection)) { - const auto &data_of_leaving_edge = node_based_graph.GetEdgeData(eid); - if (!data_of_leaving_edge.reversed && - !data_of_leaving_edge.roundabout && - !data_of_leaving_edge.circular && - !data_of_leaving_edge.road_classification.IsLowPriorityRoadClass()) + const auto &leaving_edge = node_based_graph.GetEdgeData(eid); + if (!leaving_edge.reversed && !leaving_edge.flags.roundabout && + !leaving_edge.flags.circular && + !leaving_edge.flags.road_classification.IsLowPriorityRoadClass()) return true; } return false; @@ -511,7 +516,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou ++cnt, idx += step) { auto &turn = intersection[idx]; - const auto &out_data = node_based_graph.GetEdgeData(turn.eid); + const auto &out_data = node_based_graph.GetEdgeData(turn.eid).flags; // A roundabout consists of exactly two roads at an intersection. by toggeling this // flag, we can switch between roads crossing the roundabout and roads that are on the diff --git a/src/extractor/guidance/sliproad_handler.cpp b/src/extractor/guidance/sliproad_handler.cpp index 2bbc96c46..c2290327c 100644 --- a/src/extractor/guidance/sliproad_handler.cpp +++ b/src/extractor/guidance/sliproad_handler.cpp @@ -23,10 +23,12 @@ namespace guidance SliproadHandler::SliproadHandler(const IntersectionGenerator &intersection_generator, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table) : IntersectionHandler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, @@ -109,7 +111,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter return false; } - const auto &road_data = node_based_graph.GetEdgeData(road.eid); + const auto &road_data = node_based_graph.GetEdgeData(road.eid).flags; auto is_roundabout = road_data.roundabout; @@ -156,7 +158,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter for (const auto &road : main_road_intersection->intersection) { - const auto &target_data = node_based_graph.GetEdgeData(road.eid); + const auto target_annotation_id = node_based_graph.GetEdgeData(road.eid).annotation_data; + const auto &target_data = node_data_container.GetAnnotation(target_annotation_id); target_road_name_ids.push_back(target_data.name_id); } @@ -173,7 +176,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter continue; auto &sliproad = intersection[road_index]; // this is what we're checking and assigning to - const auto &sliproad_data = node_based_graph.GetEdgeData(sliproad.eid); + const auto &sliproad_edge_data = node_based_graph.GetEdgeData(sliproad.eid); // Intersection is orderd: 0 is UTurn, then from sharp right to sharp left. // We already have an obvious index (bc) for going straight-ish. @@ -199,13 +202,13 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter } // Discard service and other low priority roads - never Sliproad candidate - if (sliproad_data.road_classification.IsLowPriorityRoadClass()) + if (sliproad_edge_data.flags.road_classification.IsLowPriorityRoadClass()) { continue; } // Incoming-only can never be a Sliproad - if (sliproad_data.reversed) + if (sliproad_edge_data.reversed) { continue; } @@ -350,7 +353,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter continue; } - const auto &onto_data = node_based_graph.GetEdgeData(onto.eid); + const auto &onto_data = node_based_graph.GetEdgeData(onto.eid).flags; if (onto_data.roundabout) { @@ -434,7 +437,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter // Check sliproads with skew main intersections if (deviation_from_straight > 180. - minimal_crossroad_angle_of_intersection && - !node_based_graph.GetEdgeData(sliproad.eid).road_classification.IsLinkClass()) + !node_based_graph.GetEdgeData(sliproad.eid) + .flags.road_classification.IsLinkClass()) { continue; } @@ -449,9 +453,10 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter // ` . // d // - const auto area_threshold = std::pow( - scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, sliproad_data.road_classification), - 2.); + const auto area_threshold = + std::pow(scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, + sliproad_edge_data.flags.road_classification), + 2.); if (!isValidSliproadArea(area_threshold, intersection_node_id, @@ -464,7 +469,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter // Check all roads at `d` if one is connected to `c`, is so `bd` is Sliproad. for (const auto &candidate_road : target_intersection) { - const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.eid); + const auto &candidate_data = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(candidate_road.eid).annotation_data); // Name mismatch: check roads at `c` and `d` for same name const auto name_mismatch = [&](const NameID road_name_id) { @@ -489,15 +495,20 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter // Check if main road -> sliproad (non-link) -> candidate road requires two name // announcements then don't suppress one announcement via sliproad handler - const auto main_road_name_id = node_based_graph.GetEdgeData(main_road.eid).name_id; - if (!sliproad_data.road_classification.IsLinkClass() && - sliproad_data.name_id != EMPTY_NAMEID && main_road_name_id != EMPTY_NAMEID && + const auto main_road_name_id = + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(main_road.eid).annotation_data) + .name_id; + const auto &sliproad_annotation = + node_data_container.GetAnnotation(sliproad_edge_data.annotation_data); + if (!sliproad_edge_data.flags.road_classification.IsLinkClass() && + sliproad_annotation.name_id != EMPTY_NAMEID && main_road_name_id != EMPTY_NAMEID && candidate_data.name_id != EMPTY_NAMEID && util::guidance::requiresNameAnnounced(main_road_name_id, - sliproad_data.name_id, + sliproad_annotation.name_id, name_table, street_name_suffix_table) && - util::guidance::requiresNameAnnounced(sliproad_data.name_id, + util::guidance::requiresNameAnnounced(sliproad_annotation.name_id, candidate_data.name_id, name_table, street_name_suffix_table)) @@ -553,6 +564,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter // In those cases the obvious non-Sliproad is now obvious and we discard the Fork turn type. if (sliproad_found && main_road.instruction.type == TurnType::Fork) { + const auto &main_data = node_based_graph.GetEdgeData(main_road.eid); + const auto &main_annotation = node_data_container.GetAnnotation(main_data.annotation_data); if (isSameName(source_edge_id, main_road.eid)) { if (angularDeviation(main_road.angle, STRAIGHT_ANGLE) < 5) @@ -562,7 +575,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter intersection[*obvious].instruction.direction_modifier = getTurnDirection(intersection[*obvious].angle); } - else if (node_based_graph.GetEdgeData(main_road.eid).name_id != EMPTY_NAMEID) + else if (main_annotation.name_id != EMPTY_NAMEID) { intersection[*obvious].instruction.type = TurnType::NewName; intersection[*obvious].instruction.direction_modifier = @@ -644,7 +657,7 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg const auto &coordinate_extractor = intersection_generator.GetCoordinateExtractor(); // Base max distance threshold on the current road class we're on - const auto &data = node_based_graph.GetEdgeData(onto); + const auto &data = node_based_graph.GetEdgeData(onto).flags; const auto threshold = scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, // <- scales down data.road_classification); @@ -662,13 +675,15 @@ bool SliproadHandler::isThroughStreet(const EdgeID from, const IntersectionView BOOST_ASSERT(from != SPECIAL_EDGEID); BOOST_ASSERT(!intersection.empty()); - const auto &edge_name_id = node_based_graph.GetEdgeData(from).name_id; + const auto from_annotation_id = node_based_graph.GetEdgeData(from).annotation_data; + const auto &edge_name_id = node_data_container.GetAnnotation(from_annotation_id).name_id; auto first = begin(intersection) + 1; // Skip UTurn road auto last = end(intersection); auto same_name = [&](const auto &road) { - const auto &road_name_id = node_based_graph.GetEdgeData(road.eid).name_id; + const auto annotation_id = node_based_graph.GetEdgeData(road.eid).annotation_data; + const auto &road_name_id = node_data_container.GetAnnotation(annotation_id).name_id; return edge_name_id != EMPTY_NAMEID && // road_name_id != EMPTY_NAMEID && // @@ -683,10 +698,13 @@ bool SliproadHandler::isThroughStreet(const EdgeID from, const IntersectionView bool SliproadHandler::roadContinues(const EdgeID current, const EdgeID next) const { - const auto ¤t_data = node_based_graph.GetEdgeData(current); - const auto &next_data = node_based_graph.GetEdgeData(next); + const auto ¤t_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(current).annotation_data); + const auto &next_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(next).annotation_data); - auto same_road_category = current_data.road_classification == next_data.road_classification; + auto same_road_category = node_based_graph.GetEdgeData(current).flags.road_classification == + node_based_graph.GetEdgeData(next).flags.road_classification; auto same_travel_mode = current_data.travel_mode == next_data.travel_mode; auto same_name = current_data.name_id != EMPTY_NAMEID && // @@ -730,22 +748,18 @@ bool SliproadHandler::isValidSliproadArea(const double max_area, } bool SliproadHandler::isValidSliproadLink(const IntersectionViewData &sliproad, - const IntersectionViewData &first, + const IntersectionViewData & /*first*/, const IntersectionViewData &second) const { - // If the sliproad is not a link we don't care - const auto &sliproad_data = node_based_graph.GetEdgeData(sliproad.eid); + // If the Sliproad is not a link we don't care + const auto &sliproad_data = node_based_graph.GetEdgeData(sliproad.eid).flags; if (!sliproad_data.road_classification.IsLinkClass()) { return true; } - // otherwise the first road leading to the intersection we shortcut - // can be a link or a usual road (ignore the check at this place) - (void)first; - // and the second road coming from the intersection we shortcut must be a non-link - const auto &second_road_data = node_based_graph.GetEdgeData(second.eid); + const auto &second_road_data = node_based_graph.GetEdgeData(second.eid).flags; if (second_road_data.road_classification.IsLinkClass()) { return false; @@ -758,10 +772,15 @@ bool SliproadHandler::allSameMode(const EdgeID from, const EdgeID sliproad_candidate, const EdgeID target_road) const { - return node_based_graph.GetEdgeData(from).travel_mode == - node_based_graph.GetEdgeData(sliproad_candidate).travel_mode && - node_based_graph.GetEdgeData(sliproad_candidate).travel_mode == - node_based_graph.GetEdgeData(target_road).travel_mode; + const auto &from_annotation = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(from).annotation_data); + const auto &sliproad_annotation = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(sliproad_candidate).annotation_data); + const auto &target_annotation = node_data_container.GetAnnotation( + node_based_graph.GetEdgeData(target_road).annotation_data); + + return (from_annotation.travel_mode == sliproad_annotation.travel_mode) && + (target_annotation.travel_mode == sliproad_annotation.travel_mode); } bool SliproadHandler::canBeTargetOfSliproad(const IntersectionView &intersection) diff --git a/src/extractor/guidance/suppress_mode_handler.cpp b/src/extractor/guidance/suppress_mode_handler.cpp index 518801131..bcb60a023 100644 --- a/src/extractor/guidance/suppress_mode_handler.cpp +++ b/src/extractor/guidance/suppress_mode_handler.cpp @@ -13,10 +13,12 @@ namespace guidance SuppressModeHandler::SuppressModeHandler(const IntersectionGenerator &intersection_generator, const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table) : IntersectionHandler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, @@ -36,14 +38,18 @@ bool SuppressModeHandler::canProcess(const NodeID, // If the approach way is not on the suppression blacklist, and not all the exit ways share that // mode, there are no ways to suppress by this criteria. - const auto in_mode = node_based_graph.GetEdgeData(via_eid).travel_mode; + const auto in_mode = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_eid).annotation_data) + .travel_mode; const auto suppress_in_mode = std::find(begin(suppressed), end(suppressed), in_mode); const auto first = begin(intersection); const auto last = end(intersection); const auto all_share_mode = std::all_of(first, last, [this, &in_mode](const auto &road) { - return node_based_graph.GetEdgeData(road.eid).travel_mode == in_mode; + return node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .travel_mode == in_mode; }); return (suppress_in_mode != end(suppressed)) && all_share_mode; diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index d74f3b92f..c569d2e34 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -21,56 +21,61 @@ namespace guidance using EdgeData = util::NodeBasedDynamicGraph::EdgeData; -bool requiresAnnouncement(const EdgeData &from, const EdgeData &to) -{ - return !from.CanCombineWith(to); -} - TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const RestrictionMap &restriction_map, const std::unordered_set &barrier_nodes, const CompressedEdgeContainer &compressed_edge_container, const util::NameTable &name_table, - const SuffixTable &street_name_suffix_table, - const ProfileProperties &profile_properties) - : node_based_graph(node_based_graph), - intersection_generator( - node_based_graph, restriction_map, barrier_nodes, coordinates, compressed_edge_container), + const SuffixTable &street_name_suffix_table) + : node_based_graph(node_based_graph), intersection_generator(node_based_graph, + node_data_container, + restriction_map, + barrier_nodes, + coordinates, + compressed_edge_container), intersection_normalizer(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, intersection_generator), roundabout_handler(node_based_graph, + node_data_container, coordinates, compressed_edge_container, name_table, street_name_suffix_table, - profile_properties, intersection_generator), motorway_handler(node_based_graph, + node_data_container, + coordinates, name_table, street_name_suffix_table, intersection_generator), turn_handler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, intersection_generator), sliproad_handler(intersection_generator, node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table), suppress_mode_handler(intersection_generator, node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table), driveway_handler(intersection_generator, node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table) @@ -163,7 +168,7 @@ Intersection TurnAnalysis::AssignTurnTypes(const NodeID node_prior_to_intersecti node_prior_to_intersection, entering_via_edge, std::move(intersection)); // Turn On Ramps Into Off Ramps, if we come from a motorway-like road - if (node_based_graph.GetEdgeData(entering_via_edge).road_classification.IsMotorwayClass()) + if (node_based_graph.GetEdgeData(entering_via_edge).flags.road_classification.IsMotorwayClass()) { std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) { if (road.instruction.type == TurnType::OnRamp) diff --git a/src/extractor/guidance/turn_handler.cpp b/src/extractor/guidance/turn_handler.cpp index 72202da3d..5b5200665 100644 --- a/src/extractor/guidance/turn_handler.cpp +++ b/src/extractor/guidance/turn_handler.cpp @@ -111,11 +111,13 @@ std::size_t TurnHandler::Fork::getLeftIndex() const } TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, const std::vector &coordinates, const util::NameTable &name_table, const SuffixTable &street_name_suffix_table, const IntersectionGenerator &intersection_generator) : IntersectionHandler(node_based_graph, + node_data_container, coordinates, name_table, street_name_suffix_table, @@ -174,12 +176,16 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge, const ConnectedRoad &road, const ConnectedRoad &other) const { - const auto &via_data = node_based_graph.GetEdgeData(via_edge); - const auto &road_data = node_based_graph.GetEdgeData(road.eid); - const auto &other_data = node_based_graph.GetEdgeData(other.eid); - const auto &via_classification = via_data.road_classification; - const auto &road_classification = road_data.road_classification; - const auto &other_classification = other_data.road_classification; + const auto &via_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data); + const auto &road_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data); + const auto &via_classification = + node_based_graph.GetEdgeData(via_edge).flags.road_classification; + const auto &road_classification = + node_based_graph.GetEdgeData(road.eid).flags.road_classification; + const auto &other_classification = + node_based_graph.GetEdgeData(other.eid).flags.road_classification; // if one of the given roads is obvious by class, obviousness is trivial if (obviousByRoadClass(via_classification, road_classification, other_classification)) @@ -335,9 +341,9 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection if (fork->size == 2) { const auto left_classification = - node_based_graph.GetEdgeData(fork->getLeft().eid).road_classification; + node_based_graph.GetEdgeData(fork->getLeft().eid).flags.road_classification; const auto right_classification = - node_based_graph.GetEdgeData(fork->getRight().eid).road_classification; + node_based_graph.GetEdgeData(fork->getRight().eid).flags.road_classification; if (canBeSeenAsFork(left_classification, right_classification)) { assignFork(via_edge, fork->getLeft(), fork->getRight()); @@ -615,26 +621,27 @@ TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const // incoming edge are compatible by class bool TurnHandler::isCompatibleByRoadClass(const Intersection &intersection, const Fork fork) const { - const auto via_class = node_based_graph.GetEdgeData(intersection[0].eid).road_classification; + const auto via_class = + node_based_graph.GetEdgeData(intersection[0].eid).flags.road_classification; // if any of the considered roads is a link road, it cannot be a fork // except if rightmost fork candidate is also a link road const auto is_right_link_class = - node_based_graph.GetEdgeData(fork.getRight().eid).road_classification.IsLinkClass(); + node_based_graph.GetEdgeData(fork.getRight().eid).flags.road_classification.IsLinkClass(); if (!std::all_of(fork.begin + 1, fork.end, [&](ConnectedRoad &road) { return is_right_link_class == - node_based_graph.GetEdgeData(road.eid).road_classification.IsLinkClass(); + node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsLinkClass(); })) { return false; } return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &base) { - const auto base_class = node_based_graph.GetEdgeData(base.eid).road_classification; + const auto base_class = node_based_graph.GetEdgeData(base.eid).flags.road_classification; // check that there is no turn obvious == check that all turns are non-onvious return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &compare) { const auto compare_class = - node_based_graph.GetEdgeData(compare.eid).road_classification; + node_based_graph.GetEdgeData(compare.eid).flags.road_classification; return compare.eid == base.eid || !(obviousByRoadClass(via_class, base_class, compare_class)); }); @@ -670,8 +677,12 @@ boost::optional TurnHandler::findFork(const EdgeID via_edge, const auto has_compatible_modes = std::all_of(fork->begin, fork->end, [&](const auto &road) { - return node_based_graph.GetEdgeData(road.eid).travel_mode == - node_based_graph.GetEdgeData(via_edge).travel_mode; + return node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data) + .travel_mode == + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data) + .travel_mode; }); if (separated_at_left_side && separated_at_right_side && !has_obvious && @@ -703,9 +714,10 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge, getTurnDirection(left.angle) == DirectionModifier::SlightLeft || getTurnDirection(right.angle) == DirectionModifier::SlightRight) { - const auto left_classification = node_based_graph.GetEdgeData(left.eid).road_classification; + const auto left_classification = + node_based_graph.GetEdgeData(left.eid).flags.road_classification; const auto right_classification = - node_based_graph.GetEdgeData(right.eid).road_classification; + node_based_graph.GetEdgeData(right.eid).flags.road_classification; if (left_classification.GetPriority() > right_classification.GetPriority()) { diff --git a/src/extractor/guidance/turn_lane_handler.cpp b/src/extractor/guidance/turn_lane_handler.cpp index 5a74d0318..4f9f2ecec 100644 --- a/src/extractor/guidance/turn_lane_handler.cpp +++ b/src/extractor/guidance/turn_lane_handler.cpp @@ -34,11 +34,12 @@ std::size_t getNumberOfTurns(const Intersection &intersection) } // namespace TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container, LaneDescriptionMap &lane_description_map, const TurnAnalysis &turn_analysis, util::guidance::LaneDataIdMap &id_map) - : node_based_graph(node_based_graph), lane_description_map(lane_description_map), - turn_analysis(turn_analysis), id_map(id_map) + : node_based_graph(node_based_graph), node_data_container(node_data_container), + lane_description_map(lane_description_map), turn_analysis(turn_analysis), id_map(id_map) { std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(lane_description_map); @@ -149,7 +150,7 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at, LaneDescriptionID &previous_description_id) { // as long as we don't want to emit lanes on roundabout, don't assign them - if (node_based_graph.GetEdgeData(via_edge).roundabout) + if (node_based_graph.GetEdgeData(via_edge).flags.roundabout) return TurnLaneScenario::NONE; // really don't touch roundabouts (#2626) @@ -179,7 +180,9 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at, (intersection.size() == 2 && ((lane_description_id != INVALID_LANE_DESCRIPTIONID && lane_description_id == - node_based_graph.GetEdgeData(intersection[1].eid).lane_description_id) && + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(intersection[1].eid).annotation_data) + .lane_description_id) && angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)); if (is_going_straight_and_turns_continue) @@ -367,7 +370,8 @@ void TurnLaneHandler::extractLaneData(const EdgeID via_edge, LaneDescriptionID &lane_description_id, LaneDataVector &lane_data) const { - const auto &edge_data = node_based_graph.GetEdgeData(via_edge); + const auto &edge_data = + node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data); lane_description_id = edge_data.lane_description_id; // create an empty lane data if (INVALID_LANE_DESCRIPTIONID != lane_description_id) @@ -719,9 +723,13 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection, return previous_intersection[sliproad_index + 1]; }(); const auto main_description_id = - node_based_graph.GetEdgeData(main_road.eid).lane_description_id; + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(main_road.eid).annotation_data) + .lane_description_id; const auto sliproad_description_id = - node_based_graph.GetEdgeData(sliproad.eid).lane_description_id; + node_data_container + .GetAnnotation(node_based_graph.GetEdgeData(sliproad.eid).annotation_data) + .lane_description_id; if (main_description_id == INVALID_LANE_DESCRIPTIONID || sliproad_description_id == INVALID_LANE_DESCRIPTIONID) diff --git a/src/extractor/node_based_graph_factory.cpp b/src/extractor/node_based_graph_factory.cpp new file mode 100644 index 000000000..657c0954f --- /dev/null +++ b/src/extractor/node_based_graph_factory.cpp @@ -0,0 +1,205 @@ +#include "extractor/node_based_graph_factory.hpp" +#include "extractor/graph_compressor.hpp" +#include "storage/io.hpp" +#include "util/graph_loader.hpp" + +#include "util/log.hpp" + +#include + +namespace osrm +{ +namespace extractor +{ + +NodeBasedGraphFactory::NodeBasedGraphFactory( + const boost::filesystem::path &input_file, + ScriptingEnvironment &scripting_environment, + std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions) +{ + LoadDataFromFile(input_file); + Compress(scripting_environment, turn_restrictions, conditional_turn_restrictions); + CompressGeometry(); + CompressAnnotationData(); +} + +// load the data serialised during the extraction run +void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &input_file) +{ + // the extraction_containers serialise all data necessary to create the node-based graph into a + // single file, the *.osrm file. It contains nodes, basic information about which of these nodes + // are traffic signals/stop signs. It also contains Edges and purely annotative meta-data + storage::io::FileReader file_reader(input_file, storage::io::FileReader::VerifyFingerprint); + + auto barriers_iter = inserter(barriers, end(barriers)); + auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals)); + + const auto number_of_node_based_nodes = util::loadNodesFromFile( + file_reader, barriers_iter, traffic_signals_iter, coordinates, osm_node_ids); + + std::vector edge_list; + util::loadEdgesFromFile(file_reader, edge_list); + + if (edge_list.empty()) + { + throw util::exception("Node-based-graph (" + input_file.string() + ") contains no edges." + + SOURCE_REF); + } + + util::loadAnnotationData(file_reader, annotation_data); + + // at this point, the data isn't compressed, but since we update the graph in-place, we assign + // it here. + compressed_output_graph = + util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list); + + // check whether the graph is sane + BOOST_ASSERT([this]() { + for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes())) + { + for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u)) + { + // we cannot have invalid edge-ids in the graph + if (nbg_edge_id == SPECIAL_EDGEID) + return false; + + const auto nbg_node_v = compressed_output_graph.GetTarget(nbg_edge_id); + + auto reverse = compressed_output_graph.FindEdge(nbg_node_v, nbg_node_u); + + // found an edge that is reversed in both directions, should be two distinct edges + if (compressed_output_graph.GetEdgeData(nbg_edge_id).reversed && + compressed_output_graph.GetEdgeData(reverse).reversed) + return false; + } + } + return true; + }()); +} + +void NodeBasedGraphFactory::Compress( + ScriptingEnvironment &scripting_environment, + std::vector &turn_restrictions, + std::vector &conditional_turn_restrictions) +{ + GraphCompressor graph_compressor; + graph_compressor.Compress(barriers, + traffic_signals, + scripting_environment, + turn_restrictions, + conditional_turn_restrictions, + compressed_output_graph, + annotation_data, + compressed_edge_container); +} + +void NodeBasedGraphFactory::CompressGeometry() +{ + for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes())) + { + for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u)) + { + BOOST_ASSERT(nbg_edge_id != SPECIAL_EDGEID); + + const auto &nbg_edge_data = compressed_output_graph.GetEdgeData(nbg_edge_id); + const auto nbg_node_v = compressed_output_graph.GetTarget(nbg_edge_id); + BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID); + BOOST_ASSERT(nbg_node_u != nbg_node_v); + + // pick only every other edge, since we have every edge as an outgoing + // and incoming egde + if (nbg_node_u >= nbg_node_v) + { + continue; + } + + auto from = nbg_node_u, to = nbg_node_v; + // if we found a non-forward edge reverse and try again + if (nbg_edge_data.reversed) + std::swap(from, to); + + // find forward edge id and + const EdgeID edge_id_1 = compressed_output_graph.FindEdge(from, to); + BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID); + + // find reverse edge id and + const EdgeID edge_id_2 = compressed_output_graph.FindEdge(to, from); + BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID); + + auto packed_geometry_id = compressed_edge_container.ZipEdges(edge_id_1, edge_id_2); + + // remember the geometry ID for both edges in the node-based graph + compressed_output_graph.GetEdgeData(edge_id_1).geometry_id = {packed_geometry_id, true}; + compressed_output_graph.GetEdgeData(edge_id_2).geometry_id = {packed_geometry_id, + false}; + } + } +} + +void NodeBasedGraphFactory::CompressAnnotationData() +{ + const constexpr AnnotationID INVALID_ANNOTATIONID = -1; + // remap all entries to find which are used + std::vector annotation_mapping(annotation_data.size(), INVALID_ANNOTATIONID); + + // first we mark entries, by setting their mapping to 0 + for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes())) + { + BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID); + for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u)) + { + auto const &edge = compressed_output_graph.GetEdgeData(nbg_edge_id); + annotation_mapping[edge.annotation_data] = 0; + } + } + + // now compute a prefix sum on all entries that are 0 to find the new mapping + AnnotationID prefix_sum = 0; + for (std::size_t i = 0; i < annotation_mapping.size(); ++i) + { + if (annotation_mapping[i] == 0) + annotation_mapping[i] = prefix_sum++; + else + { + // flag for removal + annotation_data[i].name_id = INVALID_NAMEID; + } + } + + // apply the mapping + for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes())) + { + BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID); + for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u)) + { + auto &edge = compressed_output_graph.GetEdgeData(nbg_edge_id); + edge.annotation_data = annotation_mapping[edge.annotation_data]; + BOOST_ASSERT(edge.annotation_data != INVALID_ANNOTATIONID); + } + } + + // remove unreferenced entries, shifting other entries to the front + const auto new_end = + std::remove_if(annotation_data.begin(), annotation_data.end(), [&](auto const &data) { + // both elements are considered equal (to remove the second + // one) if the annotation mapping of the second one is + // invalid + return data.name_id == INVALID_NAMEID; + }); + + const auto old_size = annotation_data.size(); + // remove all remaining elements + annotation_data.erase(new_end, annotation_data.end()); + util::Log() << " graoh compression removed " << (old_size - annotation_data.size()) + << " annotations of " << old_size; +} + +void NodeBasedGraphFactory::ReleaseOsmNodes() +{ + // replace with a new vector to release old memory + extractor::PackedOSMIDs().swap(osm_node_ids); +} + +} // namespace extractor +} // namespace osrm diff --git a/src/partition/partitioner.cpp b/src/partition/partitioner.cpp index 27f886a50..52e7cbfb0 100644 --- a/src/partition/partitioner.cpp +++ b/src/partition/partitioner.cpp @@ -218,7 +218,7 @@ int Partitioner::Run(const PartitionConfig &config) files::writePartition(config.GetPath(".osrm.partition"), mlp); files::writeCells(config.GetPath(".osrm.cells"), storage); extractor::files::writeEdgeBasedGraph(config.GetPath(".osrm.ebg"), - edge_based_graph.GetNumberOfNodes() - 1, + edge_based_graph.GetNumberOfNodes(), graphToEdges(edge_based_graph)); TIMER_STOP(writing_mld_data); util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds"; diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index fe1d05da7..64edf94b0 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -15,6 +15,7 @@ #include "extractor/class_data.hpp" #include "extractor/compressed_edge_container.hpp" #include "extractor/edge_based_edge.hpp" +#include "extractor/edge_based_node.hpp" #include "extractor/files.hpp" #include "extractor/guidance/turn_instruction.hpp" #include "extractor/original_edge_data.hpp" @@ -253,13 +254,11 @@ void Storage::PopulateLayout(DataLayout &layout) io::FileReader nodes_data_file(config.GetPath(".osrm.ebg_nodes"), io::FileReader::VerifyFingerprint); const auto nodes_number = nodes_data_file.ReadElementCount64(); - - layout.SetBlockSize(DataLayout::GEOMETRY_ID_LIST, nodes_number); - layout.SetBlockSize(DataLayout::NAME_ID_LIST, nodes_number); - layout.SetBlockSize(DataLayout::COMPONENT_ID_LIST, nodes_number); - layout.SetBlockSize(DataLayout::TRAVEL_MODE_LIST, nodes_number); - layout.SetBlockSize(DataLayout::CLASSES_LIST, nodes_number); - layout.SetBlockSize(DataLayout::IS_LEFT_HAND_DRIVING_LIST, nodes_number); + const auto annotations_number = nodes_data_file.ReadElementCount64(); + layout.SetBlockSize(DataLayout::EDGE_BASED_NODE_DATA_LIST, + nodes_number); + layout.SetBlockSize(DataLayout::ANNOTATION_DATA_LIST, + annotations_number); } if (boost::filesystem::exists(config.GetPath(".osrm.hsgr"))) @@ -709,43 +708,21 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr) // Load edge-based nodes data { - auto geometry_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::GEOMETRY_ID_LIST); - util::vector_view geometry_ids( - geometry_id_list_ptr, layout.num_entries[storage::DataLayout::GEOMETRY_ID_LIST]); + auto edge_based_node_data_list_ptr = layout.GetBlockPtr( + memory_ptr, storage::DataLayout::EDGE_BASED_NODE_DATA_LIST); + util::vector_view edge_based_node_data( + edge_based_node_data_list_ptr, + layout.num_entries[storage::DataLayout::EDGE_BASED_NODE_DATA_LIST]); - auto name_id_list_ptr = - layout.GetBlockPtr(memory_ptr, storage::DataLayout::NAME_ID_LIST); - util::vector_view name_ids(name_id_list_ptr, - layout.num_entries[storage::DataLayout::NAME_ID_LIST]); + auto annotation_data_list_ptr = + layout.GetBlockPtr( + memory_ptr, storage::DataLayout::ANNOTATION_DATA_LIST); + util::vector_view annotation_data( + annotation_data_list_ptr, + layout.num_entries[storage::DataLayout::ANNOTATION_DATA_LIST]); - auto component_ids_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::COMPONENT_ID_LIST); - util::vector_view component_ids( - component_ids_ptr, layout.num_entries[storage::DataLayout::COMPONENT_ID_LIST]); - - auto travel_mode_list_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::TRAVEL_MODE_LIST); - util::vector_view travel_modes( - travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]); - - auto classes_list_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::CLASSES_LIST); - util::vector_view classes( - classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]); - - auto is_left_hand_driving_ptr = layout.GetBlockPtr( - memory_ptr, storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST); - util::vector_view is_left_hand_driving( - is_left_hand_driving_ptr, - layout.num_entries[storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST]); - - extractor::EdgeBasedNodeDataView node_data(std::move(geometry_ids), - std::move(name_ids), - std::move(component_ids), - std::move(travel_modes), - std::move(classes), - std::move(is_left_hand_driving)); + extractor::EdgeBasedNodeDataView node_data(std::move(edge_based_node_data), + std::move(annotation_data)); extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data); } diff --git a/src/tools/components.cpp b/src/tools/components.cpp index fc9ccdb47..5a7c2ca62 100644 --- a/src/tools/components.cpp +++ b/src/tools/components.cpp @@ -55,12 +55,12 @@ std::size_t loadGraph(const std::string &path, continue; } - if (input_edge.forward) + if (input_edge.flags.forward) { graph_edge_list.emplace_back(input_edge.source, input_edge.target); } - if (input_edge.backward) + if (input_edge.flags.backward) { graph_edge_list.emplace_back(input_edge.target, input_edge.source); } diff --git a/src/updater/updater.cpp b/src/updater/updater.cpp index c278e2627..6ddc8f9bc 100644 --- a/src/updater/updater.cpp +++ b/src/updater/updater.cpp @@ -524,8 +524,9 @@ Updater::NumNodesAndEdges Updater::LoadAndUpdateEdgeExpandedGraph() const { std::vector node_weights; std::vector edge_based_edge_list; - auto max_edge_id = Updater::LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights); - return std::make_tuple(max_edge_id + 1, std::move(edge_based_edge_list)); + auto number_of_edge_based_nodes = + Updater::LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights); + return std::make_tuple(number_of_edge_based_nodes, std::move(edge_based_edge_list)); } EdgeID @@ -534,12 +535,12 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector &e { TIMER_START(load_edges); - EdgeID max_edge_id = 0; + EdgeID number_of_edge_based_nodes = 0; std::vector coordinates; extractor::PackedOSMIDs osm_node_ids; extractor::files::readEdgeBasedGraph( - config.GetPath(".osrm.ebg"), max_edge_id, edge_based_edge_list); + config.GetPath(".osrm.ebg"), number_of_edge_based_nodes, edge_based_edge_list); extractor::files::readNodes(config.GetPath(".osrm.nbg_nodes"), coordinates, osm_node_ids); const bool update_conditional_turns = @@ -550,7 +551,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector &e if (!update_edge_weights && !update_turn_penalties && !update_conditional_turns) { saveDatasourcesNames(config); - return max_edge_id; + return number_of_edge_based_nodes; } if (config.segment_speed_lookup_paths.size() + config.turn_penalty_lookup_paths.size() > 255) @@ -838,7 +839,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector &e TIMER_STOP(load_edges); util::Log() << "Done reading edges in " << TIMER_MSEC(load_edges) << "ms."; - return max_edge_id; + return number_of_edge_based_nodes; } } } diff --git a/unit_tests/extractor/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp index 305433618..c3c207a57 100644 --- a/unit_tests/extractor/graph_compressor.cpp +++ b/unit_tests/extractor/graph_compressor.cpp @@ -28,23 +28,33 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to) { // src, tgt, dist, edge_id, name_id, fwd, bkwd, roundabout, circular, startpoint, local access, // split edge, travel_mode - return { - from, // source - to, // target - 1, // weight - 1, // duration - SPECIAL_EDGEID, // edge_id - 0, // name_id - false, // reversed - false, // roundabout - false, // circular - false, // startpoint - false, // is_left_hand_driving - true, // split edge - TRAVEL_MODE_INACCESSIBLE, // travel_mode - 0, // classes - INVALID_LANE_DESCRIPTIONID // lane_description_id - }; + return {from, + to, + 1, // weight + 1, // duration + GeometryID{0, false}, // geometry_id + false, // reversed + NodeBasedEdgeClassification(), // default flags + 0}; // AnnotationID +} + +bool compatible(Graph const &graph, + const std::vector &node_data_container, + EdgeID const first, + EdgeID second) +{ + auto const &first_flags = graph.GetEdgeData(first).flags; + auto const &second_flags = graph.GetEdgeData(second).flags; + if (!(first_flags == second_flags)) + return false; + + if (graph.GetEdgeData(first).reversed != graph.GetEdgeData(second).reversed) + return false; + + auto const &first_annotation = node_data_container[graph.GetEdgeData(first).annotation_data]; + auto const &second_annotation = node_data_container[graph.GetEdgeData(second).annotation_data]; + + return first_annotation.CanCombineWith(second_annotation); } } // namespace @@ -60,6 +70,7 @@ BOOST_AUTO_TEST_CASE(long_road_test) std::unordered_set traffic_lights; std::vector restrictions; std::vector conditional_restrictions; + std::vector annotations(1); CompressedEdgeContainer container; test::MockScriptingEnvironment scripting_environment; @@ -72,19 +83,19 @@ BOOST_AUTO_TEST_CASE(long_road_test) MakeUnitEdge(3, 4), MakeUnitEdge(4, 3)}; - BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data)); - BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[4].data)); - BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[6].data)); - Graph graph(5, edges); + BOOST_ASSERT(compatible(graph, annotations, 0, 2)); + BOOST_ASSERT(compatible(graph, annotations, 2, 4)); + BOOST_ASSERT(compatible(graph, annotations, 4, 6)); + compressor.Compress(barrier_nodes, traffic_lights, scripting_environment, restrictions, conditional_restrictions, graph, + annotations, container); - BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID); BOOST_CHECK_EQUAL(graph.FindEdge(1, 2), SPECIAL_EDGEID); BOOST_CHECK_EQUAL(graph.FindEdge(2, 3), SPECIAL_EDGEID); @@ -106,6 +117,7 @@ BOOST_AUTO_TEST_CASE(loop_test) std::vector restrictions; std::vector conditional_restrictions; CompressedEdgeContainer container; + std::vector annotations(1); test::MockScriptingEnvironment scripting_environment; std::vector edges = {MakeUnitEdge(0, 1), @@ -121,26 +133,28 @@ BOOST_AUTO_TEST_CASE(loop_test) MakeUnitEdge(5, 0), MakeUnitEdge(5, 4)}; - BOOST_ASSERT(edges.size() == 12); - BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); - BOOST_ASSERT(edges[1].data.IsCompatibleTo(edges[2].data)); - BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data)); - BOOST_ASSERT(edges[3].data.IsCompatibleTo(edges[4].data)); - BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data)); - BOOST_ASSERT(edges[5].data.IsCompatibleTo(edges[6].data)); - BOOST_ASSERT(edges[6].data.IsCompatibleTo(edges[7].data)); - BOOST_ASSERT(edges[7].data.IsCompatibleTo(edges[8].data)); - BOOST_ASSERT(edges[8].data.IsCompatibleTo(edges[9].data)); - BOOST_ASSERT(edges[9].data.IsCompatibleTo(edges[10].data)); - BOOST_ASSERT(edges[10].data.IsCompatibleTo(edges[11].data)); - Graph graph(6, edges); + BOOST_ASSERT(edges.size() == 12); + BOOST_ASSERT(compatible(graph, annotations, 0, 1)); + BOOST_ASSERT(compatible(graph, annotations, 1, 2)); + BOOST_ASSERT(compatible(graph, annotations, 2, 3)); + BOOST_ASSERT(compatible(graph, annotations, 3, 4)); + BOOST_ASSERT(compatible(graph, annotations, 4, 5)); + BOOST_ASSERT(compatible(graph, annotations, 5, 6)); + BOOST_ASSERT(compatible(graph, annotations, 6, 7)); + BOOST_ASSERT(compatible(graph, annotations, 7, 8)); + BOOST_ASSERT(compatible(graph, annotations, 8, 9)); + BOOST_ASSERT(compatible(graph, annotations, 9, 10)); + BOOST_ASSERT(compatible(graph, annotations, 10, 11)); + BOOST_ASSERT(compatible(graph, annotations, 11, 0)); + compressor.Compress(barrier_nodes, traffic_lights, scripting_environment, restrictions, conditional_restrictions, graph, + annotations, container); BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID); @@ -163,6 +177,7 @@ BOOST_AUTO_TEST_CASE(t_intersection) std::unordered_set barrier_nodes; std::unordered_set traffic_lights; + std::vector annotations(1); std::vector restrictions; std::vector conditional_restrictions; CompressedEdgeContainer container; @@ -175,19 +190,20 @@ BOOST_AUTO_TEST_CASE(t_intersection) MakeUnitEdge(2, 1), MakeUnitEdge(3, 1)}; - BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); - BOOST_ASSERT(edges[1].data.IsCompatibleTo(edges[2].data)); - BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data)); - BOOST_ASSERT(edges[3].data.IsCompatibleTo(edges[4].data)); - BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data)); - Graph graph(4, edges); + BOOST_ASSERT(compatible(graph, annotations, 0, 1)); + BOOST_ASSERT(compatible(graph, annotations, 1, 2)); + BOOST_ASSERT(compatible(graph, annotations, 2, 3)); + BOOST_ASSERT(compatible(graph, annotations, 3, 4)); + BOOST_ASSERT(compatible(graph, annotations, 4, 5)); + compressor.Compress(barrier_nodes, traffic_lights, scripting_environment, restrictions, conditional_restrictions, graph, + annotations, container); BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID); @@ -204,6 +220,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes) std::unordered_set barrier_nodes; std::unordered_set traffic_lights; + std::vector annotations(2); std::vector restrictions; std::vector conditional_restrictions; CompressedEdgeContainer container; @@ -211,18 +228,21 @@ BOOST_AUTO_TEST_CASE(street_name_changes) std::vector edges = { MakeUnitEdge(0, 1), MakeUnitEdge(1, 0), MakeUnitEdge(1, 2), MakeUnitEdge(2, 1)}; - edges[2].data.name_id = edges[3].data.name_id = 1; - BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data)); - BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data)); + annotations[1].name_id = 1; + edges[2].data.annotation_data = edges[3].data.annotation_data = 1; Graph graph(5, edges); + BOOST_ASSERT(compatible(graph, annotations, 0, 1)); + BOOST_ASSERT(compatible(graph, annotations, 2, 3)); + compressor.Compress(barrier_nodes, traffic_lights, scripting_environment, restrictions, conditional_restrictions, graph, + annotations, container); BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID); @@ -238,6 +258,7 @@ BOOST_AUTO_TEST_CASE(direction_changes) std::unordered_set barrier_nodes; std::unordered_set traffic_lights; + std::vector annotations(1); std::vector restrictions; std::vector conditional_restrictions; CompressedEdgeContainer container; @@ -255,6 +276,7 @@ BOOST_AUTO_TEST_CASE(direction_changes) restrictions, conditional_restrictions, graph, + annotations, container); BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);