2016-06-21 04:41:08 -04:00
|
|
|
#include "extractor/edge_based_graph_factory.hpp"
|
2016-07-26 09:00:58 -04:00
|
|
|
#include "extractor/edge_based_edge.hpp"
|
2016-01-29 06:42:08 -05:00
|
|
|
#include "util/coordinate.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/coordinate_calculation.hpp"
|
2016-04-10 20:23:22 -04:00
|
|
|
#include "util/exception.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/integer_range.hpp"
|
2016-04-10 20:23:22 -04:00
|
|
|
#include "util/percent.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/simple_logger.hpp"
|
|
|
|
#include "util/timing_util.hpp"
|
|
|
|
|
2016-03-01 16:30:31 -05:00
|
|
|
#include "extractor/guidance/toolkit.hpp"
|
2016-04-26 07:27:40 -04:00
|
|
|
#include "extractor/guidance/turn_analysis.hpp"
|
2016-05-13 13:18:00 -04:00
|
|
|
#include "extractor/guidance/turn_lane_handler.hpp"
|
2016-07-11 11:44:58 -04:00
|
|
|
#include "extractor/scripting_environment.hpp"
|
2016-05-27 15:05:04 -04:00
|
|
|
#include "extractor/suffix_table.hpp"
|
2016-02-24 04:29:23 -05:00
|
|
|
|
2013-12-13 18:49:05 -05:00
|
|
|
#include <boost/assert.hpp>
|
2016-03-18 06:02:25 -04:00
|
|
|
#include <boost/numeric/conversion/cast.hpp>
|
2013-12-13 18:49:05 -05:00
|
|
|
|
2016-01-29 06:42:08 -05:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cmath>
|
2014-01-04 06:10:22 -05:00
|
|
|
#include <fstream>
|
2014-10-16 09:58:58 -04:00
|
|
|
#include <iomanip>
|
2014-05-09 08:21:33 -04:00
|
|
|
#include <limits>
|
2016-01-29 06:42:08 -05:00
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
2016-04-26 07:27:40 -04:00
|
|
|
#include <unordered_map>
|
2013-11-29 12:49:02 -05:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
2016-01-29 06:42:08 -05:00
|
|
|
// Configuration to find representative candidate for turn angle calculations
|
|
|
|
|
2015-08-18 06:56:34 -04:00
|
|
|
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
2016-01-05 10:51:13 -05:00
|
|
|
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
|
2016-03-04 10:13:30 -05:00
|
|
|
const CompressedEdgeContainer &compressed_edge_container,
|
2015-08-18 06:56:34 -04:00
|
|
|
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,
|
2016-03-21 17:42:47 -04:00
|
|
|
ProfileProperties profile_properties,
|
2016-05-13 13:18:00 -04:00
|
|
|
const util::NameTable &name_table,
|
2016-06-21 04:41:08 -04:00
|
|
|
const std::vector<std::uint32_t> &turn_lane_offsets,
|
|
|
|
const std::vector<guidance::TurnLaneType::Mask> &turn_lane_masks)
|
2016-01-05 06:04:04 -05:00
|
|
|
: m_max_edge_id(0), m_node_info_list(node_info_list),
|
|
|
|
m_node_based_graph(std::move(node_based_graph)),
|
2015-08-18 06:56:34 -04:00
|
|
|
m_restriction_map(std::move(restriction_map)), m_barrier_nodes(barrier_nodes),
|
|
|
|
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
2016-05-13 13:18:00 -04:00
|
|
|
profile_properties(std::move(profile_properties)), name_table(name_table),
|
2016-06-21 04:41:08 -04:00
|
|
|
turn_lane_offsets(turn_lane_offsets), turn_lane_masks(turn_lane_masks)
|
2013-11-29 13:00:00 -05:00
|
|
|
{
|
2014-01-04 06:10:22 -05:00
|
|
|
}
|
|
|
|
|
2016-01-07 19:31:57 -05:00
|
|
|
void EdgeBasedGraphFactory::GetEdgeBasedEdges(
|
|
|
|
util::DeallocatingVector<EdgeBasedEdge> &output_edge_list)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
|
|
|
BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
|
2015-12-16 12:12:18 -05:00
|
|
|
using std::swap; // Koenig swap
|
|
|
|
swap(m_edge_based_edge_list, output_edge_list);
|
2011-11-09 10:12:05 -05:00
|
|
|
}
|
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
|
|
|
|
{
|
2012-09-19 07:48:04 -04:00
|
|
|
#ifndef NDEBUG
|
2014-05-09 08:21:33 -04:00
|
|
|
for (const EdgeBasedNode &node : m_edge_based_node_list)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2016-02-23 15:23:13 -05:00
|
|
|
BOOST_ASSERT(
|
|
|
|
util::Coordinate(m_node_info_list[node.u].lon, m_node_info_list[node.u].lat).IsValid());
|
|
|
|
BOOST_ASSERT(
|
|
|
|
util::Coordinate(m_node_info_list[node.v].lon, m_node_info_list[node.v].lat).IsValid());
|
2011-12-13 04:12:41 -05:00
|
|
|
}
|
2012-09-19 07:48:04 -04:00
|
|
|
#endif
|
2015-12-16 12:12:18 -05:00
|
|
|
using std::swap; // Koenig swap
|
|
|
|
swap(nodes, m_edge_based_node_list);
|
2011-11-09 10:12:05 -05:00
|
|
|
}
|
|
|
|
|
2015-12-11 17:11:04 -05:00
|
|
|
void EdgeBasedGraphFactory::GetStartPointMarkers(std::vector<bool> &node_is_startpoint)
|
|
|
|
{
|
2015-12-16 12:12:18 -05:00
|
|
|
using std::swap; // Koenig swap
|
|
|
|
swap(m_edge_based_node_is_startpoint, node_is_startpoint);
|
2015-12-11 17:11:04 -05:00
|
|
|
}
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights)
|
|
|
|
{
|
|
|
|
using std::swap; // Koenig swap
|
|
|
|
swap(m_edge_based_node_weights, output_node_weights);
|
|
|
|
}
|
|
|
|
|
2016-06-11 11:23:29 -04:00
|
|
|
EdgeID EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; }
|
2015-07-01 11:55:54 -04:00
|
|
|
|
2016-01-05 06:04:04 -05:00
|
|
|
void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-02-11 05:42:24 -05:00
|
|
|
// merge edges together into one EdgeBasedNode
|
2014-08-13 05:00:16 -04:00
|
|
|
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
|
|
|
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
2014-02-11 05:42:24 -05:00
|
|
|
|
|
|
|
// find forward edge id and
|
2015-01-23 05:04:21 -05:00
|
|
|
const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
|
|
|
|
BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
|
2014-07-04 11:33:18 -04:00
|
|
|
|
2015-01-23 05:04:21 -05:00
|
|
|
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
|
2014-02-18 13:26:57 -05:00
|
|
|
|
2014-02-11 05:42:24 -05:00
|
|
|
// find reverse edge id and
|
2015-01-23 05:04:21 -05:00
|
|
|
const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
|
|
|
|
BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
|
2015-04-16 18:23:58 -04:00
|
|
|
|
2015-01-23 05:04:21 -05:00
|
|
|
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
|
2014-05-08 17:07:16 -04:00
|
|
|
|
2016-01-05 06:04:04 -05:00
|
|
|
if (forward_data.edge_id == SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-02-27 13:49:53 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
|
|
|
|
m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT;
|
|
|
|
|
2015-06-24 13:55:36 -04:00
|
|
|
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
|
|
|
|
m_compressed_edge_container.HasEntryForID(edge_id_2));
|
2016-03-03 21:48:39 -05:00
|
|
|
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1));
|
|
|
|
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_2));
|
|
|
|
const auto &forward_geometry = m_compressed_edge_container.GetBucketReference(edge_id_1);
|
2016-03-04 10:13:30 -05:00
|
|
|
BOOST_ASSERT(forward_geometry.size() ==
|
|
|
|
m_compressed_edge_container.GetBucketReference(edge_id_2).size());
|
2016-03-04 10:37:25 -05:00
|
|
|
const auto geometry_size = forward_geometry.size();
|
2016-03-03 21:48:39 -05:00
|
|
|
|
2016-03-03 22:27:36 -05:00
|
|
|
// There should always be some geometry
|
|
|
|
BOOST_ASSERT(0 != geometry_size);
|
|
|
|
|
2016-03-04 10:37:25 -05:00
|
|
|
NodeID current_edge_source_coordinate_id = node_u;
|
2014-05-08 17:07:16 -04:00
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id) {
|
2016-03-28 11:06:51 -04:00
|
|
|
if (edge_based_node_id == SPECIAL_NODEID)
|
|
|
|
{
|
|
|
|
return SegmentID{SPECIAL_SEGMENTID, false};
|
|
|
|
}
|
|
|
|
|
|
|
|
return SegmentID{edge_based_node_id, true};
|
|
|
|
};
|
|
|
|
|
2016-03-04 10:37:25 -05:00
|
|
|
// traverse arrays from start and end respectively
|
2016-04-10 20:23:22 -04:00
|
|
|
for (const auto i : util::irange(std::size_t{0}, geometry_size))
|
2016-03-04 10:37:25 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
BOOST_ASSERT(
|
|
|
|
current_edge_source_coordinate_id ==
|
|
|
|
m_compressed_edge_container.GetBucketReference(edge_id_2)[geometry_size - 1 - i]
|
|
|
|
.node_id);
|
2016-03-04 10:37:25 -05:00
|
|
|
const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
|
|
|
|
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
|
|
|
|
|
|
|
// build edges
|
2016-05-27 15:05:04 -04:00
|
|
|
m_edge_based_node_list.emplace_back(edge_id_to_segment_id(forward_data.edge_id),
|
|
|
|
edge_id_to_segment_id(reverse_data.edge_id),
|
|
|
|
current_edge_source_coordinate_id,
|
|
|
|
current_edge_target_coordinate_id,
|
|
|
|
forward_data.name_id,
|
|
|
|
m_compressed_edge_container.GetPositionForID(edge_id_1),
|
|
|
|
m_compressed_edge_container.GetPositionForID(edge_id_2),
|
|
|
|
false,
|
|
|
|
INVALID_COMPONENTID,
|
|
|
|
i,
|
|
|
|
forward_data.travel_mode,
|
|
|
|
reverse_data.travel_mode);
|
2016-03-04 10:37:25 -05:00
|
|
|
|
2016-01-05 06:04:04 -05:00
|
|
|
m_edge_based_node_is_startpoint.push_back(forward_data.startpoint ||
|
|
|
|
reverse_data.startpoint);
|
2016-03-04 10:37:25 -05:00
|
|
|
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
2014-02-18 13:26:57 -05:00
|
|
|
}
|
2016-03-04 10:37:25 -05:00
|
|
|
|
|
|
|
BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
|
2012-03-01 13:41:06 -05:00
|
|
|
}
|
|
|
|
|
2013-11-28 12:50:12 -05:00
|
|
|
void EdgeBasedGraphFactory::FlushVectorToStream(
|
2014-05-08 17:07:16 -04:00
|
|
|
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
|
|
|
|
{
|
2015-01-22 06:19:11 -05:00
|
|
|
if (original_edge_data_vector.empty())
|
|
|
|
{
|
2014-06-04 06:02:18 -04:00
|
|
|
return;
|
|
|
|
}
|
2014-05-08 17:07:16 -04:00
|
|
|
edge_data_file.write((char *)&(original_edge_data_vector[0]),
|
|
|
|
original_edge_data_vector.size() * sizeof(OriginalEdgeData));
|
2013-11-28 12:50:12 -05:00
|
|
|
original_edge_data_vector.clear();
|
|
|
|
}
|
|
|
|
|
2016-07-11 11:44:58 -04:00
|
|
|
void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
|
|
|
const std::string &original_edge_data_filename,
|
2016-06-15 08:38:24 -04:00
|
|
|
const std::string &turn_lane_data_filename,
|
2015-10-14 18:08:22 -04:00
|
|
|
const std::string &edge_segment_lookup_filename,
|
|
|
|
const std::string &edge_penalty_filename,
|
2015-10-14 18:08:22 -04:00
|
|
|
const bool generate_edge_lookup)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_START(renumber);
|
2015-07-01 11:55:54 -04:00
|
|
|
m_max_edge_id = RenumberEdges() - 1;
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_STOP(renumber);
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_START(generate_nodes);
|
2016-01-07 04:33:47 -05:00
|
|
|
m_edge_based_node_weights.reserve(m_max_edge_id + 1);
|
2014-05-06 19:03:45 -04:00
|
|
|
GenerateEdgeExpandedNodes();
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_STOP(generate_nodes);
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_START(generate_edges);
|
2016-07-11 11:44:58 -04:00
|
|
|
GenerateEdgeExpandedEdges(scripting_environment,
|
|
|
|
original_edge_data_filename,
|
2016-06-15 08:38:24 -04:00
|
|
|
turn_lane_data_filename,
|
2016-05-27 15:05:04 -04:00
|
|
|
edge_segment_lookup_filename,
|
|
|
|
edge_penalty_filename,
|
|
|
|
generate_edge_lookup);
|
2015-10-14 18:08:22 -04:00
|
|
|
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_STOP(generate_edges);
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
|
|
|
|
util::SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
|
|
|
util::SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
|
|
|
util::SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
|
2014-05-06 19:03:45 -04:00
|
|
|
}
|
|
|
|
|
2015-06-28 16:13:54 -04:00
|
|
|
/// Renumbers all _forward_ edges and sets the edge_id.
|
2015-06-16 05:21:38 -04:00
|
|
|
/// A specific numbering is not important. Any unique ID will do.
|
2015-07-01 11:55:54 -04:00
|
|
|
/// Returns the number of edge based nodes.
|
|
|
|
unsigned EdgeBasedGraphFactory::RenumberEdges()
|
2014-05-06 19:03:45 -04:00
|
|
|
{
|
2015-05-24 11:25:38 -04:00
|
|
|
// renumber edge based node of outgoing edges
|
2014-02-11 05:42:24 -05:00
|
|
|
unsigned numbered_edges_count = 0;
|
2016-01-05 10:51:13 -05:00
|
|
|
for (const auto current_node : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-12-23 08:32:46 -05:00
|
|
|
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
|
|
|
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
|
2015-05-24 11:25:38 -04:00
|
|
|
|
2015-06-28 18:42:22 -04:00
|
|
|
// only number incoming edges
|
|
|
|
if (edge_data.reversed)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-01-04 06:10:22 -05:00
|
|
|
continue;
|
|
|
|
}
|
2014-04-10 16:39:11 -04:00
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
// oneway streets always require this self-loop. Other streets only if a u-turn plus
|
|
|
|
// traversal
|
|
|
|
// of the street takes longer than the loop
|
2016-03-28 11:06:51 -04:00
|
|
|
m_edge_based_node_weights.push_back(edge_data.distance +
|
|
|
|
profile_properties.u_turn_penalty);
|
2016-01-07 04:33:47 -05:00
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
|
2015-06-28 16:13:54 -04:00
|
|
|
edge_data.edge_id = numbered_edges_count;
|
2014-02-11 05:42:24 -05:00
|
|
|
++numbered_edges_count;
|
|
|
|
|
2015-06-28 16:13:54 -04:00
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
|
2014-01-04 06:10:22 -05:00
|
|
|
}
|
|
|
|
}
|
2015-07-01 11:55:54 -04:00
|
|
|
|
|
|
|
return numbered_edges_count;
|
2014-05-06 19:03:45 -04:00
|
|
|
}
|
2012-04-20 12:34:49 -04:00
|
|
|
|
2015-06-23 19:55:30 -04:00
|
|
|
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
2014-05-06 19:03:45 -04:00
|
|
|
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
|
2014-02-11 05:42:24 -05:00
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
// loop over all edges and generate new set of nodes
|
2016-01-05 10:51:13 -05:00
|
|
|
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2015-01-23 05:04:21 -05:00
|
|
|
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
|
|
|
BOOST_ASSERT(node_u < m_node_based_graph->GetNumberOfNodes());
|
2016-04-28 18:46:59 -04:00
|
|
|
progress.PrintStatus(node_u);
|
2015-01-23 05:04:21 -05:00
|
|
|
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
|
|
|
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
|
|
|
BOOST_ASSERT(e1 != SPECIAL_EDGEID);
|
2015-01-23 05:04:21 -05:00
|
|
|
const NodeID node_v = m_node_based_graph->GetTarget(e1);
|
2014-02-27 13:49:53 -05:00
|
|
|
|
2015-01-23 05:04:21 -05:00
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != node_v);
|
2015-06-16 05:21:38 -04:00
|
|
|
// pick only every other edge, since we have every edge as an outgoing
|
|
|
|
// and incoming egde
|
2015-01-23 05:04:21 -05:00
|
|
|
if (node_u > node_v)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-02-11 05:42:24 -05:00
|
|
|
continue;
|
|
|
|
}
|
2014-02-27 13:49:53 -05:00
|
|
|
|
2015-01-23 05:04:21 -05:00
|
|
|
BOOST_ASSERT(node_u < node_v);
|
2013-08-14 12:43:01 -04:00
|
|
|
|
2015-07-04 11:37:24 -04:00
|
|
|
// if we found a non-forward edge reverse and try again
|
2015-06-28 16:13:54 -04:00
|
|
|
if (edge_data.edge_id == SPECIAL_NODEID)
|
2014-07-04 11:33:18 -04:00
|
|
|
{
|
2015-07-04 11:37:24 -04:00
|
|
|
InsertEdgeBasedNode(node_v, node_u);
|
2014-07-04 11:33:18 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-07-04 11:37:24 -04:00
|
|
|
InsertEdgeBasedNode(node_u, node_v);
|
2014-07-04 11:33:18 -04:00
|
|
|
}
|
2012-03-01 08:36:10 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-01 10:04:59 -05:00
|
|
|
|
2015-12-11 17:11:04 -05:00
|
|
|
BOOST_ASSERT(m_edge_based_node_list.size() == m_edge_based_node_is_startpoint.size());
|
2016-01-21 06:58:24 -05:00
|
|
|
BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
|
2015-12-11 17:11:04 -05:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
2016-01-07 19:31:57 -05:00
|
|
|
<< " nodes in edge-expanded graph";
|
2014-05-06 19:03:45 -04:00
|
|
|
}
|
2014-05-06 17:52:51 -04:00
|
|
|
|
2015-06-23 19:55:30 -04:00
|
|
|
/// Actually it also generates OriginalEdgeData and serializes them...
|
2015-01-22 06:19:11 -05:00
|
|
|
void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
2016-07-11 11:44:58 -04:00
|
|
|
ScriptingEnvironment &scripting_environment,
|
2016-01-05 06:04:04 -05:00
|
|
|
const std::string &original_edge_data_filename,
|
2016-06-15 08:38:24 -04:00
|
|
|
const std::string &turn_lane_data_filename,
|
2015-10-14 18:08:22 -04:00
|
|
|
const std::string &edge_segment_lookup_filename,
|
|
|
|
const std::string &edge_fixed_penalties_filename,
|
2015-10-14 18:08:22 -04:00
|
|
|
const bool generate_edge_lookup)
|
2014-05-06 19:03:45 -04:00
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "generating edge-expanded edges";
|
2013-08-16 05:08:07 -04:00
|
|
|
|
2016-01-29 06:42:08 -05:00
|
|
|
std::size_t node_based_edge_counter = 0;
|
|
|
|
std::size_t original_edges_counter = 0;
|
|
|
|
restricted_turns_counter = 0;
|
|
|
|
skipped_uturns_counter = 0;
|
|
|
|
skipped_barrier_turns_counter = 0;
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
|
2015-10-14 18:08:22 -04:00
|
|
|
std::ofstream edge_segment_file;
|
|
|
|
std::ofstream edge_penalty_file;
|
|
|
|
|
|
|
|
if (generate_edge_lookup)
|
|
|
|
{
|
|
|
|
edge_segment_file.open(edge_segment_lookup_filename.c_str(), std::ios::binary);
|
|
|
|
edge_penalty_file.open(edge_fixed_penalties_filename.c_str(), std::ios::binary);
|
|
|
|
}
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2016-03-18 06:02:25 -04:00
|
|
|
// Writes a dummy value at the front that is updated later with the total length
|
|
|
|
const unsigned length_prefix_empty_space{0};
|
|
|
|
edge_data_file.write(reinterpret_cast<const char *>(&length_prefix_empty_space),
|
|
|
|
sizeof(length_prefix_empty_space));
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2013-02-14 11:11:18 -05:00
|
|
|
std::vector<OriginalEdgeData> original_edge_data_vector;
|
2014-05-08 17:07:16 -04:00
|
|
|
original_edge_data_vector.reserve(1024 * 1024);
|
2013-02-14 11:11:18 -05:00
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
// 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.
|
2016-01-05 10:51:13 -05:00
|
|
|
util::Percent progress(m_node_based_graph->GetNumberOfNodes());
|
2016-07-11 11:44:58 -04:00
|
|
|
SuffixTable street_name_suffix_table(scripting_environment);
|
2016-05-27 15:05:04 -04:00
|
|
|
guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
|
|
|
|
m_node_info_list,
|
|
|
|
*m_restriction_map,
|
|
|
|
m_barrier_nodes,
|
|
|
|
m_compressed_edge_container,
|
|
|
|
name_table,
|
2016-07-18 09:34:12 -04:00
|
|
|
street_name_suffix_table,
|
|
|
|
profile_properties);
|
2016-05-13 13:18:00 -04:00
|
|
|
guidance::lanes::TurnLaneHandler turn_lane_handler(
|
2016-08-02 17:17:57 -04:00
|
|
|
*m_node_based_graph, turn_lane_offsets, turn_lane_masks, turn_analysis);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
|
|
|
bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(),
|
|
|
|
std::numeric_limits<std::uint32_t>::max());
|
|
|
|
|
2016-06-15 08:38:24 -04:00
|
|
|
guidance::LaneDataIdMap lane_data_map;
|
2016-01-05 10:51:13 -05:00
|
|
|
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
2014-04-28 13:37:42 -04:00
|
|
|
{
|
2016-04-28 18:46:59 -04:00
|
|
|
progress.PrintStatus(node_u);
|
2016-02-25 08:40:26 -05:00
|
|
|
for (const EdgeID edge_from_u : m_node_based_graph->GetAdjacentEdgeRange(node_u))
|
2014-04-28 13:37:42 -04:00
|
|
|
{
|
2016-02-25 08:40:26 -05:00
|
|
|
if (m_node_based_graph->GetEdgeData(edge_from_u).reversed)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-02-11 05:42:24 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-05-13 13:18:00 -04:00
|
|
|
const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
|
2013-11-29 13:00:00 -05:00
|
|
|
++node_based_edge_counter;
|
2016-05-13 13:18:00 -04:00
|
|
|
auto intersection = turn_analysis.getIntersection(node_u, edge_from_u);
|
|
|
|
intersection =
|
|
|
|
turn_analysis.assignTurnTypes(node_u, edge_from_u, std::move(intersection));
|
2016-01-29 06:42:08 -05:00
|
|
|
|
2016-06-15 08:38:24 -04:00
|
|
|
intersection = turn_lane_handler.assignTurnLanes(
|
|
|
|
node_u, edge_from_u, std::move(intersection), lane_data_map);
|
2016-05-13 13:18:00 -04:00
|
|
|
const auto possible_turns = turn_analysis.transformIntersectionIntoTurns(intersection);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
|
|
|
// the entry class depends on the turn, so we have to classify the interesction for
|
|
|
|
// every edge
|
2016-05-13 13:18:00 -04:00
|
|
|
const auto turn_classification = classifyIntersection(node_v,
|
|
|
|
intersection,
|
|
|
|
*m_node_based_graph,
|
|
|
|
m_compressed_edge_container,
|
|
|
|
m_node_info_list);
|
2016-04-26 07:27:40 -04:00
|
|
|
|
|
|
|
const auto entry_class_id = [&](const util::guidance::EntryClass entry_class) {
|
|
|
|
if (0 == entry_class_hash.count(entry_class))
|
|
|
|
{
|
|
|
|
const auto id = static_cast<std::uint16_t>(entry_class_hash.size());
|
|
|
|
entry_class_hash[entry_class] = id;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return entry_class_hash.find(entry_class)->second;
|
|
|
|
}
|
|
|
|
}(turn_classification.first);
|
|
|
|
|
|
|
|
const auto bearing_class_id = [&](const util::guidance::BearingClass bearing_class) {
|
|
|
|
if (0 == bearing_class_hash.count(bearing_class))
|
|
|
|
{
|
|
|
|
const auto id = static_cast<std::uint32_t>(bearing_class_hash.size());
|
|
|
|
bearing_class_hash[bearing_class] = id;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return bearing_class_hash.find(bearing_class)->second;
|
|
|
|
}
|
|
|
|
}(turn_classification.second);
|
|
|
|
bearing_class_by_node_based_node[node_v] = bearing_class_id;
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto turn : possible_turns)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
|
|
|
// only add an edge if turn is not prohibited
|
2016-02-25 08:40:26 -05:00
|
|
|
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(edge_from_u);
|
2016-01-29 06:42:08 -05:00
|
|
|
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
|
2013-11-28 12:50:12 -05:00
|
|
|
|
2015-06-28 16:13:54 -04:00
|
|
|
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
2015-06-28 18:42:22 -04:00
|
|
|
BOOST_ASSERT(!edge_data1.reversed);
|
|
|
|
BOOST_ASSERT(!edge_data2.reversed);
|
2013-11-28 09:26:13 -05:00
|
|
|
|
2013-11-28 12:50:12 -05:00
|
|
|
// the following is the core of the loop.
|
2013-11-28 09:26:13 -05:00
|
|
|
unsigned distance = edge_data1.distance;
|
2015-02-05 11:54:32 -05:00
|
|
|
if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
|
2014-04-28 13:37:42 -04:00
|
|
|
{
|
2016-03-21 17:42:47 -04:00
|
|
|
distance += profile_properties.traffic_signal_penalty;
|
2013-11-28 09:26:13 -05:00
|
|
|
}
|
2014-10-16 09:58:58 -04:00
|
|
|
|
2016-07-26 09:00:58 -04:00
|
|
|
const int32_t turn_penalty =
|
|
|
|
scripting_environment.GetTurnPenalty(180. - turn.angle);
|
2016-02-24 04:29:23 -05:00
|
|
|
const auto turn_instruction = turn.instruction;
|
2016-01-29 06:42:08 -05:00
|
|
|
|
2016-06-24 10:06:45 -04:00
|
|
|
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
|
2014-04-28 13:37:42 -04:00
|
|
|
{
|
2016-03-21 17:42:47 -04:00
|
|
|
distance += profile_properties.u_turn_penalty;
|
2016-01-05 06:04:04 -05:00
|
|
|
}
|
2015-10-14 18:08:22 -04:00
|
|
|
|
2014-01-27 05:18:26 -05:00
|
|
|
distance += turn_penalty;
|
2013-11-28 09:26:13 -05:00
|
|
|
|
2016-02-25 08:40:26 -05:00
|
|
|
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_from_u));
|
2014-05-09 08:21:33 -04:00
|
|
|
original_edge_data_vector.emplace_back(
|
2016-05-27 15:05:04 -04:00
|
|
|
m_compressed_edge_container.GetPositionForID(edge_from_u),
|
|
|
|
edge_data1.name_id,
|
2016-06-15 08:38:24 -04:00
|
|
|
turn.lane_data_id,
|
2016-05-27 15:05:04 -04:00
|
|
|
turn_instruction,
|
|
|
|
entry_class_id,
|
|
|
|
edge_data1.travel_mode);
|
2014-02-27 13:49:53 -05:00
|
|
|
|
2013-11-29 13:00:00 -05:00
|
|
|
++original_edges_counter;
|
2013-11-28 09:26:13 -05:00
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
|
2014-04-28 13:37:42 -04:00
|
|
|
{
|
|
|
|
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
2013-11-28 09:26:13 -05:00
|
|
|
}
|
|
|
|
|
2015-06-28 16:13:54 -04:00
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
2014-05-08 17:07:16 -04:00
|
|
|
|
2015-11-24 19:33:19 -05:00
|
|
|
// NOTE: potential overflow here if we hit 2^32 routable edges
|
|
|
|
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
|
2016-05-27 15:05:04 -04:00
|
|
|
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
|
|
|
|
edge_data2.edge_id,
|
|
|
|
m_edge_based_edge_list.size(),
|
|
|
|
distance,
|
|
|
|
true,
|
2016-01-05 06:04:04 -05:00
|
|
|
false);
|
2015-10-14 18:08:22 -04:00
|
|
|
|
|
|
|
// Here is where we write out the mapping between the edge-expanded edges, and
|
|
|
|
// the node-based edges that are originally used to calculate the `distance`
|
|
|
|
// for the edge-expanded edges. About 40 lines back, there is:
|
|
|
|
//
|
|
|
|
// unsigned distance = edge_data1.distance;
|
|
|
|
//
|
|
|
|
// This tells us that the weight for an edge-expanded-edge is based on the weight
|
|
|
|
// of the *source* node-based edge. Therefore, we will look up the individual
|
|
|
|
// segments of the source node-based edge, and write out a mapping between
|
|
|
|
// those and the edge-based-edge ID.
|
|
|
|
// External programs can then use this mapping to quickly perform
|
|
|
|
// updates to the edge-expanded-edge based directly on its ID.
|
|
|
|
if (generate_edge_lookup)
|
|
|
|
{
|
2016-03-17 12:22:35 -04:00
|
|
|
const auto node_based_edges =
|
2016-02-25 08:40:26 -05:00
|
|
|
m_compressed_edge_container.GetBucketReference(edge_from_u);
|
2016-03-17 12:22:35 -04:00
|
|
|
NodeID previous = node_u;
|
|
|
|
|
|
|
|
const unsigned node_count = node_based_edges.size() + 1;
|
|
|
|
const QueryNode &first_node = m_node_info_list[previous];
|
2016-06-24 01:01:37 -04:00
|
|
|
|
|
|
|
lookup::SegmentHeaderBlock header = {node_count, first_node.node_id};
|
|
|
|
|
|
|
|
edge_segment_file.write(reinterpret_cast<const char *>(&header),
|
|
|
|
sizeof(header));
|
2016-03-17 12:22:35 -04:00
|
|
|
|
|
|
|
for (auto target_node : node_based_edges)
|
2015-10-14 18:08:22 -04:00
|
|
|
{
|
2016-03-17 12:22:35 -04:00
|
|
|
const QueryNode &from = m_node_info_list[previous];
|
|
|
|
const QueryNode &to = m_node_info_list[target_node.node_id];
|
2016-01-07 19:31:57 -05:00
|
|
|
const double segment_length =
|
2016-02-23 15:23:13 -05:00
|
|
|
util::coordinate_calculation::greatCircleDistance(from, to);
|
2016-03-17 12:22:35 -04:00
|
|
|
|
2016-06-24 01:01:37 -04:00
|
|
|
lookup::SegmentBlock nodeblock = {
|
|
|
|
to.node_id, segment_length, target_node.weight};
|
|
|
|
|
|
|
|
edge_segment_file.write(reinterpret_cast<const char *>(&nodeblock),
|
|
|
|
sizeof(nodeblock));
|
2016-03-17 12:22:35 -04:00
|
|
|
previous = target_node.node_id;
|
2015-10-14 18:08:22 -04:00
|
|
|
}
|
2016-04-29 03:48:13 -04:00
|
|
|
|
|
|
|
// We also now write out the mapping between the edge-expanded edges and the
|
|
|
|
// original nodes. Since each edge represents a possible maneuver, external
|
|
|
|
// programs can use this to quickly perform updates to edge weights in order
|
|
|
|
// to penalize certain turns.
|
|
|
|
|
|
|
|
// If this edge is 'trivial' -- where the compressed edge corresponds
|
|
|
|
// exactly to an original OSM segment -- we can pull the turn's preceding
|
|
|
|
// node ID directly with `node_u`; otherwise, we need to look up the node
|
|
|
|
// immediately preceding the turn from the compressed edge container.
|
|
|
|
const bool isTrivial = m_compressed_edge_container.IsTrivial(edge_from_u);
|
|
|
|
|
|
|
|
const auto &from_node =
|
|
|
|
isTrivial
|
|
|
|
? m_node_info_list[node_u]
|
|
|
|
: m_node_info_list[m_compressed_edge_container.GetLastEdgeSourceID(
|
|
|
|
edge_from_u)];
|
|
|
|
const auto &via_node =
|
|
|
|
m_node_info_list[m_compressed_edge_container.GetLastEdgeTargetID(
|
|
|
|
edge_from_u)];
|
|
|
|
const auto &to_node =
|
|
|
|
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
|
|
|
|
turn.eid)];
|
|
|
|
|
2016-06-24 01:01:37 -04:00
|
|
|
const unsigned fixed_penalty = distance - edge_data1.distance;
|
|
|
|
lookup::PenaltyBlock penaltyblock = {
|
|
|
|
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id};
|
|
|
|
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock),
|
|
|
|
sizeof(penaltyblock));
|
2015-10-14 18:08:22 -04:00
|
|
|
}
|
2011-10-10 11:52:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-14 18:08:22 -04:00
|
|
|
|
2016-04-26 07:27:40 -04:00
|
|
|
util::SimpleLogger().Write() << "Created " << entry_class_hash.size() << " entry classes and "
|
|
|
|
<< bearing_class_hash.size() << " Bearing Classes";
|
|
|
|
|
2016-06-15 08:38:24 -04:00
|
|
|
util::SimpleLogger().Write() << "Writing Turn Lane Data to File...";
|
|
|
|
std::ofstream turn_lane_data_file(turn_lane_data_filename.c_str(), std::ios::binary);
|
|
|
|
std::vector<util::guidance::LaneTupelIdPair> lane_data(lane_data_map.size());
|
|
|
|
// extract lane data sorted by ID
|
|
|
|
for (auto itr : lane_data_map)
|
|
|
|
lane_data[itr.second] = itr.first;
|
|
|
|
|
|
|
|
std::uint64_t size = lane_data.size();
|
|
|
|
turn_lane_data_file.write(reinterpret_cast<const char *>(&size), sizeof(size));
|
|
|
|
|
|
|
|
if (!lane_data.empty())
|
|
|
|
turn_lane_data_file.write(reinterpret_cast<const char *>(&lane_data[0]),
|
|
|
|
sizeof(util::guidance::LaneTupelIdPair) * lane_data.size());
|
|
|
|
|
|
|
|
util::SimpleLogger().Write() << "done.";
|
|
|
|
|
2014-05-08 17:07:16 -04:00
|
|
|
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
2013-11-28 12:50:12 -05:00
|
|
|
|
2016-03-18 06:02:25 -04:00
|
|
|
// Finally jump back to the empty space at the beginning and write length prefix
|
2014-05-08 17:07:16 -04:00
|
|
|
edge_data_file.seekp(std::ios::beg);
|
2016-03-18 06:02:25 -04:00
|
|
|
|
|
|
|
const auto length_prefix = boost::numeric_cast<unsigned>(original_edges_counter);
|
|
|
|
static_assert(sizeof(length_prefix_empty_space) == sizeof(length_prefix), "type mismatch");
|
|
|
|
|
|
|
|
edge_data_file.write(reinterpret_cast<const char *>(&length_prefix), sizeof(length_prefix));
|
2013-08-14 12:43:01 -04:00
|
|
|
|
2016-01-07 19:31:57 -05:00
|
|
|
util::SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
|
|
|
|
<< " edge based nodes";
|
|
|
|
util::SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter
|
|
|
|
<< " edges";
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << "Edge-expanded graph ...";
|
|
|
|
util::SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
|
|
|
|
util::SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
|
2016-01-07 19:31:57 -05:00
|
|
|
"defined by "
|
|
|
|
<< m_restriction_map->size() << " restrictions";
|
2016-01-05 10:51:13 -05:00
|
|
|
util::SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
|
2016-01-07 19:31:57 -05:00
|
|
|
util::SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter
|
|
|
|
<< " turns over barriers";
|
2011-11-09 10:12:05 -05:00
|
|
|
}
|
|
|
|
|
2016-04-26 07:27:40 -04:00
|
|
|
std::vector<util::guidance::BearingClass> EdgeBasedGraphFactory::GetBearingClasses() const
|
|
|
|
{
|
|
|
|
std::vector<util::guidance::BearingClass> result(bearing_class_hash.size());
|
|
|
|
for (const auto &pair : bearing_class_hash)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(pair.second < result.size());
|
|
|
|
result[pair.second] = pair.first;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<BearingClassID> &EdgeBasedGraphFactory::GetBearingClassIds() const
|
|
|
|
{
|
|
|
|
return bearing_class_by_node_based_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<BearingClassID> &EdgeBasedGraphFactory::GetBearingClassIds()
|
|
|
|
{
|
|
|
|
return bearing_class_by_node_based_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<util::guidance::EntryClass> EdgeBasedGraphFactory::GetEntryClasses() const
|
|
|
|
{
|
|
|
|
std::vector<util::guidance::EntryClass> result(entry_class_hash.size());
|
|
|
|
for (const auto &pair : entry_class_hash)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(pair.second < result.size());
|
|
|
|
result[pair.second] = pair.first;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-01-29 06:42:08 -05:00
|
|
|
} // namespace extractor
|
|
|
|
} // namespace osrm
|