diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 7fbead463d9..3edbd20ea60 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -108,7 +108,7 @@ class EdgeBasedGraphFactory std::vector GetBearingClasses() const; std::vector GetEntryClasses() const; - unsigned GetHighestEdgeID(); + std::uint64_t GetNumberOfEdgeBasedNodes() const; // Basic analysis of a turn (u --(e1)-- v --(e2)-- w) // with known angle. @@ -136,7 +136,11 @@ class EdgeBasedGraphFactory std::vector m_edge_based_node_segments; EdgeBasedNodeDataContainer m_edge_based_node_container; util::DeallocatingVector m_edge_based_edge_list; - EdgeID m_max_edge_id; + + // the number of edge-based nodes is mostly made up out of the edges in the node-based graph. + // Any edge in the node-based graph represents a node in the edge-based graph. In addition, we + // add a set of artificial edge-based nodes into the mix to model via-way turn restrictions. + std::uint64_t m_number_of_edge_based_nodes; const std::vector &m_coordinates; const extractor::PackedOSMIDs &m_osm_node_ids; diff --git a/include/extractor/node_data_container.hpp b/include/extractor/node_data_container.hpp index 5b6bf33e6b7..4032dd694ef 100644 --- a/include/extractor/node_data_container.hpp +++ b/include/extractor/node_data_container.hpp @@ -105,7 +105,14 @@ template class EdgeBasedNodeDataContainerImpl } // all containers have the exact same size - std::size_t Size() const { return geometry_ids.size(); } + std::size_t Size() const + { + 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()); + return geometry_ids.size(); + } private: Vector geometry_ids; diff --git a/include/extractor/restriction.hpp b/include/extractor/restriction.hpp index 05d8305f90a..9e1764278a7 100644 --- a/include/extractor/restriction.hpp +++ b/include/extractor/restriction.hpp @@ -25,9 +25,9 @@ namespace extractor // ab via b to bd struct InputNodeRestriction { - OSMEdgeID_weak from; - OSMNodeID_weak via; - OSMEdgeID_weak to; + OSMWayID from; + OSMNodeID via; + OSMWayID to; }; // A restriction that uses a single via-way in between @@ -39,9 +39,9 @@ struct InputNodeRestriction // ab via be to ef -- no u turn struct InputWayRestriction { - OSMEdgeID_weak from; - OSMEdgeID_weak via; - OSMEdgeID_weak to; + OSMWayID from; + OSMWayID via; + OSMWayID to; }; // Outside view of the variant, these are equal to the `which()` results @@ -52,37 +52,20 @@ enum RestrictionType NUM_RESTRICTION_TYPES = 2 }; -namespace restriction_details -{ - -// currently these bits only hold an `is_only` value. -struct Bits -{ // mostly unused, initialised to false by default - Bits() : is_only(false) {} - - bool is_only; - // when adding more bits, consider using bitfields just as in - // bool unused : 7; - - bool operator==(const Bits &other) const { return is_only == other.is_only; } -}; - -} // namespace restriction - struct InputTurnRestriction { // keep in the same order as the turn restrictions below boost::variant node_or_way; - restriction_details::Bits flags; + bool is_only; - OSMEdgeID_weak From() const + OSMWayID From() const { return node_or_way.which() == RestrictionType::NODE_RESTRICTION ? boost::get(node_or_way).from : boost::get(node_or_way).from; } - OSMEdgeID_weak To() const + OSMWayID To() const { return node_or_way.which() == RestrictionType::NODE_RESTRICTION ? boost::get(node_or_way).to @@ -186,20 +169,18 @@ struct TurnRestriction { // keep in the same order as the turn restrictions above boost::variant node_or_way; - restriction_details::Bits flags; + bool is_only; // construction for NodeRestrictions explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false) - : node_or_way(node_restriction) + : node_or_way(node_restriction), is_only(is_only) { - flags.is_only = is_only; } // construction for WayRestrictions explicit TurnRestriction(WayRestriction way_restriction, bool is_only = false) - : node_or_way(way_restriction) + : node_or_way(way_restriction), is_only(is_only) { - flags.is_only = is_only; } explicit TurnRestriction() @@ -254,7 +235,7 @@ struct TurnRestriction bool operator==(const TurnRestriction &other) const { - if (!(flags == other.flags)) + if (is_only != other.is_only) return false; if (Type() != other.Type()) @@ -284,7 +265,7 @@ struct TurnRestriction auto const &node = AsNodeRestriction(); representation = node.ToString(); } - representation += " is_only: " + std::to_string(flags.is_only); + representation += " is_only: " + std::to_string(is_only); return representation; } }; diff --git a/include/extractor/restriction_map.hpp b/include/extractor/restriction_map.hpp index e676b589df3..09396d6d9db 100644 --- a/include/extractor/restriction_map.hpp +++ b/include/extractor/restriction_map.hpp @@ -69,7 +69,6 @@ namespace osrm { namespace extractor { - /** \brief Efficent look up if an edge is the start + via node of a TurnRestriction EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed diff --git a/include/extractor/restriction_parser.hpp b/include/extractor/restriction_parser.hpp index 91f9852b8c5..25a2a95e0e0 100644 --- a/include/extractor/restriction_parser.hpp +++ b/include/extractor/restriction_parser.hpp @@ -3,7 +3,8 @@ #include "extractor/restriction.hpp" -#include +#include + #include #include @@ -37,7 +38,6 @@ class ScriptingEnvironment; * ...----(a)-----(via)------(b)----... * So it can be represented by the tripe (a, via, b). */ - class RestrictionParser { public: diff --git a/include/extractor/serialization.hpp b/include/extractor/serialization.hpp index fc69c2a1670..3fa81e28ccb 100644 --- a/include/extractor/serialization.hpp +++ b/include/extractor/serialization.hpp @@ -163,7 +163,7 @@ inline void write(storage::io::FileWriter &writer, const WayRestriction &restric inline void read(storage::io::FileReader &reader, TurnRestriction &restriction) { - reader.ReadInto(restriction.flags); + reader.ReadInto(restriction.is_only); if (restriction.Type() == RestrictionType::WAY_RESTRICTION) { WayRestriction way_restriction; @@ -181,7 +181,7 @@ inline void read(storage::io::FileReader &reader, TurnRestriction &restriction) inline void write(storage::io::FileWriter &writer, const TurnRestriction &restriction) { - writer.WriteOne(restriction.flags); + writer.WriteOne(restriction.is_only); if (restriction.Type() == RestrictionType::WAY_RESTRICTION) { write(writer, boost::get(restriction.node_or_way)); @@ -211,7 +211,7 @@ inline void read(storage::io::FileReader &reader, ConditionalTurnRestriction &re TurnRestriction base; read(reader, base); reinterpret_cast(restriction) = std::move(base); - auto num_conditions = reader.ReadElementCount64(); + const auto num_conditions = reader.ReadElementCount64(); restriction.condition.resize(num_conditions); for (uint64_t i = 0; i < num_conditions; i++) { @@ -228,19 +228,18 @@ inline void read(storage::io::FileReader &reader, std::vector & auto num_indices = reader.ReadElementCount64(); restrictions.reserve(num_indices); TurnRestriction restriction; - while (num_indices > 0) + while (num_indices-- > 0) { read(reader, restriction); restrictions.push_back(std::move(restriction)); - num_indices--; } } inline void write(storage::io::FileWriter &writer, const std::vector &restrictions) { - std::uint64_t num_indices = restrictions.size(); + const auto num_indices = restrictions.size(); writer.WriteElementCount64(num_indices); - auto const write_restriction = [&writer](const auto &restriction) { + const auto write_restriction = [&writer](const auto &restriction) { write(writer, restriction); }; std::for_each(restrictions.begin(), restrictions.end(), write_restriction); @@ -253,20 +252,19 @@ inline void read(storage::io::FileReader &reader, auto num_indices = reader.ReadElementCount64(); restrictions.reserve(num_indices); ConditionalTurnRestriction restriction; - while (num_indices > 0) + while (num_indices-- > 0) { read(reader, restriction); restrictions.push_back(std::move(restriction)); - num_indices--; } } inline void write(storage::io::FileWriter &writer, const std::vector &restrictions) { - std::uint64_t num_indices = restrictions.size(); + const auto num_indices = restrictions.size(); writer.WriteElementCount64(num_indices); - auto const write_restriction = [&writer](const auto &restriction) { + const auto write_restriction = [&writer](const auto &restriction) { write(writer, restriction); }; std::for_each(restrictions.begin(), restrictions.end(), write_restriction); diff --git a/include/extractor/way_restriction_map.hpp b/include/extractor/way_restriction_map.hpp index 03a8a25bdf8..4e105c8af09 100644 --- a/include/extractor/way_restriction_map.hpp +++ b/include/extractor/way_restriction_map.hpp @@ -8,6 +8,7 @@ #include #include "extractor/restriction.hpp" +#include "util/integer_range.hpp" #include "util/typedefs.hpp" // Given the compressed representation of via-way turn restrictions, we provide a fast access into @@ -28,39 +29,56 @@ class WayRestrictionMap }; WayRestrictionMap(const std::vector &turn_restrictions); + // check if an edge between two nodes is a restricted turn. The check needs to be performed 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::size_t Size() const; - // number of duplicated nodes std::size_t NumberOfDuplicatedNodes() const; - // find the ID of the duplicated node (zero based) for a given restriction id - std::size_t DuplicatedNodeID(const std::size_t restriction_id) const; - // returns a representative for the duplicated way, consisting of the representative ID (first // ID of the nodes restrictions) and the from/to vertices of the via-way + // This is used to construct edge based nodes that act as intermediate nodes. std::vector DuplicatedNodeRepresentatives() const; - std::vector GetIDs(const NodeID from, const NodeID to) const; + // Access all duplicated NodeIDs for a set of nodes indicating a via way + util::range DuplicatedNodeIDs(const NodeID from, const NodeID to) const; + + // check whether a turn onto a given node is restricted, when coming from a duplicated node + bool IsRestricted(std::size_t duplicated_node, const NodeID to) const; TurnRestriction const &GetRestriction(std::size_t) const; + // changes edge_based_node to the correct duplicated_node_id in case node_based_from, + // node_based_via, node_based_to can be identified with a restriction group + NodeID RemapIfRestricted(const NodeID edge_based_node, + const NodeID node_based_from, + const NodeID node_based_via, + const NodeID node_based_to, + const NodeID number_of_edge_based_nodes) const; + private: + std::size_t AsDuplicatedNodeID(const std::size_t restriction_id) const; + // access all restrictions that have the same starting way and via way. Any duplicated node // represents the same in-way + via-way combination. This vector contains data about all // restrictions and their assigned duplicated nodes. It indicates the minimum restriciton ID // that is represented by the next node. The ID of a node is defined as the position of the // lower bound of the restrictions ID within this array + // + // a - b + // | + // y - c - x + // + // restriction nodes | restriction id + // a - b - c - x : 5 + // a - b - c - y : 6 + // + // EBN: 0 . | 2 | 3 | 4 ... + // duplicated node groups: ... | 5 | 7 | ... std::vector duplicated_node_groups; 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; }; diff --git a/include/util/serialization.hpp b/include/util/serialization.hpp index 8fd406ded5b..ebece1a430b 100644 --- a/include/util/serialization.hpp +++ b/include/util/serialization.hpp @@ -66,7 +66,7 @@ template inline void read(storage::io::FileReader &reader, DynamicGraph &graph) { storage::serialization::read(reader, graph.node_array); - auto num_edges = reader.ReadElementCount64(); + const auto num_edges = reader.ReadElementCount64(); graph.edge_list.resize(num_edges); for (auto index : irange(0, num_edges)) { diff --git a/include/util/typedefs.hpp b/include/util/typedefs.hpp index 06d52556eb6..1ba65b2c0f6 100644 --- a/include/util/typedefs.hpp +++ b/include/util/typedefs.hpp @@ -51,16 +51,17 @@ static_assert(std::is_pod(), "OSMNodeID is not a valid alias"); using OSMWayID = osrm::Alias; static_assert(std::is_pod(), "OSMWayID is not a valid alias"); -static const OSMNodeID SPECIAL_OSM_NODEID = OSMNodeID{std::numeric_limits::max()}; -static const OSMWayID SPECIAL_OSM_WAYID = OSMWayID{std::numeric_limits::max()}; - -static const OSMNodeID MAX_OSM_NODEID = OSMNodeID{std::numeric_limits::max()}; -static const OSMNodeID MIN_OSM_NODEID = OSMNodeID{std::numeric_limits::min()}; -static const OSMWayID MAX_OSM_WAYID = OSMWayID{std::numeric_limits::max()}; -static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits::min()}; - -using OSMNodeID_weak = std::uint64_t; -using OSMEdgeID_weak = std::uint64_t; +static const OSMNodeID SPECIAL_OSM_NODEID = + OSMNodeID{std::numeric_limits::max()}; +static const OSMWayID SPECIAL_OSM_WAYID = + OSMWayID{std::numeric_limits::max()}; + +static const OSMNodeID MAX_OSM_NODEID = + OSMNodeID{std::numeric_limits::max()}; +static const OSMNodeID MIN_OSM_NODEID = + OSMNodeID{std::numeric_limits::min()}; +static const OSMWayID MAX_OSM_WAYID = OSMWayID{std::numeric_limits::max()}; +static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits::min()}; using NodeID = std::uint32_t; using EdgeID = std::uint32_t; diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index d6b56bbef95..da08d2dceb4 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -20,8 +20,6 @@ #include #include -#include "util/debug.hpp" - using osrm::util::angularDeviation; using osrm::extractor::guidance::getTurnDirection; using osrm::extractor::guidance::hasRampType; @@ -253,7 +251,6 @@ 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 8e7936431c4..a56304faeac 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -51,7 +51,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( ProfileProperties profile_properties, 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_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), @@ -91,7 +91,10 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector &out swap(m_edge_based_node_weights, output_node_weights); } -EdgeID EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; } +std::uint64_t EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const +{ + return m_number_of_edge_based_nodes; +} NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v) { @@ -195,7 +198,7 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment, const WayRestrictionMap &way_restriction_map) { TIMER_START(renumber); - m_max_edge_id = RenumberEdges() - 1; + m_number_of_edge_based_nodes = RenumberEdges() + way_restriction_map.NumberOfDuplicatedNodes(); TIMER_STOP(renumber); TIMER_START(generate_nodes); @@ -267,8 +270,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re // 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_max_edge_id + way_restriction_map.NumberOfDuplicatedNodes() + 1); + 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 @@ -319,6 +321,9 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re util::UnbufferedLog log; const auto via_ways = way_restriction_map.DuplicatedNodeRepresentatives(); util::Percent progress(log, via_ways.size()); + + NodeID edge_based_node_id = + NodeID(m_number_of_edge_based_nodes - way_restriction_map.NumberOfDuplicatedNodes()); std::size_t progress_counter = 0; // allocate enough space for the mapping for (const auto way : via_ways) @@ -327,13 +332,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re const auto node_v = way.to; auto const eid = m_node_based_graph->FindEdge(node_u, node_v); - auto const revererse_id = m_node_based_graph->FindEdge(node_v, node_u); - std::cout << "Search: " << node_u << " " << node_v << " " << eid << " " << revererse_id - << std::endl; - 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; BOOST_ASSERT(m_node_based_graph->GetEdgeData(eid).edge_id != SPECIAL_NODEID); @@ -348,8 +346,6 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re // 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; BOOST_ASSERT(forward_data.edge_id < m_edge_based_node_container.Size()); m_edge_based_node_container.SetData(edge_based_node_id, @@ -362,18 +358,16 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]); + edge_based_node_id++; 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 + way_restriction_map.NumberOfDuplicatedNodes() == - m_edge_based_node_weights.size()); + BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size()); - util::Log() << "Generated " - << (m_max_edge_id + 1 + way_restriction_map.NumberOfDuplicatedNodes()) - << " nodes and " << m_edge_based_node_segments.size() - << " segments in edge-expanded graph"; + util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes and " + << m_edge_based_node_segments.size() << " segments in edge-expanded graph"; return mapping; } @@ -501,6 +495,114 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( std::vector delayed_data; }; + // add into delayed data + const auto delayed_inserter = [](const auto &edge_with_data, auto &buffer) { + buffer.delayed_data.push_back(edge_with_data); + }; + + // add into main data + const auto continuous_inserter = [](const auto &edge_with_data, auto &buffer) { + buffer.continuous_data.edges_list.push_back(edge_with_data.edge); + buffer.continuous_data.turn_indexes.push_back(edge_with_data.turn_index); + buffer.continuous_data.turn_weight_penalties.push_back( + edge_with_data.turn_weight_penalty); + buffer.continuous_data.turn_duration_penalties.push_back( + edge_with_data.turn_duration_penalty); + buffer.continuous_data.turn_data_container.push_back(edge_with_data.turn_data); + }; + + // Generate edges for either artificial nodes or the main graph + const auto generate_edges = [this, &scripting_environment, weight_multiplier]( + // what nodes will be used? In most cases this will be the id stored in the edge_data. + // In case of duplicated nodes (e.g. due to via-way restrictions), one/both of these + // might refer to a newly added edge based node + const auto edge_based_node_from, + const auto edge_based_node_to, + // the situation of the turn + const auto node_along_road_entering, + const auto node_based_edge_from, + const auto node_at_center_of_intersection, + const auto node_based_edge_to, + const auto &intersection, + const auto &turn, + const auto entry_class_id, + // we require a sorted output, additional nodes are collected and added after the + // sorting is done Here we can specify how/where to add the data + auto inserter, + auto &output_buffer) { + 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); + + 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. + TurnData turn_data = {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); + + EdgeBasedEdge edge_based_edge = { + edge_based_node_from, + edge_based_node_to, + SPECIAL_NODEID, // This will be updated once the main loop + // completes! + weight, + duration, + true, + false}; + + // 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(node_based_edge_from); + + const auto &from_node = + isTrivial ? node_along_road_entering + : m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from); + const auto &via_node = + m_compressed_edge_container.GetLastEdgeTargetID(node_based_edge_from); + const auto &to_node = m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid); + + lookup::TurnIndexBlock turn_index_block = {from_node, via_node, to_node}; + + // insert data into the designated buffer + inserter( + EdgeWithData{ + edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data}, + output_buffer); + + }; + // Second part of the pipeline is where the intersection analysis is done for // each intersection tbb::filter_t, std::shared_ptr> processor_stage( @@ -596,181 +698,9 @@ 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_ids = way_restriction_map.GetIDs( - node_along_road_entering, node_at_center_of_intersection); - - // loop over all duplicated nodes groups - auto itr = restriction_ids.begin(); - while (itr != restriction_ids.end()) - { - auto const from_id = - m_max_edge_id + 1 + way_restriction_map.DuplicatedNodeID(*itr); - const auto by_duplicated_id = [&](const auto duplicated_node, - const auto restriction_id) { - return duplicated_node < - way_restriction_map.DuplicatedNodeID(restriction_id); - }; - auto range = - std::equal_range(restriction_ids.begin(), - restriction_ids.end(), - way_restriction_map.DuplicatedNodeID(*itr), - by_duplicated_id); - - std::cout << "IDs:"; - for (auto r : restriction_ids) - std::cout << " " << way_restriction_map.DuplicatedNodeID(r); - std::cout << std::endl; - - std::cout << "Processing from: " - << std::distance(restriction_ids.begin(), range.first) - << " to " - << std::distance(restriction_ids.begin(), range.second) - << std::endl; - - bool is_only = false; - std::set restricted_nodes; - for (auto id_itr = range.first; id_itr != range.second; ++id_itr) - { - auto const &restriction = - way_restriction_map.GetRestriction(*id_itr); - auto const &way_restriction = restriction.AsWayRestriction(); - - // only handle `only` restrictions if they are actually the only - // restriction present - if (restriction.flags.is_only) - { - if (std::distance(range.first, range.second) > 1) - { - util::Log() << "Only restriction in present of other " - "restrictions"; - continue; - } - is_only = true; - } - restricted_nodes.insert(way_restriction.out_restriction.to); - } - - 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); - - const auto is_restricted = [&]() { - return is_only - ? (restricted_nodes.count(node_at_end_of_turn) == - 0) - : (restricted_nodes.count(node_at_end_of_turn) != - 0); - }; - - if (is_restricted()) - 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. - TurnData turn_data = { - 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 turning off a restricted way: instead of " - << edge_data1.edge_id << " use " << from_id << " -> " - << edge_data2.edge_id << std::endl; - - EdgeBasedEdge edge_based_edge = { - NodeID(from_id), - edge_data2.edge_id, - SPECIAL_NODEID, // This will be updated once the main loop - // completes! - weight, - duration, - true, - false}; - - // 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); - - lookup::TurnIndexBlock turn_index_block = { - from_node, via_node, to_node}; - - buffer->delayed_data.push_back({edge_based_edge, - turn_index_block, - weight_penalty, - duration_penalty, - turn_data}); - } - // advance towards the next range of duplicated nodes - itr = range.second; - } - } + // check if we are turning off a via way + const auto turning_off_via_way = way_restriction_map.IsViaWay( + node_along_road_entering, node_at_center_of_intersection); for (const auto &turn : intersection) { @@ -782,117 +712,91 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( 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. - buffer->continuous_data.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); - - auto target_id = edge_data2.edge_id; - if (way_restriction_map.IsStart( - node_at_center_of_intersection, - m_node_based_graph->GetTarget(turn.eid))) + // In case a way restriction starts at a given location, add a turn onto + // every artificial node eminating here. + // + // e - f + // | + // a - b + // | + // c - d + // + // ab via bc to cd + // ab via be to ef + // + // has two artifical nodes (be/bc) with restrictions starting at `ab`. + // Since every restriction group (abc | abe) refers to the same + // 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) + auto const target_id = way_restriction_map.RemapIfRestricted( + edge_data2.edge_id, + node_along_road_entering, + node_at_center_of_intersection, + m_node_based_graph->GetTarget(turn.eid), + m_number_of_edge_based_nodes); + + generate_edges(edge_data1.edge_id, + target_id, + node_along_road_entering, + incoming_edge, + node_at_center_of_intersection, + turn.eid, + intersection, + turn, + entry_class_id, + continuous_inserter, + *buffer); + + // when turning off a a via-way turn restriction, we need to not only + // handle the normal edges for the way, but also add turns for every + // duplicated node. This process is integrated here to avoid doing the + // turn analysis multiple times. + if (turning_off_via_way) { - const auto restriction_ids = way_restriction_map.GetIDs( - node_at_center_of_intersection, - m_node_based_graph->GetTarget(turn.eid)); - for (auto restriction_id : restriction_ids) - { - const auto &restriction = - way_restriction_map.GetRestriction(restriction_id) - .AsWayRestriction(); - - // target the artificial node - if (restriction.in_restriction.from == node_along_road_entering) - { - target_id = - m_max_edge_id + 1 + - way_restriction_map.DuplicatedNodeID(restriction_id); - std::cout << "Turning onto a restricted way at " - << node_at_center_of_intersection - << " coming from " << node_along_road_entering - << " restriction_id: " << restriction_id - << " EBN: " << target_id << std::endl; - - std::cout << "Restriction turning onto: " - << " " << target_id << " instead of " - << edge_data2.edge_id << std::endl; - } - } - } + const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs( + node_along_road_entering, node_at_center_of_intersection); + + // next to the normal restrictions tracked in `entry_allowed`, via + // ways might introduce additional restrictions. These are handled + // here when turning off a via-way + const auto add_unrestricted_turns = + [&](const auto duplicated_node_id) { + const auto from_id = + m_number_of_edge_based_nodes - + way_restriction_map.NumberOfDuplicatedNodes() + + duplicated_node_id; + + auto const node_at_end_of_turn = + m_node_based_graph->GetTarget(turn.eid); + + const auto is_restricted = way_restriction_map.IsRestricted( + duplicated_node_id, node_at_end_of_turn); + + if (is_restricted) + return; + + generate_edges( + 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, + delayed_inserter, + *buffer); - buffer->continuous_data.edges_list.emplace_back( - edge_data1.edge_id, - target_id, - SPECIAL_NODEID, // This will be updated once the main loop - // completes! - weight, - duration, - true, - false); - - 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, - // 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); - - buffer->continuous_data.turn_indexes.push_back( - {from_node, via_node, to_node}); + }; + + std::for_each(duplicated_nodes.begin(), + duplicated_nodes.end(), + add_unrestricted_turns); + } } } } diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 023127d6b01..b23019018c0 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -669,16 +669,16 @@ void ExtractionContainers::PrepareRestrictions() if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION) { const auto &way = turn_restriction.AsWayRestriction(); - referenced_ways[OSMWayID{way.from}] = dummy_segment; - referenced_ways[OSMWayID{way.to}] = dummy_segment; - referenced_ways[OSMWayID{way.via}] = dummy_segment; + referenced_ways[way.from] = dummy_segment; + referenced_ways[way.to] = dummy_segment; + referenced_ways[way.via] = dummy_segment; } else { BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION); const auto &node = turn_restriction.AsNodeRestriction(); - referenced_ways[OSMWayID{node.from}] = dummy_segment; - referenced_ways[OSMWayID{node.to}] = dummy_segment; + referenced_ways[node.from] = dummy_segment; + referenced_ways[node.to] = dummy_segment; } }; @@ -764,15 +764,15 @@ void ExtractionContainers::PrepareRestrictions() // be connected at a single location) auto const get_node_restriction_from_OSM_ids = [&]( auto const from_id, auto const to_id, const OSMNodeID via_node = MAX_OSM_NODEID) { - auto const from_segment_itr = referenced_ways.find(OSMWayID{from_id}); - if (from_segment_itr->second.way_id != OSMWayID{from_id}) + auto const from_segment_itr = referenced_ways.find(from_id); + if (from_segment_itr->second.way_id != from_id) { util::Log(logDEBUG) << "Restriction references invalid way: " << from_id; return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}; } - auto const to_segment_itr = referenced_ways.find(OSMWayID{to_id}); - if (to_segment_itr->second.way_id != OSMWayID{to_id}) + auto const to_segment_itr = referenced_ways.find(to_id); + if (to_segment_itr->second.way_id != to_id) { util::Log(logDEBUG) << "Restriction references invalid way: " << to_id; return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID}; @@ -836,7 +836,7 @@ void ExtractionContainers::PrepareRestrictions() if (external_restriction.condition.empty()) { TurnRestriction restriction; - restriction.flags = external_restriction.flags; + restriction.is_only = external_restriction.is_only; if (transform(external_restriction, restriction)) unconditional_turn_restrictions.push_back(restriction); } @@ -844,7 +844,7 @@ void ExtractionContainers::PrepareRestrictions() else { ConditionalTurnRestriction restriction; - restriction.flags = external_restriction.flags; + restriction.is_only = external_restriction.is_only; restriction.condition = std::move(external_restriction.condition); if (transform(external_restriction, restriction)) conditional_turn_restrictions.push_back(restriction); diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 54bad56ca4b..f1820260c97 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -140,7 +140,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) turn_lane_map); auto number_of_node_based_nodes = graph_size.first; - auto max_edge_id = graph_size.second; + auto max_edge_id = graph_size.second - 1; TIMER_STOP(expansion); @@ -481,7 +481,7 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, name_table, turn_lane_map); - auto const number_of_edge_based_nodes = [&]() { + const auto create_edge_based_edges = [&]() { // scoped to relase intermediate datastructures right after the call RestrictionMap via_node_restriction_map(turn_restrictions); WayRestrictionMap via_way_restriction_map(turn_restrictions); @@ -497,9 +497,10 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment, config.cnbg_ebg_graph_mapping_output_path, via_node_restriction_map, via_way_restriction_map); - return edge_based_graph_factory.GetHighestEdgeID() + - via_way_restriction_map.NumberOfDuplicatedNodes(); - }(); + return edge_based_graph_factory.GetNumberOfEdgeBasedNodes(); + }; + + const auto number_of_edge_based_nodes = create_edge_based_edges(); compressed_edge_container.PrintStatistics(); diff --git a/src/extractor/restriction_map.cpp b/src/extractor/restriction_map.cpp index e525793d84c..812ff504b99 100644 --- a/src/extractor/restriction_map.cpp +++ b/src/extractor/restriction_map.cpp @@ -47,7 +47,7 @@ RestrictionMap::RestrictionMap(const std::vector &restriction_l { continue; } - else if (restriction.flags.is_only) + else if (restriction.is_only) { // We are going to insert an is_only_*-restriction. There can be only one. m_count -= m_restriction_bucket_list.at(index).size(); @@ -55,8 +55,7 @@ RestrictionMap::RestrictionMap(const std::vector &restriction_l } } ++m_count; - m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, - restriction.flags.is_only); + m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, restriction.is_only); } } diff --git a/src/extractor/restriction_parser.cpp b/src/extractor/restriction_parser.cpp index e495d6f20e1..996743eced8 100644 --- a/src/extractor/restriction_parser.cpp +++ b/src/extractor/restriction_parser.cpp @@ -125,7 +125,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const // we pretend every restriction is a conditional restriction. If we do not find any restriction, // we can trim away the vector after parsing InputConditionalTurnRestriction restriction_container; - restriction_container.flags.is_only = is_only_restriction; + restriction_container.is_only = is_only_restriction; boost::optional from = boost::none, via = boost::none, to = boost::none; bool is_node_restriction; @@ -212,11 +212,13 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const { if (is_node_restriction) { - restriction_container.node_or_way = InputNodeRestriction{*from, *via, *to}; + // template struct requires bracket for ID initialisation :( + restriction_container.node_or_way = InputNodeRestriction{{*from}, {*via}, {*to}}; } else { - restriction_container.node_or_way = InputWayRestriction{*from, *via, *to}; + // template struct requires bracket for ID initialisation :( + restriction_container.node_or_way = InputWayRestriction{{*from}, {*via}, {*to}}; } return restriction_container; } diff --git a/src/extractor/way_restriction_map.cpp b/src/extractor/way_restriction_map.cpp index d4a6558eef4..173cc751a2b 100644 --- a/src/extractor/way_restriction_map.cpp +++ b/src/extractor/way_restriction_map.cpp @@ -1,6 +1,7 @@ #include "extractor/way_restriction_map.hpp" #include +#include #include namespace osrm @@ -8,19 +9,41 @@ namespace osrm namespace extractor { +namespace +{ +struct FindViaWay +{ + bool operator()(const std::tuple value, + const TurnRestriction &restriction) const + { + const auto &way = restriction.AsWayRestriction(); + return value < std::tie(way.in_restriction.via, way.out_restriction.via); + } + bool operator()(const TurnRestriction &restriction, + const std::tuple value) const + { + const auto &way = restriction.AsWayRestriction(); + return std::tie(way.in_restriction.via, way.out_restriction.via) < value; + } +}; + +} // namespace + WayRestrictionMap::WayRestrictionMap(const std::vector &turn_restrictions) { // get all way restrictions - const auto get_way_restrictions = [this](const auto &turn_restriction) { + const auto extract_restrictions = [this](const auto &turn_restriction) { if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION) restriction_data.push_back(turn_restriction); }; - std::for_each(turn_restrictions.begin(), turn_restrictions.end(), get_way_restrictions); + std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions); - const auto as_duplicated_node = [](auto const &restriction) { + const auto as_duplicated_node = + [](auto const &restriction) -> std::tuple { auto &way = restriction.AsWayRestriction(); - return std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), - way.out_restriction.via); + // group restrictions by the via-way. On same via-ways group by from + return std::make_tuple( + way.in_restriction.via, way.out_restriction.via, way.in_restriction.from); }; const auto by_duplicated_node = [&](auto const &lhs, auto const &rhs) { @@ -33,14 +56,9 @@ WayRestrictionMap::WayRestrictionMap(const std::vector &turn_re // map all way restrictions into access containers const auto prepare_way_restriction = [this, &index, &duplication_id, as_duplicated_node]( const auto &restriction) { - const auto &way = restriction.AsWayRestriction(); restriction_starts.insert( - std::make_pair(std::make_pair(way.in_restriction.via, way.in_restriction.to), index)); - restriction_ends.insert(std::make_pair( - std::make_pair(way.out_restriction.from, way.out_restriction.via), index)); - via_ways.insert( - std::make_pair(std::make_pair(way.in_restriction.via, way.out_restriction.via), index)); + std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index)); ++index; }; std::for_each(restriction_data.begin(), restriction_data.end(), prepare_way_restriction); @@ -60,18 +78,32 @@ WayRestrictionMap::WayRestrictionMap(const std::vector &turn_re }; std::adjacent_find(restriction_data.begin(), restriction_data.end(), add_offset_on_new_groups); duplicated_node_groups.push_back(restriction_data.size()); - - std::cout << "Node groups:"; - for (auto a : duplicated_node_groups) - std::cout << " " << a; - std::cout << std::endl; } std::size_t WayRestrictionMap::NumberOfDuplicatedNodes() const { return duplicated_node_groups.size() - 1; } -std::size_t WayRestrictionMap::DuplicatedNodeID(const std::size_t restriction_id) const + +bool WayRestrictionMap::IsViaWay(const NodeID from, const NodeID to) const +{ + // safe-guards + if (restriction_data.empty()) + return false; + + const auto itr = std::lower_bound( + restriction_data.begin(), restriction_data.end(), std::make_tuple(from, to), FindViaWay()); + + // no fitting restriction + if (itr == restriction_data.end()) + return false; + + const auto &way = itr->AsWayRestriction(); + + return way.out_restriction.from == from && way.out_restriction.via == to; +} + +std::size_t WayRestrictionMap::AsDuplicatedNodeID(const std::size_t restriction_id) const { return std::distance(duplicated_node_groups.begin(), std::upper_bound(duplicated_node_groups.begin(), @@ -80,32 +112,38 @@ std::size_t WayRestrictionMap::DuplicatedNodeID(const std::size_t restriction_id 1; } -// check if an edge between two nodes is a restricted turn -bool WayRestrictionMap::IsStart(const NodeID from, const NodeID to) const +util::range WayRestrictionMap::DuplicatedNodeIDs(const NodeID from, + const NodeID to) const { - return restriction_starts.count(std::make_pair(from, to)) > 0; -} -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; -} + const auto duplicated_node_range_itr = std::equal_range( + restriction_data.begin(), restriction_data.end(), std::make_tuple(from, to), FindViaWay()); + + const auto as_restriction_id = [this](const auto itr) { + return std::distance(restriction_data.begin(), itr); + }; -std::size_t WayRestrictionMap::Size() const { return via_ways.size(); } + return util::irange( + AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first)), + AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second))); +} -std::vector WayRestrictionMap::GetIDs(const NodeID from, const NodeID to) const +bool WayRestrictionMap::IsRestricted(std::size_t duplicated_node, const NodeID to) const { - std::vector result; - auto range = via_ways.equal_range(std::make_pair(from, to)); - std::transform(range.first, range.second, std::back_inserter(result), [](auto pair) { - return pair.second; - }); - // group by their respective duplicated nodes - std::sort(result.begin(), result.end()); - return result; + // loop over all restrictions associated with the node. Mark as restricted based on + // is_only/restricted targets + for (std::size_t restriction_index = duplicated_node_groups[duplicated_node]; + restriction_index != duplicated_node_groups[duplicated_node + 1]; + ++restriction_index) + { + const auto &restriction = restriction_data[restriction_index]; + const auto &way = restriction.AsWayRestriction(); + + if (restriction.is_only) + return way.out_restriction.to != to; + else if (to == way.out_restriction.to) + return true; + } + return false; } TurnRestriction const &WayRestrictionMap::GetRestriction(const std::size_t id) const @@ -127,5 +165,28 @@ std::vector WayRestrictionMap::DuplicatedNodeRepresen return result; } +NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node, + const NodeID node_based_from, + const NodeID node_based_via, + const NodeID node_based_to, + const NodeID number_of_edge_based_nodes) const +{ + auto range = restriction_starts.equal_range(std::make_pair(node_based_from, node_based_via)); + + // returns true if the ID saved in an iterator belongs to a turn restriction that references + // node_based_to as destination of the `in_restriction` + const auto restriction_targets_to = [node_based_to, this](const auto &pair) { + return restriction_data[pair.second].AsWayRestriction().in_restriction.to == node_based_to; + }; + const auto itr = std::find_if(range.first, range.second, restriction_targets_to); + + // in case we found a matching restriction, we can remap the edge_based_node + if (itr != range.second) + return number_of_edge_based_nodes - NumberOfDuplicatedNodes() + + AsDuplicatedNodeID(itr->second); + else + return edge_based_node; +} + } // namespace extractor } // namespace osrm diff --git a/src/updater/updater.cpp b/src/updater/updater.cpp index c26887b4b74..548a65d4e0f 100644 --- a/src/updater/updater.cpp +++ b/src/updater/updater.cpp @@ -511,7 +511,7 @@ updateConditionalTurns(const UpdaterConfig &config, // only add restrictions to the lookups if the restriction is valid now - if (node_or_way.flags.is_only) + if (node_or_way.is_only) { is_only_lookup.lookup.push_back({std::make_tuple(c.from, c.via), c.to}); }