handle conditional via-way restrictions
- refactor conditional restriction handling to not use external data (first OSM nodes on ways) - BREAKING: changes internal file format of osrm.restrictions - add support for general conditional penalties based on edge-based nodes (requires unique edges between nodes)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "extractor/edge_based_graph_factory.hpp"
|
||||
#include "extractor/conditional_turn_penalty.hpp"
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/files.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
@@ -6,6 +7,7 @@
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "extractor/serialization.hpp"
|
||||
#include "storage/io.hpp"
|
||||
|
||||
#include "util/assert.hpp"
|
||||
@@ -20,8 +22,10 @@
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
|
||||
#include "boost/unordered_map.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
@@ -35,12 +39,26 @@
|
||||
#include <tbb/pipeline.h>
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<std::pair<NodeID, NodeID>>
|
||||
{
|
||||
std::size_t operator()(const std::pair<NodeID, NodeID> &mk) const noexcept
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, mk.first);
|
||||
boost::hash_combine(seed, mk.second);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
// Configuration to find representative candidate for turn angle calculations
|
||||
|
||||
// Configuration to find representative candidate for turn angle calculations
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
|
||||
CompressedEdgeContainer &compressed_edge_container,
|
||||
@@ -199,7 +217,9 @@ 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 std::string &conditional_penalties_filename,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const ConditionalRestrictionMap &conditional_node_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map)
|
||||
{
|
||||
TIMER_START(renumber);
|
||||
@@ -220,7 +240,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
turn_weight_penalties_filename,
|
||||
turn_duration_penalties_filename,
|
||||
turn_penalties_index_filename,
|
||||
conditional_penalties_filename,
|
||||
node_restriction_map,
|
||||
conditional_node_restriction_map,
|
||||
way_restriction_map);
|
||||
|
||||
TIMER_STOP(generate_edges);
|
||||
@@ -384,7 +406,9 @@ 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 std::string &conditional_penalties_filename,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const ConditionalRestrictionMap &conditional_restriction_map,
|
||||
const WayRestrictionMap &way_restriction_map)
|
||||
{
|
||||
|
||||
@@ -427,6 +451,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto weight_multiplier =
|
||||
scripting_environment.GetProfileProperties().GetWeightMultiplier();
|
||||
|
||||
// filled in during next stage, kept alive through following scope
|
||||
std::vector<Conditional> conditionals;
|
||||
// The following block generates the edge-based-edges using a parallel processing
|
||||
// pipeline. Sets of intersection IDs are batched in groups of GRAINSIZE (100)
|
||||
// `generator_stage`,
|
||||
@@ -482,7 +508,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
};
|
||||
|
||||
// same as IntersectionData, but grouped with edge to allow sorting after creating. Edges
|
||||
// are out of order
|
||||
// can be out of order
|
||||
struct EdgeWithData
|
||||
{
|
||||
EdgeBasedEdge edge;
|
||||
@@ -497,10 +523,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
std::size_t nodes_processed = 0;
|
||||
IntersectionData continuous_data;
|
||||
std::vector<EdgeWithData> delayed_data;
|
||||
std::vector<Conditional> conditionals;
|
||||
};
|
||||
|
||||
// Generate edges for either artificial nodes or the main graph
|
||||
const auto generate_edge = [this, &scripting_environment, weight_multiplier](
|
||||
const auto generate_edge = [this,
|
||||
&scripting_environment,
|
||||
weight_multiplier,
|
||||
&conditional_restriction_map](
|
||||
// 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
|
||||
@@ -514,6 +544,24 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto &intersection,
|
||||
const auto &turn,
|
||||
const auto entry_class_id) {
|
||||
|
||||
const auto node_restricted = isRestricted(node_along_road_entering,
|
||||
node_at_center_of_intersection,
|
||||
m_node_based_graph->GetTarget(turn.eid),
|
||||
conditional_restriction_map);
|
||||
|
||||
boost::optional<Conditional> conditional = boost::none;
|
||||
if (node_restricted.first)
|
||||
{
|
||||
auto const &conditions = node_restricted.second->condition;
|
||||
// get conditions of the restriction limiting the node
|
||||
conditional = {{edge_based_node_from,
|
||||
edge_based_node_to,
|
||||
{static_cast<std::uint64_t>(-1),
|
||||
m_coordinates[node_at_center_of_intersection],
|
||||
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);
|
||||
|
||||
@@ -573,15 +621,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
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};
|
||||
lookup::TurnIndexBlock turn_index_block = {
|
||||
from_node, node_at_center_of_intersection, to_node};
|
||||
|
||||
// insert data into the designated buffer
|
||||
return EdgeWithData{
|
||||
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data};
|
||||
return std::make_pair(
|
||||
EdgeWithData{
|
||||
edge_based_edge, turn_index_block, weight_penalty, duration_penalty, turn_data},
|
||||
conditional);
|
||||
};
|
||||
|
||||
// Second part of the pipeline is where the intersection analysis is done for
|
||||
@@ -720,7 +769,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
m_number_of_edge_based_nodes);
|
||||
|
||||
{ // scope to forget edge_with_data after
|
||||
const auto edge_with_data =
|
||||
const auto edge_with_data_and_condition =
|
||||
generate_edge(edge_data1.edge_id,
|
||||
target_id,
|
||||
node_along_road_entering,
|
||||
@@ -731,15 +780,21 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
turn,
|
||||
entry_class_id);
|
||||
|
||||
buffer->continuous_data.edges_list.push_back(edge_with_data.edge);
|
||||
buffer->continuous_data.edges_list.push_back(
|
||||
edge_with_data_and_condition.first.edge);
|
||||
buffer->continuous_data.turn_indexes.push_back(
|
||||
edge_with_data.turn_index);
|
||||
edge_with_data_and_condition.first.turn_index);
|
||||
buffer->continuous_data.turn_weight_penalties.push_back(
|
||||
edge_with_data.turn_weight_penalty);
|
||||
edge_with_data_and_condition.first.turn_weight_penalty);
|
||||
buffer->continuous_data.turn_duration_penalties.push_back(
|
||||
edge_with_data.turn_duration_penalty);
|
||||
edge_with_data_and_condition.first.turn_duration_penalty);
|
||||
buffer->continuous_data.turn_data_container.push_back(
|
||||
edge_with_data.turn_data);
|
||||
edge_with_data_and_condition.first.turn_data);
|
||||
if (edge_with_data_and_condition.second)
|
||||
{
|
||||
buffer->conditionals.push_back(
|
||||
*edge_with_data_and_condition.second);
|
||||
}
|
||||
}
|
||||
|
||||
// when turning off a a via-way turn restriction, we need to not only
|
||||
@@ -764,25 +819,73 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
auto const node_at_end_of_turn =
|
||||
m_node_based_graph->GetTarget(turn.eid);
|
||||
|
||||
const auto is_restricted = way_restriction_map.IsRestricted(
|
||||
const auto is_way_restricted = way_restriction_map.IsRestricted(
|
||||
duplicated_node_id, node_at_end_of_turn);
|
||||
|
||||
if (is_restricted)
|
||||
continue;
|
||||
if (is_way_restricted)
|
||||
{
|
||||
|
||||
// add into delayed data
|
||||
auto edge_with_data = 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 const restriction = way_restriction_map.GetRestriction(
|
||||
duplicated_node_id, node_at_end_of_turn);
|
||||
|
||||
buffer->delayed_data.push_back(std::move(edge_with_data));
|
||||
if (restriction.condition.empty())
|
||||
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);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
|
||||
if (edge_with_data_and_condition.second)
|
||||
{
|
||||
buffer->conditionals.push_back(
|
||||
*edge_with_data_and_condition.second);
|
||||
}
|
||||
|
||||
// also add the conditions for the way
|
||||
if (is_way_restricted && !restriction.condition.empty())
|
||||
{
|
||||
// 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,
|
||||
{static_cast<std::uint64_t>(-1),
|
||||
m_coordinates[node_at_center_of_intersection],
|
||||
restriction.condition}});
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
|
||||
if (edge_with_data_and_condition.second)
|
||||
{
|
||||
buffer->conditionals.push_back(
|
||||
*edge_with_data_and_condition.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,6 +930,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
data.turn_indexes.begin(),
|
||||
data.turn_indexes.end());
|
||||
|
||||
conditionals.insert(
|
||||
conditionals.end(), buffer->conditionals.begin(), buffer->conditionals.end());
|
||||
|
||||
// Buffer writes to reduce syscall count
|
||||
if (turn_indexes_write_buffer.size() >= TURN_INDEX_WRITE_BUFFER_SIZE)
|
||||
{
|
||||
@@ -879,6 +985,20 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
});
|
||||
|
||||
// re-hash conditionals to ocnnect to their respective edge-based edges. Due to the
|
||||
// ordering, we
|
||||
// do not really have a choice but to index the conditional penalties and walk over all
|
||||
// edge-based-edges to find the ID of the edge
|
||||
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
|
||||
{
|
||||
util::Log() << "Writing " << indexed_conditionals.size()
|
||||
<< " conditional turn penalties...";
|
||||
// write conditional turn penalties into the restrictions file
|
||||
storage::io::FileWriter writer(conditional_penalties_filename,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
extractor::serialization::write(writer, indexed_conditionals);
|
||||
}
|
||||
|
||||
// write weight penalties per turn
|
||||
BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size());
|
||||
{
|
||||
@@ -918,11 +1038,36 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||
util::Log() << " skips " << restricted_turns_counter << " turns, "
|
||||
"defined by "
|
||||
<< node_restriction_map.size() << " restrictions";
|
||||
<< node_restriction_map.Size() << " restrictions";
|
||||
util::Log() << " skips " << skipped_uturns_counter << " U turns";
|
||||
util::Log() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||
}
|
||||
|
||||
std::vector<ConditionalTurnPenalty>
|
||||
EdgeBasedGraphFactory::IndexConditionals(std::vector<Conditional> &&conditionals) const
|
||||
{
|
||||
boost::unordered_multimap<std::pair<NodeID, NodeID>, ConditionalTurnPenalty *> index;
|
||||
|
||||
// build and index of all conditional restrictions
|
||||
for (auto &conditional : conditionals)
|
||||
index.insert(std::make_pair(std::make_pair(conditional.from_node, conditional.to_node),
|
||||
&conditional.penalty));
|
||||
|
||||
std::vector<ConditionalTurnPenalty> indexed_restrictions;
|
||||
|
||||
for (auto const &edge : m_edge_based_edge_list)
|
||||
{
|
||||
auto const range = index.equal_range(std::make_pair(edge.source, edge.target));
|
||||
for (auto itr = range.first; itr != range.second; ++itr)
|
||||
{
|
||||
itr->second->turn_offset = edge.data.turn_id;
|
||||
indexed_restrictions.push_back(*itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
return indexed_restrictions;
|
||||
}
|
||||
|
||||
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
|
||||
{
|
||||
std::vector<util::guidance::BearingClass> result(bearing_class_hash.data.size());
|
||||
|
||||
@@ -126,7 +126,6 @@ ExtractionContainers::ExtractionContainers()
|
||||
*/
|
||||
void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environment,
|
||||
const std::string &osrm_path,
|
||||
const std::string &restrictions_file_name,
|
||||
const std::string &name_file_name)
|
||||
{
|
||||
storage::io::FileWriter file_out(osrm_path, storage::io::FileWriter::GenerateFingerprint);
|
||||
@@ -139,7 +138,6 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
|
||||
WriteEdges(file_out);
|
||||
|
||||
PrepareRestrictions();
|
||||
WriteConditionalRestrictions(restrictions_file_name);
|
||||
WriteCharData(name_file_name);
|
||||
}
|
||||
|
||||
@@ -633,16 +631,6 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
|
||||
util::Log() << "Processed " << max_internal_node_id << " nodes";
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteConditionalRestrictions(const std::string &path)
|
||||
{
|
||||
std::uint64_t written_restriction_count = conditional_turn_restrictions.size();
|
||||
storage::io::FileWriter restrictions_out_file(path,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
serialization::write(restrictions_out_file, conditional_turn_restrictions);
|
||||
util::Log() << "number of conditional restrictions written to disk: "
|
||||
<< written_restriction_count;
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareRestrictions()
|
||||
{
|
||||
|
||||
@@ -837,7 +825,8 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
const auto transform_into_internal_types =
|
||||
[&](const InputConditionalTurnRestriction &external_restriction) {
|
||||
// unconditional restriction
|
||||
if (external_restriction.condition.empty())
|
||||
if (external_restriction.condition.empty() &&
|
||||
external_restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
TurnRestriction restriction;
|
||||
restriction.is_only = external_restriction.is_only;
|
||||
@@ -851,7 +840,9 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
restriction.is_only = external_restriction.is_only;
|
||||
restriction.condition = std::move(external_restriction.condition);
|
||||
if (transform(external_restriction, restriction))
|
||||
{
|
||||
conditional_turn_restrictions.push_back(std::move(restriction));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+41
-21
@@ -23,7 +23,7 @@
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
#include "util/static_graph.hpp"
|
||||
#include "util/static_rtree.hpp"
|
||||
@@ -110,7 +110,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
guidance::LaneDescriptionMap turn_lane_map;
|
||||
std::vector<TurnRestriction> turn_restrictions;
|
||||
std::tie(turn_lane_map, turn_restrictions) =
|
||||
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
|
||||
std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
|
||||
ParseOSMData(scripting_environment, number_of_threads);
|
||||
|
||||
// Transform the node-based graph that OSM is based on into an edge-based graph
|
||||
@@ -138,6 +139,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
edge_based_edge_list,
|
||||
config.GetPath(".osrm.icd").string(),
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
turn_lane_map);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
@@ -190,7 +192,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::tuple<guidance::LaneDescriptionMap, std::vector<TurnRestriction>>
|
||||
std::tuple<guidance::LaneDescriptionMap,
|
||||
std::vector<TurnRestriction>,
|
||||
std::vector<ConditionalTurnRestriction>>
|
||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
const unsigned number_of_threads)
|
||||
{
|
||||
@@ -333,7 +337,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
extraction_containers.PrepareData(scripting_environment,
|
||||
config.GetPath(".osrm").string(),
|
||||
config.GetPath(".osrm.restrictions").string(),
|
||||
config.GetPath(".osrm.names").string());
|
||||
|
||||
auto profile_properties = scripting_environment.GetProfileProperties();
|
||||
@@ -344,7 +347,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||
|
||||
return std::make_tuple(std::move(turn_lane_map),
|
||||
std::move(extraction_containers.unconditional_turn_restrictions));
|
||||
std::move(extraction_containers.unconditional_turn_restrictions),
|
||||
std::move(extraction_containers.conditional_turn_restrictions));
|
||||
}
|
||||
|
||||
void Extractor::FindComponents(unsigned max_edge_id,
|
||||
@@ -440,18 +444,19 @@ Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
|
||||
/**
|
||||
\brief Building an edge-expanded graph from node-based input and turn restrictions
|
||||
*/
|
||||
std::pair<std::size_t, EdgeID>
|
||||
Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map)
|
||||
std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map)
|
||||
{
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_signals;
|
||||
@@ -465,10 +470,12 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
traffic_signals,
|
||||
scripting_environment,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
*node_based_graph,
|
||||
compressed_edge_container);
|
||||
|
||||
turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), *node_based_graph);
|
||||
conditional_turn_restrictions =
|
||||
removeInvalidRestrictions(std::move(conditional_turn_restrictions), *node_based_graph);
|
||||
|
||||
util::NameTable name_table(config.GetPath(".osrm.names").string());
|
||||
|
||||
@@ -484,8 +491,20 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
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);
|
||||
std::vector<TurnRestriction> node_restrictions;
|
||||
for (auto const &t : turn_restrictions)
|
||||
if (t.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
node_restrictions.push_back(t);
|
||||
|
||||
std::vector<ConditionalTurnRestriction> conditional_node_restrictions;
|
||||
for (auto const &t : conditional_turn_restrictions)
|
||||
if (t.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
conditional_node_restrictions.push_back(t);
|
||||
|
||||
RestrictionMap via_node_restriction_map(node_restrictions, IndexNodeByFromAndVia());
|
||||
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();
|
||||
|
||||
@@ -496,13 +515,14 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
config.GetPath(".osrm.turn_duration_penalties").string(),
|
||||
config.GetPath(".osrm.turn_penalties_index").string(),
|
||||
config.GetPath(".osrm.cnbg_to_ebg").string(),
|
||||
config.GetPath(".osrm.restrictions").string(),
|
||||
via_node_restriction_map,
|
||||
conditional_node_restriction_map,
|
||||
via_way_restriction_map);
|
||||
return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
|
||||
};
|
||||
|
||||
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.
|
||||
|
||||
@@ -20,17 +20,19 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_signals,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
CompressedEdgeContainer &geometry_compressor)
|
||||
void GraphCompressor::Compress(
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_signals,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
CompressedEdgeContainer &geometry_compressor)
|
||||
{
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
|
||||
|
||||
RestrictionCompressor restriction_compressor(turn_restrictions);
|
||||
RestrictionCompressor restriction_compressor(turn_restrictions, conditional_turn_restrictions);
|
||||
|
||||
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to
|
||||
// indicated `directed` barriers
|
||||
@@ -51,6 +53,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
|
||||
std::for_each(conditional_turn_restrictions.begin(),
|
||||
conditional_turn_restrictions.end(),
|
||||
remember_via_nodes);
|
||||
|
||||
{
|
||||
const auto weight_multiplier =
|
||||
|
||||
@@ -236,8 +236,25 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
||||
{
|
||||
const auto node_at_intersection = node_based_graph.GetTarget(entering_via_edge);
|
||||
|
||||
// check if there is a single valid turn entering the current intersection
|
||||
const auto only_valid_turn = GetOnlyAllowedTurnIfExistent(previous_node, node_at_intersection);
|
||||
// request all turn restrictions
|
||||
auto const restrictions = restriction_map.Restrictions(previous_node, node_at_intersection);
|
||||
|
||||
// check turn restrictions to find a node that is the only allowed target when coming from a
|
||||
// node to an intersection
|
||||
// d
|
||||
// |
|
||||
// a - b - c and `only_straight_on ab | bc would return `c` for `a,b`
|
||||
const auto find_only_valid_turn = [&]() -> boost::optional<NodeID> {
|
||||
const auto itr = std::find_if(restrictions.first, restrictions.second, [](auto pair) {
|
||||
return pair.second->is_only;
|
||||
});
|
||||
if (itr != restrictions.second)
|
||||
return {itr->second->AsNodeRestriction().to};
|
||||
else
|
||||
return boost::none;
|
||||
};
|
||||
|
||||
const auto only_valid_turn = find_only_valid_turn();
|
||||
|
||||
// barriers change our behaviour regarding u-turns
|
||||
const bool is_barrier_node = barrier_nodes.find(node_at_intersection) != barrier_nodes.end();
|
||||
@@ -258,12 +275,14 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
||||
|
||||
const auto is_restricted = [&](const NodeID destination) {
|
||||
// check if we have a dedicated destination
|
||||
if (only_valid_turn && *only_valid_turn != destination)
|
||||
return true;
|
||||
if (only_valid_turn)
|
||||
return *only_valid_turn != destination;
|
||||
|
||||
// not explicitly forbidden
|
||||
return restriction_map.CheckIfTurnIsRestricted(
|
||||
previous_node, node_at_intersection, destination);
|
||||
// check if explicitly forbidden
|
||||
return restrictions.second !=
|
||||
std::find_if(restrictions.first, restrictions.second, [&](const auto &restriction) {
|
||||
return restriction.second->AsNodeRestriction().to == destination;
|
||||
});
|
||||
};
|
||||
|
||||
const auto is_allowed_turn = [&](const IntersectionShapeData &road) {
|
||||
@@ -396,21 +415,6 @@ IntersectionView IntersectionGenerator::TransformIntersectionShapeIntoView(
|
||||
return intersection_view;
|
||||
}
|
||||
|
||||
boost::optional<NodeID>
|
||||
IntersectionGenerator::GetOnlyAllowedTurnIfExistent(const NodeID coming_from_node,
|
||||
const NodeID node_at_intersection) const
|
||||
{
|
||||
// If only restrictions refer to invalid ways somewhere far away, we rather ignore the
|
||||
// restriction than to not route over the intersection at all.
|
||||
const auto only_restriction_to_node =
|
||||
restriction_map.CheckForEmanatingIsOnlyTurn(coming_from_node, node_at_intersection);
|
||||
if (only_restriction_to_node != SPECIAL_NODEID)
|
||||
return only_restriction_to_node;
|
||||
|
||||
// Ignore broken only restrictions.
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
const CoordinateExtractor &IntersectionGenerator::GetCoordinateExtractor() const
|
||||
{
|
||||
return coordinate_extractor;
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restrictions)
|
||||
RestrictionCompressor::RestrictionCompressor(
|
||||
std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
|
||||
{
|
||||
// add a node restriction ptr to the starts/ends maps, needs to be a reference!
|
||||
auto index = [&](auto &element) {
|
||||
@@ -35,6 +37,9 @@ RestrictionCompressor::RestrictionCompressor(std::vector<TurnRestriction> &restr
|
||||
|
||||
// add all restrictions as their respective startend pointers
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_starts_and_ends);
|
||||
std::for_each(conditional_turn_restrictions.begin(),
|
||||
conditional_turn_restrictions.end(),
|
||||
index_starts_and_ends);
|
||||
}
|
||||
|
||||
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
std::vector<TurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
|
||||
std::vector<ConditionalTurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<ConditionalTurnRestriction> restrictions,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
// definition of what we presume to be a valid via-node restriction
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
#include "extractor/restriction_map.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionMap::RestrictionMap(const std::vector<TurnRestriction> &restriction_list) : m_count(0)
|
||||
{
|
||||
// decompose restriction consisting of a start, via and end node into a
|
||||
// a pair of starting edge and a list of all end nodes
|
||||
for (auto &restriction : restriction_list)
|
||||
{
|
||||
// only handle node restrictions here
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
continue;
|
||||
|
||||
const auto &node_restriction = restriction.AsNodeRestriction();
|
||||
BOOST_ASSERT(node_restriction.Valid());
|
||||
// This downcasting is OK because when this is called, the node IDs have been
|
||||
// renumbered into internal values, which should be well under 2^32
|
||||
// This will be a problem if we have more than 2^32 actual restrictions
|
||||
BOOST_ASSERT(node_restriction.from < std::numeric_limits<NodeID>::max());
|
||||
BOOST_ASSERT(node_restriction.via < std::numeric_limits<NodeID>::max());
|
||||
m_restriction_start_nodes.insert(node_restriction.from);
|
||||
m_no_turn_via_node_set.insert(node_restriction.via);
|
||||
|
||||
// This explicit downcasting is also OK for the same reason.
|
||||
RestrictionSource restriction_source = {static_cast<NodeID>(node_restriction.from),
|
||||
static_cast<NodeID>(node_restriction.via)};
|
||||
|
||||
std::size_t index;
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iter == m_restriction_map.end())
|
||||
{
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index + 1);
|
||||
m_restriction_map.emplace(restriction_source, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = restriction_iter->second;
|
||||
// Map already contains an is_only_*-restriction
|
||||
if (m_restriction_bucket_list.at(index).begin()->is_only)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
++m_count;
|
||||
m_restriction_bucket_list.at(index).emplace_back(node_restriction.to, restriction.is_only);
|
||||
}
|
||||
}
|
||||
|
||||
bool RestrictionMap::IsViaNode(const NodeID node) const
|
||||
{
|
||||
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
|
||||
}
|
||||
|
||||
// Check if edge (u, v) is the start of any turn restriction.
|
||||
// If so returns id of first target node.
|
||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (restriction_target.is_only)
|
||||
{
|
||||
return restriction_target.target_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
// Checks if turn <u,v,w> is actually a turn restriction.
|
||||
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w) const
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter == m_restriction_map.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (node_w == restriction_target.target_node && // target found
|
||||
!restriction_target.is_only) // and not an only_-restr.
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// We could be tempted to check for `only` restrictions here as well. However, that check is
|
||||
// actually perfomed in intersection generation where we can also verify if the only
|
||||
// restriction is valid at all.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// check of node is the start of any restriction
|
||||
bool RestrictionMap::IsSourceNode(const NodeID node) const
|
||||
{
|
||||
return m_restriction_start_nodes.find(node) != m_restriction_start_nodes.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
#include "util/for_each_pair.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
@@ -28,12 +29,46 @@ struct FindViaWay
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_restrictions)
|
||||
template <typename restriction_type> auto asDuplicatedNode(const restriction_type &restriction)
|
||||
{
|
||||
// get all way restrictions
|
||||
const auto extract_restrictions = [this](const auto &turn_restriction) {
|
||||
auto &way = restriction.AsWayRestriction();
|
||||
// group restrictions by the via-way. On same via-ways group by from
|
||||
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
|
||||
};
|
||||
|
||||
template <typename restriction_type> struct CompareByDuplicatedNode
|
||||
{
|
||||
bool operator()(const ConditionalTurnRestriction &lhs, const ConditionalTurnRestriction &rhs)
|
||||
{
|
||||
if (asDuplicatedNode(lhs) < asDuplicatedNode(rhs))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (asDuplicatedNode(rhs) < asDuplicatedNode(lhs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto lhs_to = lhs.AsWayRestriction().out_restriction.to;
|
||||
const auto rhs_to = rhs.AsWayRestriction().out_restriction.to;
|
||||
|
||||
const bool has_conditions_lhs = !lhs.condition.empty();
|
||||
const bool has_conditions_rhs = !rhs.condition.empty();
|
||||
|
||||
return std::tie(lhs_to, lhs.is_only, has_conditions_lhs) <
|
||||
std::tie(rhs_to, rhs.is_only, has_conditions_rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename restriction_type>
|
||||
std::vector<restriction_type>
|
||||
extractRestrictions(const std::vector<restriction_type> &turn_restrictions)
|
||||
{
|
||||
std::vector<restriction_type> result;
|
||||
for (const auto &turn_restriction : turn_restrictions)
|
||||
{
|
||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
const auto &way = turn_restriction.AsWayRestriction();
|
||||
@@ -41,32 +76,32 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
|
||||
// so far we can only handle restrictions that are not interrupted
|
||||
if (way.in_restriction.via == way.out_restriction.from &&
|
||||
way.in_restriction.to == way.out_restriction.via)
|
||||
restriction_data.push_back(turn_restriction);
|
||||
result.push_back(turn_restriction);
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), extract_restrictions);
|
||||
}
|
||||
std::sort(result.begin(), result.end(), CompareByDuplicatedNode<restriction_type>());
|
||||
auto new_end = std::unique(result.begin(), result.end());
|
||||
result.erase(new_end, result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto as_duplicated_node = [](auto const &restriction) {
|
||||
auto &way = restriction.AsWayRestriction();
|
||||
// group restrictions by the via-way. On same via-ways group by from
|
||||
return std::tie(way.in_restriction.via, way.out_restriction.via, way.in_restriction.from);
|
||||
};
|
||||
|
||||
const auto by_duplicated_node = [&](auto const &lhs, auto const &rhs) {
|
||||
return as_duplicated_node(lhs) < as_duplicated_node(rhs);
|
||||
};
|
||||
|
||||
std::sort(restriction_data.begin(), restriction_data.end(), by_duplicated_node);
|
||||
|
||||
// map all way restrictions into access containers
|
||||
for (RestrictionID index = 0; index < restriction_data.size(); ++index)
|
||||
template <typename restriction_type> struct ByInFromAndVia
|
||||
{
|
||||
std::pair<NodeID, NodeID> operator()(const restriction_type &restriction)
|
||||
{
|
||||
const auto &restriction = restriction_data[index];
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
restriction_starts.insert(
|
||||
std::make_pair(std::make_pair(way.in_restriction.from, way.in_restriction.via), index));
|
||||
};
|
||||
return std::make_pair(way.in_restriction.from, way.in_restriction.via);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// get all way restrictions
|
||||
WayRestrictionMap::WayRestrictionMap(
|
||||
const std::vector<ConditionalTurnRestriction> &turn_restrictions_)
|
||||
: restriction_data(extractRestrictions(turn_restrictions_)),
|
||||
restriction_starts(restriction_data, ByInFromAndVia<ConditionalTurnRestriction>())
|
||||
{
|
||||
std::size_t offset = 1;
|
||||
// the first group starts at 0
|
||||
if (!restriction_data.empty())
|
||||
@@ -74,8 +109,10 @@ WayRestrictionMap::WayRestrictionMap(const std::vector<TurnRestriction> &turn_re
|
||||
|
||||
auto const add_offset_on_new_groups = [&](auto const &lhs, auto const &rhs) {
|
||||
BOOST_ASSERT(rhs == restriction_data[offset]);
|
||||
BOOST_ASSERT(lhs.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
BOOST_ASSERT(rhs.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
// add a new lower bound for rhs
|
||||
if (as_duplicated_node(lhs) != as_duplicated_node(rhs))
|
||||
if (asDuplicatedNode(lhs) != asDuplicatedNode(rhs))
|
||||
duplicated_node_groups.push_back(offset);
|
||||
++offset;
|
||||
};
|
||||
@@ -115,7 +152,7 @@ DuplicatedNodeID WayRestrictionMap::AsDuplicatedNodeID(const RestrictionID restr
|
||||
return distance_to_upper_bound - 1;
|
||||
}
|
||||
|
||||
util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
|
||||
std::vector<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID from,
|
||||
const NodeID to) const
|
||||
{
|
||||
const auto duplicated_node_range_itr = std::equal_range(
|
||||
@@ -125,9 +162,13 @@ util::range<DuplicatedNodeID> WayRestrictionMap::DuplicatedNodeIDs(const NodeID
|
||||
return std::distance(restriction_data.begin(), itr);
|
||||
};
|
||||
|
||||
return util::irange<DuplicatedNodeID>(
|
||||
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first)),
|
||||
AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second)));
|
||||
auto first = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.first));
|
||||
auto end = AsDuplicatedNodeID(as_restriction_id(duplicated_node_range_itr.second));
|
||||
|
||||
std::vector<DuplicatedNodeID> result(end - first);
|
||||
std::iota(result.begin(), result.end(), first);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const NodeID to) const
|
||||
@@ -138,6 +179,7 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
|
||||
restriction_index != duplicated_node_groups[duplicated_node + 1];
|
||||
++restriction_index)
|
||||
{
|
||||
BOOST_ASSERT(restriction_index < restriction_data.size());
|
||||
const auto &restriction = restriction_data[restriction_index];
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
|
||||
@@ -149,6 +191,32 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
|
||||
return false;
|
||||
}
|
||||
|
||||
ConditionalTurnRestriction const &
|
||||
WayRestrictionMap::GetRestriction(DuplicatedNodeID duplicated_node, const NodeID to) const
|
||||
{
|
||||
// loop over all restrictions associated with the node. Mark as restricted based on
|
||||
// is_only/restricted targets
|
||||
for (RestrictionID restriction_index = duplicated_node_groups[duplicated_node];
|
||||
restriction_index != duplicated_node_groups[duplicated_node + 1];
|
||||
++restriction_index)
|
||||
{
|
||||
BOOST_ASSERT(restriction_index < restriction_data.size());
|
||||
const auto &restriction = restriction_data[restriction_index];
|
||||
const auto &way = restriction.AsWayRestriction();
|
||||
|
||||
if (restriction.is_only && (way.out_restriction.to != to))
|
||||
{
|
||||
return restriction;
|
||||
}
|
||||
else if (!restriction.is_only && (to == way.out_restriction.to))
|
||||
{
|
||||
return restriction;
|
||||
}
|
||||
}
|
||||
throw("Asking for the restriction of an unrestricted turn. Check with `IsRestricted` before "
|
||||
"calling GetRestriction");
|
||||
}
|
||||
|
||||
std::vector<WayRestrictionMap::ViaWay> WayRestrictionMap::DuplicatedNodeRepresentatives() const
|
||||
{
|
||||
std::vector<ViaWay> result;
|
||||
@@ -169,19 +237,19 @@ NodeID WayRestrictionMap::RemapIfRestricted(const NodeID edge_based_node,
|
||||
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));
|
||||
auto range = restriction_starts.Restrictions(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;
|
||||
return 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);
|
||||
AsDuplicatedNodeID(itr->second - &restriction_data[0]);
|
||||
else
|
||||
return edge_based_node;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user