2016-01-02 11:13:44 -05:00
|
|
|
#include "extractor/extractor.hpp"
|
|
|
|
|
2016-01-11 10:55:22 -05:00
|
|
|
#include "extractor/edge_based_edge.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "extractor/extraction_containers.hpp"
|
|
|
|
#include "extractor/extraction_node.hpp"
|
|
|
|
#include "extractor/extraction_way.hpp"
|
|
|
|
#include "extractor/extractor_callbacks.hpp"
|
2017-04-01 14:44:49 -04:00
|
|
|
#include "extractor/files.hpp"
|
2017-03-08 19:06:06 -05:00
|
|
|
#include "extractor/raster_source.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "extractor/restriction_parser.hpp"
|
|
|
|
#include "extractor/scripting_environment.hpp"
|
|
|
|
|
2016-11-21 20:32:00 -05:00
|
|
|
#include "storage/io.hpp"
|
2017-04-02 13:47:17 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
#include "util/exception.hpp"
|
|
|
|
#include "util/exception_utils.hpp"
|
2016-04-26 07:27:40 -04:00
|
|
|
#include "util/graph_loader.hpp"
|
2017-01-26 11:53:19 -05:00
|
|
|
#include "util/integer_range.hpp"
|
2016-12-06 15:30:46 -05:00
|
|
|
#include "util/log.hpp"
|
2016-04-26 07:27:40 -04:00
|
|
|
#include "util/name_table.hpp"
|
2016-05-10 02:37:45 -04:00
|
|
|
#include "util/range_table.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/timing_util.hpp"
|
|
|
|
|
|
|
|
#include "extractor/compressed_edge_container.hpp"
|
2016-01-03 12:55:42 -05:00
|
|
|
#include "extractor/restriction_map.hpp"
|
2016-04-26 07:27:40 -04:00
|
|
|
#include "util/static_graph.hpp"
|
|
|
|
#include "util/static_rtree.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
|
2016-08-02 09:09:09 -04:00
|
|
|
// Keep debug include to make sure the debug header is in sync with types.
|
|
|
|
#include "util/debug.hpp"
|
|
|
|
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "extractor/tarjan_scc.hpp"
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2015-01-31 15:17:16 -05:00
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
#include <boost/filesystem/fstream.hpp>
|
2015-09-18 08:26:32 -04:00
|
|
|
#include <boost/optional/optional.hpp>
|
2017-01-26 11:53:19 -05:00
|
|
|
#include <boost/scope_exit.hpp>
|
2015-01-31 15:17:16 -05:00
|
|
|
|
2014-11-28 09:00:48 -05:00
|
|
|
#include <osmium/io/any_input.hpp>
|
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
#include <tbb/concurrent_vector.h>
|
2014-11-28 09:00:48 -05:00
|
|
|
#include <tbb/task_scheduler_init.h>
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <atomic>
|
2016-04-26 07:27:40 -04:00
|
|
|
#include <bitset>
|
|
|
|
#include <chrono>
|
2017-01-26 11:53:19 -05:00
|
|
|
#include <future>
|
2014-11-28 09:00:48 -05:00
|
|
|
#include <iostream>
|
2016-11-14 17:43:24 -05:00
|
|
|
#include <iterator>
|
2016-10-17 14:23:19 -04:00
|
|
|
#include <memory>
|
2016-06-30 03:31:08 -04:00
|
|
|
#include <numeric> //partial_sum
|
2014-11-28 09:00:48 -05:00
|
|
|
#include <thread>
|
2016-07-22 03:08:40 -04:00
|
|
|
#include <tuple>
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <type_traits>
|
2014-11-28 09:00:48 -05:00
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
|
|
|
|
2016-07-22 03:08:40 -04:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
std::tuple<std::vector<std::uint32_t>, std::vector<guidance::TurnLaneType::Mask>>
|
|
|
|
transformTurnLaneMapIntoArrays(const guidance::LaneDescriptionMap &turn_lane_map)
|
|
|
|
{
|
|
|
|
// could use some additional capacity? To avoid a copy during processing, though small data so
|
|
|
|
// probably not that important.
|
|
|
|
//
|
|
|
|
// From the map, we construct an adjacency array that allows access from all IDs to the list of
|
|
|
|
// associated Turn Lane Masks.
|
|
|
|
//
|
|
|
|
// turn lane offsets points into the locations of the turn_lane_masks array. We use a standard
|
|
|
|
// adjacency array like structure to store the turn lane masks.
|
|
|
|
std::vector<std::uint32_t> turn_lane_offsets(turn_lane_map.size() + 2); // empty ID + sentinel
|
|
|
|
for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry)
|
|
|
|
turn_lane_offsets[entry->second + 1] = entry->first.size();
|
|
|
|
|
|
|
|
// inplace prefix sum
|
|
|
|
std::partial_sum(turn_lane_offsets.begin(), turn_lane_offsets.end(), turn_lane_offsets.begin());
|
|
|
|
|
|
|
|
// allocate the current masks
|
|
|
|
std::vector<guidance::TurnLaneType::Mask> turn_lane_masks(turn_lane_offsets.back());
|
|
|
|
for (auto entry = turn_lane_map.begin(); entry != turn_lane_map.end(); ++entry)
|
|
|
|
std::copy(entry->first.begin(),
|
|
|
|
entry->first.end(),
|
|
|
|
turn_lane_masks.begin() + turn_lane_offsets[entry->second]);
|
|
|
|
return std::make_tuple(std::move(turn_lane_offsets), std::move(turn_lane_masks));
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2015-04-09 06:26:46 -04:00
|
|
|
/**
|
|
|
|
* TODO: Refactor this function into smaller functions for better readability.
|
|
|
|
*
|
|
|
|
* This function is the entry point for the whole extraction process. The goal of the extraction
|
|
|
|
* step is to filter and convert the OSM geometry to something more fitting for routing.
|
|
|
|
* That includes:
|
|
|
|
* - extracting turn restrictions
|
|
|
|
* - splitting ways into (directional!) edge segments
|
|
|
|
* - checking if nodes are barriers or traffic signal
|
|
|
|
* - discarding all tag information: All relevant type information for nodes/ways
|
|
|
|
* is extracted at this point.
|
|
|
|
*
|
|
|
|
* The result of this process are the following files:
|
|
|
|
* .names : Names of all streets, stored as long consecutive string with prefix sum based index
|
2016-02-15 19:16:49 -05:00
|
|
|
* .osrm : Nodes and edges in a intermediate format that easy to digest for osrm-contract
|
|
|
|
* .restrictions : Turn restrictions that are used by osrm-contract to construct the edge-expanded
|
2015-12-11 17:11:04 -05:00
|
|
|
* graph
|
2015-04-09 06:26:46 -04:00
|
|
|
*
|
|
|
|
*/
|
2016-07-11 11:44:58 -04:00
|
|
|
int Extractor::run(ScriptingEnvironment &scripting_environment)
|
2014-11-28 09:00:48 -05:00
|
|
|
{
|
2016-10-10 12:05:17 -04:00
|
|
|
util::LogPolicy::GetInstance().Unmute();
|
|
|
|
TIMER_START(extracting);
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2016-10-10 12:05:17 -04:00
|
|
|
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
|
2016-10-21 18:24:55 -04:00
|
|
|
const auto number_of_threads = std::min(recommended_num_threads, config.requested_num_threads);
|
2017-03-08 10:00:56 -05:00
|
|
|
tbb::task_scheduler_init init(number_of_threads ? number_of_threads
|
|
|
|
: tbb::task_scheduler_init::automatic);
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2016-10-10 12:05:17 -04:00
|
|
|
{
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Input file: " << config.input_path.filename().string();
|
2016-07-26 09:00:58 -04:00
|
|
|
if (!config.profile_path.empty())
|
|
|
|
{
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Profile: " << config.profile_path.filename().string();
|
2016-07-11 11:44:58 -04:00
|
|
|
}
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Threads: " << number_of_threads;
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2015-04-24 08:51:25 -04:00
|
|
|
const osmium::io::File input_file(config.input_path.string());
|
2017-01-04 04:49:34 -05:00
|
|
|
|
|
|
|
osmium::io::Reader reader(
|
|
|
|
input_file,
|
|
|
|
(config.use_metadata ? osmium::io::read_meta::yes : osmium::io::read_meta::no));
|
|
|
|
|
2014-12-12 18:23:41 -05:00
|
|
|
const osmium::io::Header header = reader.header();
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
unsigned number_of_nodes = 0;
|
|
|
|
unsigned number_of_ways = 0;
|
|
|
|
unsigned number_of_relations = 0;
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Parsing in progress..";
|
2014-11-28 09:00:48 -05:00
|
|
|
TIMER_START(parsing);
|
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
ExtractionContainers extraction_containers;
|
|
|
|
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(
|
|
|
|
extraction_containers, scripting_environment.GetProfileProperties());
|
|
|
|
|
2016-03-21 17:42:47 -04:00
|
|
|
// setup raster sources
|
2016-07-11 11:44:58 -04:00
|
|
|
scripting_environment.SetupSources();
|
2015-05-29 20:28:29 -04:00
|
|
|
|
2014-11-28 09:00:48 -05:00
|
|
|
std::string generator = header.get("generator");
|
|
|
|
if (generator.empty())
|
|
|
|
{
|
|
|
|
generator = "unknown tool";
|
|
|
|
}
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "input file generated by " << generator;
|
2014-11-28 09:00:48 -05:00
|
|
|
|
|
|
|
// write .timestamp data file
|
|
|
|
std::string timestamp = header.get("osmosis_replication_timestamp");
|
|
|
|
if (timestamp.empty())
|
|
|
|
{
|
|
|
|
timestamp = "n/a";
|
|
|
|
}
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "timestamp: " << timestamp;
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2017-03-04 05:52:40 -05:00
|
|
|
storage::io::FileWriter timestamp_file(config.timestamp_file_name,
|
|
|
|
storage::io::FileWriter::HasNoFingerprint);
|
|
|
|
|
|
|
|
timestamp_file.WriteFrom(timestamp.c_str(), timestamp.length());
|
2014-11-28 09:00:48 -05:00
|
|
|
|
|
|
|
// 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;
|
2015-09-18 08:26:32 -04:00
|
|
|
tbb::concurrent_vector<boost::optional<InputRestrictionContainer>> resulting_restrictions;
|
2014-11-28 09:00:48 -05:00
|
|
|
|
|
|
|
// setup restriction parser
|
2016-07-11 11:44:58 -04:00
|
|
|
const RestrictionParser restriction_parser(scripting_environment);
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2017-01-11 10:56:42 -05:00
|
|
|
// 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())
|
2014-11-28 09:00:48 -05:00
|
|
|
{
|
2015-09-14 19:13:31 -04:00
|
|
|
for (auto iter = std::begin(buffer), end = std::end(buffer); iter != end; ++iter)
|
2015-01-22 06:19:11 -05:00
|
|
|
{
|
2014-11-28 09:00:48 -05:00
|
|
|
osm_elements.push_back(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear resulting vectors
|
|
|
|
resulting_nodes.clear();
|
|
|
|
resulting_ways.clear();
|
|
|
|
resulting_restrictions.clear();
|
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
scripting_environment.ProcessElements(osm_elements,
|
|
|
|
restriction_parser,
|
|
|
|
resulting_nodes,
|
|
|
|
resulting_ways,
|
|
|
|
resulting_restrictions);
|
|
|
|
|
|
|
|
number_of_nodes += resulting_nodes.size();
|
2014-11-28 09:00:48 -05:00
|
|
|
// put parsed objects thru extractor callbacks
|
|
|
|
for (const auto &result : resulting_nodes)
|
|
|
|
{
|
|
|
|
extractor_callbacks->ProcessNode(
|
2015-01-22 06:19:11 -05:00
|
|
|
static_cast<const osmium::Node &>(*(osm_elements[result.first])),
|
|
|
|
result.second);
|
2014-11-28 09:00:48 -05:00
|
|
|
}
|
2016-07-11 11:44:58 -04:00
|
|
|
number_of_ways += resulting_ways.size();
|
2014-11-28 09:00:48 -05:00
|
|
|
for (const auto &result : resulting_ways)
|
|
|
|
{
|
|
|
|
extractor_callbacks->ProcessWay(
|
2014-12-12 18:23:41 -05:00
|
|
|
static_cast<const osmium::Way &>(*(osm_elements[result.first])), result.second);
|
2014-11-28 09:00:48 -05:00
|
|
|
}
|
2016-07-11 11:44:58 -04:00
|
|
|
number_of_relations += resulting_restrictions.size();
|
2014-11-28 09:00:48 -05:00
|
|
|
for (const auto &result : resulting_restrictions)
|
|
|
|
{
|
|
|
|
extractor_callbacks->ProcessRestriction(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TIMER_STOP(parsing);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Parsing finished after " << TIMER_SEC(parsing) << " seconds";
|
2014-12-12 18:16:32 -05:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
|
|
|
|
<< " ways, and " << number_of_relations << " relations";
|
2014-11-28 09:00:48 -05:00
|
|
|
|
2016-07-22 03:08:40 -04:00
|
|
|
// take control over the turn lane map
|
|
|
|
turn_lane_map = extractor_callbacks->moveOutLaneDescriptionMap();
|
|
|
|
|
2014-11-28 09:00:48 -05:00
|
|
|
extractor_callbacks.reset();
|
|
|
|
|
|
|
|
if (extraction_containers.all_edges_list.empty())
|
|
|
|
{
|
2016-12-06 15:30:46 -05:00
|
|
|
throw util::exception(std::string("There are no edges remaining after parsing.") +
|
|
|
|
SOURCE_REF);
|
2014-11-28 09:00:48 -05:00
|
|
|
}
|
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
extraction_containers.PrepareData(scripting_environment,
|
|
|
|
config.output_file_name,
|
2016-05-27 15:05:04 -04:00
|
|
|
config.restriction_file_name,
|
2016-06-30 03:31:08 -04:00
|
|
|
config.names_file_name);
|
2016-03-21 17:42:47 -04:00
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
WriteProfileProperties(config.profile_properties_output_path,
|
|
|
|
scripting_environment.GetProfileProperties());
|
2015-05-29 20:28:29 -04:00
|
|
|
|
2014-11-28 09:00:48 -05:00
|
|
|
TIMER_STOP(extracting);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
2016-07-19 07:13:52 -04:00
|
|
|
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
|
|
|
// 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
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Generating edge-expanded graph representation";
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
TIMER_START(expansion);
|
|
|
|
|
2016-01-26 17:24:43 -05:00
|
|
|
std::vector<EdgeBasedNode> edge_based_node_list;
|
2016-01-05 10:51:13 -05:00
|
|
|
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
2015-12-11 17:11:04 -05:00
|
|
|
std::vector<bool> node_is_startpoint;
|
2016-01-07 04:33:47 -05:00
|
|
|
std::vector<EdgeWeight> edge_based_node_weights;
|
2017-04-02 19:58:06 -04:00
|
|
|
std::vector<util::Coordinate> coordinates;
|
|
|
|
util::PackedVector<OSMNodeID> osm_node_ids;
|
2016-12-06 07:22:51 -05:00
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
auto graph_size = BuildEdgeExpandedGraph(scripting_environment,
|
2017-04-02 19:58:06 -04:00
|
|
|
coordinates,
|
|
|
|
osm_node_ids,
|
2016-05-27 15:05:04 -04:00
|
|
|
edge_based_node_list,
|
|
|
|
node_is_startpoint,
|
|
|
|
edge_based_node_weights,
|
|
|
|
edge_based_edge_list,
|
|
|
|
config.intersection_class_data_output_path);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
auto number_of_node_based_nodes = graph_size.first;
|
|
|
|
auto max_edge_id = graph_size.second;
|
|
|
|
|
|
|
|
TIMER_STOP(expansion);
|
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Saving edge-based node weights to file.";
|
2016-01-07 04:33:47 -05:00
|
|
|
TIMER_START(timer_write_node_weights);
|
2017-03-04 05:52:40 -05:00
|
|
|
|
|
|
|
storage::io::FileWriter edge_file(config.edge_based_node_weights_output_path,
|
|
|
|
storage::io::FileWriter::GenerateFingerprint);
|
|
|
|
edge_file.SerializeVector(edge_based_node_weights);
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
TIMER_STOP(timer_write_node_weights);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
|
2016-01-07 04:33:47 -05:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Computing strictly connected components ...";
|
2016-01-26 17:24:43 -05:00
|
|
|
FindComponents(max_edge_id, edge_based_edge_list, edge_based_node_list);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Building r-tree ...";
|
2016-07-25 06:03:30 -04:00
|
|
|
TIMER_START(rtree);
|
2017-04-02 19:58:06 -04:00
|
|
|
BuildRTree(std::move(edge_based_node_list), std::move(node_is_startpoint), coordinates);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
TIMER_STOP(rtree);
|
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Writing node map ...";
|
2017-04-02 19:58:06 -04:00
|
|
|
files::writeNodes<storage::Ownership::Container>(config.node_output_path, coordinates, osm_node_ids);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
WriteEdgeBasedGraph(config.edge_graph_output_path, max_edge_id, edge_based_edge_list);
|
|
|
|
|
2016-11-18 06:14:38 -05:00
|
|
|
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));
|
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
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;
|
2014-11-28 09:00:48 -05:00
|
|
|
}
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2014-11-28 09:00:48 -05:00
|
|
|
return 0;
|
|
|
|
}
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-03-28 11:06:51 -04:00
|
|
|
void Extractor::WriteProfileProperties(const std::string &output_path,
|
|
|
|
const ProfileProperties &properties) const
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2017-03-04 05:52:40 -05:00
|
|
|
storage::io::FileWriter file(output_path, storage::io::FileWriter::HasNoFingerprint);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2017-03-04 05:52:40 -05:00
|
|
|
file.WriteOne(properties);
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
void Extractor::FindComponents(unsigned max_edge_id,
|
2016-01-05 10:51:13 -05:00
|
|
|
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
|
2015-10-01 15:47:29 -04:00
|
|
|
std::vector<EdgeBasedNode> &input_nodes) const
|
|
|
|
{
|
2017-02-22 08:15:07 -05:00
|
|
|
using InputEdge = util::static_graph_details::SortableEdgeWithData<void>;
|
|
|
|
using UncontractedGraph = util::StaticGraph<void>;
|
2015-10-01 15:47:29 -04:00
|
|
|
std::vector<InputEdge> edges;
|
|
|
|
edges.reserve(input_edge_list.size() * 2);
|
|
|
|
|
|
|
|
for (const auto &edge : input_edge_list)
|
|
|
|
{
|
2017-03-06 17:00:11 -05:00
|
|
|
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(edge.data.weight, 1)) > 0,
|
2015-10-01 15:47:29 -04:00
|
|
|
"edge distance < 1");
|
2016-03-05 14:53:53 -05:00
|
|
|
BOOST_ASSERT(edge.source <= max_edge_id);
|
|
|
|
BOOST_ASSERT(edge.target <= max_edge_id);
|
2017-03-06 17:00:11 -05:00
|
|
|
if (edge.data.forward)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2017-02-22 08:15:07 -05:00
|
|
|
edges.push_back({edge.source, edge.target});
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
|
2017-03-06 17:00:11 -05:00
|
|
|
if (edge.data.backward)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2017-02-22 08:15:07 -05:00
|
|
|
edges.push_back({edge.target, edge.source});
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// connect forward and backward nodes of each edge
|
|
|
|
for (const auto &node : input_nodes)
|
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
if (node.reverse_segment_id.enabled)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
BOOST_ASSERT(node.forward_segment_id.id <= max_edge_id);
|
|
|
|
BOOST_ASSERT(node.reverse_segment_id.id <= max_edge_id);
|
2017-02-22 08:15:07 -05:00
|
|
|
edges.push_back({node.forward_segment_id.id, node.reverse_segment_id.id});
|
|
|
|
edges.push_back({node.reverse_segment_id.id, node.forward_segment_id.id});
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tbb::parallel_sort(edges.begin(), edges.end());
|
2017-02-22 08:15:07 -05:00
|
|
|
edges.erase(std::unique(edges.begin(), edges.end()), edges.end());
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2017-01-26 04:34:01 -05:00
|
|
|
auto uncontracted_graph = UncontractedGraph(max_edge_id + 1, edges);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2017-01-26 04:34:01 -05:00
|
|
|
TarjanSCC<UncontractedGraph> component_search(uncontracted_graph);
|
2016-04-28 18:39:59 -04:00
|
|
|
component_search.Run();
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
for (auto &node : input_nodes)
|
|
|
|
{
|
2016-04-28 18:39:59 -04:00
|
|
|
auto forward_component = component_search.GetComponentID(node.forward_segment_id.id);
|
2016-03-28 11:06:51 -04:00
|
|
|
BOOST_ASSERT(!node.reverse_segment_id.enabled ||
|
2015-10-01 15:47:29 -04:00
|
|
|
forward_component ==
|
2016-04-28 18:39:59 -04:00
|
|
|
component_search.GetComponentID(node.reverse_segment_id.id));
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-04-28 18:39:59 -04:00
|
|
|
const unsigned component_size = component_search.GetComponentSize(forward_component);
|
2015-12-01 20:46:29 -05:00
|
|
|
node.component.is_tiny = component_size < config.small_component_size;
|
2015-11-18 11:47:37 -05:00
|
|
|
node.component.id = 1 + forward_component;
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Build load restrictions from .restriction file
|
|
|
|
*/
|
2016-01-07 04:33:47 -05:00
|
|
|
std::shared_ptr<RestrictionMap> Extractor::LoadRestrictionMap()
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2016-11-21 20:32:00 -05:00
|
|
|
storage::io::FileReader file_reader(config.restriction_file_name,
|
|
|
|
storage::io::FileReader::VerifyFingerprint);
|
2015-10-01 15:47:29 -04:00
|
|
|
std::vector<TurnRestriction> restriction_list;
|
2016-11-21 20:32:00 -05:00
|
|
|
|
|
|
|
util::loadRestrictionsFromFile(file_reader, restriction_list);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << " - " << restriction_list.size() << " restrictions.";
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
return std::make_shared<RestrictionMap>(restriction_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Load node based graph from .osrm file
|
|
|
|
*/
|
2016-01-05 10:51:13 -05:00
|
|
|
std::shared_ptr<util::NodeBasedDynamicGraph>
|
2016-11-14 17:43:24 -05:00
|
|
|
Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
|
|
|
|
std::unordered_set<NodeID> &traffic_signals,
|
2017-04-02 19:58:06 -04:00
|
|
|
std::vector<util::Coordinate> &coordiantes,
|
|
|
|
util::PackedVector<OSMNodeID> &osm_node_ids)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2016-11-21 20:32:00 -05:00
|
|
|
storage::io::FileReader file_reader(config.output_file_name,
|
|
|
|
storage::io::FileReader::VerifyFingerprint);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-11-14 17:43:24 -05:00
|
|
|
auto barriers_iter = inserter(barriers, end(barriers));
|
|
|
|
auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals));
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-11-14 17:43:24 -05:00
|
|
|
NodeID number_of_node_based_nodes = util::loadNodesFromFile(
|
2017-04-02 19:58:06 -04:00
|
|
|
file_reader, barriers_iter, traffic_signals_iter, coordiantes, osm_node_ids);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << " - " << barriers.size() << " bollard nodes, " << traffic_signals.size()
|
|
|
|
<< " traffic lights";
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-11-14 17:43:24 -05:00
|
|
|
std::vector<NodeBasedEdge> edge_list;
|
2016-11-21 20:32:00 -05:00
|
|
|
util::loadEdgesFromFile(file_reader, edge_list);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
if (edge_list.empty())
|
|
|
|
{
|
2016-12-06 15:30:46 -05:00
|
|
|
throw util::exception("Node-based-graph (" + config.output_file_name +
|
|
|
|
") contains no edges." + SOURCE_REF);
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Building an edge-expanded graph from node-based input and turn restrictions
|
|
|
|
*/
|
2016-06-11 11:23:29 -04:00
|
|
|
std::pair<std::size_t, EdgeID>
|
2016-07-11 11:44:58 -04:00
|
|
|
Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
2017-04-02 19:58:06 -04:00
|
|
|
std::vector<util::Coordinate> &coordinates,
|
|
|
|
util::PackedVector<OSMNodeID> &osm_node_ids,
|
2015-12-11 17:11:04 -05:00
|
|
|
std::vector<EdgeBasedNode> &node_based_edge_list,
|
|
|
|
std::vector<bool> &node_is_startpoint,
|
2016-01-07 04:33:47 -05:00
|
|
|
std::vector<EdgeWeight> &edge_based_node_weights,
|
2016-04-26 07:27:40 -04:00
|
|
|
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
|
|
|
const std::string &intersection_class_output_file)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
|
|
|
std::unordered_set<NodeID> barrier_nodes;
|
|
|
|
std::unordered_set<NodeID> traffic_lights;
|
|
|
|
|
|
|
|
auto restriction_map = LoadRestrictionMap();
|
|
|
|
auto node_based_graph =
|
2017-04-02 19:58:06 -04:00
|
|
|
LoadNodeBasedGraph(barrier_nodes, traffic_lights, coordinates, osm_node_ids);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
CompressedEdgeContainer compressed_edge_container;
|
2016-03-21 17:42:47 -04:00
|
|
|
GraphCompressor graph_compressor;
|
2016-05-27 15:05:04 -04:00
|
|
|
graph_compressor.Compress(barrier_nodes,
|
|
|
|
traffic_lights,
|
|
|
|
*restriction_map,
|
|
|
|
*node_based_graph,
|
2015-10-01 15:47:29 -04:00
|
|
|
compressed_edge_container);
|
|
|
|
|
2016-03-16 10:47:33 -04:00
|
|
|
util::NameTable name_table(config.names_file_name);
|
2016-06-21 04:41:08 -04:00
|
|
|
|
2016-06-30 03:31:08 -04:00
|
|
|
// could use some additional capacity? To avoid a copy during processing, though small data so
|
|
|
|
// probably not that important.
|
2016-07-22 03:08:40 -04:00
|
|
|
std::vector<std::uint32_t> turn_lane_offsets;
|
|
|
|
std::vector<guidance::TurnLaneType::Mask> turn_lane_masks;
|
|
|
|
std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map);
|
2016-03-16 10:47:33 -04:00
|
|
|
|
2015-10-01 15:47:29 -04:00
|
|
|
EdgeBasedGraphFactory edge_based_graph_factory(
|
2016-05-27 15:05:04 -04:00
|
|
|
node_based_graph,
|
|
|
|
compressed_edge_container,
|
|
|
|
barrier_nodes,
|
|
|
|
traffic_lights,
|
2015-10-01 15:47:29 -04:00
|
|
|
std::const_pointer_cast<RestrictionMap const>(restriction_map),
|
2017-04-02 19:58:06 -04:00
|
|
|
coordinates,
|
|
|
|
osm_node_ids,
|
2016-07-11 11:44:58 -04:00
|
|
|
scripting_environment.GetProfileProperties(),
|
2016-05-13 13:18:00 -04:00
|
|
|
name_table,
|
2016-06-21 04:41:08 -04:00
|
|
|
turn_lane_offsets,
|
2016-06-30 03:31:08 -04:00
|
|
|
turn_lane_masks,
|
|
|
|
turn_lane_map);
|
2016-05-27 15:05:04 -04:00
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
edge_based_graph_factory.Run(scripting_environment,
|
|
|
|
config.edge_output_path,
|
2016-06-15 08:38:24 -04:00
|
|
|
config.turn_lane_data_file_name,
|
2016-05-12 12:50:10 -04:00
|
|
|
config.turn_weight_penalties_path,
|
|
|
|
config.turn_duration_penalties_path,
|
|
|
|
config.turn_penalties_index_path,
|
2017-03-15 19:52:01 -04:00
|
|
|
config.cnbg_ebg_graph_mapping_output_path);
|
2016-01-29 20:52:20 -05:00
|
|
|
|
2017-01-26 11:53:19 -05:00
|
|
|
// The osrm-partition tool requires the compressed node based graph with an embedding.
|
|
|
|
//
|
|
|
|
// The `Run` function above re-numbers non-reverse compressed node based graph edges
|
|
|
|
// to a continuous range so that the nodes in the edge based graph are continuous.
|
|
|
|
//
|
|
|
|
// Luckily node based node ids still coincide with the coordinate array.
|
|
|
|
// That's the reason we can only here write out the final compressed node based graph.
|
|
|
|
|
|
|
|
// Dumps to file asynchronously and makes sure we wait for its completion.
|
|
|
|
std::future<void> compressed_node_based_graph_writing;
|
|
|
|
|
|
|
|
BOOST_SCOPE_EXIT_ALL(&)
|
|
|
|
{
|
|
|
|
if (compressed_node_based_graph_writing.valid())
|
|
|
|
compressed_node_based_graph_writing.wait();
|
|
|
|
};
|
|
|
|
|
2017-02-28 20:02:58 -05:00
|
|
|
compressed_node_based_graph_writing = std::async(std::launch::async, [&] {
|
|
|
|
WriteCompressedNodeBasedGraph(config.compressed_node_based_graph_output_path,
|
|
|
|
*node_based_graph,
|
2017-04-02 19:58:06 -04:00
|
|
|
coordinates);
|
2017-02-28 20:02:58 -05:00
|
|
|
});
|
2017-01-26 11:53:19 -05:00
|
|
|
|
2016-06-30 03:31:08 -04:00
|
|
|
WriteTurnLaneData(config.turn_lane_descriptions_file_name);
|
2017-04-01 21:25:55 -04:00
|
|
|
files::writeSegmentData(config.geometry_output_path,
|
|
|
|
*compressed_edge_container.ToSegmentData());
|
2016-06-30 03:31:08 -04:00
|
|
|
|
2015-10-01 15:47:29 -04:00
|
|
|
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
|
|
|
|
edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
|
2015-12-11 17:11:04 -05:00
|
|
|
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
|
2016-01-07 04:33:47 -05:00
|
|
|
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
|
2015-10-01 15:47:29 -04:00
|
|
|
auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
|
|
|
|
|
|
|
|
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
|
2016-04-26 07:27:40 -04:00
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
WriteIntersectionClassificationData(intersection_class_output_file,
|
|
|
|
edge_based_graph_factory.GetBearingClassIds(),
|
|
|
|
edge_based_graph_factory.GetBearingClasses(),
|
|
|
|
edge_based_graph_factory.GetEntryClasses());
|
2016-04-26 07:27:40 -04:00
|
|
|
|
2015-10-01 15:47:29 -04:00
|
|
|
return std::make_pair(number_of_node_based_nodes, max_edge_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Building rtree-based nearest-neighbor data structure
|
|
|
|
|
|
|
|
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
|
|
|
|
*/
|
2016-01-07 04:33:47 -05:00
|
|
|
void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
2015-12-11 17:11:04 -05:00
|
|
|
std::vector<bool> node_is_startpoint,
|
2017-04-02 19:58:06 -04:00
|
|
|
const std::vector<util::Coordinate> &coordinates)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "constructing r-tree of " << node_based_edge_list.size()
|
2017-04-02 19:58:06 -04:00
|
|
|
<< " edge elements build on-top of " << coordinates.size() << " coordinates";
|
2015-12-11 17:11:04 -05:00
|
|
|
|
|
|
|
BOOST_ASSERT(node_is_startpoint.size() == node_based_edge_list.size());
|
|
|
|
|
|
|
|
// Filter node based edges based on startpoint
|
|
|
|
auto out_iter = node_based_edge_list.begin();
|
|
|
|
auto in_iter = node_based_edge_list.begin();
|
2016-04-12 06:42:16 -04:00
|
|
|
for (auto index : util::irange<std::size_t>(0UL, node_is_startpoint.size()))
|
2015-12-11 17:11:04 -05:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(in_iter != node_based_edge_list.end());
|
|
|
|
if (node_is_startpoint[index])
|
|
|
|
{
|
|
|
|
*out_iter = *in_iter;
|
|
|
|
out_iter++;
|
|
|
|
}
|
|
|
|
in_iter++;
|
|
|
|
}
|
|
|
|
auto new_size = out_iter - node_based_edge_list.begin();
|
2016-04-14 16:07:23 -04:00
|
|
|
if (new_size == 0)
|
|
|
|
{
|
2016-04-14 17:39:20 -04:00
|
|
|
throw util::exception("There are no snappable edges left after processing. Are you "
|
2016-12-06 15:30:46 -05:00
|
|
|
"setting travel modes correctly in the profile? Cannot continue." +
|
|
|
|
SOURCE_REF);
|
2016-04-14 16:07:23 -04:00
|
|
|
}
|
2015-12-11 17:11:04 -05:00
|
|
|
node_based_edge_list.resize(new_size);
|
2015-12-03 14:04:23 -05:00
|
|
|
|
|
|
|
TIMER_START(construction);
|
2017-04-02 19:58:06 -04:00
|
|
|
util::StaticRTree<EdgeBasedNode> rtree(node_based_edge_list,
|
|
|
|
config.rtree_nodes_output_path,
|
|
|
|
config.rtree_leafs_output_path,
|
|
|
|
coordinates);
|
2015-12-03 14:04:23 -05:00
|
|
|
|
|
|
|
TIMER_STOP(construction);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "finished r-tree construction in " << TIMER_SEC(construction) << " seconds";
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
void Extractor::WriteEdgeBasedGraph(
|
2016-01-07 19:31:57 -05:00
|
|
|
std::string const &output_file_filename,
|
2016-06-11 11:23:29 -04:00
|
|
|
EdgeID const max_edge_id,
|
2016-01-07 19:31:57 -05:00
|
|
|
util::DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list)
|
2015-10-01 15:47:29 -04:00
|
|
|
{
|
2017-03-04 05:52:40 -05:00
|
|
|
storage::io::FileWriter file(output_file_filename,
|
|
|
|
storage::io::FileWriter::GenerateFingerprint);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Writing edge-based-graph edges ... " << std::flush;
|
2015-10-01 15:47:29 -04:00
|
|
|
TIMER_START(write_edges);
|
|
|
|
|
2016-06-11 11:23:29 -04:00
|
|
|
std::uint64_t number_of_used_edges = edge_based_edge_list.size();
|
2017-03-04 05:52:40 -05:00
|
|
|
file.WriteElementCount64(number_of_used_edges);
|
|
|
|
file.WriteOne(max_edge_id);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2015-12-11 17:11:04 -05:00
|
|
|
for (const auto &edge : edge_based_edge_list)
|
|
|
|
{
|
2017-03-04 05:52:40 -05:00
|
|
|
file.WriteOne(edge);
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
TIMER_STOP(write_edges);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s";
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Processed " << number_of_used_edges << " edges";
|
2015-10-01 15:47:29 -04:00
|
|
|
}
|
2016-04-26 07:27:40 -04:00
|
|
|
|
|
|
|
void Extractor::WriteIntersectionClassificationData(
|
|
|
|
const std::string &output_file_name,
|
|
|
|
const std::vector<BearingClassID> &node_based_intersection_classes,
|
|
|
|
const std::vector<util::guidance::BearingClass> &bearing_classes,
|
|
|
|
const std::vector<util::guidance::EntryClass> &entry_classes) const
|
|
|
|
{
|
2017-03-04 05:52:40 -05:00
|
|
|
storage::io::FileWriter file(output_file_name, storage::io::FileWriter::GenerateFingerprint);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Writing Intersection Classification Data";
|
2016-04-26 07:27:40 -04:00
|
|
|
TIMER_START(write_edges);
|
2017-03-04 05:52:40 -05:00
|
|
|
file.SerializeVector(node_based_intersection_classes);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
2016-05-10 02:37:45 -04:00
|
|
|
// create range table for vectors:
|
|
|
|
std::vector<unsigned> bearing_counts;
|
|
|
|
bearing_counts.reserve(bearing_classes.size());
|
|
|
|
std::uint64_t total_bearings = 0;
|
2016-05-27 15:05:04 -04:00
|
|
|
for (const auto &bearing_class : bearing_classes)
|
|
|
|
{
|
|
|
|
bearing_counts.push_back(
|
|
|
|
static_cast<unsigned>(bearing_class.getAvailableBearings().size()));
|
2016-05-10 02:37:45 -04:00
|
|
|
total_bearings += bearing_class.getAvailableBearings().size();
|
|
|
|
}
|
|
|
|
|
|
|
|
util::RangeTable<> bearing_class_range_table(bearing_counts);
|
2017-03-04 05:52:40 -05:00
|
|
|
bearing_class_range_table.Write(file);
|
|
|
|
|
|
|
|
file.WriteOne(total_bearings);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
for (const auto &bearing_class : bearing_classes)
|
2016-05-10 02:37:45 -04:00
|
|
|
{
|
|
|
|
const auto &bearings = bearing_class.getAvailableBearings();
|
2017-03-04 05:52:40 -05:00
|
|
|
file.WriteFrom(bearings.data(), bearings.size());
|
2016-05-10 02:37:45 -04:00
|
|
|
}
|
2016-04-26 07:27:40 -04:00
|
|
|
|
2017-03-04 05:52:40 -05:00
|
|
|
file.SerializeVector(entry_classes);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
|
|
|
TIMER_STOP(write_edges);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s for "
|
|
|
|
<< node_based_intersection_classes.size() << " Indices into "
|
|
|
|
<< bearing_classes.size() << " bearing classes and " << entry_classes.size()
|
|
|
|
<< " entry classes and " << total_bearings << " bearing values.";
|
2016-04-26 07:27:40 -04:00
|
|
|
}
|
2016-06-30 03:31:08 -04:00
|
|
|
|
|
|
|
void Extractor::WriteTurnLaneData(const std::string &turn_lane_file) const
|
|
|
|
{
|
|
|
|
// Write the turn lane data to file
|
2016-07-22 03:08:40 -04:00
|
|
|
std::vector<std::uint32_t> turn_lane_offsets;
|
|
|
|
std::vector<guidance::TurnLaneType::Mask> turn_lane_masks;
|
|
|
|
std::tie(turn_lane_offsets, turn_lane_masks) = transformTurnLaneMapIntoArrays(turn_lane_map);
|
2016-06-30 03:31:08 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Writing turn lane masks...";
|
2016-06-30 03:31:08 -04:00
|
|
|
TIMER_START(turn_lane_timer);
|
|
|
|
|
2017-03-04 05:52:40 -05:00
|
|
|
storage::io::FileWriter file(turn_lane_file, storage::io::FileWriter::HasNoFingerprint);
|
|
|
|
file.SerializeVector(turn_lane_offsets);
|
|
|
|
file.SerializeVector(turn_lane_masks);
|
2016-06-30 03:31:08 -04:00
|
|
|
|
|
|
|
TIMER_STOP(turn_lane_timer);
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "done (" << TIMER_SEC(turn_lane_timer) << ")";
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
2016-06-30 03:31:08 -04:00
|
|
|
|
2017-01-26 11:53:19 -05:00
|
|
|
void Extractor::WriteCompressedNodeBasedGraph(const std::string &path,
|
|
|
|
const util::NodeBasedDynamicGraph &graph,
|
2017-04-02 19:58:06 -04:00
|
|
|
const std::vector<util::Coordinate> &coordinates)
|
2017-01-26 11:53:19 -05:00
|
|
|
{
|
|
|
|
const auto fingerprint = storage::io::FileWriter::GenerateFingerprint;
|
|
|
|
|
|
|
|
storage::io::FileWriter writer{path, fingerprint};
|
|
|
|
|
|
|
|
// Writes: | Fingerprint | #e | #n | edges | coordinates |
|
|
|
|
// - uint64: number of edges (from, to) pairs
|
|
|
|
// - uint64: number of nodes and therefore also coordinates
|
|
|
|
// - (uint32_t, uint32_t): num_edges * edges
|
|
|
|
// - (int32_t, int32_t: num_nodes * coordinates (lon, lat)
|
|
|
|
|
|
|
|
const auto num_edges = graph.GetNumberOfEdges();
|
|
|
|
const auto num_nodes = graph.GetNumberOfNodes();
|
|
|
|
|
2017-04-02 19:58:06 -04:00
|
|
|
BOOST_ASSERT_MSG(num_nodes == coordinates.size(), "graph and embedding out of sync");
|
2017-01-26 11:53:19 -05:00
|
|
|
|
2017-02-01 09:50:06 -05:00
|
|
|
writer.WriteElementCount64(num_edges);
|
|
|
|
writer.WriteElementCount64(num_nodes);
|
2017-01-26 11:53:19 -05:00
|
|
|
|
|
|
|
// For all nodes iterate over its edges and dump (from, to) pairs
|
|
|
|
for (const NodeID from_node : util::irange(0u, num_nodes))
|
|
|
|
{
|
|
|
|
for (const EdgeID edge : graph.GetAdjacentEdgeRange(from_node))
|
|
|
|
{
|
|
|
|
const auto to_node = graph.GetTarget(edge);
|
|
|
|
|
2017-02-01 09:50:06 -05:00
|
|
|
writer.WriteOne(from_node);
|
|
|
|
writer.WriteOne(to_node);
|
2017-01-26 11:53:19 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-02 19:58:06 -04:00
|
|
|
// FIXME this is unneccesary: We have this data
|
|
|
|
for (const auto &qnode : coordinates)
|
2017-01-26 11:53:19 -05:00
|
|
|
{
|
2017-02-01 09:50:06 -05:00
|
|
|
writer.WriteOne(qnode.lon);
|
|
|
|
writer.WriteOne(qnode.lat);
|
2017-01-26 11:53:19 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 03:31:08 -04:00
|
|
|
} // namespace extractor
|
|
|
|
} // namespace osrm
|