Conditional turn restriction support (#3841)
* optionally include condition and via node coords in InputRestrictionContainer * only write conditionals to disk, custom serialization for restrictions * conditional turn lookup, reuse timezone validation from extract-conditionals * adapt updater to use coordinates/osm ids, remove internal to external map * add utc time now parameter to contraction * only compile timezone code where libshp is found, adapt test running * slight refactor, more tests * catch invalid via nodes in restriction parsing, set default cucumber origin to guinée * add another run to test mld routed paths * cosmetic review changes * Simplify Timezoner for windows build * Split declaration and parsing parts for opening hours * adjust conditional tests to run without shapefiles * always include parse conditionals option * Adjust travis timeout * Added dummy TZ shapefile with test timezone polygons * [skip ci] update changelog
This commit is contained in:
@@ -547,20 +547,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// 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.
|
||||
// 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 ? m_osm_node_ids[node_along_road_entering]
|
||||
: m_osm_node_ids[m_compressed_edge_container.GetLastEdgeSourceID(
|
||||
incoming_edge)];
|
||||
isTrivial ? node_along_road_entering
|
||||
: m_compressed_edge_container.GetLastEdgeSourceID(incoming_edge);
|
||||
const auto &via_node =
|
||||
m_osm_node_ids[m_compressed_edge_container.GetLastEdgeTargetID(
|
||||
incoming_edge)];
|
||||
m_compressed_edge_container.GetLastEdgeTargetID(incoming_edge);
|
||||
const auto &to_node =
|
||||
m_osm_node_ids[m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid)];
|
||||
m_compressed_edge_container.GetFirstEdgeTargetID(turn.eid);
|
||||
|
||||
lookup::TurnIndexBlock turn_index_block = {from_node, via_node, to_node};
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "extractor/extraction_containers.hpp"
|
||||
#include "extractor/extraction_segment.hpp"
|
||||
#include "extractor/extraction_way.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/serialization.hpp"
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
@@ -134,7 +136,6 @@ void ExtractionContainers::FlushVectors()
|
||||
all_edges_list.flush();
|
||||
name_char_data.flush();
|
||||
name_offsets.flush();
|
||||
restrictions_list.flush();
|
||||
way_start_end_id_list.flush();
|
||||
}
|
||||
|
||||
@@ -142,7 +143,7 @@ void ExtractionContainers::FlushVectors()
|
||||
* Processes the collected data and serializes it.
|
||||
* At this point nodes are still referenced by their OSM id.
|
||||
*
|
||||
* - map start-end nodes of ways to ways used int restrictions to compute compressed
|
||||
* - map start-end nodes of ways to ways used in restrictions to compute compressed
|
||||
* trippe representation
|
||||
* - filter nodes list to nodes that are referenced by ways
|
||||
* - merge edges with nodes to include location of start/end points and serialize
|
||||
@@ -630,7 +631,7 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
|
||||
util::Log() << "Processed " << max_internal_node_id << " nodes";
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteRestrictions(const std::string &path) const
|
||||
void ExtractionContainers::WriteRestrictions(const std::string &path)
|
||||
{
|
||||
// serialize restrictions
|
||||
std::uint64_t written_restriction_count = 0;
|
||||
@@ -645,13 +646,27 @@ void ExtractionContainers::WriteRestrictions(const std::string &path) const
|
||||
SPECIAL_NODEID != restriction_container.restriction.via.node &&
|
||||
SPECIAL_NODEID != restriction_container.restriction.to.node)
|
||||
{
|
||||
restrictions_out_file.WriteOne(restriction_container.restriction);
|
||||
++written_restriction_count;
|
||||
if (!restriction_container.restriction.condition.empty())
|
||||
{
|
||||
// write conditional turn restrictions to disk, for use in contractor later
|
||||
extractor::serialization::write(restrictions_out_file,
|
||||
restriction_container.restriction);
|
||||
++written_restriction_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// save unconditional turn restriction to memory, for use in ebg later
|
||||
unconditional_turn_restrictions.push_back(
|
||||
std::move(restriction_container.restriction));
|
||||
}
|
||||
}
|
||||
}
|
||||
restrictions_out_file.SkipToBeginning();
|
||||
restrictions_out_file.WriteElementCount64(written_restriction_count);
|
||||
util::Log() << "usable restrictions: " << written_restriction_count;
|
||||
util::Log() << "number of restrictions saved to memory: "
|
||||
<< unconditional_turn_restrictions.size();
|
||||
util::Log() << "number of conditional restrictions written to disk: "
|
||||
<< written_restriction_count;
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareRestrictions()
|
||||
@@ -672,10 +687,8 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
util::UnbufferedLog log;
|
||||
log << "Sorting " << restrictions_list.size() << " restriction. by from... ";
|
||||
TIMER_START(sort_restrictions);
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByFrom(),
|
||||
stxxl_memory);
|
||||
std::sort(
|
||||
restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByFrom());
|
||||
TIMER_STOP(sort_restrictions);
|
||||
log << "ok, after " << TIMER_SEC(sort_restrictions) << "s";
|
||||
}
|
||||
@@ -758,6 +771,11 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
}
|
||||
restrictions_iterator->restriction.from.node = id_iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if it's neither, this is an invalid restriction
|
||||
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
|
||||
@@ -769,10 +787,8 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
util::UnbufferedLog log;
|
||||
log << "Sorting restrictions. by to ... " << std::flush;
|
||||
TIMER_START(sort_restrictions_to);
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByTo(),
|
||||
stxxl_memory);
|
||||
std::sort(
|
||||
restrictions_list.begin(), restrictions_list.end(), CmpRestrictionContainerByTo());
|
||||
TIMER_STOP(sort_restrictions_to);
|
||||
log << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s";
|
||||
}
|
||||
@@ -850,6 +866,11 @@ void ExtractionContainers::PrepareRestrictions()
|
||||
}
|
||||
restrictions_iterator->restriction.to.node = to_id_iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if it's neither, this is an invalid restriction
|
||||
restrictions_iterator->restriction.to.node = SPECIAL_NODEID;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
TIMER_STOP(fix_restriction_ends);
|
||||
|
||||
+194
-201
@@ -115,208 +115,216 @@ transformTurnLaneMapIntoArrays(const guidance::LaneDescriptionMap &turn_lane_map
|
||||
int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
{
|
||||
util::LogPolicy::GetInstance().Unmute();
|
||||
TIMER_START(extracting);
|
||||
|
||||
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
|
||||
const auto number_of_threads = std::min(recommended_num_threads, config.requested_num_threads);
|
||||
tbb::task_scheduler_init init(number_of_threads ? number_of_threads
|
||||
: tbb::task_scheduler_init::automatic);
|
||||
|
||||
auto turn_restrictions = ParseOSMData(scripting_environment, number_of_threads);
|
||||
|
||||
// Transform the node-based graph that OSM is based on into an edge-based graph
|
||||
// that is better for routing. Every edge becomes a node, and every valid
|
||||
// movement (e.g. turn from A->B, and B->A) becomes an edge
|
||||
util::Log() << "Generating edge-expanded graph representation";
|
||||
|
||||
TIMER_START(expansion);
|
||||
|
||||
std::vector<EdgeBasedNode> edge_based_node_list;
|
||||
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
||||
std::vector<bool> node_is_startpoint;
|
||||
std::vector<EdgeWeight> edge_based_node_weights;
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
extractor::PackedOSMIDs osm_node_ids;
|
||||
|
||||
auto graph_size = BuildEdgeExpandedGraph(scripting_environment,
|
||||
coordinates,
|
||||
osm_node_ids,
|
||||
edge_based_node_list,
|
||||
node_is_startpoint,
|
||||
edge_based_node_weights,
|
||||
edge_based_edge_list,
|
||||
config.intersection_class_data_output_path,
|
||||
turn_restrictions);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
auto max_edge_id = graph_size.second;
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
|
||||
util::Log() << "Saving edge-based node weights to file.";
|
||||
TIMER_START(timer_write_node_weights);
|
||||
{
|
||||
util::Log() << "Input file: " << config.input_path.filename().string();
|
||||
if (!config.profile_path.empty())
|
||||
{
|
||||
util::Log() << "Profile: " << config.profile_path.filename().string();
|
||||
}
|
||||
util::Log() << "Threads: " << number_of_threads;
|
||||
|
||||
const osmium::io::File input_file(config.input_path.string());
|
||||
|
||||
osmium::io::Reader reader(
|
||||
input_file,
|
||||
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no));
|
||||
|
||||
const osmium::io::Header header = reader.header();
|
||||
|
||||
unsigned number_of_nodes = 0;
|
||||
unsigned number_of_ways = 0;
|
||||
unsigned number_of_relations = 0;
|
||||
|
||||
util::Log() << "Parsing in progress..";
|
||||
TIMER_START(parsing);
|
||||
|
||||
ExtractionContainers extraction_containers;
|
||||
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(
|
||||
extraction_containers, scripting_environment.GetProfileProperties());
|
||||
|
||||
// setup raster sources
|
||||
scripting_environment.SetupSources();
|
||||
|
||||
std::string generator = header.get("generator");
|
||||
if (generator.empty())
|
||||
{
|
||||
generator = "unknown tool";
|
||||
}
|
||||
util::Log() << "input file generated by " << generator;
|
||||
|
||||
// write .timestamp data file
|
||||
std::string timestamp = header.get("osmosis_replication_timestamp");
|
||||
if (timestamp.empty())
|
||||
{
|
||||
timestamp = "n/a";
|
||||
}
|
||||
util::Log() << "timestamp: " << timestamp;
|
||||
|
||||
storage::io::FileWriter timestamp_file(config.timestamp_file_name,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
|
||||
timestamp_file.WriteFrom(timestamp.c_str(), timestamp.length());
|
||||
|
||||
// initialize vectors holding parsed objects
|
||||
tbb::concurrent_vector<std::pair<std::size_t, ExtractionNode>> resulting_nodes;
|
||||
tbb::concurrent_vector<std::pair<std::size_t, ExtractionWay>> resulting_ways;
|
||||
tbb::concurrent_vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
|
||||
|
||||
// setup restriction parser
|
||||
const RestrictionParser restriction_parser(scripting_environment);
|
||||
|
||||
// create a vector of iterators into the buffer
|
||||
for (std::vector<osmium::memory::Buffer::const_iterator> osm_elements;
|
||||
const osmium::memory::Buffer buffer = reader.read();
|
||||
osm_elements.clear())
|
||||
{
|
||||
for (auto iter = std::begin(buffer), end = std::end(buffer); iter != end; ++iter)
|
||||
{
|
||||
osm_elements.push_back(iter);
|
||||
}
|
||||
|
||||
// clear resulting vectors
|
||||
resulting_nodes.clear();
|
||||
resulting_ways.clear();
|
||||
resulting_restrictions.clear();
|
||||
|
||||
scripting_environment.ProcessElements(osm_elements,
|
||||
restriction_parser,
|
||||
resulting_nodes,
|
||||
resulting_ways,
|
||||
resulting_restrictions);
|
||||
|
||||
number_of_nodes += resulting_nodes.size();
|
||||
// put parsed objects thru extractor callbacks
|
||||
for (const auto &result : resulting_nodes)
|
||||
{
|
||||
extractor_callbacks->ProcessNode(
|
||||
static_cast<const osmium::Node &>(*(osm_elements[result.first])),
|
||||
result.second);
|
||||
}
|
||||
number_of_ways += resulting_ways.size();
|
||||
for (const auto &result : resulting_ways)
|
||||
{
|
||||
extractor_callbacks->ProcessWay(
|
||||
static_cast<const osmium::Way &>(*(osm_elements[result.first])), result.second);
|
||||
}
|
||||
number_of_relations += resulting_restrictions.size();
|
||||
for (const auto &result : resulting_restrictions)
|
||||
{
|
||||
extractor_callbacks->ProcessRestriction(result);
|
||||
}
|
||||
}
|
||||
TIMER_STOP(parsing);
|
||||
util::Log() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
|
||||
|
||||
util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
|
||||
<< " ways, and " << number_of_relations << " relations";
|
||||
|
||||
// take control over the turn lane map
|
||||
turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap();
|
||||
|
||||
extractor_callbacks.reset();
|
||||
|
||||
if (extraction_containers.all_edges_list.empty())
|
||||
{
|
||||
throw util::exception(std::string("There are no edges remaining after parsing.") +
|
||||
SOURCE_REF);
|
||||
}
|
||||
|
||||
extraction_containers.PrepareData(scripting_environment,
|
||||
config.output_file_name,
|
||||
config.restriction_file_name,
|
||||
config.names_file_name);
|
||||
|
||||
WriteProfileProperties(config.profile_properties_output_path,
|
||||
scripting_environment.GetProfileProperties());
|
||||
|
||||
TIMER_STOP(extracting);
|
||||
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||
storage::io::FileWriter writer(config.edge_based_node_weights_output_path,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
storage::serialization::write(writer, edge_based_node_weights);
|
||||
}
|
||||
TIMER_STOP(timer_write_node_weights);
|
||||
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
|
||||
|
||||
{
|
||||
// Transform the node-based graph that OSM is based on into an edge-based graph
|
||||
// that is better for routing. Every edge becomes a node, and every valid
|
||||
// movement (e.g. turn from A->B, and B->A) becomes an edge
|
||||
util::Log() << "Generating edge-expanded graph representation";
|
||||
util::Log() << "Computing strictly connected components ...";
|
||||
FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
|
||||
|
||||
TIMER_START(expansion);
|
||||
util::Log() << "Building r-tree ...";
|
||||
TIMER_START(rtree);
|
||||
BuildRTree(std::move(edge_based_node_list), std::move(node_is_startpoint), coordinates);
|
||||
|
||||
std::vector<EdgeBasedNode> edge_based_node_list;
|
||||
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
||||
std::vector<bool> node_is_startpoint;
|
||||
std::vector<EdgeWeight> edge_based_node_weights;
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
extractor::PackedOSMIDs osm_node_ids;
|
||||
TIMER_STOP(rtree);
|
||||
|
||||
auto graph_size = BuildEdgeExpandedGraph(scripting_environment,
|
||||
coordinates,
|
||||
osm_node_ids,
|
||||
edge_based_node_list,
|
||||
node_is_startpoint,
|
||||
edge_based_node_weights,
|
||||
edge_based_edge_list,
|
||||
config.intersection_class_data_output_path);
|
||||
util::Log() << "Writing node map ...";
|
||||
files::writeNodes(config.node_output_path, coordinates, osm_node_ids);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
auto max_edge_id = graph_size.second;
|
||||
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
const auto nodes_per_second =
|
||||
static_cast<std::uint64_t>(number_of_node_based_nodes / TIMER_SEC(expansion));
|
||||
const auto edges_per_second =
|
||||
static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion));
|
||||
|
||||
util::Log() << "Saving edge-based node weights to file.";
|
||||
TIMER_START(timer_write_node_weights);
|
||||
{
|
||||
storage::io::FileWriter writer(config.edge_based_node_weights_output_path,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
storage::serialization::write(writer, edge_based_node_weights);
|
||||
}
|
||||
TIMER_STOP(timer_write_node_weights);
|
||||
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
|
||||
|
||||
util::Log() << "Computing strictly connected components ...";
|
||||
FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
|
||||
|
||||
util::Log() << "Building r-tree ...";
|
||||
TIMER_START(rtree);
|
||||
BuildRTree(std::move(edge_based_node_list), std::move(node_is_startpoint), coordinates);
|
||||
|
||||
TIMER_STOP(rtree);
|
||||
|
||||
util::Log() << "Writing node map ...";
|
||||
files::writeNodes(config.node_output_path, coordinates, osm_node_ids);
|
||||
|
||||
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
|
||||
|
||||
const auto nodes_per_second =
|
||||
static_cast<std::uint64_t>(number_of_node_based_nodes / TIMER_SEC(expansion));
|
||||
const auto edges_per_second =
|
||||
static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion));
|
||||
|
||||
util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second
|
||||
<< " edges/sec";
|
||||
util::Log() << "To prepare the data for routing, run: "
|
||||
<< "./osrm-contract " << config.output_file_name;
|
||||
}
|
||||
util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second
|
||||
<< " edges/sec";
|
||||
util::Log() << "To prepare the data for routing, run: "
|
||||
<< "./osrm-contract " << config.output_file_name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<TurnRestriction> Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
const unsigned number_of_threads)
|
||||
{
|
||||
TIMER_START(extracting);
|
||||
|
||||
util::Log() << "Input file: " << config.input_path.filename().string();
|
||||
if (!config.profile_path.empty())
|
||||
{
|
||||
util::Log() << "Profile: " << config.profile_path.filename().string();
|
||||
}
|
||||
util::Log() << "Threads: " << number_of_threads;
|
||||
|
||||
const osmium::io::File input_file(config.input_path.string());
|
||||
|
||||
osmium::io::Reader reader(
|
||||
input_file, (config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no));
|
||||
|
||||
const osmium::io::Header header = reader.header();
|
||||
|
||||
unsigned number_of_nodes = 0;
|
||||
unsigned number_of_ways = 0;
|
||||
unsigned number_of_relations = 0;
|
||||
|
||||
util::Log() << "Parsing in progress..";
|
||||
TIMER_START(parsing);
|
||||
|
||||
ExtractionContainers extraction_containers;
|
||||
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(
|
||||
extraction_containers, scripting_environment.GetProfileProperties());
|
||||
|
||||
// setup raster sources
|
||||
scripting_environment.SetupSources();
|
||||
|
||||
std::string generator = header.get("generator");
|
||||
if (generator.empty())
|
||||
{
|
||||
generator = "unknown tool";
|
||||
}
|
||||
util::Log() << "input file generated by " << generator;
|
||||
|
||||
// write .timestamp data file
|
||||
std::string timestamp = header.get("osmosis_replication_timestamp");
|
||||
if (timestamp.empty())
|
||||
{
|
||||
timestamp = "n/a";
|
||||
}
|
||||
util::Log() << "timestamp: " << timestamp;
|
||||
|
||||
storage::io::FileWriter timestamp_file(config.timestamp_file_name,
|
||||
storage::io::FileWriter::GenerateFingerprint);
|
||||
|
||||
timestamp_file.WriteFrom(timestamp.c_str(), timestamp.length());
|
||||
|
||||
// initialize vectors holding parsed objects
|
||||
tbb::concurrent_vector<std::pair<std::size_t, ExtractionNode>> resulting_nodes;
|
||||
tbb::concurrent_vector<std::pair<std::size_t, ExtractionWay>> resulting_ways;
|
||||
tbb::concurrent_vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
|
||||
|
||||
std::vector<std::string> restrictions = scripting_environment.GetRestrictions();
|
||||
// setup restriction parser
|
||||
const RestrictionParser restriction_parser(
|
||||
scripting_environment.GetProfileProperties().use_turn_restrictions,
|
||||
config.parse_conditionals,
|
||||
restrictions);
|
||||
|
||||
// create a vector of iterators into the buffer
|
||||
for (std::vector<osmium::memory::Buffer::const_iterator> osm_elements;
|
||||
const osmium::memory::Buffer buffer = reader.read();
|
||||
osm_elements.clear())
|
||||
{
|
||||
for (auto iter = std::begin(buffer), end = std::end(buffer); iter != end; ++iter)
|
||||
{
|
||||
osm_elements.push_back(iter);
|
||||
}
|
||||
|
||||
// clear resulting vectors
|
||||
resulting_nodes.clear();
|
||||
resulting_ways.clear();
|
||||
resulting_restrictions.clear();
|
||||
|
||||
scripting_environment.ProcessElements(osm_elements,
|
||||
restriction_parser,
|
||||
resulting_nodes,
|
||||
resulting_ways,
|
||||
resulting_restrictions);
|
||||
|
||||
number_of_nodes += resulting_nodes.size();
|
||||
// put parsed objects thru extractor callbacks
|
||||
for (const auto &result : resulting_nodes)
|
||||
{
|
||||
extractor_callbacks->ProcessNode(
|
||||
static_cast<const osmium::Node &>(*(osm_elements[result.first])), result.second);
|
||||
}
|
||||
number_of_ways += resulting_ways.size();
|
||||
for (const auto &result : resulting_ways)
|
||||
{
|
||||
extractor_callbacks->ProcessWay(
|
||||
static_cast<const osmium::Way &>(*(osm_elements[result.first])), result.second);
|
||||
}
|
||||
number_of_relations += resulting_restrictions.size();
|
||||
for (const auto &result : resulting_restrictions)
|
||||
{
|
||||
extractor_callbacks->ProcessRestriction(result);
|
||||
}
|
||||
}
|
||||
TIMER_STOP(parsing);
|
||||
util::Log() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
|
||||
|
||||
util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
|
||||
<< " ways, and " << number_of_relations << " relations";
|
||||
|
||||
// take control over the turn lane map
|
||||
turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap();
|
||||
|
||||
extractor_callbacks.reset();
|
||||
|
||||
if (extraction_containers.all_edges_list.empty())
|
||||
{
|
||||
throw util::exception(std::string("There are no edges remaining after parsing.") +
|
||||
SOURCE_REF);
|
||||
}
|
||||
|
||||
extraction_containers.PrepareData(scripting_environment,
|
||||
config.output_file_name,
|
||||
config.restriction_file_name,
|
||||
config.names_file_name);
|
||||
|
||||
WriteProfileProperties(config.profile_properties_output_path,
|
||||
scripting_environment.GetProfileProperties());
|
||||
|
||||
TIMER_STOP(extracting);
|
||||
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||
|
||||
return extraction_containers.unconditional_turn_restrictions;
|
||||
}
|
||||
|
||||
void Extractor::WriteProfileProperties(const std::string &output_path,
|
||||
const ProfileProperties &properties) const
|
||||
{
|
||||
@@ -384,22 +392,6 @@ void Extractor::FindComponents(unsigned max_edge_id,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Build load restrictions from .restriction file
|
||||
*/
|
||||
std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
|
||||
{
|
||||
storage::io::FileReader file_reader(config.restriction_file_name,
|
||||
storage::io::FileReader::VerifyFingerprint);
|
||||
std::vector<TurnRestriction> restriction_list;
|
||||
|
||||
util::loadRestrictionsFromFile(file_reader, restriction_list);
|
||||
|
||||
util::Log() << " - " << restriction_list.size() << " restrictions.";
|
||||
|
||||
return std::make_shared<RestrictionMap>(restriction_list);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Load node based graph from .osrm file
|
||||
*/
|
||||
@@ -444,12 +436,13 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
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)
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions)
|
||||
{
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
|
||||
auto restriction_map = LoadRestrictionMap();
|
||||
auto restriction_map = std::make_shared<RestrictionMap>(turn_restrictions);
|
||||
auto node_based_graph =
|
||||
LoadNodeBasedGraph(barrier_nodes, traffic_lights, coordinates, osm_node_ids);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "extractor/restriction_parser.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
|
||||
#include "extractor/external_memory_node.hpp"
|
||||
|
||||
#include "util/conditional_restrictions.hpp"
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -24,12 +24,14 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionParser::RestrictionParser(ScriptingEnvironment &scripting_environment)
|
||||
: use_turn_restrictions(scripting_environment.GetProfileProperties().use_turn_restrictions)
|
||||
RestrictionParser::RestrictionParser(bool use_turn_restrictions_,
|
||||
bool parse_conditionals_,
|
||||
std::vector<std::string> &restrictions_)
|
||||
: use_turn_restrictions(use_turn_restrictions_), parse_conditionals(parse_conditionals_),
|
||||
restrictions(restrictions_)
|
||||
{
|
||||
if (use_turn_restrictions)
|
||||
{
|
||||
restrictions = scripting_environment.GetRestrictions();
|
||||
const unsigned count = restrictions.size();
|
||||
if (count > 0)
|
||||
{
|
||||
@@ -54,9 +56,10 @@ RestrictionParser::RestrictionParser(ScriptingEnvironment &scripting_environment
|
||||
* in the corresponding profile. We use it for both namespacing restrictions, as in
|
||||
* restriction:motorcar as well as whitelisting if its in except:motorcar.
|
||||
*/
|
||||
boost::optional<InputRestrictionContainer>
|
||||
std::vector<InputRestrictionContainer>
|
||||
RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
{
|
||||
std::vector<InputRestrictionContainer> parsed_restrictions;
|
||||
// return if turn restrictions should be ignored
|
||||
if (!use_turn_restrictions)
|
||||
{
|
||||
@@ -65,10 +68,21 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
|
||||
osmium::tags::KeyFilter filter(false);
|
||||
filter.add(true, "restriction");
|
||||
if (parse_conditionals)
|
||||
{
|
||||
filter.add(true, "restriction:conditional");
|
||||
for (const auto &namespaced : restrictions)
|
||||
{
|
||||
filter.add(true, "restriction:" + namespaced + ":conditional");
|
||||
}
|
||||
}
|
||||
|
||||
// Not only use restriction= but also e.g. restriction:motorcar=
|
||||
// Include restriction:{mode}:conditional if flagged
|
||||
for (const auto &namespaced : restrictions)
|
||||
{
|
||||
filter.add(true, "restriction:" + namespaced);
|
||||
}
|
||||
|
||||
const osmium::TagList &tag_list = relation.tags();
|
||||
|
||||
@@ -160,7 +174,42 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
break;
|
||||
}
|
||||
}
|
||||
return boost::make_optional(std::move(restriction_container));
|
||||
|
||||
// parse conditional tags
|
||||
if (parse_conditionals)
|
||||
{
|
||||
osmium::tags::KeyFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
|
||||
osmium::tags::KeyFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
|
||||
for (; fi_begin != fi_end; ++fi_begin)
|
||||
{
|
||||
const std::string key(fi_begin->key());
|
||||
const std::string value(fi_begin->value());
|
||||
|
||||
// Parse condition and add independent value/condition pairs
|
||||
const auto &parsed = osrm::util::ParseConditionalRestrictions(value);
|
||||
|
||||
if (parsed.empty())
|
||||
continue;
|
||||
|
||||
for (const auto &p : parsed)
|
||||
{
|
||||
std::vector<util::OpeningHours> hours = util::ParseOpeningHours(p.condition);
|
||||
// found unrecognized condition, continue
|
||||
if (hours.empty())
|
||||
return {};
|
||||
|
||||
restriction_container.restriction.condition = std::move(hours);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// push back a copy of turn restriction
|
||||
if (restriction_container.restriction.via.node != SPECIAL_NODEID &&
|
||||
restriction_container.restriction.from.node != SPECIAL_NODEID &&
|
||||
restriction_container.restriction.to.node != SPECIAL_NODEID)
|
||||
parsed_restrictions.push_back(restriction_container);
|
||||
|
||||
return parsed_restrictions;
|
||||
}
|
||||
|
||||
bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
|
||||
|
||||
@@ -498,6 +498,7 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
||||
[&](const tbb::blocked_range<std::size_t> &range) {
|
||||
ExtractionNode result_node;
|
||||
ExtractionWay result_way;
|
||||
std::vector<InputRestrictionContainer> result_res;
|
||||
auto &local_context = this->GetSol2Context();
|
||||
|
||||
for (auto x = range.begin(), end = range.end(); x != end; ++x)
|
||||
@@ -525,8 +526,13 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
||||
resulting_ways.push_back(std::make_pair(x, std::move(result_way)));
|
||||
break;
|
||||
case osmium::item_type::relation:
|
||||
resulting_restrictions.push_back(restriction_parser.TryParse(
|
||||
static_cast<const osmium::Relation &>(*entity)));
|
||||
result_res.clear();
|
||||
result_res =
|
||||
restriction_parser.TryParse(static_cast<const osmium::Relation &>(*entity));
|
||||
for (const InputRestrictionContainer &r : result_res)
|
||||
{
|
||||
resulting_restrictions.push_back(r);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user