From 07459e978a76d434af98b3a010dffa3ed8bb55f2 Mon Sep 17 00:00:00 2001 From: Moritz Kobitzsch Date: Wed, 12 Jul 2017 10:27:54 +0200 Subject: [PATCH] initial version of handling via-way turn restrictions (this is dirty) - requires update of data structures - requires clean-up - requires optimisation --- features/car/restrictions.feature | 34 +- .../extractor/edge_based_graph_factory.hpp | 12 +- include/extractor/way_restriction_map.hpp | 12 + src/engine/guidance/post_processing.cpp | 3 + src/extractor/edge_based_graph_factory.cpp | 367 +++++++++++++++--- src/extractor/extractor.cpp | 12 +- src/extractor/way_restriction_map.cpp | 39 +- 7 files changed, 402 insertions(+), 77 deletions(-) diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature index 85250468e6f..81a7e83586e 100644 --- a/features/car/restrictions.feature +++ b/features/car/restrictions.feature @@ -537,7 +537,7 @@ Feature: Car - Turn restrictions | from | to | route | | a | h | abc,cde,efc,cgh,cgh | - @restriction + @restriction-way Scenario: Car - prohibit turn Given the node map """ @@ -563,9 +563,11 @@ Feature: Car - Turn restrictions | restriction | ab | be | de | no_right_turn | When I route I should get - | from | to | route | - | a | d | ab,be,de,de | - | a | f | ab,be,ef,ef | + | from | to | route | turns | locations | + | a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d | + | a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f | + | c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d | + | c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f | @restriction Scenario: Car - allow only turn @@ -593,9 +595,11 @@ Feature: Car - Turn restrictions | restriction | ab | be | ef | only_left_on | When I route I should get - | from | to | route | - | a | d | ab,be,de,de | - + | from | to | route | turns | locations | + | a | d | ab,be,ef,ef,de,de | depart,turn right,turn left,continue uturn,new name straight,arrive | a,b,e,f,e,d | + | a | f | ab,be,ef,ef | depart,turn right,turn left,arrive | a,b,e,f | + | c | d | bc,be,de,de | depart,turn left,turn right,arrive | c,b,e,d | + | c | f | bc,be,ef,ef | depart,turn left,turn left,arrive | c,b,e,f | @restriction Scenario: Car - allow only turn @@ -692,11 +696,11 @@ Feature: Car - Turn restrictions | restriction | gf | fb,bc | cd | only_u_turn | When I route I should get - | from | to | route | - | a | d | abcd,abcd | - | a | e | abcd,ce,ce | - | a | f | abcd,hfb,hfb | - | g | e | gf,hfb,abcd,ce,ce | - | g | d | gf,hfb,abcd,abcd | - | h | e | hfb,abcd,ce,ce | - | h | d | hfb,abcd,abcd | + | from | to | route | turns | locations | + | a | d | abcd,ce,ce,abcd,abcd | depart,turn left,continue uturn,turn left,arrive | a,c,e,c,d | + | a | e | abcd,ce,ce | depart,turn left,arrive | a,c,e | + | a | f | abcd,hfb,hfb | depart,turn right,arrive | a,b,f | + | g | e | gf,hfb,abcd,ce,ce | depart,turn right,turn right,turn left,arrive | g,f,b,c,e | + | g | d | gf,hfb,abcd,abcd | depart,turn right,turn right,arrive | g,f,b,d | + | h | e | hfb,abcd,ce,ce | depart,end of road right,turn left,arrive | h,b,c,e | + | h | d | hfb,abcd,abcd | depart,end of road right,arrive | h,b,d | diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 61a12fa1921..1510c969de2 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -17,6 +17,7 @@ #include "extractor/profile_properties.hpp" #include "extractor/query_node.hpp" #include "extractor/restriction_map.hpp" +#include "extractor/way_restriction_map.hpp" #include "util/concurrent_id_map.hpp" #include "util/deallocating_vector.hpp" @@ -91,7 +92,8 @@ class EdgeBasedGraphFactory const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, const std::string &cnbg_ebg_mapping_path, - const RestrictionMap & restriction_map); + const RestrictionMap &restriction_map, + const WayRestrictionMap &way_restriction_map); // The following get access functions destroy the content in the factory void GetEdgeBasedEdges(util::DeallocatingVector &edges); @@ -151,7 +153,7 @@ class EdgeBasedGraphFactory unsigned RenumberEdges(); - std::vector GenerateEdgeExpandedNodes(); + std::vector GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map); void GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment, const std::string &original_edge_data_filename, @@ -159,7 +161,8 @@ class EdgeBasedGraphFactory const std::string &turn_weight_penalties_filename, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, - const RestrictionMap & restriction_map); + const RestrictionMap &restriction_map, + const WayRestrictionMap &way_restriction_map); NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v); @@ -170,6 +173,9 @@ class EdgeBasedGraphFactory util::ConcurrentIDMap bearing_class_hash; std::vector bearing_class_by_node_based_node; util::ConcurrentIDMap entry_class_hash; + + // a mapping from a restriction way to the duplicate node + std::vector edge_based_node_by_via_way; }; } // namespace extractor } // namespace osrm diff --git a/include/extractor/way_restriction_map.hpp b/include/extractor/way_restriction_map.hpp index b6fd89785b0..18e569ee52a 100644 --- a/include/extractor/way_restriction_map.hpp +++ b/include/extractor/way_restriction_map.hpp @@ -22,14 +22,26 @@ class WayRestrictionMap public: WayRestrictionMap(const std::vector &turn_restrictions); + bool IsViaWay(const NodeID from, const NodeID to) const; + // check if an edge between two nodes is a restricted turn bool IsStart(const NodeID from, const NodeID to) const; bool IsEnd(const NodeID from, const NodeID to) const; + std::vector> ViaWays() const; + + std::size_t Size() const; + std::size_t GetID(const NodeID from, const NodeID to) const; + + TurnRestriction const& GetRestriction(std::size_t) const; private: // acces to the turn restrictions based on the via way they use boost::unordered_multimap, std::size_t> restriction_starts; boost::unordered_multimap, std::size_t> restriction_ends; + + boost::unordered_multimap, std::size_t> via_ways; + + std::vector restriction_data; }; } // namespace extractor diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index da08d2dceb4..d6b56bbef95 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -20,6 +20,8 @@ #include #include +#include "util/debug.hpp" + using osrm::util::angularDeviation; using osrm::extractor::guidance::getTurnDirection; using osrm::extractor::guidance::hasRampType; @@ -251,6 +253,7 @@ void closeOffRoundabout(const bool on_roundabout, // that we come across. std::vector postProcess(std::vector steps) { + util::guidance::print(steps); // the steps should always include the first/last step in form of a location BOOST_ASSERT(steps.size() >= 2); if (steps.size() == 2) diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 6b335f9e6c0..f9f79f37d97 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -52,8 +52,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( const util::NameTable &name_table, guidance::LaneDescriptionMap &lane_description_map) : m_max_edge_id(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_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), lane_description_map(lane_description_map) @@ -144,6 +143,8 @@ 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); + std::cout << "Adding edge based node: " << node_u << " " << node_v << " - " + << forward_data.edge_id << std::endl; m_edge_based_node_container.SetData(forward_data.edge_id, GeometryID{packed_geometry_id, true}, forward_data.name_id, @@ -151,6 +152,8 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N forward_data.classes); if (reverse_data.edge_id != SPECIAL_EDGEID) { + std::cout << "Adding edge based node: " << node_u << " " << node_v << " (rev) - " + << reverse_data.edge_id << std::endl; m_edge_based_node_container.SetData(reverse_data.edge_id, GeometryID{packed_geometry_id, false}, reverse_data.name_id, @@ -175,8 +178,8 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N 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.startpoint || reverse_data.startpoint)); current_edge_source_coordinate_id = current_edge_target_coordinate_id; } @@ -192,7 +195,8 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, const std::string &cnbg_ebg_mapping_path, - const RestrictionMap &restriction_map) + const RestrictionMap &restriction_map, + const WayRestrictionMap &way_restriction_map) { TIMER_START(renumber); m_max_edge_id = RenumberEdges() - 1; @@ -200,7 +204,7 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, TIMER_START(generate_nodes); { - auto mapping = GenerateEdgeExpandedNodes(); + auto mapping = GenerateEdgeExpandedNodes(way_restriction_map); files::writeNBGMapping(cnbg_ebg_mapping_path, mapping); } TIMER_STOP(generate_nodes); @@ -212,7 +216,8 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, turn_weight_penalties_filename, turn_duration_penalties_filename, turn_penalties_index_filename, - restriction_map); + restriction_map, + way_restriction_map); TIMER_STOP(generate_edges); @@ -258,14 +263,20 @@ unsigned EdgeBasedGraphFactory::RenumberEdges() } /// Creates the nodes in the edge expanded graph from edges in the node-based graph. -std::vector EdgeBasedGraphFactory::GenerateEdgeExpandedNodes() +std::vector +EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map) { std::vector mapping; // Allocate memory for edge-based nodes - m_edge_based_node_container = EdgeBasedNodeDataContainer(m_max_edge_id + 1); + // In addition to the normal edges, allocate enough space for copied edges from + // via-way-restrictions + m_edge_based_node_container = + EdgeBasedNodeDataContainer(m_max_edge_id + way_restriction_map.Size() + 1); 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()); @@ -306,10 +317,67 @@ std::vector EdgeBasedGraphFactory::GenerateEdgeExpandedNodes() } } + util::Log() << "Expanding via-way turn restrictions ... "; + // Add copies of the nodes + { + util::UnbufferedLog log; + const auto via_ways = way_restriction_map.ViaWays(); + util::Percent progress(log, via_ways.size()); + std::size_t progress_counter = 0; + // allocate enough space for the mapping + edge_based_node_by_via_way.resize(way_restriction_map.Size(), SPECIAL_NODEID); + for (const auto way : via_ways) + { + const auto node_u = way.first; + const auto node_v = way.second; + + auto const eid = m_node_based_graph->FindEdge(node_u, node_v); + const NodeID edge_based_node_id = m_max_edge_id + 1 + progress_counter; + std::cout << "Restriction: " << node_u << " " << node_v << " -- " << eid << " " + << m_node_based_graph->GetEdgeData(eid).edge_id + << " EBN: " << edge_based_node_id << std::endl; + + edge_based_node_by_via_way[way_restriction_map.GetID(node_u, node_v)] = + edge_based_node_id; + + BOOST_ASSERT(m_node_based_graph->GetEdgeData(eid).edge_id != SPECIAL_NODEID); + std::cout << "Adding " << node_u << " to " << node_v << std::endl; + + // merge edges together into one EdgeBasedNode + BOOST_ASSERT(node_u != SPECIAL_NODEID); + BOOST_ASSERT(node_v != SPECIAL_NODEID); + + // find forward edge id, we only require the forward ID + 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); + + // what is this ID all about? :( + BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID); + + // Add edge-based node data for forward and reverse nodes indexed by edge_id + BOOST_ASSERT(forward_data.edge_id != SPECIAL_EDGEID); + std::cout << "Adding edge based node: " << node_u << " " << node_v << " - " + << forward_data.edge_id << std::endl; + m_edge_based_node_container.SetData( + edge_based_node_id, + // fetch the known geometry ID + m_edge_based_node_container.GetGeometryID(static_cast(eid)), + forward_data.name_id, + forward_data.travel_mode, + forward_data.classes); + + m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]); + + progress.PrintStatus(progress_counter++); + } + } + BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size()); - BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size()); + BOOST_ASSERT(m_max_edge_id + 1 + way_restriction_map.Size() == + m_edge_based_node_weights.size()); - util::Log() << "Generated " << (m_max_edge_id + 1) << " nodes and " + util::Log() << "Generated " << (m_max_edge_id + 1 + way_restriction_map.Size()) << " nodes and " << m_edge_based_node_segments.size() << " segments in edge-expanded graph"; return mapping; @@ -323,11 +391,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const std::string &turn_weight_penalties_filename, const std::string &turn_duration_penalties_filename, const std::string &turn_penalties_index_filename, - const RestrictionMap &restriction_map) + const RestrictionMap &restriction_map, + const WayRestrictionMap &way_restriction_map) { util::Log() << "Generating edge-expanded edges "; + std::cout << "Restriction ids ["; + for (auto id : edge_based_node_by_via_way) + std::cout << " " << id; + std::cout << " ]" << std::endl; + std::size_t node_based_edge_counter = 0; restricted_turns_counter = 0; skipped_uturns_counter = 0; @@ -412,7 +486,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // appended to the various output arrays/files by the `output_stage`. struct IntersectionData { - std::size_t nodes_processed = 0; std::vector turn_indexes; std::vector edges_list; std::vector turn_weight_penalties; @@ -420,13 +493,19 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( std::vector turn_data_container; }; + struct PipelineBuffer + { + std::size_t nodes_processed = 0; + IntersectionData continuous_data; + IntersectionData delayed_data; + }; + // Second part of the pipeline is where the intersection analysis is done for // each intersection - tbb::filter_t, std::shared_ptr> - processor_stage( + tbb::filter_t, std::shared_ptr> processor_stage( tbb::filter::parallel, [&](const tbb::blocked_range &intersection_node_range) { - auto buffer = std::make_shared(); + auto buffer = std::make_shared(); buffer->nodes_processed = intersection_node_range.end() - intersection_node_range.begin(); @@ -515,13 +594,137 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( bearing_class_by_node_based_node[node_at_center_of_intersection] = bearing_class_id; + if (way_restriction_map.IsEnd(node_along_road_entering, + node_at_center_of_intersection)) + { + auto restriction_id = way_restriction_map.GetID( + node_along_road_entering, node_at_center_of_intersection); + auto const &restriction = + way_restriction_map.GetRestriction(restriction_id); + auto const &way_restriction = restriction.AsWayRestriction(); + auto from_id = edge_based_node_by_via_way[restriction_id]; + std::cout << "Turning off a restricted way (" << restriction_id + << ") at: " << node_at_center_of_intersection + << " coming from " << node_along_road_entering + << " duplication node: " << from_id << std::endl; + // auto &output_target = buffer->delayed_data; + auto &output_target = buffer->continuous_data; + for (const auto &turn : intersection) + { + // only keep valid turns + if (!turn.entry_allowed) + continue; + + auto const node_at_end_of_turn = + m_node_based_graph->GetTarget(turn.eid); + // skip not explicitly allowed turns + if (restriction.flags.is_only && + node_at_end_of_turn != way_restriction.out_restriction.to) + continue; + + // skip forbidden turns + if (!restriction.flags.is_only && + node_at_end_of_turn == way_restriction.out_restriction.to) + continue; + + const EdgeData &edge_data1 = + m_node_based_graph->GetEdgeData(incoming_edge); + const EdgeData &edge_data2 = + m_node_based_graph->GetEdgeData(turn.eid); + + BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id); + BOOST_ASSERT(!edge_data1.reversed); + BOOST_ASSERT(!edge_data2.reversed); + + // the following is the core of the loop. + output_target.turn_data_container.push_back( + {turn.instruction, + turn.lane_data_id, + entry_class_id, + util::guidance::TurnBearing(intersection[0].bearing), + util::guidance::TurnBearing(turn.bearing)}); + + // 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); + extracted_turn.source_restricted = edge_data1.restricted; + extracted_turn.target_restricted = edge_data2.restricted; + scripting_environment.ProcessTurn(extracted_turn); + + // turn penalties are limited to [-2^15, 2^15) which roughly + // translates to 54 minutes and fits signed 16bit deci-seconds + auto weight_penalty = 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); + + // auto turn_id = m_edge_based_edge_list.size(); + auto weight = boost::numeric_cast(edge_data1.weight + + weight_penalty); + auto duration = boost::numeric_cast( + edge_data1.duration + duration_penalty); + + std::cout + << "Restriction off turn: instead of: " << edge_data1.edge_id + << " use " << from_id << " " << edge_data2.edge_id << std::endl; + std::cout << "Turneid: " << turn.eid << std::endl; + + output_target.edges_list.emplace_back( + from_id, + edge_data2.edge_id, + SPECIAL_NODEID, // This will be updated once the main loop + // completes! + weight, + duration, + true, + false); + + BOOST_ASSERT(output_target.turn_weight_penalties.size() == + output_target.edges_list.size() - 1); + output_target.turn_weight_penalties.push_back(weight_penalty); + BOOST_ASSERT(output_target.turn_duration_penalties.size() == + output_target.edges_list.size() - 1); + output_target.turn_duration_penalties.push_back(duration_penalty); + + // We write out the mapping between the edge-expanded edges and the + // original nodes. Since each edge represents a possible maneuver, + // external programs can use this to quickly perform updates to edge + // weights in order to penalize certain turns. + + // If this edge is 'trivial' -- where the compressed edge + // corresponds + // exactly to an original OSM segment -- we can pull the turn's + // preceding node ID directly with `node_along_road_entering`; + // otherwise, we need to look up the node immediately preceding the + // turn + // from the compressed edge container. + const bool isTrivial = + m_compressed_edge_container.IsTrivial(incoming_edge); + + const auto &from_node = + isTrivial ? node_along_road_entering + : m_compressed_edge_container.GetLastEdgeSourceID( + incoming_edge); + const auto &via_node = + m_compressed_edge_container.GetLastEdgeTargetID(incoming_edge); + const auto &to_node = + m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid); + + output_target.turn_indexes.push_back( + {from_node, via_node, to_node}); + } + } + for (const auto &turn : intersection) { // only keep valid turns if (!turn.entry_allowed) continue; - // only add an edge if turn is not prohibited const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(incoming_edge); const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid); @@ -531,7 +734,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( BOOST_ASSERT(!edge_data2.reversed); // the following is the core of the loop. - buffer->turn_data_container.push_back( + buffer->continuous_data.turn_data_container.push_back( {turn.instruction, turn.lane_data_id, entry_class_id, @@ -561,9 +764,41 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( boost::numeric_cast(edge_data1.weight + weight_penalty); auto duration = boost::numeric_cast(edge_data1.duration + duration_penalty); - buffer->edges_list.emplace_back( + + auto target_id = edge_data2.edge_id; + if (way_restriction_map.IsStart( + node_at_center_of_intersection, + m_node_based_graph->GetTarget(turn.eid))) + { + + const auto restriction_id = way_restriction_map.GetID( + node_at_center_of_intersection, + m_node_based_graph->GetTarget(turn.eid)); + const auto &restriction = + way_restriction_map.GetRestriction(restriction_id) + .AsWayRestriction(); + + // target the artificial node + if (restriction.in_restriction.from == node_along_road_entering) + { + std::cout + << "Turning onto a restricted way at " + << node_at_center_of_intersection << " coming from " + << node_along_road_entering + << " restriction_id: " << restriction_id + << " EBN: " << edge_based_node_by_via_way[restriction_id] + << std::endl; + + target_id = edge_based_node_by_via_way[restriction_id]; + std::cout << "Restriction turning onto: " << edge_data1.edge_id + << " " << target_id << " instead of " + << edge_data2.edge_id << std::endl; + } + } + + buffer->continuous_data.edges_list.emplace_back( edge_data1.edge_id, - edge_data2.edge_id, + target_id, SPECIAL_NODEID, // This will be updated once the main loop // completes! weight, @@ -571,12 +806,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( true, false); - BOOST_ASSERT(buffer->turn_weight_penalties.size() == - buffer->edges_list.size() - 1); - buffer->turn_weight_penalties.push_back(weight_penalty); - BOOST_ASSERT(buffer->turn_duration_penalties.size() == - buffer->edges_list.size() - 1); - buffer->turn_duration_penalties.push_back(duration_penalty); + BOOST_ASSERT(buffer->continuous_data.turn_weight_penalties.size() == + buffer->continuous_data.edges_list.size() - 1); + buffer->continuous_data.turn_weight_penalties.push_back(weight_penalty); + BOOST_ASSERT(buffer->continuous_data.turn_duration_penalties.size() == + buffer->continuous_data.edges_list.size() - 1); + buffer->continuous_data.turn_duration_penalties.push_back( + duration_penalty); // We write out the mapping between the edge-expanded edges and the // original nodes. Since each edge represents a possible maneuver, @@ -600,7 +836,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid); - buffer->turn_indexes.push_back({from_node, via_node, to_node}); + buffer->continuous_data.turn_indexes.push_back( + {from_node, via_node, to_node}); } } } @@ -617,36 +854,55 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( std::vector turn_indexes_write_buffer; turn_indexes_write_buffer.reserve(TURN_INDEX_WRITE_BUFFER_SIZE); + IntersectionData delayed_data; + + auto const append_data_to_output = [&](IntersectionData const &data) { + // NOTE: potential overflow here if we hit 2^32 routable edges + m_edge_based_edge_list.append(data.edges_list.begin(), data.edges_list.end()); + + BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits::max()); + + turn_weight_penalties.insert(turn_weight_penalties.end(), + data.turn_weight_penalties.begin(), + data.turn_weight_penalties.end()); + turn_duration_penalties.insert(turn_duration_penalties.end(), + data.turn_duration_penalties.begin(), + data.turn_duration_penalties.end()); + turn_data_container.append(data.turn_data_container); + turn_indexes_write_buffer.insert(turn_indexes_write_buffer.end(), + data.turn_indexes.begin(), + data.turn_indexes.end()); + + // Buffer writes to reduce syscall count + if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE) + { + turn_penalties_index_file.WriteFrom(turn_indexes_write_buffer.data(), + turn_indexes_write_buffer.size()); + turn_indexes_write_buffer.clear(); + } + }; + // Last part of the pipeline puts all the calculated data into the serial buffers - tbb::filter_t, void> output_stage( - tbb::filter::serial_in_order, [&](const std::shared_ptr buffer) { + tbb::filter_t, void> output_stage( + tbb::filter::serial_in_order, [&](const std::shared_ptr buffer) { + // append an input vector to an output vector + auto const append = [](auto &target, const auto &source) { + target.insert(target.end(), source.begin(), source.end()); + }; nodes_completed += buffer->nodes_processed; progress.PrintStatus(nodes_completed); + append_data_to_output(buffer->continuous_data); // NOTE: potential overflow here if we hit 2^32 routable edges - m_edge_based_edge_list.append(buffer->edges_list.begin(), buffer->edges_list.end()); - BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits::max()); - - turn_weight_penalties.insert(turn_weight_penalties.end(), - buffer->turn_weight_penalties.begin(), - buffer->turn_weight_penalties.end()); - turn_duration_penalties.insert(turn_duration_penalties.end(), - buffer->turn_duration_penalties.begin(), - buffer->turn_duration_penalties.end()); - turn_data_container.append(buffer->turn_data_container); - - turn_indexes_write_buffer.insert(turn_indexes_write_buffer.end(), - buffer->turn_indexes.begin(), - buffer->turn_indexes.end()); - - // Buffer writes to reduce syscall count - if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE) - { - turn_penalties_index_file.WriteFrom(turn_indexes_write_buffer.data(), - turn_indexes_write_buffer.size()); - turn_indexes_write_buffer.clear(); - } + append(delayed_data.edges_list, buffer->delayed_data.edges_list); + append(delayed_data.turn_weight_penalties, + buffer->delayed_data.turn_weight_penalties); + append(delayed_data.turn_duration_penalties, + buffer->delayed_data.turn_duration_penalties); + append(delayed_data.turn_data_container, + buffer->continuous_data.turn_data_container); + append(delayed_data.turn_indexes, buffer->delayed_data.turn_indexes); }); // Now, execute the pipeline. The value of "5" here was chosen by experimentation @@ -657,6 +913,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( tbb::parallel_pipeline(tbb::task_scheduler_init::default_num_threads() * 5, generator_stage & processor_stage & output_stage); + append_data_to_output(delayed_data); + // Flush the turn_indexes_write_buffer if it's not empty if (!turn_indexes_write_buffer.empty()) { @@ -677,6 +935,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( } }); + std::cout << "Edges\n"; + for (auto const &edge : m_edge_based_edge_list) + std::cout << "\t" << edge.source << " " << edge.target << " " << std::endl; + // write weight penalties per turn BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size()); { @@ -715,7 +977,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( util::Log() << "Edge-expanded graph ..."; util::Log() << " contains " << m_edge_based_edge_list.size() << " edges"; util::Log() << " skips " << restricted_turns_counter << " turns, " - "defined by " << restriction_map.size() << " restrictions"; + "defined by " + << restriction_map.size() << " restrictions"; util::Log() << " skips " << skipped_uturns_counter << " U turns"; util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers"; } diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 7f15de1813b..5ae6761f25e 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -481,7 +481,8 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, name_table, turn_lane_map); - { // scoped to relase right after the run + auto const number_of_edge_based_nodes = [&](){ + // scoped to relase intermediate datastructures right after the call RestrictionMap via_node_restriction_map(turn_restrictions); WayRestrictionMap via_way_restriction_map(turn_restrictions); turn_restrictions.clear(); @@ -494,8 +495,10 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, config.turn_duration_penalties_path, config.turn_penalties_index_path, config.cnbg_ebg_graph_mapping_output_path, - via_node_restriction_map); - } + via_node_restriction_map, + via_way_restriction_map); + return edge_based_graph_factory.GetHighestEdgeID() + via_way_restriction_map.Size(); + }(); compressed_edge_container.PrintStatistics(); @@ -537,7 +540,6 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, 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); - auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID(); const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes(); @@ -551,7 +553,7 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, TIMER_STOP(write_intersections); util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s"; - return std::make_pair(number_of_node_based_nodes, max_edge_id); + return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes); } /** diff --git a/src/extractor/way_restriction_map.cpp b/src/extractor/way_restriction_map.cpp index 672a301016c..de0fb95b8b3 100644 --- a/src/extractor/way_restriction_map.cpp +++ b/src/extractor/way_restriction_map.cpp @@ -1,5 +1,7 @@ #include "extractor/way_restriction_map.hpp" +#include + namespace osrm { namespace extractor @@ -14,9 +16,13 @@ WayRestrictionMap::WayRestrictionMap(const std::vector &turn_re const auto &way = restriction.AsWayRestriction(); restriction_starts.insert( - std::make_pair(std::make_pair(way.in_restriction.via, way.in_restriction.to), 0)); + std::make_pair(std::make_pair(way.in_restriction.via, way.in_restriction.to), restriction_data.size())); restriction_ends.insert( - std::make_pair(std::make_pair(way.out_restriction.from, way.out_restriction.via), 0)); + std::make_pair(std::make_pair(way.out_restriction.from, way.out_restriction.via), restriction_data.size())); + via_ways.insert( + std::make_pair(std::make_pair(way.in_restriction.via, way.out_restriction.via), restriction_data.size())); + + restriction_data.push_back(restriction); }; std::for_each(turn_restrictions.begin(), turn_restrictions.end(), prepare_way_restriction); } @@ -30,6 +36,35 @@ bool WayRestrictionMap::IsEnd(const NodeID from, const NodeID to) const { return restriction_ends.count(std::make_pair(from, to)) > 0; } +bool WayRestrictionMap::IsViaWay(const NodeID from, const NodeID to) const +{ + return via_ways.count(std::make_pair(from, to)) > 0; +} + +std::size_t WayRestrictionMap::Size() const { + return via_ways.size(); +} + +std::size_t WayRestrictionMap::GetID(const NodeID from, const NodeID to) const +{ + return via_ways.find(std::make_pair(from,to))->second; +} + +TurnRestriction const& WayRestrictionMap::GetRestriction(const std::size_t id) const +{ + return restriction_data[id]; +} + +std::vector> WayRestrictionMap::ViaWays() const +{ + std::vector> result; + result.reserve(via_ways.size()); + std::transform(via_ways.begin(), + via_ways.end(), + std::back_inserter(result), + [](auto const pair) { return pair.first; }); + return result; +} } // namespace extractor } // namespace osrm