Refactor edge expansion into extract phase. New temporary file is generated - '.osrm.ebg' which is used by
This commit is contained in:
@@ -48,9 +48,6 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
|
||||
// declare a group of options that will be allowed both on command line and in config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()(
|
||||
"restrictions,r",
|
||||
boost::program_options::value<boost::filesystem::path>(&contractor_config.restrictions_path),
|
||||
"Restrictions file in .osrm.restrictions format")(
|
||||
"profile,p", boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
|
||||
->default_value("profile.lua"),
|
||||
"Path to LUA routing profile")(
|
||||
@@ -114,11 +111,6 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
|
||||
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
if (!option_variables.count("restrictions"))
|
||||
{
|
||||
contractor_config.restrictions_path = contractor_config.osrm_input_path.string() + ".restrictions";
|
||||
}
|
||||
|
||||
if (!option_variables.count("input"))
|
||||
{
|
||||
SimpleLogger().Write() << "\n" << visible_options;
|
||||
@@ -130,11 +122,7 @@ ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &cont
|
||||
|
||||
void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
|
||||
{
|
||||
contractor_config.node_output_path = contractor_config.osrm_input_path.string() + ".nodes";
|
||||
contractor_config.core_output_path = contractor_config.osrm_input_path.string() + ".core";
|
||||
contractor_config.edge_output_path = contractor_config.osrm_input_path.string() + ".edges";
|
||||
contractor_config.geometry_output_path = contractor_config.osrm_input_path.string() + ".geometry";
|
||||
contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
|
||||
contractor_config.rtree_nodes_output_path = contractor_config.osrm_input_path.string() + ".ramIndex";
|
||||
contractor_config.rtree_leafs_output_path = contractor_config.osrm_input_path.string() + ".fileIndex";
|
||||
contractor_config.edge_based_graph_path = contractor_config.osrm_input_path.string() + ".ebg";
|
||||
}
|
||||
|
||||
@@ -45,16 +45,11 @@ struct ContractorConfig
|
||||
|
||||
boost::filesystem::path config_file_path;
|
||||
boost::filesystem::path osrm_input_path;
|
||||
boost::filesystem::path restrictions_path;
|
||||
boost::filesystem::path profile_path;
|
||||
|
||||
std::string node_output_path;
|
||||
std::string core_output_path;
|
||||
std::string edge_output_path;
|
||||
std::string geometry_output_path;
|
||||
std::string graph_output_path;
|
||||
std::string rtree_nodes_output_path;
|
||||
std::string rtree_leafs_output_path;
|
||||
std::string edge_based_graph_path;
|
||||
|
||||
unsigned requested_num_threads;
|
||||
|
||||
|
||||
@@ -1,562 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "edge_based_graph_factory.hpp"
|
||||
#include "../data_structures/percent.hpp"
|
||||
#include "../util/compute_angle.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/lua_util.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
std::shared_ptr<const RestrictionMap> restriction_map,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
SpeedProfileProperties speed_profile)
|
||||
: m_max_edge_id(0), m_node_info_list(node_info_list), m_node_based_graph(std::move(node_based_graph)),
|
||||
m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
|
||||
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
||||
speed_profile(std::move(speed_profile))
|
||||
{
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
|
||||
{
|
||||
BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
|
||||
m_edge_based_edge_list.swap(output_edge_list);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (const EdgeBasedNode &node : m_edge_based_node_list)
|
||||
{
|
||||
BOOST_ASSERT(m_node_info_list.at(node.u).lat != INT_MAX);
|
||||
BOOST_ASSERT(m_node_info_list.at(node.u).lon != INT_MAX);
|
||||
BOOST_ASSERT(m_node_info_list.at(node.v).lon != INT_MAX);
|
||||
BOOST_ASSERT(m_node_info_list.at(node.v).lat != INT_MAX);
|
||||
}
|
||||
#endif
|
||||
nodes.swap(m_edge_based_node_list);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetHighestEdgeID()
|
||||
{
|
||||
return m_max_edge_id;
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
|
||||
const NodeID node_v)
|
||||
{
|
||||
// merge edges together into one EdgeBasedNode
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
// find forward edge id and
|
||||
const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
|
||||
|
||||
// find reverse edge id and
|
||||
const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
|
||||
BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
|
||||
|
||||
if (forward_data.edge_id == SPECIAL_NODEID &&
|
||||
reverse_data.edge_id == SPECIAL_NODEID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
|
||||
m_compressed_edge_container.HasEntryForID(edge_id_2));
|
||||
if (m_compressed_edge_container.HasEntryForID(edge_id_1))
|
||||
{
|
||||
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
|
||||
|
||||
// reconstruct geometry and put in each individual edge with its offset
|
||||
const auto& forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
|
||||
const auto& reverse_geometry = m_compressed_edge_container.GetBucketReference(edge_id_2);
|
||||
BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
|
||||
BOOST_ASSERT(0 != forward_geometry.size());
|
||||
const unsigned geometry_size = static_cast<unsigned>(forward_geometry.size());
|
||||
BOOST_ASSERT(geometry_size > 1);
|
||||
|
||||
// reconstruct bidirectional edge with individual weights and put each into the NN index
|
||||
|
||||
std::vector<int> forward_dist_prefix_sum(forward_geometry.size(), 0);
|
||||
std::vector<int> reverse_dist_prefix_sum(reverse_geometry.size(), 0);
|
||||
|
||||
// quick'n'dirty prefix sum as std::partial_sum needs addtional casts
|
||||
// TODO: move to lambda function with C++11
|
||||
int temp_sum = 0;
|
||||
|
||||
for (const auto i : osrm::irange(0u, geometry_size))
|
||||
{
|
||||
forward_dist_prefix_sum[i] = temp_sum;
|
||||
temp_sum += forward_geometry[i].second;
|
||||
|
||||
BOOST_ASSERT(forward_data.distance >= temp_sum);
|
||||
}
|
||||
|
||||
temp_sum = 0;
|
||||
for (const auto i : osrm::irange(0u, geometry_size))
|
||||
{
|
||||
temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
|
||||
reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
|
||||
// BOOST_ASSERT(reverse_data.distance >= temp_sum);
|
||||
}
|
||||
|
||||
NodeID current_edge_source_coordinate_id = node_u;
|
||||
|
||||
// traverse arrays from start and end respectively
|
||||
for (const auto i : osrm::irange(0u, geometry_size))
|
||||
{
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id ==
|
||||
reverse_geometry[geometry_size - 1 - i].first);
|
||||
const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
|
||||
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
||||
|
||||
// build edges
|
||||
m_edge_based_node_list.emplace_back(
|
||||
forward_data.edge_id, reverse_data.edge_id,
|
||||
current_edge_source_coordinate_id, current_edge_target_coordinate_id,
|
||||
forward_data.name_id, forward_geometry[i].second,
|
||||
reverse_geometry[geometry_size - 1 - i].second, forward_dist_prefix_sum[i],
|
||||
reverse_dist_prefix_sum[i], m_compressed_edge_container.GetPositionForID(edge_id_1),
|
||||
INVALID_COMPONENTID, i, forward_data.travel_mode, reverse_data.travel_mode);
|
||||
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
||||
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
|
||||
BOOST_ASSERT(node_u != m_edge_based_node_list.back().u ||
|
||||
node_v != m_edge_based_node_list.back().v);
|
||||
|
||||
BOOST_ASSERT(node_u != m_edge_based_node_list.back().v ||
|
||||
node_v != m_edge_based_node_list.back().u);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(!m_compressed_edge_container.HasEntryForID(edge_id_2));
|
||||
|
||||
if (forward_data.edge_id != SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(!forward_data.reversed);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(forward_data.reversed);
|
||||
}
|
||||
|
||||
if (reverse_data.edge_id != SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(!reverse_data.reversed);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(reverse_data.reversed);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID ||
|
||||
reverse_data.edge_id != SPECIAL_NODEID);
|
||||
|
||||
m_edge_based_node_list.emplace_back(
|
||||
forward_data.edge_id, reverse_data.edge_id, node_u, node_v,
|
||||
forward_data.name_id, forward_data.distance, reverse_data.distance, 0, 0, SPECIAL_EDGEID,
|
||||
INVALID_COMPONENTID, 0, forward_data.travel_mode, reverse_data.travel_mode);
|
||||
BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::FlushVectorToStream(
|
||||
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
|
||||
{
|
||||
if (original_edge_data_vector.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
edge_data_file.write((char *)&(original_edge_data_vector[0]),
|
||||
original_edge_data_vector.size() * sizeof(OriginalEdgeData));
|
||||
original_edge_data_vector.clear();
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state)
|
||||
{
|
||||
TIMER_START(renumber);
|
||||
m_max_edge_id = RenumberEdges() - 1;
|
||||
TIMER_STOP(renumber);
|
||||
|
||||
TIMER_START(generate_nodes);
|
||||
GenerateEdgeExpandedNodes();
|
||||
TIMER_STOP(generate_nodes);
|
||||
|
||||
TIMER_START(generate_edges);
|
||||
GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state);
|
||||
TIMER_STOP(generate_edges);
|
||||
|
||||
SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
|
||||
SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
||||
SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
||||
SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
|
||||
}
|
||||
|
||||
|
||||
/// Renumbers all _forward_ edges and sets the edge_id.
|
||||
/// A specific numbering is not important. Any unique ID will do.
|
||||
/// Returns the number of edge based nodes.
|
||||
unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
{
|
||||
// renumber edge based node of outgoing edges
|
||||
unsigned numbered_edges_count = 0;
|
||||
for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
|
||||
{
|
||||
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
|
||||
|
||||
// only number incoming edges
|
||||
if (edge_data.reversed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
|
||||
edge_data.edge_id = numbered_edges_count;
|
||||
++numbered_edges_count;
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
|
||||
}
|
||||
}
|
||||
|
||||
return numbered_edges_count;
|
||||
}
|
||||
|
||||
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
||||
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
{
|
||||
Percent progress(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
// loop over all edges and generate new set of nodes
|
||||
for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
|
||||
progress.printStatus(node_u);
|
||||
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
|
||||
{
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
||||
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
||||
const NodeID node_v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != node_v);
|
||||
// pick only every other edge, since we have every edge as an outgoing
|
||||
// and incoming egde
|
||||
if (node_u > node_v)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(node_u < node_v);
|
||||
|
||||
// if we found a non-forward edge reverse and try again
|
||||
if (edge_data.edge_id == SPECIAL_NODEID)
|
||||
{
|
||||
InsertEdgeBasedNode(node_v, node_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertEdgeBasedNode(node_u, node_v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
||||
<< " nodes in edge-expanded graph";
|
||||
}
|
||||
|
||||
/// Actually it also generates OriginalEdgeData and serializes them...
|
||||
void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const std::string &original_edge_data_filename, lua_State *lua_state)
|
||||
{
|
||||
SimpleLogger().Write() << "generating edge-expanded edges";
|
||||
|
||||
unsigned node_based_edge_counter = 0;
|
||||
unsigned original_edges_counter = 0;
|
||||
|
||||
std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
|
||||
|
||||
// writes a dummy value that is updated later
|
||||
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
|
||||
|
||||
std::vector<OriginalEdgeData> original_edge_data_vector;
|
||||
original_edge_data_vector.reserve(1024 * 1024);
|
||||
|
||||
// Loop over all turns and generate new set of edges.
|
||||
// Three nested loop look super-linear, but we are dealing with a (kind of)
|
||||
// linear number of turns only.
|
||||
unsigned restricted_turns_counter = 0;
|
||||
unsigned skipped_uturns_counter = 0;
|
||||
unsigned skipped_barrier_turns_counter = 0;
|
||||
unsigned compressed = 0;
|
||||
|
||||
Percent progress(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
for (const auto node_u : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
{
|
||||
progress.printStatus(node_u);
|
||||
for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
|
||||
{
|
||||
if (m_node_based_graph->GetEdgeData(e1).reversed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
++node_based_edge_counter;
|
||||
const NodeID node_v = m_node_based_graph->GetTarget(e1);
|
||||
const NodeID only_restriction_to_node =
|
||||
m_restriction_map->CheckForEmanatingIsOnlyTurn(node_u, node_v);
|
||||
const bool is_barrier_node = m_barrier_nodes.find(node_v) != m_barrier_nodes.end();
|
||||
|
||||
for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
|
||||
{
|
||||
if (m_node_based_graph->GetEdgeData(e2).reversed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const NodeID node_w = m_node_based_graph->GetTarget(e2);
|
||||
|
||||
if ((only_restriction_to_node != SPECIAL_NODEID) &&
|
||||
(node_w != only_restriction_to_node))
|
||||
{
|
||||
// We are at an only_-restriction but not at the right turn.
|
||||
++restricted_turns_counter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_barrier_node)
|
||||
{
|
||||
if (node_u != node_w)
|
||||
{
|
||||
++skipped_barrier_turns_counter;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((node_u == node_w) && (m_node_based_graph->GetOutDegree(node_v) > 1))
|
||||
{
|
||||
++skipped_uturns_counter;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// only add an edge if turn is not a U-turn except when it is
|
||||
// at the end of a dead-end street
|
||||
if (m_restriction_map->CheckIfTurnIsRestricted(node_u, node_v, node_w) &&
|
||||
(only_restriction_to_node == SPECIAL_NODEID) &&
|
||||
(node_w != only_restriction_to_node))
|
||||
{
|
||||
// We are at an only_-restriction but not at the right turn.
|
||||
++restricted_turns_counter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// only add an edge if turn is not prohibited
|
||||
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
|
||||
|
||||
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
||||
BOOST_ASSERT(!edge_data1.reversed);
|
||||
BOOST_ASSERT(!edge_data2.reversed);
|
||||
|
||||
// the following is the core of the loop.
|
||||
unsigned distance = edge_data1.distance;
|
||||
if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
|
||||
{
|
||||
distance += speed_profile.traffic_signal_penalty;
|
||||
}
|
||||
|
||||
// unpack last node of first segment if packed
|
||||
const auto first_coordinate =
|
||||
m_node_info_list[(m_compressed_edge_container.HasEntryForID(e1)
|
||||
? m_compressed_edge_container.GetLastEdgeSourceID(e1)
|
||||
: node_u)];
|
||||
|
||||
// unpack first node of second segment if packed
|
||||
const auto third_coordinate =
|
||||
m_node_info_list[(m_compressed_edge_container.HasEntryForID(e2)
|
||||
? m_compressed_edge_container.GetFirstEdgeTargetID(e2)
|
||||
: node_w)];
|
||||
|
||||
const double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
|
||||
first_coordinate, m_node_info_list[node_v], third_coordinate);
|
||||
|
||||
const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
|
||||
TurnInstruction turn_instruction = AnalyzeTurn(node_u, node_v, node_w, turn_angle);
|
||||
if (turn_instruction == TurnInstruction::UTurn)
|
||||
{
|
||||
distance += speed_profile.u_turn_penalty;
|
||||
}
|
||||
distance += turn_penalty;
|
||||
|
||||
const bool edge_is_compressed = m_compressed_edge_container.HasEntryForID(e1);
|
||||
|
||||
if (edge_is_compressed)
|
||||
{
|
||||
++compressed;
|
||||
}
|
||||
|
||||
original_edge_data_vector.emplace_back(
|
||||
(edge_is_compressed ? m_compressed_edge_container.GetPositionForID(e1) : node_v),
|
||||
edge_data1.name_id, turn_instruction, edge_is_compressed,
|
||||
edge_data2.travel_mode);
|
||||
|
||||
++original_edges_counter;
|
||||
|
||||
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
|
||||
{
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
||||
|
||||
m_edge_based_edge_list.emplace_back(edge_data1.edge_id, edge_data2.edge_id,
|
||||
m_edge_based_edge_list.size(), distance, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
|
||||
edge_data_file.seekp(std::ios::beg);
|
||||
edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
|
||||
edge_data_file.close();
|
||||
|
||||
SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
|
||||
SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter << " edges";
|
||||
SimpleLogger().Write() << "Edge-expanded graph ...";
|
||||
SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
|
||||
SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
|
||||
"defined by "
|
||||
<< m_restriction_map->size() << " restrictions";
|
||||
SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
|
||||
SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||
}
|
||||
|
||||
int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
|
||||
{
|
||||
|
||||
if (speed_profile.has_turn_penalty_function)
|
||||
{
|
||||
try
|
||||
{
|
||||
// call lua profile to compute turn penalty
|
||||
double penalty = luabind::call_function<double>(lua_state, "turn_function", 180. - angle);
|
||||
return static_cast<int>(penalty);
|
||||
}
|
||||
catch (const luabind::error &er)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << er.what();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w,
|
||||
const double angle) const
|
||||
{
|
||||
if (node_u == node_w)
|
||||
{
|
||||
return TurnInstruction::UTurn;
|
||||
}
|
||||
|
||||
const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
|
||||
|
||||
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
|
||||
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
|
||||
|
||||
// roundabouts need to be handled explicitely
|
||||
if (data1.roundabout && data2.roundabout)
|
||||
{
|
||||
// Is a turn possible? If yes, we stay on the roundabout!
|
||||
if (1 == m_node_based_graph->GetDirectedOutDegree(node_v))
|
||||
{
|
||||
// No turn possible.
|
||||
return TurnInstruction::NoTurn;
|
||||
}
|
||||
return TurnInstruction::StayOnRoundAbout;
|
||||
}
|
||||
// Does turn start or end on roundabout?
|
||||
if (data1.roundabout || data2.roundabout)
|
||||
{
|
||||
// We are entering the roundabout
|
||||
if ((!data1.roundabout) && data2.roundabout)
|
||||
{
|
||||
return TurnInstruction::EnterRoundAbout;
|
||||
}
|
||||
// We are leaving the roundabout
|
||||
if (data1.roundabout && (!data2.roundabout))
|
||||
{
|
||||
return TurnInstruction::LeaveRoundAbout;
|
||||
}
|
||||
}
|
||||
|
||||
// If street names stay the same and if we are certain that it is not a
|
||||
// a segment of a roundabout, we skip it.
|
||||
if (data1.name_id == data2.name_id && data1.travel_mode == data2.travel_mode)
|
||||
{
|
||||
// TODO: Here we should also do a small graph exploration to check for
|
||||
// more complex situations
|
||||
if (0 != data1.name_id || m_node_based_graph->GetOutDegree(node_v) <= 2)
|
||||
{
|
||||
return TurnInstruction::NoTurn;
|
||||
}
|
||||
}
|
||||
|
||||
return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// This class constructs the edge-expanded routing graph
|
||||
|
||||
#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
|
||||
#define EDGE_BASED_GRAPH_FACTORY_HPP_
|
||||
|
||||
#include "speed_profile.hpp"
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/compressed_edge_container.hpp"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/edge_based_node.hpp"
|
||||
#include "../data_structures/original_edge_data.hpp"
|
||||
#include "../data_structures/query_node.hpp"
|
||||
#include "../data_structures/turn_instructions.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
#include "../data_structures/restriction_map.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class EdgeBasedGraphFactory
|
||||
{
|
||||
public:
|
||||
EdgeBasedGraphFactory() = delete;
|
||||
EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
|
||||
|
||||
explicit EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
std::shared_ptr<const RestrictionMap> restriction_map,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
SpeedProfileProperties speed_profile);
|
||||
|
||||
void Run(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state);
|
||||
|
||||
void GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &edges);
|
||||
|
||||
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
|
||||
|
||||
unsigned GetHighestEdgeID();
|
||||
|
||||
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
|
||||
|
||||
int GetTurnPenalty(double angle, lua_State *lua_state) const;
|
||||
|
||||
private:
|
||||
using EdgeData = NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
std::vector<EdgeBasedNode> m_edge_based_node_list;
|
||||
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
unsigned m_max_edge_id;
|
||||
|
||||
const std::vector<QueryNode>& m_node_info_list;
|
||||
std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
|
||||
std::shared_ptr<RestrictionMap const> m_restriction_map;
|
||||
|
||||
const std::unordered_set<NodeID>& m_barrier_nodes;
|
||||
const std::unordered_set<NodeID>& m_traffic_lights;
|
||||
const CompressedEdgeContainer& m_compressed_edge_container;
|
||||
|
||||
SpeedProfileProperties speed_profile;
|
||||
|
||||
void CompressGeometry();
|
||||
unsigned RenumberEdges();
|
||||
void GenerateEdgeExpandedNodes();
|
||||
void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state);
|
||||
|
||||
void InsertEdgeBasedNode(const NodeID u, const NodeID v);
|
||||
|
||||
void FlushVectorToStream(std::ofstream &edge_data_file,
|
||||
std::vector<OriginalEdgeData> &original_edge_data_vector) const;
|
||||
|
||||
};
|
||||
|
||||
#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
|
||||
+33
-290
@@ -28,14 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "processing_chain.hpp"
|
||||
|
||||
#include "contractor.hpp"
|
||||
#include "../algorithms/graph_compressor.hpp"
|
||||
#include "../algorithms/tarjan_scc.hpp"
|
||||
#include "../algorithms/crc32_processor.hpp"
|
||||
#include "../data_structures/compressed_edge_container.hpp"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/static_rtree.hpp"
|
||||
#include "../data_structures/restriction_map.hpp"
|
||||
|
||||
#include "../algorithms/crc32_processor.hpp"
|
||||
#include "../util/graph_loader.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/lua_util.hpp"
|
||||
@@ -73,32 +68,11 @@ int Prepare::Run()
|
||||
|
||||
// Create a new lua state
|
||||
|
||||
SimpleLogger().Write() << "Generating edge-expanded graph representation";
|
||||
SimpleLogger().Write() << "Loading edge-expanded graph representation";
|
||||
|
||||
TIMER_START(expansion);
|
||||
|
||||
std::vector<EdgeBasedNode> node_based_edge_list;
|
||||
DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
||||
std::vector<QueryNode> internal_to_external_node_map;
|
||||
auto graph_size = BuildEdgeExpandedGraph(internal_to_external_node_map, node_based_edge_list,
|
||||
edge_based_edge_list);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
auto max_edge_id = graph_size.second;
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
|
||||
SimpleLogger().Write() << "building r-tree ...";
|
||||
TIMER_START(rtree);
|
||||
|
||||
FindComponents(max_edge_id, edge_based_edge_list, node_based_edge_list);
|
||||
|
||||
BuildRTree(node_based_edge_list, internal_to_external_node_map);
|
||||
|
||||
TIMER_STOP(rtree);
|
||||
|
||||
SimpleLogger().Write() << "writing node map ...";
|
||||
WriteNodeMapping(internal_to_external_node_map);
|
||||
size_t max_edge_id = LoadEdgeExpandedGraph(config.edge_based_graph_path, edge_based_edge_list);
|
||||
|
||||
// Contracting the edge-expanded graph
|
||||
|
||||
@@ -111,16 +85,12 @@ int Prepare::Run()
|
||||
SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||
|
||||
std::size_t number_of_used_edges =
|
||||
WriteContractedGraph(max_edge_id, node_based_edge_list, contracted_edge_list);
|
||||
WriteContractedGraph(max_edge_id, contracted_edge_list);
|
||||
WriteCoreNodeMarker(std::move(is_core_node));
|
||||
|
||||
TIMER_STOP(preparing);
|
||||
|
||||
SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
|
||||
SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
|
||||
<< " nodes/sec and " << ((max_edge_id + 1) / TIMER_SEC(expansion))
|
||||
<< " edges/sec";
|
||||
|
||||
SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
|
||||
<< " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
|
||||
<< " edges/sec";
|
||||
@@ -130,81 +100,38 @@ int Prepare::Run()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Prepare::FindComponents(unsigned max_edge_id,
|
||||
const DeallocatingVector<EdgeBasedEdge> &input_edge_list,
|
||||
std::vector<EdgeBasedNode> &input_nodes) const
|
||||
std::size_t Prepare::LoadEdgeExpandedGraph(
|
||||
std::string const & edge_based_graph_filename,
|
||||
DeallocatingVector<EdgeBasedEdge> & edge_based_edge_list)
|
||||
{
|
||||
struct UncontractedEdgeData
|
||||
{
|
||||
};
|
||||
struct InputEdge
|
||||
{
|
||||
unsigned source;
|
||||
unsigned target;
|
||||
UncontractedEdgeData data;
|
||||
SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
|
||||
boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::in | std::ios::binary);
|
||||
|
||||
bool operator<(const InputEdge &rhs) const
|
||||
{
|
||||
return source < rhs.source || (source == rhs.source && target < rhs.target);
|
||||
}
|
||||
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
|
||||
FingerPrint fingerprint_loaded;
|
||||
input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
|
||||
fingerprint_loaded.TestPrepare(fingerprint_valid);
|
||||
|
||||
bool operator==(const InputEdge &rhs) const
|
||||
{
|
||||
return source == rhs.source && target == rhs.target;
|
||||
}
|
||||
};
|
||||
using UncontractedGraph = StaticGraph<UncontractedEdgeData>;
|
||||
std::vector<InputEdge> edges;
|
||||
edges.reserve(input_edge_list.size() * 2);
|
||||
size_t number_of_edges = 0;
|
||||
size_t max_edge_id = SPECIAL_EDGEID;
|
||||
input_stream.read((char *)&number_of_edges, sizeof(size_t));
|
||||
input_stream.read((char *)&max_edge_id, sizeof(size_t));
|
||||
|
||||
for (const auto &edge : input_edge_list)
|
||||
{
|
||||
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(edge.weight, 1)) > 0,
|
||||
"edge distance < 1");
|
||||
if (edge.forward)
|
||||
{
|
||||
edges.push_back({edge.source, edge.target, {}});
|
||||
}
|
||||
edge_based_edge_list.resize(number_of_edges);
|
||||
SimpleLogger().Write() << "Reading " << number_of_edges << " edges from the edge based graph";
|
||||
|
||||
if (edge.backward)
|
||||
{
|
||||
edges.push_back({edge.target, edge.source, {}});
|
||||
}
|
||||
}
|
||||
|
||||
// connect forward and backward nodes of each edge
|
||||
for (const auto &node : input_nodes)
|
||||
{
|
||||
if (node.reverse_edge_based_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
edges.push_back({node.forward_edge_based_node_id, node.reverse_edge_based_node_id, {}});
|
||||
edges.push_back({node.reverse_edge_based_node_id, node.forward_edge_based_node_id, {}});
|
||||
}
|
||||
}
|
||||
|
||||
tbb::parallel_sort(edges.begin(), edges.end());
|
||||
auto new_end = std::unique(edges.begin(), edges.end());
|
||||
edges.resize(new_end - edges.begin());
|
||||
|
||||
auto uncontractor_graph = std::make_shared<UncontractedGraph>(max_edge_id + 1, edges);
|
||||
|
||||
TarjanSCC<UncontractedGraph> component_search(
|
||||
std::const_pointer_cast<const UncontractedGraph>(uncontractor_graph));
|
||||
component_search.run();
|
||||
|
||||
for (auto &node : input_nodes)
|
||||
{
|
||||
auto forward_component = component_search.get_component_id(node.forward_edge_based_node_id);
|
||||
BOOST_ASSERT(node.reverse_edge_based_node_id == SPECIAL_EDGEID ||
|
||||
forward_component ==
|
||||
component_search.get_component_id(node.reverse_edge_based_node_id));
|
||||
|
||||
const unsigned component_size = component_search.get_component_size(forward_component);
|
||||
const bool is_tiny_component = component_size < 1000;
|
||||
node.component_id = is_tiny_component ? (1 + forward_component) : 0;
|
||||
// TODO: can we read this in bulk? DeallocatingVector isn't necessarily
|
||||
// all stored contiguously
|
||||
for (;number_of_edges > 0; --number_of_edges) {
|
||||
EdgeBasedEdge inbuffer;
|
||||
input_stream.read((char *) &inbuffer, sizeof(EdgeBasedEdge));
|
||||
edge_based_edge_list.emplace_back(std::move(inbuffer));
|
||||
}
|
||||
SimpleLogger().Write() << "Done reading edges";
|
||||
return max_edge_id;
|
||||
}
|
||||
|
||||
|
||||
void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
|
||||
{
|
||||
std::vector<bool> is_core_node(in_is_core_node);
|
||||
@@ -223,11 +150,8 @@ void Prepare::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
|
||||
}
|
||||
|
||||
std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
|
||||
const std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
const DeallocatingVector<QueryEdge> &contracted_edge_list)
|
||||
{
|
||||
const unsigned crc32_value = CalculateEdgeChecksum(node_based_edge_list);
|
||||
|
||||
// Sorting contracted edges in a way that the static query graph can read some in in-place.
|
||||
tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
|
||||
const unsigned contracted_edge_count = contracted_edge_list.size();
|
||||
@@ -283,9 +207,13 @@ std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
|
||||
|
||||
SimpleLogger().Write() << "Serializing node array";
|
||||
|
||||
RangebasedCRC32 crc32_calculator;
|
||||
const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
|
||||
SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;
|
||||
|
||||
const unsigned node_array_size = node_array.size();
|
||||
// serialize crc32, aka checksum
|
||||
hsgr_output_stream.write((char *)&crc32_value, sizeof(unsigned));
|
||||
hsgr_output_stream.write((char *)&edges_crc32, sizeof(unsigned));
|
||||
// serialize number of nodes
|
||||
hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
|
||||
// serialize number of edges
|
||||
@@ -334,165 +262,7 @@ std::size_t Prepare::WriteContractedGraph(unsigned max_node_id,
|
||||
return number_of_used_edges;
|
||||
}
|
||||
|
||||
unsigned Prepare::CalculateEdgeChecksum(const std::vector<EdgeBasedNode> &node_based_edge_list)
|
||||
{
|
||||
RangebasedCRC32 crc32;
|
||||
if (crc32.using_hardware())
|
||||
{
|
||||
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleLogger().Write() << "using software based CRC32 computation";
|
||||
}
|
||||
|
||||
const unsigned crc32_value = crc32(node_based_edge_list);
|
||||
SimpleLogger().Write() << "CRC32: " << crc32_value;
|
||||
|
||||
return crc32_value;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Setups scripting environment (lua-scripting)
|
||||
Also initializes speed profile.
|
||||
*/
|
||||
void Prepare::SetupScriptingEnvironment(lua_State *lua_state, SpeedProfileProperties &speed_profile)
|
||||
{
|
||||
// open utility libraries string library;
|
||||
luaL_openlibs(lua_state);
|
||||
|
||||
// adjust lua load path
|
||||
luaAddScriptFolderToLoadPath(lua_state, config.profile_path.string().c_str());
|
||||
|
||||
// Now call our function in a lua script
|
||||
if (0 != luaL_dofile(lua_state, config.profile_path.string().c_str()))
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
|
||||
throw osrm::exception(msg.str());
|
||||
}
|
||||
|
||||
if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
|
||||
throw osrm::exception(msg.str());
|
||||
}
|
||||
speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
<< "traffic_signal_penalty: " << speed_profile.traffic_signal_penalty;
|
||||
|
||||
if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
|
||||
throw osrm::exception(msg.str());
|
||||
}
|
||||
|
||||
speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
|
||||
speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Build load restrictions from .restriction file
|
||||
*/
|
||||
std::shared_ptr<RestrictionMap> Prepare::LoadRestrictionMap()
|
||||
{
|
||||
boost::filesystem::ifstream input_stream(config.restrictions_path,
|
||||
std::ios::in | std::ios::binary);
|
||||
|
||||
std::vector<TurnRestriction> restriction_list;
|
||||
loadRestrictionsFromFile(input_stream, restriction_list);
|
||||
|
||||
SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
|
||||
|
||||
return std::make_shared<RestrictionMap>(restriction_list);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Load node based graph from .osrm file
|
||||
*/
|
||||
std::shared_ptr<NodeBasedDynamicGraph>
|
||||
Prepare::LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<QueryNode> &internal_to_external_node_map)
|
||||
{
|
||||
std::vector<NodeBasedEdge> edge_list;
|
||||
|
||||
boost::filesystem::ifstream input_stream(config.osrm_input_path,
|
||||
std::ios::in | std::ios::binary);
|
||||
|
||||
std::vector<NodeID> barrier_list;
|
||||
std::vector<NodeID> traffic_light_list;
|
||||
NodeID number_of_node_based_nodes = loadNodesFromFile(
|
||||
input_stream, barrier_list, traffic_light_list, internal_to_external_node_map);
|
||||
|
||||
SimpleLogger().Write() << " - " << barrier_list.size() << " bollard nodes, "
|
||||
<< traffic_light_list.size() << " traffic lights";
|
||||
|
||||
// insert into unordered sets for fast lookup
|
||||
barrier_nodes.insert(barrier_list.begin(), barrier_list.end());
|
||||
traffic_lights.insert(traffic_light_list.begin(), traffic_light_list.end());
|
||||
|
||||
barrier_list.clear();
|
||||
barrier_list.shrink_to_fit();
|
||||
traffic_light_list.clear();
|
||||
traffic_light_list.shrink_to_fit();
|
||||
|
||||
loadEdgesFromFile(input_stream, edge_list);
|
||||
|
||||
if (edge_list.empty())
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
|
||||
return std::shared_ptr<NodeBasedDynamicGraph>();
|
||||
}
|
||||
|
||||
return NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Building an edge-expanded graph from node-based input and turn restrictions
|
||||
*/
|
||||
std::pair<std::size_t, std::size_t>
|
||||
Prepare::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
|
||||
std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
|
||||
{
|
||||
lua_State *lua_state = luaL_newstate();
|
||||
luabind::open(lua_state);
|
||||
|
||||
SpeedProfileProperties speed_profile;
|
||||
SetupScriptingEnvironment(lua_state, speed_profile);
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
|
||||
auto restriction_map = LoadRestrictionMap();
|
||||
auto node_based_graph =
|
||||
LoadNodeBasedGraph(barrier_nodes, traffic_lights, internal_to_external_node_map);
|
||||
|
||||
CompressedEdgeContainer compressed_edge_container;
|
||||
GraphCompressor graph_compressor(speed_profile);
|
||||
graph_compressor.Compress(barrier_nodes, traffic_lights, *restriction_map, *node_based_graph,
|
||||
compressed_edge_container);
|
||||
|
||||
EdgeBasedGraphFactory edge_based_graph_factory(
|
||||
node_based_graph, compressed_edge_container, barrier_nodes, traffic_lights,
|
||||
std::const_pointer_cast<RestrictionMap const>(restriction_map),
|
||||
internal_to_external_node_map, speed_profile);
|
||||
|
||||
compressed_edge_container.SerializeInternalVector(config.geometry_output_path);
|
||||
|
||||
edge_based_graph_factory.Run(config.edge_output_path, lua_state);
|
||||
lua_close(lua_state);
|
||||
|
||||
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
|
||||
edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
|
||||
auto max_edge_id = edge_based_graph_factory.GetHighestEdgeID();
|
||||
|
||||
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
|
||||
return std::make_pair(number_of_node_based_nodes, max_edge_id);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Build contracted graph.
|
||||
@@ -508,31 +278,4 @@ void Prepare::ContractGraph(const unsigned max_edge_id,
|
||||
contractor.GetCoreMarker(is_core_node);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Writing info on original (node-based) nodes
|
||||
*/
|
||||
void Prepare::WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map)
|
||||
{
|
||||
boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary);
|
||||
const unsigned size_of_mapping = internal_to_external_node_map.size();
|
||||
node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
|
||||
if (size_of_mapping > 0)
|
||||
{
|
||||
node_stream.write((char *)internal_to_external_node_map.data(),
|
||||
size_of_mapping * sizeof(QueryNode));
|
||||
}
|
||||
node_stream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Building rtree-based nearest-neighbor data structure
|
||||
|
||||
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
|
||||
*/
|
||||
void Prepare::BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
const std::vector<QueryNode> &internal_to_external_node_map)
|
||||
{
|
||||
StaticRTree<EdgeBasedNode>(node_based_edge_list, config.rtree_nodes_output_path.c_str(),
|
||||
config.rtree_leafs_output_path.c_str(),
|
||||
internal_to_external_node_map);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define PROCESSING_CHAIN_HPP
|
||||
|
||||
#include "contractor_options.hpp"
|
||||
#include "edge_based_graph_factory.hpp"
|
||||
#include "../data_structures/query_edge.hpp"
|
||||
#include "../data_structures/static_graph.hpp"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
|
||||
struct SpeedProfileProperties;
|
||||
struct EdgeBasedNode;
|
||||
@@ -48,8 +49,6 @@ class Prepare
|
||||
{
|
||||
public:
|
||||
using EdgeData = QueryEdge::EdgeData;
|
||||
using InputEdge = DynamicGraph<EdgeData>::InputEdge;
|
||||
using StaticEdge = StaticGraph<EdgeData>::InputEdge;
|
||||
|
||||
explicit Prepare(ContractorConfig contractor_config) : config(std::move(contractor_config)) {}
|
||||
Prepare(const Prepare &) = delete;
|
||||
@@ -58,34 +57,21 @@ class Prepare
|
||||
int Run();
|
||||
|
||||
protected:
|
||||
void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile);
|
||||
unsigned CalculateEdgeChecksum(const std::vector<EdgeBasedNode> &node_based_edge_list);
|
||||
void ContractGraph(const unsigned max_edge_id,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
DeallocatingVector<QueryEdge> &contracted_edge_list,
|
||||
std::vector<bool> &is_core_node);
|
||||
void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
|
||||
std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
|
||||
const std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
const DeallocatingVector<QueryEdge> &contracted_edge_list);
|
||||
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
|
||||
std::shared_ptr<NodeBasedDynamicGraph>
|
||||
LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<QueryNode> &internal_to_external_node_map);
|
||||
std::pair<std::size_t, std::size_t>
|
||||
BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
|
||||
std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
|
||||
void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map);
|
||||
void FindComponents(unsigned max_edge_id,
|
||||
const DeallocatingVector<EdgeBasedEdge> &edges,
|
||||
std::vector<EdgeBasedNode> &nodes) const;
|
||||
void BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
const std::vector<QueryNode> &internal_to_external_node_map);
|
||||
|
||||
private:
|
||||
ContractorConfig config;
|
||||
std::size_t LoadEdgeExpandedGraph(
|
||||
const std::string & edge_based_graph_path,
|
||||
DeallocatingVector<EdgeBasedEdge> & edge_based_edge_list);
|
||||
};
|
||||
|
||||
#endif // PROCESSING_CHAIN_HPP
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef SPEED_PROFILE_PROPERTIES_HPP
|
||||
#define SPEED_PROFILE_PROPERTIES_HPP
|
||||
|
||||
struct SpeedProfileProperties
|
||||
{
|
||||
SpeedProfileProperties()
|
||||
: traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
|
||||
{
|
||||
}
|
||||
|
||||
int traffic_signal_penalty;
|
||||
int u_turn_penalty;
|
||||
bool has_turn_penalty_function;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user