2016-06-30 03:31:08 -04:00
|
|
|
#include "extractor/edge_based_graph_factory.hpp"
|
2017-08-01 11:18:12 -04:00
|
|
|
#include "extractor/conditional_turn_penalty.hpp"
|
2016-07-22 03:08:40 -04:00
|
|
|
#include "extractor/edge_based_edge.hpp"
|
2017-04-01 21:25:55 -04:00
|
|
|
#include "extractor/files.hpp"
|
2018-01-05 08:33:53 -05:00
|
|
|
#include "extractor/intersection/intersection_analysis.hpp"
|
2017-02-02 10:55:19 -05:00
|
|
|
#include "extractor/scripting_environment.hpp"
|
2018-01-05 08:33:53 -05:00
|
|
|
#include "extractor/serialization.hpp"
|
2017-02-02 10:55:19 -05:00
|
|
|
#include "extractor/suffix_table.hpp"
|
2018-01-05 08:33:53 -05:00
|
|
|
|
2017-03-04 05:52:40 -05:00
|
|
|
#include "storage/io.hpp"
|
|
|
|
|
2017-05-16 10:32:50 -04:00
|
|
|
#include "util/assert.hpp"
|
2016-08-17 03:49:19 -04:00
|
|
|
#include "util/bearing.hpp"
|
2018-02-01 10:00:15 -05:00
|
|
|
#include "util/connectivity_checksum.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-12-06 15:30:46 -05:00
|
|
|
#include "util/log.hpp"
|
2016-04-10 20:23:22 -04:00
|
|
|
#include "util/percent.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "util/timing_util.hpp"
|
|
|
|
|
2013-12-13 18:49:05 -05:00
|
|
|
#include <boost/assert.hpp>
|
2018-02-01 10:00:15 -05:00
|
|
|
#include <boost/crc.hpp>
|
2017-08-01 11:18:12 -04:00
|
|
|
#include <boost/functional/hash.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-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>
|
2020-09-01 07:25:51 -04:00
|
|
|
#include <thread>
|
2018-02-09 13:32:09 -05:00
|
|
|
#include <tuple>
|
2016-04-26 07:27:40 -04:00
|
|
|
#include <unordered_map>
|
2013-11-29 12:49:02 -05:00
|
|
|
|
2017-06-07 00:31:07 -04:00
|
|
|
#include <tbb/blocked_range.h>
|
|
|
|
#include <tbb/parallel_for.h>
|
|
|
|
#include <tbb/pipeline.h>
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template <> struct hash<std::pair<NodeID, NodeID>>
|
|
|
|
{
|
|
|
|
std::size_t operator()(const std::pair<NodeID, NodeID> &mk) const noexcept
|
|
|
|
{
|
|
|
|
std::size_t seed = 0;
|
|
|
|
boost::hash_combine(seed, mk.first);
|
|
|
|
boost::hash_combine(seed, mk.second);
|
|
|
|
return seed;
|
|
|
|
}
|
|
|
|
};
|
2020-11-26 10:21:39 -05:00
|
|
|
} // namespace std
|
2017-08-01 11:18:12 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
2016-01-29 06:42:08 -05:00
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
// Configuration to find representative candidate for turn angle calculations
|
2015-08-18 06:56:34 -04:00
|
|
|
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
2017-09-25 09:37:11 -04:00
|
|
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
|
|
EdgeBasedNodeDataContainer &node_data_container,
|
|
|
|
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,
|
2017-04-02 19:58:06 -04:00
|
|
|
const std::vector<util::Coordinate> &coordinates,
|
2018-03-21 07:10:02 -04:00
|
|
|
const NameTable &name_table,
|
2017-11-09 08:37:16 -05:00
|
|
|
const std::unordered_set<EdgeID> &segregated_edges,
|
2018-01-08 13:12:06 -05:00
|
|
|
const extractor::LaneDescriptionMap &lane_description_map)
|
2018-02-01 10:00:15 -05:00
|
|
|
: m_edge_based_node_container(node_data_container), m_connectivity_checksum(0),
|
|
|
|
m_number_of_edge_based_nodes(0), m_coordinates(coordinates),
|
|
|
|
m_node_based_graph(std::move(node_based_graph)), m_barrier_nodes(barrier_nodes),
|
|
|
|
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
|
|
|
name_table(name_table), segregated_edges(segregated_edges),
|
|
|
|
lane_description_map(lane_description_map)
|
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
|
|
|
}
|
|
|
|
|
2017-05-16 13:22:41 -04:00
|
|
|
void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2015-12-16 12:12:18 -05:00
|
|
|
using std::swap; // Koenig swap
|
2017-05-16 13:22:41 -04:00
|
|
|
swap(nodes, m_edge_based_node_segments);
|
2011-11-09 10:12:05 -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);
|
|
|
|
}
|
|
|
|
|
2018-04-22 14:05:11 -04:00
|
|
|
void EdgeBasedGraphFactory::GetEdgeBasedNodeDurations(
|
|
|
|
std::vector<EdgeWeight> &output_node_durations)
|
|
|
|
{
|
|
|
|
using std::swap; // Koenig swap
|
|
|
|
swap(m_edge_based_node_durations, output_node_durations);
|
|
|
|
}
|
|
|
|
|
2018-10-30 00:47:49 -04:00
|
|
|
void EdgeBasedGraphFactory::GetEdgeBasedNodeDistances(
|
|
|
|
std::vector<EdgeDistance> &output_node_distances)
|
|
|
|
{
|
|
|
|
using std::swap; // Koenig swap
|
|
|
|
swap(m_edge_based_node_distances, output_node_distances);
|
|
|
|
}
|
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
std::uint32_t EdgeBasedGraphFactory::GetConnectivityChecksum() const
|
|
|
|
{
|
|
|
|
return m_connectivity_checksum;
|
|
|
|
}
|
|
|
|
|
2017-07-11 08:22:28 -04:00
|
|
|
std::uint64_t EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const
|
|
|
|
{
|
|
|
|
return m_number_of_edge_based_nodes;
|
|
|
|
}
|
2015-07-01 11:55:54 -04:00
|
|
|
|
2017-03-15 10:30:12 -04:00
|
|
|
NBGToEBG 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
|
2017-09-25 09:37:11 -04:00
|
|
|
const EdgeID edge_id_1 = m_node_based_graph.FindEdge(node_u, node_v);
|
2015-01-23 05:04:21 -05:00
|
|
|
BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
|
2014-07-04 11:33:18 -04:00
|
|
|
|
2017-09-25 09:37:11 -04: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
|
2017-09-25 09:37:11 -04:00
|
|
|
const EdgeID edge_id_2 = m_node_based_graph.FindEdge(node_v, node_u);
|
2015-01-23 05:04:21 -05:00
|
|
|
BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
|
2015-04-16 18:23:58 -04:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
const EdgeData &reverse_data = m_node_based_graph.GetEdgeData(edge_id_2);
|
2014-05-08 17:07:16 -04:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
BOOST_ASSERT(nbe_to_ebn_mapping[edge_id_1] != SPECIAL_NODEID ||
|
|
|
|
nbe_to_ebn_mapping[edge_id_2] != SPECIAL_NODEID);
|
2014-02-27 13:49:53 -05:00
|
|
|
|
2018-04-27 12:43:13 -04:00
|
|
|
// ⚠ Use the sign bit of node weights to distinguish oneway streets:
|
|
|
|
// * MSB is set - a node corresponds to a one-way street
|
|
|
|
// * MSB is clear - a node corresponds to a bidirectional street
|
|
|
|
// Before using node weights data values must be adjusted:
|
|
|
|
// * in contraction if MSB is set the node weight is INVALID_EDGE_WEIGHT.
|
|
|
|
// This adjustment is needed to enforce loop creation for oneways.
|
|
|
|
// * in other cases node weights must be masked with 0x7fffffff to clear MSB
|
2017-09-25 09:37:11 -04:00
|
|
|
if (nbe_to_ebn_mapping[edge_id_1] != SPECIAL_NODEID &&
|
|
|
|
nbe_to_ebn_mapping[edge_id_2] == SPECIAL_NODEID)
|
2018-04-23 04:00:30 -04:00
|
|
|
m_edge_based_node_weights[nbe_to_ebn_mapping[edge_id_1]] |= 0x80000000;
|
2016-01-07 04:33:47 -05:00
|
|
|
|
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-07-22 12:23:54 -04:00
|
|
|
const auto segment_count = 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
|
2016-07-22 12:23:54 -04:00
|
|
|
BOOST_ASSERT(0 != segment_count);
|
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
// const unsigned packed_geometry_id = m_compressed_edge_container.ZipEdges(edge_id_1,
|
|
|
|
// edge_id_2);
|
2016-03-03 22:27:36 -05:00
|
|
|
|
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};
|
|
|
|
};
|
|
|
|
|
2017-05-10 15:02:19 -04:00
|
|
|
// Add edge-based node data for forward and reverse nodes indexed by edge_id
|
2017-09-25 09:37:11 -04:00
|
|
|
BOOST_ASSERT(nbe_to_ebn_mapping[edge_id_1] != SPECIAL_EDGEID);
|
|
|
|
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].geometry_id =
|
|
|
|
forward_data.geometry_id;
|
|
|
|
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].annotation_id =
|
|
|
|
forward_data.annotation_data;
|
2017-10-14 08:21:31 -04:00
|
|
|
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].segregated =
|
2017-11-09 08:37:16 -05:00
|
|
|
segregated_edges.count(edge_id_1) > 0;
|
2017-10-14 08:21:31 -04:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
if (nbe_to_ebn_mapping[edge_id_2] != SPECIAL_EDGEID)
|
2017-05-10 15:02:19 -04:00
|
|
|
{
|
2017-09-25 09:37:11 -04:00
|
|
|
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].geometry_id =
|
|
|
|
reverse_data.geometry_id;
|
|
|
|
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].annotation_id =
|
|
|
|
reverse_data.annotation_data;
|
2017-10-14 08:21:31 -04:00
|
|
|
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].segregated =
|
2017-11-09 08:37:16 -05:00
|
|
|
segregated_edges.count(edge_id_2) > 0;
|
2017-05-10 15:02:19 -04:00
|
|
|
}
|
2017-10-14 08:21:31 -04:00
|
|
|
|
2017-05-10 15:02:19 -04:00
|
|
|
// Add segments of edge-based nodes
|
2016-07-22 12:23:54 -04:00
|
|
|
for (const auto i : util::irange(std::size_t{0}, segment_count))
|
2016-03-04 10:37:25 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
BOOST_ASSERT(
|
|
|
|
current_edge_source_coordinate_id ==
|
2016-07-22 12:23:54 -04:00
|
|
|
m_compressed_edge_container.GetBucketReference(edge_id_2)[segment_count - 1 - i]
|
2016-03-28 11:06:51 -04:00
|
|
|
.node_id);
|
2016-03-04 10:37:25 -05:00
|
|
|
const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
|
2017-07-20 08:03:39 -04:00
|
|
|
|
|
|
|
// don't add node-segments for penalties
|
|
|
|
if (current_edge_target_coordinate_id == current_edge_source_coordinate_id)
|
|
|
|
continue;
|
|
|
|
|
2016-03-04 10:37:25 -05:00
|
|
|
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
|
|
|
|
|
|
|
// build edges
|
2017-09-25 09:37:11 -04:00
|
|
|
m_edge_based_node_segments.emplace_back(
|
|
|
|
edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_1]),
|
|
|
|
edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]),
|
|
|
|
current_edge_source_coordinate_id,
|
|
|
|
current_edge_target_coordinate_id,
|
2018-12-13 19:10:32 -05:00
|
|
|
i,
|
|
|
|
forward_data.flags.startpoint || reverse_data.flags.startpoint);
|
2017-09-25 09:37:11 -04:00
|
|
|
|
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);
|
2017-02-02 10:55:19 -05:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
return NBGToEBG{node_u, node_v, nbe_to_ebn_mapping[edge_id_1], nbe_to_ebn_mapping[edge_id_2]};
|
2012-03-01 13:41:06 -05:00
|
|
|
}
|
|
|
|
|
2018-02-09 13:32:09 -05:00
|
|
|
void EdgeBasedGraphFactory::Run(
|
|
|
|
ScriptingEnvironment &scripting_environment,
|
|
|
|
const std::string &turn_weight_penalties_filename,
|
|
|
|
const std::string &turn_duration_penalties_filename,
|
|
|
|
const std::string &turn_penalties_index_filename,
|
|
|
|
const std::string &cnbg_ebg_mapping_path,
|
|
|
|
const std::string &conditional_penalties_filename,
|
|
|
|
const std::string &maneuver_overrides_filename,
|
2020-12-20 16:59:57 -05:00
|
|
|
const RestrictionMap &unconditional_node_restriction_map,
|
2018-02-09 13:32:09 -05:00
|
|
|
const ConditionalRestrictionMap &conditional_node_restriction_map,
|
|
|
|
const WayRestrictionMap &way_restriction_map,
|
|
|
|
const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_START(renumber);
|
2017-09-25 09:37:11 -04:00
|
|
|
m_number_of_edge_based_nodes =
|
|
|
|
LabelEdgeBasedNodes() + way_restriction_map.NumberOfDuplicatedNodes();
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_STOP(renumber);
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
// Allocate memory for edge-based nodes
|
|
|
|
// In addition to the normal edges, allocate enough space for copied edges from
|
|
|
|
// via-way-restrictions, see calculation above
|
|
|
|
m_edge_based_node_container.nodes.resize(m_number_of_edge_based_nodes);
|
|
|
|
|
2014-05-08 17:51:28 -04:00
|
|
|
TIMER_START(generate_nodes);
|
2017-03-15 10:30:12 -04:00
|
|
|
{
|
2017-07-11 08:22:28 -04:00
|
|
|
auto mapping = GenerateEdgeExpandedNodes(way_restriction_map);
|
2017-04-01 14:44:49 -04:00
|
|
|
files::writeNBGMapping(cnbg_ebg_mapping_path, mapping);
|
2017-03-15 10:30:12 -04:00
|
|
|
}
|
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,
|
2016-05-12 12:50:10 -04:00
|
|
|
turn_weight_penalties_filename,
|
|
|
|
turn_duration_penalties_filename,
|
2017-07-11 08:22:28 -04:00
|
|
|
turn_penalties_index_filename,
|
2017-08-01 11:18:12 -04:00
|
|
|
conditional_penalties_filename,
|
2018-02-09 13:32:09 -05:00
|
|
|
maneuver_overrides_filename,
|
2020-12-20 16:59:57 -05:00
|
|
|
unconditional_node_restriction_map,
|
2017-08-01 11:18:12 -04:00
|
|
|
conditional_node_restriction_map,
|
2018-02-09 13:32:09 -05:00
|
|
|
way_restriction_map,
|
|
|
|
unresolved_maneuver_overrides);
|
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-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Timing statistics for edge-expanded graph:";
|
|
|
|
util::Log() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
|
|
|
util::Log() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
|
|
|
util::Log() << "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.
|
2017-07-27 05:42:13 -04:00
|
|
|
/// Returns the number of edge-based nodes.
|
2017-09-25 09:37:11 -04:00
|
|
|
unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
2014-05-06 19:03:45 -04:00
|
|
|
{
|
2018-01-24 15:39:55 -05:00
|
|
|
// heuristic: node-based graph node is a simple intersection with four edges
|
|
|
|
// (edge-based nodes)
|
2018-10-30 00:47:49 -04:00
|
|
|
constexpr std::size_t ESTIMATED_EDGE_COUNT = 4;
|
|
|
|
m_edge_based_node_weights.reserve(ESTIMATED_EDGE_COUNT * m_node_based_graph.GetNumberOfNodes());
|
|
|
|
m_edge_based_node_durations.reserve(ESTIMATED_EDGE_COUNT *
|
|
|
|
m_node_based_graph.GetNumberOfNodes());
|
|
|
|
m_edge_based_node_distances.reserve(ESTIMATED_EDGE_COUNT *
|
|
|
|
m_node_based_graph.GetNumberOfNodes());
|
2017-09-25 09:37:11 -04:00
|
|
|
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
|
2017-05-03 03:34:57 -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;
|
2017-09-25 09:37:11 -04:00
|
|
|
for (const auto current_node : util::irange(0u, m_node_based_graph.GetNumberOfNodes()))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2017-09-25 09:37:11 -04:00
|
|
|
for (const auto current_edge : m_node_based_graph.GetAdjacentEdgeRange(current_node))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2017-09-25 09:37:11 -04:00
|
|
|
const EdgeData &edge_data = m_node_based_graph.GetEdgeData(current_edge);
|
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-05-12 12:50:10 -04:00
|
|
|
m_edge_based_node_weights.push_back(edge_data.weight);
|
2018-04-22 14:05:11 -04:00
|
|
|
m_edge_based_node_durations.push_back(edge_data.duration);
|
2018-10-30 00:47:49 -04:00
|
|
|
m_edge_based_node_distances.push_back(edge_data.distance);
|
2016-01-07 04:33:47 -05:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges());
|
|
|
|
nbe_to_ebn_mapping[current_edge] = numbered_edges_count;
|
2014-02-11 05:42:24 -05:00
|
|
|
++numbered_edges_count;
|
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
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
2017-07-11 08:22:28 -04:00
|
|
|
std::vector<NBGToEBG>
|
|
|
|
EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_restriction_map)
|
2014-05-06 19:03:45 -04:00
|
|
|
{
|
2017-03-15 10:30:12 -04:00
|
|
|
std::vector<NBGToEBG> mapping;
|
2017-02-02 10:55:19 -05:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Generating edge expanded nodes ... ";
|
2017-07-11 08:22:28 -04:00
|
|
|
// indicating a normal node within the edge-based graph. This node represents an edge in the
|
|
|
|
// node-based graph
|
2016-12-06 15:30:46 -05:00
|
|
|
{
|
|
|
|
util::UnbufferedLog log;
|
2017-09-25 09:37:11 -04:00
|
|
|
util::Percent progress(log, m_node_based_graph.GetNumberOfNodes());
|
2014-02-11 05:42:24 -05:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
// m_compressed_edge_container.InitializeBothwayVector();
|
2016-07-22 12:23:54 -04:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
// loop over all edges and generate new set of nodes
|
2017-09-25 09:37:11 -04:00
|
|
|
for (const auto nbg_node_u : util::irange(0u, m_node_based_graph.GetNumberOfNodes()))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2017-05-10 15:02:19 -04:00
|
|
|
BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID);
|
|
|
|
progress.PrintStatus(nbg_node_u);
|
2017-09-25 09:37:11 -04:00
|
|
|
for (EdgeID nbg_edge_id : m_node_based_graph.GetAdjacentEdgeRange(nbg_node_u))
|
2014-05-08 17:07:16 -04:00
|
|
|
{
|
2017-05-10 15:02:19 -04:00
|
|
|
BOOST_ASSERT(nbg_edge_id != SPECIAL_EDGEID);
|
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
const NodeID nbg_node_v = m_node_based_graph.GetTarget(nbg_edge_id);
|
2017-05-10 15:02:19 -04:00
|
|
|
BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID);
|
|
|
|
BOOST_ASSERT(nbg_node_u != nbg_node_v);
|
2016-12-06 15:30:46 -05:00
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// pick only every other edge, since we have every edge as an outgoing and incoming
|
|
|
|
// egde
|
2017-05-10 15:02:19 -04:00
|
|
|
if (nbg_node_u >= nbg_node_v)
|
2016-12-06 15:30:46 -05:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2014-02-27 13:49:53 -05:00
|
|
|
|
2016-12-06 15:30:46 -05:00
|
|
|
// if we found a non-forward edge reverse and try again
|
2017-09-25 09:37:11 -04:00
|
|
|
if (nbe_to_ebn_mapping[nbg_edge_id] == SPECIAL_NODEID)
|
2016-12-06 15:30:46 -05:00
|
|
|
{
|
2017-05-10 15:02:19 -04:00
|
|
|
mapping.push_back(InsertEdgeBasedNode(nbg_node_v, nbg_node_u));
|
2016-12-06 15:30:46 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-05-10 15:02:19 -04:00
|
|
|
mapping.push_back(InsertEdgeBasedNode(nbg_node_u, nbg_node_v));
|
2017-03-06 08:06:01 -05:00
|
|
|
}
|
2014-07-04 11:33:18 -04:00
|
|
|
}
|
2012-03-01 08:36:10 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-01 10:04:59 -05:00
|
|
|
|
2017-07-11 08:22:28 -04:00
|
|
|
util::Log() << "Expanding via-way turn restrictions ... ";
|
|
|
|
// Add copies of the nodes
|
|
|
|
{
|
|
|
|
util::UnbufferedLog log;
|
2020-12-20 16:59:57 -05:00
|
|
|
const auto via_edges = way_restriction_map.DuplicatedViaEdges();
|
|
|
|
util::Percent progress(log, via_edges.size());
|
2017-07-11 08:22:28 -04:00
|
|
|
|
|
|
|
NodeID edge_based_node_id =
|
|
|
|
NodeID(m_number_of_edge_based_nodes - way_restriction_map.NumberOfDuplicatedNodes());
|
|
|
|
std::size_t progress_counter = 0;
|
|
|
|
// allocate enough space for the mapping
|
2020-12-20 16:59:57 -05:00
|
|
|
for (const auto edge : via_edges)
|
2017-07-11 08:22:28 -04:00
|
|
|
{
|
2020-12-20 16:59:57 -05:00
|
|
|
const auto node_u = edge.from;
|
|
|
|
const auto node_v = edge.to;
|
2017-07-11 08:22:28 -04:00
|
|
|
// we know that the edge exists as non-reversed edge
|
2017-09-25 09:37:11 -04:00
|
|
|
const auto eid = m_node_based_graph.FindEdge(node_u, node_v);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
BOOST_ASSERT(nbe_to_ebn_mapping[eid] != SPECIAL_NODEID);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
|
|
|
// merge edges together into one EdgeBasedNode
|
|
|
|
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
|
|
|
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
|
|
|
|
|
|
|
// find node in the edge based graph, we only require one id:
|
2017-09-25 09:37:11 -04:00
|
|
|
const EdgeData &edge_data = m_node_based_graph.GetEdgeData(eid);
|
|
|
|
// BOOST_ASSERT(edge_data.edge_id < m_edge_based_node_container.Size());
|
|
|
|
m_edge_based_node_container.nodes[edge_based_node_id].geometry_id =
|
|
|
|
edge_data.geometry_id;
|
|
|
|
m_edge_based_node_container.nodes[edge_based_node_id].annotation_id =
|
|
|
|
edge_data.annotation_data;
|
2017-11-09 08:37:16 -05:00
|
|
|
m_edge_based_node_container.nodes[edge_based_node_id].segregated =
|
|
|
|
segregated_edges.count(eid) > 0;
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2018-01-02 04:54:46 -05:00
|
|
|
const auto ebn_weight = m_edge_based_node_weights[nbe_to_ebn_mapping[eid]];
|
2018-04-30 02:39:10 -04:00
|
|
|
BOOST_ASSERT((ebn_weight & 0x7fffffff) == edge_data.weight);
|
2018-01-02 04:54:46 -05:00
|
|
|
m_edge_based_node_weights.push_back(ebn_weight);
|
2018-04-22 14:05:11 -04:00
|
|
|
m_edge_based_node_durations.push_back(
|
|
|
|
m_edge_based_node_durations[nbe_to_ebn_mapping[eid]]);
|
2018-10-30 00:47:49 -04:00
|
|
|
m_edge_based_node_distances.push_back(
|
|
|
|
m_edge_based_node_distances[nbe_to_ebn_mapping[eid]]);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
|
|
|
edge_based_node_id++;
|
|
|
|
progress.PrintStatus(progress_counter++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size());
|
2018-04-22 14:05:11 -04:00
|
|
|
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_durations.size());
|
2018-10-30 00:47:49 -04:00
|
|
|
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size());
|
2015-12-11 17:11:04 -05:00
|
|
|
|
2017-07-27 05:42:13 -04:00
|
|
|
util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes ("
|
|
|
|
<< way_restriction_map.NumberOfDuplicatedNodes()
|
|
|
|
<< " of which are duplicates) and " << m_edge_based_node_segments.size()
|
|
|
|
<< " segments in edge-expanded graph";
|
2017-05-03 05:48:43 -04:00
|
|
|
|
|
|
|
return mapping;
|
2017-04-25 05:36:34 -04:00
|
|
|
}
|
|
|
|
|
2017-04-01 21:00:03 -04:00
|
|
|
/// Actually it also generates turn data 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-05-12 12:50:10 -04:00
|
|
|
const std::string &turn_weight_penalties_filename,
|
|
|
|
const std::string &turn_duration_penalties_filename,
|
2017-07-11 08:22:28 -04:00
|
|
|
const std::string &turn_penalties_index_filename,
|
2017-08-01 11:18:12 -04:00
|
|
|
const std::string &conditional_penalties_filename,
|
2018-02-09 13:32:09 -05:00
|
|
|
const std::string &maneuver_overrides_filename,
|
2020-12-20 16:59:57 -05:00
|
|
|
const RestrictionMap &unconditional_node_restriction_map,
|
|
|
|
const ConditionalRestrictionMap &conditional_node_restriction_map,
|
2018-02-09 13:32:09 -05:00
|
|
|
const WayRestrictionMap &way_restriction_map,
|
|
|
|
const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
|
2014-05-06 19:03:45 -04:00
|
|
|
{
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "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;
|
2014-05-06 19:03:45 -04:00
|
|
|
|
2017-12-03 15:32:17 -05:00
|
|
|
SuffixTable street_name_suffix_table(scripting_environment);
|
|
|
|
const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map);
|
2018-01-05 08:33:53 -05:00
|
|
|
intersection::MergableRoadDetector mergable_road_detector(m_node_based_graph,
|
|
|
|
m_edge_based_node_container,
|
|
|
|
m_coordinates,
|
|
|
|
m_compressed_edge_container,
|
2020-12-20 16:59:57 -05:00
|
|
|
unconditional_node_restriction_map,
|
2018-01-05 08:33:53 -05:00
|
|
|
m_barrier_nodes,
|
|
|
|
turn_lanes_data,
|
|
|
|
name_table,
|
|
|
|
street_name_suffix_table);
|
2017-12-03 15:32:17 -05:00
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
// FIXME these need to be tuned in pre-allocated size
|
|
|
|
std::vector<TurnPenalty> turn_weight_penalties;
|
|
|
|
std::vector<TurnPenalty> turn_duration_penalties;
|
2020-10-23 05:38:56 -04:00
|
|
|
std::vector<lookup::TurnIndexBlock> turn_penalties_index;
|
2016-05-12 12:50:10 -04:00
|
|
|
|
2018-02-09 13:32:09 -05:00
|
|
|
// Now, renumber all our maneuver overrides to use edge-based-nodes
|
|
|
|
std::vector<StorageManeuverOverride> storage_maneuver_overrides;
|
|
|
|
std::vector<NodeID> maneuver_override_sequences;
|
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
const auto weight_multiplier =
|
2017-01-17 03:24:52 -05:00
|
|
|
scripting_environment.GetProfileProperties().GetWeightMultiplier();
|
2016-05-12 12:50:10 -04:00
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
// filled in during next stage, kept alive through following scope
|
|
|
|
std::vector<Conditional> conditionals;
|
2018-01-24 15:39:55 -05:00
|
|
|
// The following block generates the edge-based-edges using a parallel processing pipeline.
|
|
|
|
// Sets of intersection IDs are batched in groups of GRAINSIZE (100) `generator_stage`, then
|
|
|
|
// those groups are processed in parallel `processor_stage`. Finally, results are appended to
|
|
|
|
// the various buffer vectors by the `output_stage` in the same order that the `generator_stage`
|
|
|
|
// created them in (tbb::filter::serial_in_order creates this guarantee). The order needs to be
|
|
|
|
// maintained because we depend on it later in the processing pipeline.
|
2014-04-28 13:37:42 -04:00
|
|
|
{
|
2017-09-25 09:37:11 -04:00
|
|
|
const NodeID node_count = m_node_based_graph.GetNumberOfNodes();
|
2017-11-08 23:04:32 -05:00
|
|
|
|
|
|
|
// This struct is the buffered output of the `processor_stage`. This data is
|
|
|
|
// appended to the various output arrays/files by the `output_stage`.
|
2017-12-01 18:37:09 -05:00
|
|
|
// same as IntersectionData, but grouped with edge to allow sorting after creating.
|
2017-11-08 23:04:32 -05:00
|
|
|
struct EdgeWithData
|
|
|
|
{
|
|
|
|
EdgeBasedEdge edge;
|
|
|
|
lookup::TurnIndexBlock turn_index;
|
|
|
|
TurnPenalty turn_weight_penalty;
|
|
|
|
TurnPenalty turn_duration_penalty;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto const transfer_data = [&](const EdgeWithData &edge_with_data) {
|
|
|
|
m_edge_based_edge_list.push_back(edge_with_data.edge);
|
|
|
|
turn_weight_penalties.push_back(edge_with_data.turn_weight_penalty);
|
|
|
|
turn_duration_penalties.push_back(edge_with_data.turn_duration_penalty);
|
2020-10-23 05:38:56 -04:00
|
|
|
turn_penalties_index.push_back(edge_with_data.turn_index);
|
2017-11-08 23:04:32 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct EdgesPipelineBuffer
|
|
|
|
{
|
|
|
|
std::size_t nodes_processed = 0;
|
|
|
|
|
2017-11-09 11:40:06 -05:00
|
|
|
std::vector<EdgeWithData> continuous_data; // may need this
|
|
|
|
std::vector<EdgeWithData> delayed_data; // may need this
|
2017-11-08 23:04:32 -05:00
|
|
|
std::vector<Conditional> conditionals;
|
2018-02-01 10:00:15 -05:00
|
|
|
|
2018-02-09 13:32:09 -05:00
|
|
|
std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> turn_to_ebn_map;
|
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
util::ConnectivityChecksum checksum;
|
2017-11-08 23:04:32 -05:00
|
|
|
};
|
|
|
|
using EdgesPipelineBufferPtr = std::shared_ptr<EdgesPipelineBuffer>;
|
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
m_connectivity_checksum = 0;
|
|
|
|
|
2018-02-09 13:32:09 -05:00
|
|
|
std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> global_turn_to_ebn_map;
|
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// going over all nodes (which form the center of an intersection), we compute all possible
|
|
|
|
// turns along these intersections.
|
2017-06-07 00:31:07 -04:00
|
|
|
NodeID current_node = 0;
|
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// Handle intersections in sets of 100. The pipeline below has a serial bottleneck during
|
|
|
|
// the writing phase, so we want to make the parallel workers do more work to give the
|
|
|
|
// serial final stage time to complete its tasks.
|
2017-06-07 00:31:07 -04:00
|
|
|
const constexpr unsigned GRAINSIZE = 100;
|
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
// First part of the pipeline generates iterator ranges of IDs in sets of GRAINSIZE
|
2017-06-07 00:31:07 -04:00
|
|
|
tbb::filter_t<void, tbb::blocked_range<NodeID>> generator_stage(
|
2017-11-08 23:04:32 -05:00
|
|
|
tbb::filter::serial_in_order, [&](tbb::flow_control &fc) {
|
2017-06-07 00:31:07 -04:00
|
|
|
if (current_node < node_count)
|
|
|
|
{
|
|
|
|
auto next_node = std::min(current_node + GRAINSIZE, node_count);
|
|
|
|
auto result = tbb::blocked_range<NodeID>(current_node, next_node);
|
|
|
|
current_node = next_node;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fc.stop();
|
|
|
|
return tbb::blocked_range<NodeID>(node_count, node_count);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-07-11 08:22:28 -04:00
|
|
|
// Generate edges for either artificial nodes or the main graph
|
2020-12-20 16:59:57 -05:00
|
|
|
const auto generate_edge = [this, &scripting_environment, weight_multiplier](
|
2020-11-26 10:21:39 -05:00
|
|
|
// what nodes will be used? In most cases this will be the id
|
|
|
|
// stored in the edge_data. In case of duplicated nodes (e.g.
|
|
|
|
// due to via-way restrictions), one/both of these might
|
|
|
|
// refer to a newly added edge based node
|
|
|
|
const auto edge_based_node_from,
|
|
|
|
const auto edge_based_node_to,
|
|
|
|
// the situation of the turn
|
|
|
|
const auto node_along_road_entering,
|
|
|
|
const auto node_based_edge_from,
|
|
|
|
const auto intersection_node,
|
|
|
|
const auto node_based_edge_to,
|
|
|
|
const auto &turn_angle,
|
|
|
|
const auto &road_legs_on_the_right,
|
|
|
|
const auto &road_legs_on_the_left,
|
|
|
|
const auto &edge_geometries) {
|
2017-09-25 09:37:11 -04:00
|
|
|
const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from);
|
|
|
|
const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
BOOST_ASSERT(nbe_to_ebn_mapping[node_based_edge_from] !=
|
|
|
|
nbe_to_ebn_mapping[node_based_edge_to]);
|
2017-07-11 08:22:28 -04:00
|
|
|
BOOST_ASSERT(!edge_data1.reversed);
|
|
|
|
BOOST_ASSERT(!edge_data2.reversed);
|
|
|
|
|
|
|
|
// compute weight and duration penalties
|
2017-11-10 11:05:01 -05:00
|
|
|
const auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
2018-01-05 08:33:53 -05:00
|
|
|
const auto is_uturn =
|
|
|
|
guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn;
|
2018-01-24 15:39:55 -05:00
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
ExtractionTurn extracted_turn(
|
2018-01-24 15:39:55 -05:00
|
|
|
// general info
|
2017-11-10 11:05:01 -05:00
|
|
|
turn_angle,
|
|
|
|
road_legs_on_the_right.size() + road_legs_on_the_left.size() + 2 - is_uturn,
|
|
|
|
is_uturn,
|
2017-09-25 09:37:11 -04:00
|
|
|
is_traffic_light,
|
|
|
|
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
|
2017-11-03 13:08:11 -04:00
|
|
|
.is_left_hand_driving,
|
2018-01-24 15:39:55 -05:00
|
|
|
// source info
|
|
|
|
edge_data1.flags.restricted,
|
2017-11-03 13:08:11 -04:00
|
|
|
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data).travel_mode,
|
2018-01-24 15:39:55 -05:00
|
|
|
edge_data1.flags.road_classification.IsMotorwayClass(),
|
|
|
|
edge_data1.flags.road_classification.IsLinkClass(),
|
|
|
|
edge_data1.flags.road_classification.GetNumberOfLanes(),
|
|
|
|
edge_data1.flags.highway_turn_classification,
|
|
|
|
edge_data1.flags.access_turn_classification,
|
|
|
|
((double)intersection::findEdgeLength(edge_geometries, node_based_edge_from) /
|
|
|
|
edge_data1.duration) *
|
|
|
|
36,
|
2018-02-07 05:39:02 -05:00
|
|
|
edge_data1.flags.road_classification.GetPriority(),
|
2018-01-24 15:39:55 -05:00
|
|
|
// target info
|
|
|
|
edge_data2.flags.restricted,
|
|
|
|
m_edge_based_node_container.GetAnnotation(edge_data2.annotation_data).travel_mode,
|
|
|
|
edge_data2.flags.road_classification.IsMotorwayClass(),
|
|
|
|
edge_data2.flags.road_classification.IsLinkClass(),
|
|
|
|
edge_data2.flags.road_classification.GetNumberOfLanes(),
|
|
|
|
edge_data2.flags.highway_turn_classification,
|
|
|
|
edge_data2.flags.access_turn_classification,
|
|
|
|
((double)intersection::findEdgeLength(edge_geometries, node_based_edge_to) /
|
|
|
|
edge_data2.duration) *
|
|
|
|
36,
|
2018-02-07 05:39:02 -05:00
|
|
|
edge_data2.flags.road_classification.GetPriority(),
|
2018-01-24 15:39:55 -05:00
|
|
|
// connected roads
|
|
|
|
road_legs_on_the_right,
|
|
|
|
road_legs_on_the_left);
|
|
|
|
|
2017-07-11 08:22:28 -04:00
|
|
|
scripting_environment.ProcessTurn(extracted_turn);
|
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// turn penalties are limited to [-2^15, 2^15) which roughly translates to 54 minutes
|
|
|
|
// and fits signed 16bit deci-seconds
|
2017-07-11 08:22:28 -04:00
|
|
|
auto weight_penalty =
|
|
|
|
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
|
|
|
auto duration_penalty = boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != nbe_to_ebn_mapping[node_based_edge_from]);
|
|
|
|
BOOST_ASSERT(SPECIAL_NODEID != nbe_to_ebn_mapping[node_based_edge_to]);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
|
|
|
// auto turn_id = m_edge_based_edge_list.size();
|
|
|
|
auto weight = boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
|
|
|
|
auto duration = boost::numeric_cast<EdgeWeight>(edge_data1.duration + duration_penalty);
|
2018-10-30 00:47:49 -04:00
|
|
|
auto distance = boost::numeric_cast<EdgeDistance>(edge_data1.distance);
|
|
|
|
|
|
|
|
EdgeBasedEdge edge_based_edge = {edge_based_node_from,
|
|
|
|
edge_based_node_to,
|
|
|
|
SPECIAL_NODEID, // This will be updated once the main
|
|
|
|
// loop completes!
|
|
|
|
weight,
|
|
|
|
duration,
|
|
|
|
distance,
|
|
|
|
true,
|
|
|
|
false};
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// We 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.
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
|
|
|
|
// original OSM segment -- we can pull the turn's preceding node ID directly with
|
|
|
|
// `node_along_road_entering`;
|
|
|
|
// otherwise, we need to look up the node immediately preceding the turn from the
|
|
|
|
// compressed edge container.
|
2017-07-11 08:22:28 -04:00
|
|
|
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
|
|
|
|
|
|
|
const auto &from_node =
|
|
|
|
isTrivial ? node_along_road_entering
|
|
|
|
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
2017-11-10 11:05:01 -05:00
|
|
|
const auto &to_node =
|
|
|
|
m_compressed_edge_container.GetFirstEdgeTargetID(node_based_edge_to);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2017-12-05 08:54:20 -05:00
|
|
|
lookup::TurnIndexBlock turn_index_block = {from_node, intersection_node, to_node};
|
2017-07-11 08:22:28 -04:00
|
|
|
|
|
|
|
// insert data into the designated buffer
|
2020-12-20 16:59:57 -05:00
|
|
|
return EdgeWithData{
|
|
|
|
edge_based_edge, turn_index_block, weight_penalty, duration_penalty};
|
2017-07-11 08:22:28 -04:00
|
|
|
};
|
|
|
|
|
2017-11-08 23:04:32 -05:00
|
|
|
//
|
|
|
|
// Edge-based-graph stage
|
|
|
|
//
|
|
|
|
tbb::filter_t<tbb::blocked_range<NodeID>, EdgesPipelineBufferPtr> processor_stage(
|
2017-06-07 00:31:07 -04:00
|
|
|
tbb::filter::parallel, [&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
2017-11-08 23:04:32 -05:00
|
|
|
auto buffer = std::make_shared<EdgesPipelineBuffer>();
|
|
|
|
buffer->nodes_processed = intersection_node_range.size();
|
2017-06-07 00:31:07 -04:00
|
|
|
|
2017-12-05 08:54:20 -05:00
|
|
|
for (auto intersection_node = intersection_node_range.begin(),
|
2017-06-07 00:31:07 -04:00
|
|
|
end = intersection_node_range.end();
|
2017-12-05 08:54:20 -05:00
|
|
|
intersection_node < end;
|
|
|
|
++intersection_node)
|
2017-06-07 00:31:07 -04:00
|
|
|
{
|
2018-01-24 15:39:55 -05:00
|
|
|
// We capture the thread-local work in these objects, then flush them in a
|
|
|
|
// controlled manner at the end of the parallel range
|
2017-12-05 08:54:20 -05:00
|
|
|
const auto &incoming_edges =
|
|
|
|
intersection::getIncomingEdges(m_node_based_graph, intersection_node);
|
|
|
|
const auto &outgoing_edges =
|
|
|
|
intersection::getOutgoingEdges(m_node_based_graph, intersection_node);
|
|
|
|
|
|
|
|
intersection::IntersectionEdgeGeometries edge_geometries;
|
|
|
|
std::unordered_set<EdgeID> merged_edge_ids;
|
|
|
|
std::tie(edge_geometries, merged_edge_ids) =
|
2017-11-21 14:23:35 -05:00
|
|
|
intersection::getIntersectionGeometries(m_node_based_graph,
|
|
|
|
m_compressed_edge_container,
|
|
|
|
m_coordinates,
|
|
|
|
mergable_road_detector,
|
2017-12-05 08:54:20 -05:00
|
|
|
intersection_node);
|
2017-06-07 00:31:07 -04:00
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
buffer->checksum.process_byte(incoming_edges.size());
|
|
|
|
buffer->checksum.process_byte(outgoing_edges.size());
|
|
|
|
|
2017-06-07 00:31:07 -04:00
|
|
|
// all nodes in the graph are connected in both directions. We check all
|
|
|
|
// outgoing nodes to find the incoming edge. This is a larger search overhead,
|
|
|
|
// but the cost we need to pay to generate edges here is worth the additional
|
|
|
|
// search overhead.
|
|
|
|
//
|
|
|
|
// a -> b <-> c
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// d
|
|
|
|
//
|
|
|
|
// will have:
|
|
|
|
// a: b,rev=0
|
|
|
|
// b: a,rev=1 c,rev=0 d,rev=0
|
|
|
|
// c: b,rev=0
|
|
|
|
//
|
2018-01-24 15:39:55 -05:00
|
|
|
// From the flags alone, we cannot determine which nodes are connected to `b` by
|
|
|
|
// an outgoing edge. Therefore, we have to search all connected edges for edges
|
|
|
|
// entering `b`
|
2017-11-20 11:20:49 -05:00
|
|
|
|
2017-11-21 14:23:35 -05:00
|
|
|
for (const auto &incoming_edge : incoming_edges)
|
2017-06-07 00:31:07 -04:00
|
|
|
{
|
|
|
|
++node_based_edge_counter;
|
2016-08-17 03:49:19 -04:00
|
|
|
|
2018-07-04 15:14:58 -04:00
|
|
|
const auto connected_roads =
|
|
|
|
extractor::intersection::getConnectedRoads<false>(m_node_based_graph,
|
|
|
|
m_edge_based_node_container,
|
|
|
|
m_coordinates,
|
|
|
|
m_compressed_edge_container,
|
|
|
|
unconditional_node_restriction_map,
|
|
|
|
m_barrier_nodes,
|
|
|
|
turn_lanes_data,
|
|
|
|
incoming_edge);
|
2015-10-14 18:08:22 -04:00
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
// check if this edge is part of a restriction via-way
|
|
|
|
const auto is_restriction_via_edge =
|
|
|
|
way_restriction_map.IsViaWayEdge(incoming_edge.node, intersection_node);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2017-11-21 14:23:35 -05:00
|
|
|
for (const auto &outgoing_edge : outgoing_edges)
|
2016-12-06 15:30:46 -05:00
|
|
|
{
|
2018-02-01 10:00:15 -05:00
|
|
|
auto is_turn_allowed =
|
|
|
|
intersection::isTurnAllowed(m_node_based_graph,
|
|
|
|
m_edge_based_node_container,
|
2020-12-20 16:59:57 -05:00
|
|
|
unconditional_node_restriction_map,
|
2018-02-01 10:00:15 -05:00
|
|
|
m_barrier_nodes,
|
|
|
|
edge_geometries,
|
|
|
|
turn_lanes_data,
|
|
|
|
incoming_edge,
|
|
|
|
outgoing_edge);
|
|
|
|
buffer->checksum.process_bit(is_turn_allowed);
|
|
|
|
|
|
|
|
if (!is_turn_allowed)
|
2017-06-07 00:31:07 -04:00
|
|
|
continue;
|
|
|
|
|
2017-11-21 14:23:35 -05:00
|
|
|
const auto turn =
|
2018-07-04 15:14:58 -04:00
|
|
|
std::find_if(connected_roads.begin(),
|
|
|
|
connected_roads.end(),
|
2017-11-21 14:23:35 -05:00
|
|
|
[edge = outgoing_edge.edge](const auto &road) {
|
|
|
|
return road.eid == edge;
|
|
|
|
});
|
2018-07-04 15:14:58 -04:00
|
|
|
OSRM_ASSERT(turn != connected_roads.end(),
|
2017-12-05 08:54:20 -05:00
|
|
|
m_coordinates[intersection_node]);
|
2017-11-20 11:20:49 -05:00
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
std::vector<ExtractionTurnLeg> road_legs_on_the_right;
|
|
|
|
std::vector<ExtractionTurnLeg> road_legs_on_the_left;
|
|
|
|
|
|
|
|
auto get_connected_road_info = [&](const auto &connected_edge) {
|
|
|
|
const auto &edge_data =
|
|
|
|
m_node_based_graph.GetEdgeData(connected_edge.eid);
|
2018-07-04 15:14:58 -04:00
|
|
|
|
|
|
|
bool is_incoming, is_outgoing;
|
|
|
|
if (edge_data.reversed)
|
|
|
|
{
|
|
|
|
// If getConnectedRoads adds reversed edge it means
|
|
|
|
// this edge is incoming-only
|
|
|
|
is_incoming = true;
|
|
|
|
is_outgoing = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// It does not add incoming edge if there is outgoing so we should
|
|
|
|
// find it ourselves
|
|
|
|
is_incoming = false;
|
|
|
|
auto reversed_edge = m_node_based_graph.FindEdge(
|
|
|
|
m_node_based_graph.GetTarget(connected_edge.eid),
|
|
|
|
intersection_node);
|
|
|
|
if (reversed_edge != SPECIAL_EDGEID)
|
|
|
|
{
|
|
|
|
const auto &reversed_edge_data =
|
|
|
|
m_node_based_graph.GetEdgeData(reversed_edge);
|
|
|
|
|
|
|
|
if (!reversed_edge_data.reversed)
|
|
|
|
{
|
|
|
|
is_incoming = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
is_outgoing = true;
|
|
|
|
}
|
|
|
|
|
2018-01-24 15:39:55 -05:00
|
|
|
return ExtractionTurnLeg(
|
|
|
|
edge_data.flags.restricted,
|
|
|
|
edge_data.flags.road_classification.IsMotorwayClass(),
|
|
|
|
edge_data.flags.road_classification.IsLinkClass(),
|
|
|
|
edge_data.flags.road_classification.GetNumberOfLanes(),
|
|
|
|
edge_data.flags.highway_turn_classification,
|
|
|
|
edge_data.flags.access_turn_classification,
|
|
|
|
((double)intersection::findEdgeLength(edge_geometries,
|
|
|
|
connected_edge.eid) /
|
|
|
|
edge_data.duration) *
|
|
|
|
36,
|
2018-02-07 05:39:02 -05:00
|
|
|
edge_data.flags.road_classification.GetPriority(),
|
2018-07-04 15:14:58 -04:00
|
|
|
is_incoming,
|
|
|
|
is_outgoing);
|
2018-01-24 15:39:55 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// all connected roads on the right of a u turn
|
2018-01-05 08:33:53 -05:00
|
|
|
const auto is_uturn = guidance::getTurnDirection(turn->angle) ==
|
|
|
|
guidance::DirectionModifier::UTurn;
|
2017-11-10 11:05:01 -05:00
|
|
|
if (is_uturn)
|
2018-01-24 15:39:55 -05:00
|
|
|
{
|
2018-07-04 15:14:58 -04:00
|
|
|
if (turn != connected_roads.begin())
|
2018-01-24 15:39:55 -05:00
|
|
|
{
|
2018-07-04 15:14:58 -04:00
|
|
|
std::transform(connected_roads.begin() + 1,
|
2018-01-24 15:39:55 -05:00
|
|
|
turn,
|
|
|
|
std::back_inserter(road_legs_on_the_right),
|
|
|
|
get_connected_road_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::transform(turn + 1,
|
2018-07-04 15:14:58 -04:00
|
|
|
connected_roads.end(),
|
2018-01-24 15:39:55 -05:00
|
|
|
std::back_inserter(road_legs_on_the_right),
|
|
|
|
get_connected_road_info);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-07-04 15:14:58 -04:00
|
|
|
if (connected_roads.begin() != turn)
|
2018-01-24 15:39:55 -05:00
|
|
|
{
|
2018-07-04 15:14:58 -04:00
|
|
|
std::transform(connected_roads.begin() + 1,
|
2018-01-24 15:39:55 -05:00
|
|
|
turn,
|
|
|
|
std::back_inserter(road_legs_on_the_right),
|
|
|
|
get_connected_road_info);
|
|
|
|
}
|
|
|
|
std::transform(turn + 1,
|
2018-07-04 15:14:58 -04:00
|
|
|
connected_roads.end(),
|
2018-01-24 15:39:55 -05:00
|
|
|
std::back_inserter(road_legs_on_the_left),
|
|
|
|
get_connected_road_info);
|
|
|
|
}
|
|
|
|
|
2018-07-04 15:14:58 -04:00
|
|
|
if (is_uturn && turn != connected_roads.begin())
|
2018-01-24 15:39:55 -05:00
|
|
|
{
|
|
|
|
util::Log(logWARNING)
|
|
|
|
<< "Turn is a u turn but not turning to the first connected "
|
|
|
|
"edge of the intersection. Node ID: "
|
|
|
|
<< intersection_node << ", OSM link: "
|
2018-02-02 07:34:53 -05:00
|
|
|
<< toOSMLink(m_coordinates[intersection_node]);
|
2018-01-24 15:39:55 -05:00
|
|
|
}
|
2018-07-04 15:14:58 -04:00
|
|
|
else if (turn == connected_roads.begin() && !is_uturn)
|
2018-01-24 15:39:55 -05:00
|
|
|
{
|
|
|
|
util::Log(logWARNING)
|
|
|
|
<< "Turn is a u turn but not classified as a u turn. Node ID: "
|
|
|
|
<< intersection_node << ", OSM link: "
|
2018-02-02 07:34:53 -05:00
|
|
|
<< toOSMLink(m_coordinates[intersection_node]);
|
2018-01-24 15:39:55 -05:00
|
|
|
}
|
|
|
|
|
2017-07-11 08:22:28 -04:00
|
|
|
// In case a way restriction starts at a given location, add a turn onto
|
2020-12-20 16:59:57 -05:00
|
|
|
// every artificial node emanating here.
|
2017-07-11 08:22:28 -04:00
|
|
|
//
|
|
|
|
// e - f
|
|
|
|
// |
|
|
|
|
// a - b
|
|
|
|
// |
|
|
|
|
// c - d
|
|
|
|
//
|
|
|
|
// ab via bc to cd
|
|
|
|
// ab via be to ef
|
|
|
|
//
|
2020-12-20 16:59:57 -05:00
|
|
|
// has two artificial nodes (be/bc) with restrictions starting at `ab`.
|
2017-07-11 08:22:28 -04:00
|
|
|
// Since every restriction group (abc | abe) refers to the same
|
|
|
|
// artificial node, we simply have to find a single representative for
|
|
|
|
// the turn. Here we check whether the turn in question is the start of
|
2018-01-24 15:39:55 -05:00
|
|
|
// a via way restriction. If that should be the case, we switch the id
|
|
|
|
// of the edge-based-node for the target to the ID of the duplicated
|
|
|
|
// node associated with the turn. (e.g. ab via bc switches bc to bc_dup)
|
2020-12-20 16:59:57 -05:00
|
|
|
auto const target_id = way_restriction_map.RemapIfRestrictionStart(
|
2017-11-21 14:23:35 -05:00
|
|
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
|
|
|
incoming_edge.node,
|
|
|
|
outgoing_edge.node,
|
|
|
|
m_node_based_graph.GetTarget(outgoing_edge.edge),
|
2017-07-11 08:22:28 -04:00
|
|
|
m_number_of_edge_based_nodes);
|
|
|
|
|
2018-02-09 13:32:09 -05:00
|
|
|
/***************************/
|
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
const auto outgoing_edge_target =
|
2018-02-09 13:32:09 -05:00
|
|
|
m_node_based_graph.GetTarget(outgoing_edge.edge);
|
|
|
|
|
|
|
|
// TODO: this loop is not optimized - once we have a few
|
|
|
|
// overrides available, we should index this for faster
|
|
|
|
// lookups
|
2020-11-26 10:21:39 -05:00
|
|
|
for (auto &override : unresolved_maneuver_overrides)
|
2018-02-09 13:32:09 -05:00
|
|
|
{
|
|
|
|
for (auto &turn : override.turn_sequence)
|
|
|
|
{
|
|
|
|
if (turn.from == incoming_edge.node &&
|
2020-12-20 16:59:57 -05:00
|
|
|
turn.via == intersection_node &&
|
|
|
|
turn.to == outgoing_edge_target)
|
2018-02-09 13:32:09 -05:00
|
|
|
{
|
|
|
|
const auto &ebn_from =
|
|
|
|
nbe_to_ebn_mapping[incoming_edge.edge];
|
|
|
|
const auto &ebn_to = target_id;
|
|
|
|
buffer->turn_to_ebn_map[turn] =
|
|
|
|
std::make_pair(ebn_from, ebn_to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-27 05:42:13 -04:00
|
|
|
{ // scope to forget edge_with_data after
|
2020-12-20 16:59:57 -05:00
|
|
|
const auto edge_with_data =
|
2017-11-21 14:23:35 -05:00
|
|
|
generate_edge(nbe_to_ebn_mapping[incoming_edge.edge],
|
2017-07-27 05:42:13 -04:00
|
|
|
target_id,
|
2017-11-21 14:23:35 -05:00
|
|
|
incoming_edge.node,
|
|
|
|
incoming_edge.edge,
|
|
|
|
outgoing_edge.node,
|
|
|
|
outgoing_edge.edge,
|
2017-11-10 11:05:01 -05:00
|
|
|
turn->angle,
|
2018-01-24 15:39:55 -05:00
|
|
|
road_legs_on_the_right,
|
|
|
|
road_legs_on_the_left,
|
|
|
|
edge_geometries);
|
2017-07-27 05:42:13 -04:00
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
buffer->continuous_data.push_back(edge_with_data);
|
|
|
|
|
|
|
|
// get conditional restrictions that apply to this turn
|
|
|
|
const auto &restrictions =
|
|
|
|
conditional_node_restriction_map.Restrictions(
|
|
|
|
incoming_edge.node,
|
|
|
|
outgoing_edge.node,
|
|
|
|
outgoing_edge_target);
|
|
|
|
for (const auto &restriction : restrictions)
|
2017-08-01 11:18:12 -04:00
|
|
|
{
|
|
|
|
buffer->conditionals.push_back(
|
2020-12-20 16:59:57 -05:00
|
|
|
{nbe_to_ebn_mapping[incoming_edge.edge],
|
|
|
|
target_id,
|
|
|
|
{static_cast<std::uint64_t>(-1),
|
|
|
|
m_coordinates[intersection_node],
|
|
|
|
restriction->condition}});
|
2017-08-01 11:18:12 -04:00
|
|
|
}
|
2017-07-27 05:42:13 -04:00
|
|
|
}
|
2017-07-11 08:22:28 -04:00
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
// When on the edge of a via-way turn restriction, we need to not only
|
2017-07-11 08:22:28 -04:00
|
|
|
// handle the normal edges for the way, but also add turns for every
|
|
|
|
// duplicated node. This process is integrated here to avoid doing the
|
|
|
|
// turn analysis multiple times.
|
2020-12-20 16:59:57 -05:00
|
|
|
if (is_restriction_via_edge)
|
2017-07-11 08:22:28 -04:00
|
|
|
{
|
|
|
|
const auto duplicated_nodes = way_restriction_map.DuplicatedNodeIDs(
|
2017-12-05 08:54:20 -05:00
|
|
|
incoming_edge.node, intersection_node);
|
2017-07-11 08:22:28 -04:00
|
|
|
|
|
|
|
// next to the normal restrictions tracked in `entry_allowed`, via
|
|
|
|
// ways might introduce additional restrictions. These are handled
|
|
|
|
// here when turning off a via-way
|
2017-08-01 16:57:28 -04:00
|
|
|
for (auto duplicated_node_id : duplicated_nodes)
|
|
|
|
{
|
|
|
|
const auto from_id =
|
2017-11-21 14:23:35 -05:00
|
|
|
NodeID(m_number_of_edge_based_nodes -
|
|
|
|
way_restriction_map.NumberOfDuplicatedNodes() +
|
|
|
|
duplicated_node_id);
|
2017-08-01 16:57:28 -04:00
|
|
|
|
|
|
|
auto const node_at_end_of_turn =
|
2017-11-21 14:23:35 -05:00
|
|
|
m_node_based_graph.GetTarget(outgoing_edge.edge);
|
2017-08-01 16:57:28 -04:00
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
const auto is_restricted = way_restriction_map.IsRestricted(
|
2017-08-01 16:57:28 -04:00
|
|
|
duplicated_node_id, node_at_end_of_turn);
|
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
if (is_restricted)
|
2017-08-01 11:18:12 -04:00
|
|
|
{
|
2020-12-20 16:59:57 -05:00
|
|
|
auto const &restrictions =
|
|
|
|
way_restriction_map.GetRestrictions(
|
|
|
|
duplicated_node_id, node_at_end_of_turn);
|
|
|
|
|
|
|
|
auto const has_unconditional =
|
|
|
|
std::any_of(restrictions.begin(),
|
|
|
|
restrictions.end(),
|
|
|
|
[](const auto &restriction) {
|
|
|
|
return restriction->IsUnconditional();
|
|
|
|
});
|
|
|
|
if (has_unconditional)
|
2017-08-01 11:18:12 -04:00
|
|
|
continue;
|
|
|
|
|
2020-12-20 16:59:57 -05:00
|
|
|
// From this via way, the outgoing edge will either:
|
|
|
|
// a) take a conditional turn transferring to a via
|
|
|
|
// path of an overlapping restriction.
|
|
|
|
// b) take a conditional turn to exit the restriction.
|
|
|
|
// If a) is applicable here, we change the target to be
|
|
|
|
// the duplicate restriction node.
|
|
|
|
auto const via_target_id =
|
|
|
|
way_restriction_map.RemapIfRestrictionVia(
|
|
|
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
|
|
|
from_id,
|
|
|
|
m_node_based_graph.GetTarget(outgoing_edge.edge),
|
|
|
|
m_number_of_edge_based_nodes);
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
// add into delayed data
|
2020-12-20 16:59:57 -05:00
|
|
|
auto edge_with_data = generate_edge(from_id,
|
|
|
|
via_target_id,
|
|
|
|
incoming_edge.node,
|
|
|
|
incoming_edge.edge,
|
|
|
|
outgoing_edge.node,
|
|
|
|
outgoing_edge.edge,
|
|
|
|
turn->angle,
|
|
|
|
road_legs_on_the_right,
|
|
|
|
road_legs_on_the_left,
|
|
|
|
edge_geometries);
|
|
|
|
|
|
|
|
buffer->delayed_data.push_back(edge_with_data);
|
2017-08-01 11:18:12 -04:00
|
|
|
|
|
|
|
// also add the conditions for the way
|
2020-12-20 16:59:57 -05:00
|
|
|
for (const auto &restriction : restrictions)
|
2017-08-01 11:18:12 -04:00
|
|
|
{
|
2020-12-20 16:59:57 -05:00
|
|
|
// add a new conditional for the edge we just
|
|
|
|
// created
|
2017-08-01 11:18:12 -04:00
|
|
|
buffer->conditionals.push_back(
|
2017-11-21 14:23:35 -05:00
|
|
|
{from_id,
|
2020-12-20 16:59:57 -05:00
|
|
|
via_target_id,
|
2017-08-01 11:18:12 -04:00
|
|
|
{static_cast<std::uint64_t>(-1),
|
2017-12-05 08:54:20 -05:00
|
|
|
m_coordinates[intersection_node],
|
2020-12-20 16:59:57 -05:00
|
|
|
restriction->condition}});
|
2017-08-01 11:18:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-12-20 16:59:57 -05:00
|
|
|
// From this via way, the outgoing edge will either:
|
|
|
|
// a) continue along the current via path
|
|
|
|
// b) transfer to a via path of an overlapping restriction.
|
|
|
|
// c) exit the restriction
|
|
|
|
// If a) or b) are applicable here, we change the target to
|
|
|
|
// be the duplicate restriction node.
|
|
|
|
auto const via_target_id =
|
|
|
|
way_restriction_map.RemapIfRestrictionVia(
|
|
|
|
nbe_to_ebn_mapping[outgoing_edge.edge],
|
|
|
|
from_id,
|
|
|
|
m_node_based_graph.GetTarget(outgoing_edge.edge),
|
|
|
|
m_number_of_edge_based_nodes);
|
|
|
|
|
|
|
|
auto edge_with_data = generate_edge(from_id,
|
|
|
|
via_target_id,
|
|
|
|
incoming_edge.node,
|
|
|
|
incoming_edge.edge,
|
|
|
|
outgoing_edge.node,
|
|
|
|
outgoing_edge.edge,
|
|
|
|
turn->angle,
|
|
|
|
road_legs_on_the_right,
|
|
|
|
road_legs_on_the_left,
|
|
|
|
edge_geometries);
|
|
|
|
|
|
|
|
buffer->delayed_data.push_back(edge_with_data);
|
2017-08-01 11:18:12 -04:00
|
|
|
}
|
2017-08-01 16:57:28 -04:00
|
|
|
}
|
2017-07-11 08:22:28 -04:00
|
|
|
}
|
2016-12-06 15:30:46 -05:00
|
|
|
}
|
2017-06-07 00:31:07 -04:00
|
|
|
}
|
|
|
|
}
|
2016-12-06 15:30:46 -05:00
|
|
|
|
2017-06-07 00:31:07 -04:00
|
|
|
return buffer;
|
|
|
|
});
|
|
|
|
|
2017-11-08 23:04:32 -05:00
|
|
|
// Last part of the pipeline puts all the calculated data into the serial buffers
|
2018-01-08 13:12:06 -05:00
|
|
|
util::UnbufferedLog log;
|
2017-12-01 18:37:09 -05:00
|
|
|
util::Percent routing_progress(log, node_count);
|
2017-11-08 23:04:32 -05:00
|
|
|
std::vector<EdgeWithData> delayed_data;
|
|
|
|
tbb::filter_t<EdgesPipelineBufferPtr, void> output_stage(
|
|
|
|
tbb::filter::serial_in_order, [&](auto buffer) {
|
2017-12-01 18:37:09 -05:00
|
|
|
routing_progress.PrintAddition(buffer->nodes_processed);
|
2017-11-08 23:04:32 -05:00
|
|
|
|
2018-02-01 10:00:15 -05:00
|
|
|
m_connectivity_checksum = buffer->checksum.update_checksum(m_connectivity_checksum);
|
|
|
|
|
2017-11-10 11:05:01 -05:00
|
|
|
// Copy data from local buffers into global EBG data
|
2017-11-08 23:04:32 -05:00
|
|
|
std::for_each(
|
|
|
|
buffer->continuous_data.begin(), buffer->continuous_data.end(), transfer_data);
|
2017-08-01 11:18:12 -04:00
|
|
|
conditionals.insert(
|
|
|
|
conditionals.end(), buffer->conditionals.begin(), buffer->conditionals.end());
|
|
|
|
|
2017-11-08 23:04:32 -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());
|
|
|
|
|
|
|
|
// Copy via-way restrictions delayed data
|
2017-07-11 08:22:28 -04:00
|
|
|
delayed_data.insert(
|
|
|
|
delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end());
|
2018-02-09 13:32:09 -05:00
|
|
|
|
|
|
|
std::for_each(buffer->turn_to_ebn_map.begin(),
|
|
|
|
buffer->turn_to_ebn_map.end(),
|
|
|
|
[&global_turn_to_ebn_map](const auto &p) {
|
|
|
|
// TODO: log conflicts here
|
|
|
|
global_turn_to_ebn_map.insert(p);
|
|
|
|
});
|
2017-06-07 00:31:07 -04:00
|
|
|
});
|
|
|
|
|
2017-11-08 23:04:32 -05:00
|
|
|
// Now, execute the pipeline. The value of "5" here was chosen by experimentation
|
|
|
|
// on a 16-CPU machine and seemed to give the best performance. This value needs
|
|
|
|
// to be balanced with the GRAINSIZE above - ideally, the pipeline puts as much work
|
2017-11-10 11:05:01 -05:00
|
|
|
// as possible in the `intersection_handler` step so that those parallel workers don't
|
2017-11-08 23:04:32 -05:00
|
|
|
// get blocked too much by the slower (io-performing) `buffer_storage`
|
2020-09-01 07:25:51 -04:00
|
|
|
tbb::parallel_pipeline(std::thread::hardware_concurrency() * 5,
|
2017-06-07 00:31:07 -04:00
|
|
|
generator_stage & processor_stage & output_stage);
|
2017-11-08 23:04:32 -05:00
|
|
|
|
|
|
|
// NOTE: buffer.delayed_data and buffer.delayed_turn_data have the same index
|
2017-07-11 08:22:28 -04:00
|
|
|
std::for_each(delayed_data.begin(), delayed_data.end(), transfer_data);
|
|
|
|
|
2018-02-09 13:32:09 -05:00
|
|
|
// Now, replace node-based-node ID values in the `node_sequence` with
|
|
|
|
// the edge-based-node values we found and stored in the `turn_to_ebn_map`
|
|
|
|
for (auto &unresolved_override : unresolved_maneuver_overrides)
|
|
|
|
{
|
|
|
|
StorageManeuverOverride storage_override;
|
|
|
|
storage_override.instruction_node = unresolved_override.instruction_node;
|
|
|
|
storage_override.override_type = unresolved_override.override_type;
|
|
|
|
storage_override.direction = unresolved_override.direction;
|
|
|
|
|
|
|
|
std::vector<NodeID> node_sequence(unresolved_override.turn_sequence.size() + 1,
|
|
|
|
SPECIAL_NODEID);
|
|
|
|
|
|
|
|
for (std::int64_t i = unresolved_override.turn_sequence.size() - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
const auto v = global_turn_to_ebn_map.find(unresolved_override.turn_sequence[i]);
|
|
|
|
if (v != global_turn_to_ebn_map.end())
|
|
|
|
{
|
|
|
|
node_sequence[i] = v->second.first;
|
|
|
|
node_sequence[i + 1] = v->second.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
storage_override.node_sequence_offset_begin = maneuver_override_sequences.size();
|
|
|
|
storage_override.node_sequence_offset_end =
|
|
|
|
maneuver_override_sequences.size() + node_sequence.size();
|
|
|
|
|
|
|
|
storage_override.start_node = node_sequence.front();
|
|
|
|
|
|
|
|
maneuver_override_sequences.insert(
|
|
|
|
maneuver_override_sequences.end(), node_sequence.begin(), node_sequence.end());
|
|
|
|
|
|
|
|
storage_maneuver_overrides.push_back(storage_override);
|
|
|
|
}
|
2011-10-10 11:52:47 -04:00
|
|
|
}
|
2018-02-09 13:32:09 -05:00
|
|
|
{
|
|
|
|
util::Log() << "Sorting and writing " << storage_maneuver_overrides.size()
|
|
|
|
<< " maneuver overrides...";
|
|
|
|
|
|
|
|
// Sort by `from_node`, so that later lookups can be done with a binary search.
|
|
|
|
std::sort(storage_maneuver_overrides.begin(),
|
|
|
|
storage_maneuver_overrides.end(),
|
|
|
|
[](const auto &a, const auto &b) { return a.start_node < b.start_node; });
|
2018-02-22 04:49:01 -05:00
|
|
|
|
|
|
|
files::writeManeuverOverrides(
|
|
|
|
maneuver_overrides_filename, storage_maneuver_overrides, maneuver_override_sequences);
|
2018-02-09 13:32:09 -05:00
|
|
|
}
|
2015-10-14 18:08:22 -04:00
|
|
|
|
2018-01-08 13:12:06 -05:00
|
|
|
util::Log() << "done.";
|
|
|
|
util::Log() << "Renumbering turns";
|
2018-01-24 15:39:55 -05:00
|
|
|
// Now, update the turn_id property on every EdgeBasedEdge - it will equal the position in the
|
|
|
|
// m_edge_based_edge_list array for each object.
|
2017-06-07 00:31:07 -04:00
|
|
|
tbb::parallel_for(tbb::blocked_range<NodeID>(0, m_edge_based_edge_list.size()),
|
|
|
|
[this](const tbb::blocked_range<NodeID> &range) {
|
|
|
|
for (auto x = range.begin(), end = range.end(); x != end; ++x)
|
|
|
|
{
|
|
|
|
m_edge_based_edge_list[x].data.turn_id = x;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-01-08 13:12:06 -05:00
|
|
|
// re-hash conditionals to connect to their respective edge-based edges. Due to the ordering, we
|
2017-08-01 11:18:12 -04:00
|
|
|
// do not really have a choice but to index the conditional penalties and walk over all
|
|
|
|
// edge-based-edges to find the ID of the edge
|
|
|
|
auto const indexed_conditionals = IndexConditionals(std::move(conditionals));
|
2018-03-19 19:31:49 -04:00
|
|
|
util::Log() << "Writing " << indexed_conditionals.size() << " conditional turn penalties...";
|
|
|
|
extractor::files::writeConditionalRestrictions(conditional_penalties_filename,
|
|
|
|
indexed_conditionals);
|
2017-08-01 11:18:12 -04:00
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
// write weight penalties per turn
|
2020-10-25 21:19:17 -04:00
|
|
|
BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size() &&
|
|
|
|
turn_weight_penalties.size() == turn_penalties_index.size());
|
2018-03-19 11:57:57 -04:00
|
|
|
files::writeTurnWeightPenalty(turn_weight_penalties_filename, turn_weight_penalties);
|
|
|
|
files::writeTurnDurationPenalty(turn_duration_penalties_filename, turn_duration_penalties);
|
2020-10-23 05:38:56 -04:00
|
|
|
files::writeTurnPenaltiesIndex(turn_penalties_index_filename, turn_penalties_index);
|
2016-05-12 12:50:10 -04:00
|
|
|
|
2017-05-16 13:22:41 -04:00
|
|
|
util::Log() << "Generated " << m_edge_based_node_segments.size() << " edge based node segments";
|
2016-12-06 15:30:46 -05:00
|
|
|
util::Log() << "Node-based graph contains " << node_based_edge_counter << " edges";
|
|
|
|
util::Log() << "Edge-expanded graph ...";
|
|
|
|
util::Log() << " contains " << m_edge_based_edge_list.size() << " edges";
|
2011-11-09 10:12:05 -05:00
|
|
|
}
|
|
|
|
|
2017-08-01 11:18:12 -04:00
|
|
|
std::vector<ConditionalTurnPenalty>
|
|
|
|
EdgeBasedGraphFactory::IndexConditionals(std::vector<Conditional> &&conditionals) const
|
|
|
|
{
|
|
|
|
boost::unordered_multimap<std::pair<NodeID, NodeID>, ConditionalTurnPenalty *> index;
|
|
|
|
|
|
|
|
// build and index of all conditional restrictions
|
|
|
|
for (auto &conditional : conditionals)
|
|
|
|
index.insert(std::make_pair(std::make_pair(conditional.from_node, conditional.to_node),
|
|
|
|
&conditional.penalty));
|
|
|
|
|
|
|
|
std::vector<ConditionalTurnPenalty> indexed_restrictions;
|
|
|
|
|
|
|
|
for (auto const &edge : m_edge_based_edge_list)
|
|
|
|
{
|
|
|
|
auto const range = index.equal_range(std::make_pair(edge.source, edge.target));
|
|
|
|
for (auto itr = range.first; itr != range.second; ++itr)
|
|
|
|
{
|
|
|
|
itr->second->turn_offset = edge.data.turn_id;
|
|
|
|
indexed_restrictions.push_back(*itr->second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return indexed_restrictions;
|
|
|
|
}
|
|
|
|
|
2016-01-29 06:42:08 -05:00
|
|
|
} // namespace extractor
|
|
|
|
} // namespace osrm
|