2016-01-02 11:13:44 -05:00
|
|
|
#include "contractor/contractor.hpp"
|
2016-03-09 07:18:09 -05:00
|
|
|
#include "contractor/crc32_processor.hpp"
|
2016-01-07 13:19:55 -05:00
|
|
|
#include "contractor/graph_contractor.hpp"
|
2015-11-09 15:14:39 -05:00
|
|
|
|
2016-03-09 07:18:09 -05:00
|
|
|
#include "extractor/node_based_edge.hpp"
|
2016-01-29 20:52:20 -05:00
|
|
|
#include "extractor/compressed_edge_container.hpp"
|
|
|
|
|
2016-03-09 07:18:09 -05:00
|
|
|
#include "util/static_graph.hpp"
|
2016-01-29 20:52:20 -05:00
|
|
|
#include "util/static_rtree.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/graph_loader.hpp"
|
2016-01-07 04:33:47 -05:00
|
|
|
#include "util/io.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/integer_range.hpp"
|
2016-01-28 08:27:05 -05:00
|
|
|
#include "util/exception.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/simple_logger.hpp"
|
|
|
|
#include "util/string_util.hpp"
|
|
|
|
#include "util/timing_util.hpp"
|
|
|
|
#include "util/typedefs.hpp"
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2015-10-14 18:08:22 -04:00
|
|
|
#include <fast-cpp-csv-parser/csv.h>
|
|
|
|
|
2016-03-09 07:18:09 -05:00
|
|
|
#include <boost/assert.hpp>
|
2014-07-03 07:29:15 -04:00
|
|
|
#include <boost/filesystem/fstream.hpp>
|
|
|
|
|
|
|
|
#include <tbb/parallel_sort.h>
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
#include <cstdint>
|
|
|
|
#include <bitset>
|
2014-07-03 07:29:15 -04:00
|
|
|
#include <chrono>
|
|
|
|
#include <memory>
|
|
|
|
#include <thread>
|
2016-01-29 20:52:20 -05:00
|
|
|
#include <iterator>
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
|
|
|
|
template <> struct hash<std::pair<OSMNodeID, OSMNodeID>>
|
|
|
|
{
|
|
|
|
std::size_t operator()(const std::pair<OSMNodeID, OSMNodeID> &k) const
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
return static_cast<uint64_t>(k.first) ^ (static_cast<uint64_t>(k.second) << 12);
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace contractor
|
|
|
|
{
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
int Contractor::Run()
|
2014-07-03 07:29:15 -04:00
|
|
|
{
|
2015-04-21 04:43:02 -04:00
|
|
|
#ifdef WIN32
|
|
|
|
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
|
|
|
|
#else
|
2016-03-01 16:30:31 -05:00
|
|
|
static_assert(sizeof(extractor::NodeBasedEdge) == 20,
|
2016-01-05 10:51:13 -05:00
|
|
|
"changing extractor::NodeBasedEdge type has influence on memory consumption!");
|
|
|
|
static_assert(sizeof(extractor::EdgeBasedEdge) == 16,
|
2015-04-21 04:43:02 -04:00
|
|
|
"changing EdgeBasedEdge type has influence on memory consumption!");
|
|
|
|
#endif
|
|
|
|
|
2016-01-05 06:04:04 -05:00
|
|
|
if (config.core_factor > 1.0 || config.core_factor < 0)
|
2015-10-14 18:08:22 -04:00
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
|
2015-10-14 18:08:22 -04:00
|
|
|
}
|
|
|
|
|
2014-07-03 07:29:15 -04:00
|
|
|
TIMER_START(preparing);
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Loading edge-expanded graph representation";
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
2015-07-04 11:37:24 -04:00
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
std::size_t max_edge_id = LoadEdgeExpandedGraph(
|
2016-02-23 15:23:13 -05:00
|
|
|
config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
|
2016-03-15 02:03:19 -04:00
|
|
|
config.edge_penalty_path, config.segment_speed_lookup_paths, config.node_based_graph_path,
|
|
|
|
config.geometry_path, config.datasource_names_path, config.datasource_indexes_path,
|
|
|
|
config.rtree_leaf_path);
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2015-04-23 11:48:41 -04:00
|
|
|
// Contracting the edge-expanded graph
|
2014-07-03 07:29:15 -04:00
|
|
|
|
|
|
|
TIMER_START(contraction);
|
2015-08-08 09:28:05 -04:00
|
|
|
std::vector<bool> is_core_node;
|
2015-11-09 15:14:39 -05:00
|
|
|
std::vector<float> node_levels;
|
|
|
|
if (config.use_cached_priority)
|
|
|
|
{
|
|
|
|
ReadNodeLevels(node_levels);
|
|
|
|
}
|
2016-01-07 04:33:47 -05:00
|
|
|
|
|
|
|
util::SimpleLogger().Write() << "Reading node weights.";
|
|
|
|
std::vector<EdgeWeight> node_weights;
|
|
|
|
std::string node_file_name = config.osrm_input_path.string() + ".enw";
|
|
|
|
if (util::deserializeVector(node_file_name, node_weights))
|
2016-01-20 22:00:12 -05:00
|
|
|
{
|
2016-01-07 04:33:47 -05:00
|
|
|
util::SimpleLogger().Write() << "Done reading node weights.";
|
2016-01-20 22:00:12 -05:00
|
|
|
}
|
2016-01-07 04:33:47 -05:00
|
|
|
else
|
2016-01-20 22:00:12 -05:00
|
|
|
{
|
|
|
|
throw util::exception("Failed reading node weights.");
|
|
|
|
}
|
2016-01-07 04:33:47 -05:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::DeallocatingVector<QueryEdge> contracted_edge_list;
|
2016-01-07 04:33:47 -05:00
|
|
|
ContractGraph(max_edge_id, edge_based_edge_list, contracted_edge_list, std::move(node_weights),
|
|
|
|
is_core_node, node_levels);
|
2014-07-03 07:29:15 -04:00
|
|
|
TIMER_STOP(contraction);
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2015-10-14 18:08:22 -04:00
|
|
|
std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
|
2015-08-08 09:28:05 -04:00
|
|
|
WriteCoreNodeMarker(std::move(is_core_node));
|
2015-11-09 15:14:39 -05:00
|
|
|
if (!config.use_cached_priority)
|
|
|
|
{
|
|
|
|
WriteNodeLevels(std::move(node_levels));
|
|
|
|
}
|
2015-04-23 12:53:36 -04:00
|
|
|
|
|
|
|
TIMER_STOP(preparing);
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
|
|
|
|
util::SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
|
2016-01-07 19:31:57 -05:00
|
|
|
<< " nodes/sec and "
|
|
|
|
<< number_of_used_edges / TIMER_SEC(contraction) << " edges/sec";
|
2015-04-23 12:53:36 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "finished preprocessing";
|
2015-04-23 12:53:36 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
std::size_t Contractor::LoadEdgeExpandedGraph(
|
2016-01-07 19:31:57 -05:00
|
|
|
std::string const &edge_based_graph_filename,
|
|
|
|
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
|
|
|
const std::string &edge_segment_lookup_filename,
|
|
|
|
const std::string &edge_penalty_filename,
|
2016-03-15 02:03:19 -04:00
|
|
|
const std::vector<std::string> &segment_speed_filenames,
|
2016-01-29 20:52:20 -05:00
|
|
|
const std::string &nodes_filename,
|
|
|
|
const std::string &geometry_filename,
|
2016-03-15 02:03:19 -04:00
|
|
|
const std::string &datasource_names_filename,
|
|
|
|
const std::string &datasource_indexes_filename,
|
2016-01-29 20:52:20 -05:00
|
|
|
const std::string &rtree_leaf_filename)
|
2015-07-04 11:37:24 -04:00
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
|
2015-10-14 18:08:22 -04:00
|
|
|
boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::binary);
|
|
|
|
|
2016-03-15 02:03:19 -04:00
|
|
|
const bool update_edge_weights = !segment_speed_filenames.empty();
|
2015-10-14 18:08:22 -04:00
|
|
|
|
|
|
|
boost::filesystem::ifstream edge_segment_input_stream;
|
|
|
|
boost::filesystem::ifstream edge_fixed_penalties_input_stream;
|
|
|
|
|
|
|
|
if (update_edge_weights)
|
|
|
|
{
|
|
|
|
edge_segment_input_stream.open(edge_segment_lookup_filename, std::ios::binary);
|
|
|
|
edge_fixed_penalties_input_stream.open(edge_penalty_filename, std::ios::binary);
|
|
|
|
if (!edge_segment_input_stream || !edge_fixed_penalties_input_stream)
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
throw util::exception("Could not load .edge_segment_lookup or .edge_penalties, did you "
|
2015-10-14 18:08:22 -04:00
|
|
|
"run osrm-extract with '--generate-edge-lookup'?");
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
|
|
|
|
util::FingerPrint fingerprint_loaded;
|
|
|
|
input_stream.read((char *)&fingerprint_loaded, sizeof(util::FingerPrint));
|
2016-01-07 13:19:55 -05:00
|
|
|
fingerprint_loaded.TestContractor(fingerprint_valid);
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
// TODO std::size_t can vary on systems. Our files are not transferable, but we might want to
|
|
|
|
// consider using a fixed size type for I/O
|
|
|
|
std::size_t number_of_edges = 0;
|
|
|
|
std::size_t max_edge_id = SPECIAL_EDGEID;
|
|
|
|
input_stream.read((char *)&number_of_edges, sizeof(std::size_t));
|
|
|
|
input_stream.read((char *)&max_edge_id, sizeof(std::size_t));
|
2015-10-01 15:47:29 -04:00
|
|
|
|
|
|
|
edge_based_edge_list.resize(number_of_edges);
|
2016-01-07 19:31:57 -05:00
|
|
|
util::SimpleLogger().Write() << "Reading " << number_of_edges
|
|
|
|
<< " edges from the edge based graph";
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-03-15 02:03:19 -04:00
|
|
|
std::unordered_map<std::pair<OSMNodeID, OSMNodeID>, std::pair<unsigned, uint8_t>>
|
|
|
|
segment_speed_lookup;
|
2015-10-14 18:08:22 -04:00
|
|
|
|
|
|
|
if (update_edge_weights)
|
|
|
|
{
|
2016-03-15 02:03:19 -04:00
|
|
|
uint8_t file_id = 1;
|
|
|
|
for (auto segment_speed_filename : segment_speed_filenames)
|
2015-10-14 18:08:22 -04:00
|
|
|
{
|
2016-03-15 02:03:19 -04:00
|
|
|
util::SimpleLogger().Write()
|
|
|
|
<< "Segment speed data supplied, will update edge weights from "
|
|
|
|
<< segment_speed_filename;
|
|
|
|
io::CSVReader<3> csv_in(segment_speed_filename);
|
|
|
|
csv_in.set_header("from_node", "to_node", "speed");
|
|
|
|
uint64_t from_node_id{};
|
|
|
|
uint64_t to_node_id{};
|
|
|
|
unsigned speed{};
|
|
|
|
while (csv_in.read_row(from_node_id, to_node_id, speed))
|
|
|
|
{
|
|
|
|
segment_speed_lookup[std::make_pair(OSMNodeID(from_node_id),
|
|
|
|
OSMNodeID(to_node_id))] =
|
|
|
|
std::make_pair(speed, file_id);
|
|
|
|
}
|
|
|
|
++file_id;
|
|
|
|
|
|
|
|
// Check for overflow
|
|
|
|
if (file_id == 0)
|
|
|
|
{
|
|
|
|
throw util::exception(
|
|
|
|
"Sorry, there's a limit of 254 segment speed files, you supplied too many");
|
|
|
|
}
|
2015-10-14 18:08:22 -04:00
|
|
|
}
|
2016-01-29 20:52:20 -05:00
|
|
|
|
|
|
|
std::vector<extractor::QueryNode> internal_to_external_node_map;
|
|
|
|
|
|
|
|
// Here, we have to update the compressed geometry weights
|
|
|
|
// First, we need the external-to-internal node lookup table
|
|
|
|
{
|
|
|
|
boost::filesystem::ifstream nodes_input_stream(nodes_filename, std::ios::binary);
|
|
|
|
|
|
|
|
if (!nodes_input_stream)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
throw util::exception("Failed to open " + nodes_filename);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned number_of_nodes = 0;
|
|
|
|
nodes_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
|
|
|
|
internal_to_external_node_map.resize(number_of_nodes);
|
|
|
|
|
|
|
|
// Load all the query nodes into a vector
|
2016-02-23 15:23:13 -05:00
|
|
|
nodes_input_stream.read(reinterpret_cast<char *>(&(internal_to_external_node_map[0])),
|
|
|
|
number_of_nodes * sizeof(extractor::QueryNode));
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<unsigned> m_geometry_indices;
|
|
|
|
std::vector<extractor::CompressedEdgeContainer::CompressedEdge> m_geometry_list;
|
|
|
|
|
|
|
|
{
|
|
|
|
std::ifstream geometry_stream(geometry_filename, std::ios::binary);
|
|
|
|
if (!geometry_stream)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
throw util::exception("Failed to open " + geometry_filename);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
unsigned number_of_indices = 0;
|
|
|
|
unsigned number_of_compressed_geometries = 0;
|
|
|
|
|
|
|
|
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
|
|
|
|
|
|
|
|
m_geometry_indices.resize(number_of_indices);
|
|
|
|
if (number_of_indices > 0)
|
|
|
|
{
|
|
|
|
geometry_stream.read((char *)&(m_geometry_indices[0]),
|
2016-02-23 15:23:13 -05:00
|
|
|
number_of_indices * sizeof(unsigned));
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
|
|
|
|
|
|
|
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
|
|
|
|
m_geometry_list.resize(number_of_compressed_geometries);
|
2016-02-23 15:23:13 -05:00
|
|
|
|
2016-01-29 20:52:20 -05:00
|
|
|
if (number_of_compressed_geometries > 0)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
geometry_stream.read(
|
|
|
|
(char *)&(m_geometry_list[0]),
|
|
|
|
number_of_compressed_geometries *
|
|
|
|
sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 02:03:19 -04:00
|
|
|
// This is a list of the "data source id" for every segment in the compressed
|
|
|
|
// geometry container. We assume that everything so far has come from the
|
|
|
|
// profile (data source 0). Here, we replace the 0's with the index of the
|
|
|
|
// CSV file that supplied the value that gets used for that segment, then
|
|
|
|
// we write out this list so that it can be returned by the debugging
|
|
|
|
// vector tiles later on.
|
|
|
|
std::vector<uint8_t> m_geometry_datasource(m_geometry_list.size(), 0);
|
|
|
|
|
2016-01-29 20:52:20 -05:00
|
|
|
// Now, we iterate over all the segments stored in the StaticRTree, updating
|
|
|
|
// the packed geometry weights in the `.geometries` file (note: we do not
|
|
|
|
// update the RTree itself, we just use the leaf nodes to iterate over all segments)
|
|
|
|
{
|
|
|
|
|
|
|
|
using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
|
|
|
|
|
|
|
|
std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in);
|
|
|
|
if (!leaf_node_file)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
throw util::exception("Failed to open " + rtree_leaf_filename);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
uint64_t m_element_count;
|
|
|
|
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
|
|
|
|
|
|
|
|
LeafNode current_node;
|
|
|
|
while (m_element_count > 0)
|
|
|
|
{
|
|
|
|
leaf_node_file.read(reinterpret_cast<char *>(¤t_node), sizeof(current_node));
|
|
|
|
|
2016-02-23 15:23:13 -05:00
|
|
|
for (size_t i = 0; i < current_node.object_count; i++)
|
2016-01-29 20:52:20 -05:00
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
auto &leaf_object = current_node.objects[i];
|
2016-01-29 20:52:20 -05:00
|
|
|
extractor::QueryNode *u;
|
|
|
|
extractor::QueryNode *v;
|
|
|
|
|
|
|
|
if (leaf_object.forward_packed_geometry_id != SPECIAL_EDGEID)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
const unsigned forward_begin =
|
|
|
|
m_geometry_indices.at(leaf_object.forward_packed_geometry_id);
|
2016-01-29 20:52:20 -05:00
|
|
|
|
|
|
|
if (leaf_object.fwd_segment_position == 0)
|
|
|
|
{
|
|
|
|
u = &(internal_to_external_node_map[leaf_object.u]);
|
2016-02-23 15:23:13 -05:00
|
|
|
v = &(internal_to_external_node_map[m_geometry_list[forward_begin]
|
|
|
|
.node_id]);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
u = &(internal_to_external_node_map
|
|
|
|
[m_geometry_list[forward_begin +
|
|
|
|
leaf_object.fwd_segment_position - 1]
|
|
|
|
.node_id]);
|
|
|
|
v = &(internal_to_external_node_map
|
|
|
|
[m_geometry_list[forward_begin +
|
|
|
|
leaf_object.fwd_segment_position]
|
|
|
|
.node_id]);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
const double segment_length =
|
2016-02-23 15:23:13 -05:00
|
|
|
util::coordinate_calculation::greatCircleDistance(
|
|
|
|
util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
|
2016-01-29 20:52:20 -05:00
|
|
|
|
2016-02-23 15:23:13 -05:00
|
|
|
auto forward_speed_iter =
|
|
|
|
segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
|
2016-01-29 20:52:20 -05:00
|
|
|
if (forward_speed_iter != segment_speed_lookup.end())
|
|
|
|
{
|
2016-03-15 02:03:19 -04:00
|
|
|
int new_segment_weight =
|
|
|
|
std::max(1, static_cast<int>(std::floor(
|
|
|
|
(segment_length * 10.) /
|
|
|
|
(forward_speed_iter->second.first / 3.6) +
|
|
|
|
.5)));
|
2016-02-23 15:23:13 -05:00
|
|
|
m_geometry_list[forward_begin + leaf_object.fwd_segment_position]
|
|
|
|
.weight = new_segment_weight;
|
2016-03-15 02:03:19 -04:00
|
|
|
m_geometry_datasource[forward_begin +
|
|
|
|
leaf_object.fwd_segment_position] =
|
|
|
|
forward_speed_iter->second.second;
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
const unsigned reverse_begin =
|
|
|
|
m_geometry_indices.at(leaf_object.reverse_packed_geometry_id);
|
|
|
|
const unsigned reverse_end =
|
|
|
|
m_geometry_indices.at(leaf_object.reverse_packed_geometry_id + 1);
|
2016-01-29 20:52:20 -05:00
|
|
|
|
2016-02-23 15:23:13 -05:00
|
|
|
int rev_segment_position =
|
|
|
|
(reverse_end - reverse_begin) - leaf_object.fwd_segment_position - 1;
|
2016-01-29 20:52:20 -05:00
|
|
|
if (rev_segment_position == 0)
|
|
|
|
{
|
|
|
|
u = &(internal_to_external_node_map[leaf_object.v]);
|
2016-02-23 15:23:13 -05:00
|
|
|
v = &(internal_to_external_node_map[m_geometry_list[reverse_begin]
|
|
|
|
.node_id]);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
u = &(internal_to_external_node_map
|
|
|
|
[m_geometry_list[reverse_begin + rev_segment_position - 1]
|
|
|
|
.node_id]);
|
|
|
|
v = &(
|
|
|
|
internal_to_external_node_map[m_geometry_list[reverse_begin +
|
|
|
|
rev_segment_position]
|
|
|
|
.node_id]);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
const double segment_length =
|
2016-02-23 15:23:13 -05:00
|
|
|
util::coordinate_calculation::greatCircleDistance(
|
|
|
|
util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
|
2016-01-29 20:52:20 -05:00
|
|
|
|
2016-02-23 15:23:13 -05:00
|
|
|
auto reverse_speed_iter =
|
|
|
|
segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
|
2016-01-29 20:52:20 -05:00
|
|
|
if (reverse_speed_iter != segment_speed_lookup.end())
|
|
|
|
{
|
2016-03-15 02:03:19 -04:00
|
|
|
int new_segment_weight =
|
|
|
|
std::max(1, static_cast<int>(std::floor(
|
|
|
|
(segment_length * 10.) /
|
|
|
|
(reverse_speed_iter->second.first / 3.6) +
|
|
|
|
.5)));
|
2016-02-23 15:23:13 -05:00
|
|
|
m_geometry_list[reverse_begin + rev_segment_position].weight =
|
|
|
|
new_segment_weight;
|
2016-03-15 02:03:19 -04:00
|
|
|
m_geometry_datasource[reverse_begin + rev_segment_position] =
|
|
|
|
reverse_speed_iter->second.second;
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_element_count -= current_node.object_count;
|
|
|
|
}
|
|
|
|
}
|
2016-02-23 15:23:13 -05:00
|
|
|
|
2016-01-29 20:52:20 -05:00
|
|
|
// Now save out the updated compressed geometries
|
|
|
|
{
|
|
|
|
std::ofstream geometry_stream(geometry_filename, std::ios::binary);
|
|
|
|
if (!geometry_stream)
|
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
throw util::exception("Failed to open " + geometry_filename + " for writing");
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
const unsigned number_of_indices = m_geometry_indices.size();
|
|
|
|
const unsigned number_of_compressed_geometries = m_geometry_list.size();
|
2016-02-23 15:23:13 -05:00
|
|
|
geometry_stream.write(reinterpret_cast<const char *>(&number_of_indices),
|
|
|
|
sizeof(unsigned));
|
|
|
|
geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_indices[0])),
|
|
|
|
number_of_indices * sizeof(unsigned));
|
|
|
|
geometry_stream.write(reinterpret_cast<const char *>(&number_of_compressed_geometries),
|
|
|
|
sizeof(unsigned));
|
|
|
|
geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_list[0])),
|
|
|
|
number_of_compressed_geometries *
|
|
|
|
sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
2016-03-15 02:03:19 -04:00
|
|
|
|
|
|
|
{
|
|
|
|
std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
|
|
|
|
if (!datasource_stream)
|
|
|
|
{
|
|
|
|
throw util::exception("Failed to open " + datasource_indexes_filename +
|
|
|
|
" for writing");
|
|
|
|
}
|
|
|
|
auto number_of_datasource_entries = m_geometry_datasource.size();
|
|
|
|
datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries),
|
|
|
|
sizeof(number_of_datasource_entries));
|
|
|
|
datasource_stream.write(reinterpret_cast<char *>(&(m_geometry_datasource[0])),
|
|
|
|
number_of_datasource_entries * sizeof(uint8_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
|
|
|
|
if (!datasource_stream)
|
|
|
|
{
|
|
|
|
throw util::exception("Failed to open " + datasource_names_filename +
|
|
|
|
" for writing");
|
|
|
|
}
|
|
|
|
datasource_stream << "lua profile" << std::endl;
|
|
|
|
for (auto const &name : segment_speed_filenames)
|
|
|
|
{
|
|
|
|
datasource_stream << name << std::endl;
|
|
|
|
}
|
|
|
|
}
|
2015-10-14 18:08:22 -04:00
|
|
|
}
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
// TODO: can we read this in bulk? util::DeallocatingVector isn't necessarily
|
2015-10-01 15:47:29 -04:00
|
|
|
// all stored contiguously
|
2015-10-14 18:08:22 -04:00
|
|
|
for (; number_of_edges > 0; --number_of_edges)
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
extractor::EdgeBasedEdge inbuffer;
|
|
|
|
input_stream.read((char *)&inbuffer, sizeof(extractor::EdgeBasedEdge));
|
2015-10-14 18:08:22 -04:00
|
|
|
if (update_edge_weights)
|
|
|
|
{
|
|
|
|
// Processing-time edge updates
|
|
|
|
unsigned fixed_penalty;
|
|
|
|
edge_fixed_penalties_input_stream.read(reinterpret_cast<char *>(&fixed_penalty),
|
|
|
|
sizeof(fixed_penalty));
|
|
|
|
|
|
|
|
int new_weight = 0;
|
|
|
|
|
|
|
|
unsigned num_osm_nodes = 0;
|
|
|
|
edge_segment_input_stream.read(reinterpret_cast<char *>(&num_osm_nodes),
|
|
|
|
sizeof(num_osm_nodes));
|
2015-11-24 19:33:19 -05:00
|
|
|
OSMNodeID previous_osm_node_id;
|
2015-10-14 18:08:22 -04:00
|
|
|
edge_segment_input_stream.read(reinterpret_cast<char *>(&previous_osm_node_id),
|
|
|
|
sizeof(previous_osm_node_id));
|
2015-11-24 19:33:19 -05:00
|
|
|
OSMNodeID this_osm_node_id;
|
2015-10-14 18:08:22 -04:00
|
|
|
double segment_length;
|
|
|
|
int segment_weight;
|
|
|
|
--num_osm_nodes;
|
|
|
|
for (; num_osm_nodes != 0; --num_osm_nodes)
|
|
|
|
{
|
|
|
|
edge_segment_input_stream.read(reinterpret_cast<char *>(&this_osm_node_id),
|
|
|
|
sizeof(this_osm_node_id));
|
|
|
|
edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_length),
|
|
|
|
sizeof(segment_length));
|
|
|
|
edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight),
|
|
|
|
sizeof(segment_weight));
|
|
|
|
|
|
|
|
auto speed_iter = segment_speed_lookup.find(
|
2015-11-24 19:33:19 -05:00
|
|
|
std::make_pair(previous_osm_node_id, this_osm_node_id));
|
2015-10-14 18:08:22 -04:00
|
|
|
if (speed_iter != segment_speed_lookup.end())
|
|
|
|
{
|
|
|
|
// This sets the segment weight using the same formula as the
|
|
|
|
// EdgeBasedGraphFactory for consistency. The *why* of this formula
|
|
|
|
// is lost in the annals of time.
|
2016-03-15 02:03:19 -04:00
|
|
|
int new_segment_weight = std::max(
|
|
|
|
1, static_cast<int>(std::floor(
|
|
|
|
(segment_length * 10.) / (speed_iter->second.first / 3.6) + .5)));
|
2015-10-14 18:08:22 -04:00
|
|
|
new_weight += new_segment_weight;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If no lookup found, use the original weight value for this segment
|
|
|
|
new_weight += segment_weight;
|
|
|
|
}
|
|
|
|
|
|
|
|
previous_osm_node_id = this_osm_node_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
inbuffer.weight = fixed_penalty + new_weight;
|
|
|
|
}
|
|
|
|
|
2015-10-01 15:47:29 -04:00
|
|
|
edge_based_edge_list.emplace_back(std::move(inbuffer));
|
2015-07-04 11:37:24 -04:00
|
|
|
}
|
2015-10-14 18:08:22 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Done reading edges";
|
2015-10-01 15:47:29 -04:00
|
|
|
return max_edge_id;
|
2015-07-04 11:37:24 -04:00
|
|
|
}
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
void Contractor::ReadNodeLevels(std::vector<float> &node_levels) const
|
2015-11-09 15:14:39 -05:00
|
|
|
{
|
2015-10-14 18:08:22 -04:00
|
|
|
boost::filesystem::ifstream order_input_stream(config.level_output_path, std::ios::binary);
|
2015-11-09 15:14:39 -05:00
|
|
|
|
|
|
|
unsigned level_size;
|
|
|
|
order_input_stream.read((char *)&level_size, sizeof(unsigned));
|
|
|
|
node_levels.resize(level_size);
|
2015-10-14 18:08:22 -04:00
|
|
|
order_input_stream.read((char *)node_levels.data(), sizeof(float) * node_levels.size());
|
2015-11-09 15:14:39 -05:00
|
|
|
}
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
void Contractor::WriteNodeLevels(std::vector<float> &&in_node_levels) const
|
2015-11-09 15:14:39 -05:00
|
|
|
{
|
|
|
|
std::vector<float> node_levels(std::move(in_node_levels));
|
|
|
|
|
2015-10-14 18:08:22 -04:00
|
|
|
boost::filesystem::ofstream order_output_stream(config.level_output_path, std::ios::binary);
|
2015-11-09 15:14:39 -05:00
|
|
|
|
|
|
|
unsigned level_size = node_levels.size();
|
|
|
|
order_output_stream.write((char *)&level_size, sizeof(unsigned));
|
2015-10-14 18:08:22 -04:00
|
|
|
order_output_stream.write((char *)node_levels.data(), sizeof(float) * node_levels.size());
|
2015-11-09 15:14:39 -05:00
|
|
|
}
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
void Contractor::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
|
2015-08-08 09:28:05 -04:00
|
|
|
{
|
2015-11-09 15:14:39 -05:00
|
|
|
std::vector<bool> is_core_node(std::move(in_is_core_node));
|
|
|
|
std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
|
2015-08-08 09:28:05 -04:00
|
|
|
for (auto i = 0u; i < is_core_node.size(); ++i)
|
|
|
|
{
|
|
|
|
unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2015-09-09 12:34:09 -04:00
|
|
|
boost::filesystem::ofstream core_marker_output_stream(config.core_output_path,
|
|
|
|
std::ios::binary);
|
2015-08-09 12:30:04 -04:00
|
|
|
unsigned size = unpacked_bool_flags.size();
|
|
|
|
core_marker_output_stream.write((char *)&size, sizeof(unsigned));
|
2015-09-09 12:34:09 -04:00
|
|
|
core_marker_output_stream.write((char *)unpacked_bool_flags.data(),
|
|
|
|
sizeof(char) * unpacked_bool_flags.size());
|
2015-08-08 09:28:05 -04:00
|
|
|
}
|
|
|
|
|
2016-01-07 19:31:57 -05:00
|
|
|
std::size_t
|
2016-01-07 13:19:55 -05:00
|
|
|
Contractor::WriteContractedGraph(unsigned max_node_id,
|
2016-02-26 06:29:57 -05:00
|
|
|
const util::DeallocatingVector<QueryEdge> &contracted_edge_list)
|
2015-04-23 12:53:36 -04:00
|
|
|
{
|
|
|
|
// Sorting contracted edges in a way that the static query graph can read some in in-place.
|
2015-09-10 05:04:50 -04:00
|
|
|
tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
|
2015-09-09 12:34:09 -04:00
|
|
|
const unsigned contracted_edge_count = contracted_edge_list.size();
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
|
2016-01-07 19:31:57 -05:00
|
|
|
<< " edges";
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
|
2015-04-24 08:51:25 -04:00
|
|
|
boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
|
2016-01-05 10:51:13 -05:00
|
|
|
hsgr_output_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
|
2015-07-01 11:55:54 -04:00
|
|
|
const unsigned max_used_node_id = [&contracted_edge_list]
|
2014-08-07 07:40:43 -04:00
|
|
|
{
|
2014-08-07 06:02:57 -04:00
|
|
|
unsigned tmp_max = 0;
|
2015-09-09 12:34:09 -04:00
|
|
|
for (const QueryEdge &edge : contracted_edge_list)
|
2014-08-07 06:02:57 -04:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != edge.source);
|
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != edge.target);
|
|
|
|
tmp_max = std::max(tmp_max, edge.source);
|
|
|
|
tmp_max = std::max(tmp_max, edge.target);
|
|
|
|
}
|
|
|
|
return tmp_max;
|
|
|
|
}();
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
|
2016-01-07 19:31:57 -05:00
|
|
|
util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1)
|
|
|
|
<< " nodes";
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
|
2015-07-01 11:55:54 -04:00
|
|
|
// make sure we have at least one sentinel
|
|
|
|
node_array.resize(max_node_id + 2);
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Building node array";
|
|
|
|
util::StaticGraph<EdgeData>::EdgeIterator edge = 0;
|
|
|
|
util::StaticGraph<EdgeData>::EdgeIterator position = 0;
|
|
|
|
util::StaticGraph<EdgeData>::EdgeIterator last_edge;
|
2014-07-03 07:29:15 -04:00
|
|
|
|
|
|
|
// initializing 'first_edge'-field of nodes:
|
2016-01-05 10:51:13 -05:00
|
|
|
for (const auto node : util::irange(0u, max_used_node_id + 1))
|
2014-07-03 07:29:15 -04:00
|
|
|
{
|
|
|
|
last_edge = edge;
|
2015-09-09 12:34:09 -04:00
|
|
|
while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
|
2014-07-03 07:29:15 -04:00
|
|
|
{
|
|
|
|
++edge;
|
|
|
|
}
|
|
|
|
node_array[node].first_edge = position; //=edge
|
|
|
|
position += edge - last_edge; // remove
|
|
|
|
}
|
|
|
|
|
2015-09-09 12:34:09 -04:00
|
|
|
for (const auto sentinel_counter :
|
2016-01-05 10:51:13 -05:00
|
|
|
util::irange<unsigned>(max_used_node_id + 1, node_array.size()))
|
2014-07-03 07:29:15 -04:00
|
|
|
{
|
|
|
|
// sentinel element, guarded against underflow
|
|
|
|
node_array[sentinel_counter].first_edge = contracted_edge_count;
|
|
|
|
}
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Serializing node array";
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2015-10-01 15:47:29 -04:00
|
|
|
RangebasedCRC32 crc32_calculator;
|
|
|
|
const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
|
2015-10-01 15:47:29 -04:00
|
|
|
|
2014-07-03 07:29:15 -04:00
|
|
|
const unsigned node_array_size = node_array.size();
|
|
|
|
// serialize crc32, aka checksum
|
2015-10-01 15:47:29 -04:00
|
|
|
hsgr_output_stream.write((char *)&edges_crc32, sizeof(unsigned));
|
2014-07-03 07:29:15 -04:00
|
|
|
// serialize number of nodes
|
|
|
|
hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
|
|
|
|
// serialize number of edges
|
|
|
|
hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
|
|
|
|
// serialize all nodes
|
|
|
|
if (node_array_size > 0)
|
|
|
|
{
|
|
|
|
hsgr_output_stream.write((char *)&node_array[0],
|
2016-01-07 19:31:57 -05:00
|
|
|
sizeof(util::StaticGraph<EdgeData>::NodeArrayEntry) *
|
|
|
|
node_array_size);
|
2014-07-03 07:29:15 -04:00
|
|
|
}
|
|
|
|
|
2015-04-23 11:48:41 -04:00
|
|
|
// serialize all edges
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Building edge array";
|
2014-07-03 07:29:15 -04:00
|
|
|
int number_of_used_edges = 0;
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
|
|
|
|
for (const auto edge : util::irange<std::size_t>(0, contracted_edge_list.size()))
|
2014-07-03 07:29:15 -04:00
|
|
|
{
|
2016-01-07 04:33:47 -05:00
|
|
|
// some self-loops are required for oneway handling. Need to assertthat we only keep these
|
|
|
|
// (TODO)
|
2014-07-03 07:29:15 -04:00
|
|
|
// no eigen loops
|
2016-01-07 04:33:47 -05:00
|
|
|
// BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target ||
|
|
|
|
// node_represents_oneway[contracted_edge_list[edge].source]);
|
2015-09-09 12:34:09 -04:00
|
|
|
current_edge.target = contracted_edge_list[edge].target;
|
|
|
|
current_edge.data = contracted_edge_list[edge].data;
|
2014-07-03 07:29:15 -04:00
|
|
|
|
|
|
|
// every target needs to be valid
|
2015-07-01 11:55:54 -04:00
|
|
|
BOOST_ASSERT(current_edge.target <= max_used_node_id);
|
2014-07-03 07:29:15 -04:00
|
|
|
#ifndef NDEBUG
|
|
|
|
if (current_edge.data.distance <= 0)
|
|
|
|
{
|
2016-01-07 19:31:57 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
|
|
|
|
<< ", target: " << contracted_edge_list[edge].target
|
|
|
|
<< ", dist: " << current_edge.data.distance;
|
2014-07-03 07:29:15 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
|
2016-01-07 19:31:57 -05:00
|
|
|
<< contracted_edge_list[edge].source << "/"
|
|
|
|
<< node_array.size() - 1;
|
2014-07-03 07:29:15 -04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
hsgr_output_stream.write((char *)¤t_edge,
|
2016-01-05 10:51:13 -05:00
|
|
|
sizeof(util::StaticGraph<EdgeData>::EdgeArrayEntry));
|
2014-07-03 07:29:15 -04:00
|
|
|
|
|
|
|
++number_of_used_edges;
|
|
|
|
}
|
|
|
|
|
2015-04-23 12:53:36 -04:00
|
|
|
return number_of_used_edges;
|
2014-07-03 07:29:15 -04:00
|
|
|
}
|
|
|
|
|
2015-04-23 11:48:41 -04:00
|
|
|
/**
|
|
|
|
\brief Build contracted graph.
|
|
|
|
*/
|
2016-01-07 13:19:55 -05:00
|
|
|
void Contractor::ContractGraph(
|
2016-01-07 19:31:57 -05:00
|
|
|
const unsigned max_edge_id,
|
|
|
|
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
|
|
|
util::DeallocatingVector<QueryEdge> &contracted_edge_list,
|
2016-01-07 04:33:47 -05:00
|
|
|
std::vector<EdgeWeight> &&node_weights,
|
2016-01-07 19:31:57 -05:00
|
|
|
std::vector<bool> &is_core_node,
|
|
|
|
std::vector<float> &inout_node_levels) const
|
2015-04-23 11:48:41 -04:00
|
|
|
{
|
2015-11-09 15:14:39 -05:00
|
|
|
std::vector<float> node_levels;
|
|
|
|
node_levels.swap(inout_node_levels);
|
|
|
|
|
2016-01-07 13:19:55 -05:00
|
|
|
GraphContractor graph_contractor(max_edge_id + 1, edge_based_edge_list, std::move(node_levels),
|
2016-02-26 06:29:57 -05:00
|
|
|
std::move(node_weights));
|
2016-01-07 13:19:55 -05:00
|
|
|
graph_contractor.Run(config.core_factor);
|
|
|
|
graph_contractor.GetEdges(contracted_edge_list);
|
|
|
|
graph_contractor.GetCoreMarker(is_core_node);
|
|
|
|
graph_contractor.GetNodeLevels(inout_node_levels);
|
2015-04-23 11:48:41 -04:00
|
|
|
}
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
|
|
|
}
|