Allow specifing a weight for routing that is independent of duration
This commit is contained in:
committed by
Patrick Niklaus
parent
e463733138
commit
279f8aabfb
+172
-80
@@ -74,7 +74,9 @@ struct Segment final
|
||||
|
||||
struct SpeedSource final
|
||||
{
|
||||
SpeedSource() : speed(0), weight(INVALID_EDGE_WEIGHT) {}
|
||||
unsigned speed;
|
||||
EdgeWeight weight;
|
||||
std::uint8_t source;
|
||||
};
|
||||
|
||||
@@ -86,7 +88,7 @@ struct Turn final
|
||||
: from(from), via(via), to(to)
|
||||
{
|
||||
}
|
||||
Turn(const osrm::extractor::lookup::PenaltyBlock &turn)
|
||||
Turn(const osrm::extractor::lookup::TurnIndexBlock &turn)
|
||||
: from(static_cast<std::uint64_t>(turn.from_id)),
|
||||
via(static_cast<std::uint64_t>(turn.via_id)), to(static_cast<std::uint64_t>(turn.to_id))
|
||||
{
|
||||
@@ -103,7 +105,9 @@ struct Turn final
|
||||
|
||||
struct PenaltySource final
|
||||
{
|
||||
double penalty;
|
||||
PenaltySource() : duration(0.), weight(std::numeric_limits<double>::quiet_NaN()) {}
|
||||
double duration;
|
||||
double weight;
|
||||
std::uint8_t source;
|
||||
};
|
||||
|
||||
@@ -115,11 +119,15 @@ template <typename T> inline bool is_aligned(const void *pointer)
|
||||
} // anon ns
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(Segment, (decltype(Segment::from), from)(decltype(Segment::to), to))
|
||||
BOOST_FUSION_ADAPT_STRUCT(SpeedSource, (decltype(SpeedSource::speed), speed))
|
||||
BOOST_FUSION_ADAPT_STRUCT(SpeedSource,
|
||||
(decltype(SpeedSource::speed), speed)(decltype(SpeedSource::weight),
|
||||
weight))
|
||||
BOOST_FUSION_ADAPT_STRUCT(Turn,
|
||||
(decltype(Turn::from), from)(decltype(Turn::via), via)(decltype(Turn::to),
|
||||
to))
|
||||
BOOST_FUSION_ADAPT_STRUCT(PenaltySource, (decltype(PenaltySource::penalty), penalty))
|
||||
BOOST_FUSION_ADAPT_STRUCT(PenaltySource,
|
||||
(decltype(PenaltySource::duration),
|
||||
duration)(decltype(PenaltySource::weight), weight))
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -240,29 +248,37 @@ inline EdgeWeight ConvertToDuration(double distance_in_meters, double speed_in_k
|
||||
BOOST_ASSERT(speed_in_kmh > 0);
|
||||
const double speed_in_ms = speed_in_kmh / 3.6;
|
||||
const double duration = distance_in_meters / speed_in_ms;
|
||||
return std::max<EdgeWeight>(1, static_cast<EdgeWeight>(std::round(duration * 10)));
|
||||
return std::max<EdgeWeight>(1, static_cast<EdgeWeight>(std::round(duration * 10.)));
|
||||
}
|
||||
|
||||
// Returns updated edge weight
|
||||
EdgeWeight GetNewWeight(const SpeedSource &value,
|
||||
const double &segment_length,
|
||||
const std::vector<std::string> &segment_speed_filenames,
|
||||
const EdgeWeight old_weight,
|
||||
const double log_edge_updates_factor,
|
||||
const OSMNodeID &from,
|
||||
const OSMNodeID &to)
|
||||
void GetNewWeight(const SpeedSource &value,
|
||||
const double &segment_length,
|
||||
const std::vector<std::string> &segment_speed_filenames,
|
||||
const EdgeWeight current_duration,
|
||||
const double log_edge_updates_factor,
|
||||
const OSMNodeID from,
|
||||
const OSMNodeID to,
|
||||
EdgeWeight &new_segment_weight,
|
||||
EdgeWeight &new_segment_duration)
|
||||
{
|
||||
const auto new_segment_weight =
|
||||
// Update the edge duration as distance/speed
|
||||
new_segment_duration =
|
||||
(value.speed > 0) ? ConvertToDuration(segment_length, value.speed) : INVALID_EDGE_WEIGHT;
|
||||
// the check here is enabled by the `--edge-weight-updates-over-factor` flag it logs
|
||||
// a warning if the new weight exceeds a heuristic of what a reasonable weight update is
|
||||
if (log_edge_updates_factor > 0 && old_weight != 0)
|
||||
|
||||
// Update the edge weight or fallback to the new edge duration
|
||||
new_segment_weight =
|
||||
(value.weight == INVALID_EDGE_WEIGHT) ? new_segment_duration : value.weight;
|
||||
|
||||
// The check here is enabled by the `--edge-weight-updates-over-factor` flag it logs a warning
|
||||
// if the new duration exceeds a heuristic of what a reasonable duration update is
|
||||
if (log_edge_updates_factor > 0 && current_duration != 0)
|
||||
{
|
||||
auto new_secs = new_segment_weight / 10.0;
|
||||
auto old_secs = old_weight / 10.0;
|
||||
auto approx_original_speed = (segment_length / old_secs) * 3.6;
|
||||
if (old_weight >= (new_segment_weight * log_edge_updates_factor))
|
||||
if (current_duration >= (new_segment_duration * log_edge_updates_factor))
|
||||
{
|
||||
auto new_secs = new_segment_duration / 10.;
|
||||
auto old_secs = current_duration / 10.;
|
||||
auto approx_original_speed = (segment_length / old_secs) * 3.6;
|
||||
auto speed_file = segment_speed_filenames.at(value.source - 1);
|
||||
util::Log(logWARNING) << "[weight updates] Edge weight update from " << old_secs
|
||||
<< "s to " << new_secs << "s New speed: " << value.speed
|
||||
@@ -273,21 +289,10 @@ EdgeWeight GetNewWeight(const SpeedSource &value,
|
||||
<< speed_file;
|
||||
}
|
||||
}
|
||||
|
||||
return new_segment_weight;
|
||||
}
|
||||
|
||||
int Contractor::Run()
|
||||
{
|
||||
#ifdef WIN32
|
||||
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
|
||||
#else
|
||||
static_assert(sizeof(extractor::NodeBasedEdge) == 24,
|
||||
"changing extractor::NodeBasedEdge type has influence on memory consumption!");
|
||||
static_assert(sizeof(extractor::EdgeBasedEdge) == 16,
|
||||
"changing EdgeBasedEdge type has influence on memory consumption!");
|
||||
#endif
|
||||
|
||||
if (config.core_factor > 1.0 || config.core_factor < 0)
|
||||
{
|
||||
throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)" + SOURCE_REF);
|
||||
@@ -314,7 +319,9 @@ int Contractor::Run()
|
||||
edge_based_edge_list,
|
||||
node_weights,
|
||||
config.edge_segment_lookup_path,
|
||||
config.edge_penalty_path,
|
||||
config.turn_weight_penalties_path,
|
||||
config.turn_duration_penalties_path,
|
||||
config.turn_penalties_index_path,
|
||||
config.segment_speed_lookup_paths,
|
||||
config.turn_penalty_lookup_paths,
|
||||
config.node_based_graph_path,
|
||||
@@ -377,7 +384,9 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
|
||||
std::vector<EdgeWeight> &node_weights,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_penalty_filename,
|
||||
const std::string &turn_weight_penalties_filename,
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const std::vector<std::string> &segment_speed_filenames,
|
||||
const std::vector<std::string> &turn_penalty_filenames,
|
||||
const std::string &nodes_filename,
|
||||
@@ -393,15 +402,14 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
|
||||
util::Log() << "Opening " << edge_based_graph_filename;
|
||||
|
||||
auto mmap_file = [](const std::string &filename) {
|
||||
auto mmap_file = [](const std::string &filename, boost::interprocess::mode_t mode) {
|
||||
using boost::interprocess::file_mapping;
|
||||
using boost::interprocess::mapped_region;
|
||||
using boost::interprocess::read_only;
|
||||
|
||||
try
|
||||
{
|
||||
const file_mapping mapping{filename.c_str(), read_only};
|
||||
mapped_region region{mapping, read_only};
|
||||
const file_mapping mapping{filename.c_str(), mode};
|
||||
mapped_region region{mapping, mode};
|
||||
region.advise(mapped_region::advice_sequential);
|
||||
return region;
|
||||
}
|
||||
@@ -412,15 +420,16 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
}
|
||||
};
|
||||
|
||||
const auto edge_based_graph_region = mmap_file(edge_based_graph_filename);
|
||||
const auto edge_based_graph_region =
|
||||
mmap_file(edge_based_graph_filename, boost::interprocess::read_only);
|
||||
|
||||
const bool update_edge_weights = !segment_speed_filenames.empty();
|
||||
const bool update_turn_penalties = !turn_penalty_filenames.empty();
|
||||
|
||||
const auto edge_penalty_region = [&] {
|
||||
const auto turn_penalties_index_region = [&] {
|
||||
if (update_edge_weights || update_turn_penalties)
|
||||
{
|
||||
return mmap_file(edge_penalty_filename);
|
||||
return mmap_file(turn_penalties_index_filename, boost::interprocess::read_only);
|
||||
}
|
||||
return boost::interprocess::mapped_region();
|
||||
}();
|
||||
@@ -428,7 +437,7 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
const auto edge_segment_region = [&] {
|
||||
if (update_edge_weights || update_turn_penalties)
|
||||
{
|
||||
return mmap_file(edge_segment_lookup_filename);
|
||||
return mmap_file(edge_segment_lookup_filename, boost::interprocess::read_only);
|
||||
}
|
||||
return boost::interprocess::mapped_region();
|
||||
}();
|
||||
@@ -474,12 +483,13 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
util::Log() << "Reading " << graph_header.number_of_edges << " edges from the edge based graph";
|
||||
|
||||
auto segment_speed_lookup = CSVFilesParser<Segment, SpeedSource>(
|
||||
1, qi::ulong_long >> ',' >> qi::ulong_long, qi::uint_)(segment_speed_filenames);
|
||||
1, qi::ulong_long >> ',' >> qi::ulong_long, qi::uint_ >> -(',' >> qi::uint_))(
|
||||
segment_speed_filenames);
|
||||
|
||||
auto turn_penalty_lookup = CSVFilesParser<Turn, PenaltySource>(
|
||||
1 + segment_speed_filenames.size(),
|
||||
qi::ulong_long >> ',' >> qi::ulong_long >> ',' >> qi::ulong_long,
|
||||
qi::double_)(turn_penalty_filenames);
|
||||
qi::double_ >> -(',' >> qi::double_))(turn_penalty_filenames);
|
||||
|
||||
// If we update the edge weights, this file will hold the datasource information for each
|
||||
// segment; the other files will also be conditionally filled concurrently if we make an update
|
||||
@@ -490,9 +500,11 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
std::vector<NodeID> geometry_node_list;
|
||||
std::vector<EdgeWeight> geometry_fwd_weight_list;
|
||||
std::vector<EdgeWeight> geometry_rev_weight_list;
|
||||
std::vector<EdgeWeight> geometry_fwd_duration_list;
|
||||
std::vector<EdgeWeight> geometry_rev_duration_list;
|
||||
|
||||
const auto maybe_load_internal_to_external_node_map = [&] {
|
||||
if (!(update_edge_weights || update_turn_penalties))
|
||||
if (!update_edge_weights)
|
||||
return;
|
||||
|
||||
storage::io::FileReader nodes_file(nodes_filename,
|
||||
@@ -503,7 +515,7 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
};
|
||||
|
||||
const auto maybe_load_geometries = [&] {
|
||||
if (!(update_edge_weights || update_turn_penalties))
|
||||
if (!update_edge_weights)
|
||||
return;
|
||||
|
||||
storage::io::FileReader geometry_file(geometry_filename,
|
||||
@@ -518,6 +530,8 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
geometry_node_list.resize(number_of_compressed_geometries);
|
||||
geometry_fwd_weight_list.resize(number_of_compressed_geometries);
|
||||
geometry_rev_weight_list.resize(number_of_compressed_geometries);
|
||||
geometry_fwd_duration_list.resize(number_of_compressed_geometries);
|
||||
geometry_rev_duration_list.resize(number_of_compressed_geometries);
|
||||
|
||||
if (number_of_compressed_geometries > 0)
|
||||
{
|
||||
@@ -526,13 +540,17 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
number_of_compressed_geometries);
|
||||
geometry_file.ReadInto(geometry_rev_weight_list.data(),
|
||||
number_of_compressed_geometries);
|
||||
geometry_file.ReadInto(geometry_fwd_duration_list.data(),
|
||||
number_of_compressed_geometries);
|
||||
geometry_file.ReadInto(geometry_rev_duration_list.data(),
|
||||
number_of_compressed_geometries);
|
||||
}
|
||||
};
|
||||
|
||||
// Folds all our actions into independently concurrently executing lambdas
|
||||
tbb::parallel_invoke(maybe_load_internal_to_external_node_map, maybe_load_geometries);
|
||||
|
||||
if (update_edge_weights || update_turn_penalties)
|
||||
if (update_edge_weights)
|
||||
{
|
||||
// Here, we have to update the compressed geometry weights
|
||||
// First, we need the external-to-internal node lookup table
|
||||
@@ -552,7 +570,7 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
|
||||
using boost::interprocess::mapped_region;
|
||||
|
||||
auto region = mmap_file(rtree_leaf_filename.c_str());
|
||||
auto region = mmap_file(rtree_leaf_filename.c_str(), boost::interprocess::read_only);
|
||||
region.advise(mapped_region::advice_willneed);
|
||||
BOOST_ASSERT(is_aligned<LeafNode>(region.get_address()));
|
||||
|
||||
@@ -589,32 +607,38 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
auto fwd_source = LUA_SOURCE, rev_source = LUA_SOURCE;
|
||||
if (auto value = segment_speed_lookup({u.node_id, v.node_id}))
|
||||
{
|
||||
const auto current_fwd_weight = geometry_fwd_weight_list[u_index];
|
||||
const auto new_segment_weight = GetNewWeight(*value,
|
||||
segment_length,
|
||||
segment_speed_filenames,
|
||||
current_fwd_weight,
|
||||
log_edge_updates_factor,
|
||||
u.node_id,
|
||||
v.node_id);
|
||||
EdgeWeight new_segment_weight, new_segment_duration;
|
||||
GetNewWeight(*value,
|
||||
segment_length,
|
||||
segment_speed_filenames,
|
||||
geometry_fwd_duration_list[u_index],
|
||||
log_edge_updates_factor,
|
||||
u.node_id,
|
||||
v.node_id,
|
||||
new_segment_weight,
|
||||
new_segment_duration);
|
||||
|
||||
geometry_fwd_weight_list[v_index] = new_segment_weight;
|
||||
geometry_fwd_duration_list[v_index] = new_segment_duration;
|
||||
geometry_datasource[v_index] = value->source;
|
||||
fwd_source = value->source;
|
||||
}
|
||||
|
||||
if (auto value = segment_speed_lookup({v.node_id, u.node_id}))
|
||||
{
|
||||
const auto current_rev_weight = geometry_rev_weight_list[u_index];
|
||||
const auto new_segment_weight = GetNewWeight(*value,
|
||||
segment_length,
|
||||
segment_speed_filenames,
|
||||
current_rev_weight,
|
||||
log_edge_updates_factor,
|
||||
v.node_id,
|
||||
u.node_id);
|
||||
EdgeWeight new_segment_weight, new_segment_duration;
|
||||
GetNewWeight(*value,
|
||||
segment_length,
|
||||
segment_speed_filenames,
|
||||
geometry_rev_duration_list[u_index],
|
||||
log_edge_updates_factor,
|
||||
v.node_id,
|
||||
u.node_id,
|
||||
new_segment_weight,
|
||||
new_segment_duration);
|
||||
|
||||
geometry_rev_weight_list[u_index] = new_segment_weight;
|
||||
geometry_rev_duration_list[u_index] = new_segment_duration;
|
||||
geometry_datasource[u_index] = value->source;
|
||||
rev_source = value->source;
|
||||
}
|
||||
@@ -652,7 +676,7 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
}
|
||||
|
||||
const auto maybe_save_geometries = [&] {
|
||||
if (!(update_edge_weights || update_turn_penalties))
|
||||
if (!update_edge_weights)
|
||||
return;
|
||||
|
||||
// Now save out the updated compressed geometries
|
||||
@@ -675,6 +699,10 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
number_of_compressed_geometries * sizeof(EdgeWeight));
|
||||
geometry_stream.write(reinterpret_cast<char *>(&(geometry_rev_weight_list[0])),
|
||||
number_of_compressed_geometries * sizeof(EdgeWeight));
|
||||
geometry_stream.write(reinterpret_cast<char *>(&(geometry_fwd_duration_list[0])),
|
||||
number_of_compressed_geometries * sizeof(EdgeWeight));
|
||||
geometry_stream.write(reinterpret_cast<char *>(&(geometry_rev_duration_list[0])),
|
||||
number_of_compressed_geometries * sizeof(EdgeWeight));
|
||||
};
|
||||
|
||||
const auto save_datasource_indexes = [&] {
|
||||
@@ -716,17 +744,47 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
|
||||
tbb::parallel_invoke(maybe_save_geometries, save_datasource_indexes, save_datastore_names);
|
||||
|
||||
auto turn_penalty_blocks_ptr = reinterpret_cast<const extractor::lookup::PenaltyBlock *>(
|
||||
edge_penalty_region.get_address());
|
||||
BOOST_ASSERT(is_aligned<extractor::lookup::PenaltyBlock>(turn_penalty_blocks_ptr));
|
||||
std::vector<TurnPenalty> turn_weight_penalties;
|
||||
std::vector<TurnPenalty> turn_duration_penalties;
|
||||
|
||||
auto edge_based_edge_ptr = reinterpret_cast<extractor::EdgeBasedEdge *>(
|
||||
const auto maybe_load_turn_weight_penalties = [&] {
|
||||
if (!update_edge_weights && !update_turn_penalties)
|
||||
return;
|
||||
using storage::io::FileReader;
|
||||
FileReader file(turn_weight_penalties_filename, FileReader::HasNoFingerprint);
|
||||
file.DeserializeVector(turn_weight_penalties);
|
||||
};
|
||||
|
||||
const auto maybe_load_turn_duration_penalties = [&] {
|
||||
if (!update_turn_penalties)
|
||||
return;
|
||||
using storage::io::FileReader;
|
||||
FileReader file(turn_duration_penalties_filename, FileReader::HasNoFingerprint);
|
||||
file.DeserializeVector(turn_duration_penalties);
|
||||
};
|
||||
|
||||
tbb::parallel_invoke(maybe_load_turn_weight_penalties, maybe_load_turn_duration_penalties);
|
||||
|
||||
if (update_turn_penalties && turn_duration_penalties.empty())
|
||||
{ // Copy-on-write for duration penalties as turn weight penalties
|
||||
turn_duration_penalties = turn_weight_penalties;
|
||||
}
|
||||
|
||||
// Mapped file pointer for turn indices
|
||||
const extractor::lookup::TurnIndexBlock *turn_index_blocks =
|
||||
reinterpret_cast<const extractor::lookup::TurnIndexBlock *>(
|
||||
turn_penalties_index_region.get_address());
|
||||
BOOST_ASSERT(is_aligned<extractor::lookup::TurnIndexBlock>(turn_index_blocks));
|
||||
|
||||
// Mapped file pointers for edge-based graph edges
|
||||
auto edge_based_edge_ptr = reinterpret_cast<const extractor::EdgeBasedEdge *>(
|
||||
reinterpret_cast<char *>(edge_based_graph_region.get_address()) +
|
||||
sizeof(EdgeBasedGraphHeader));
|
||||
BOOST_ASSERT(is_aligned<extractor::EdgeBasedEdge>(edge_based_edge_ptr));
|
||||
|
||||
auto edge_segment_byte_ptr = reinterpret_cast<const char *>(edge_segment_region.get_address());
|
||||
|
||||
bool fallback_to_duration = true;
|
||||
for (std::uint64_t edge_index = 0; edge_index < graph_header.number_of_edges; ++edge_index)
|
||||
{
|
||||
// Make a copy of the data from the memory map
|
||||
@@ -759,7 +817,10 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
if (value->speed == 0)
|
||||
return true;
|
||||
|
||||
segment_weight = ConvertToDuration(segment.segment_length, value->speed);
|
||||
segment_weight =
|
||||
value->weight == INVALID_EDGE_WEIGHT
|
||||
? ConvertToDuration(segment.segment_length, value->speed)
|
||||
: value->weight;
|
||||
}
|
||||
|
||||
// Update the edge weight and the next OSM node ID
|
||||
@@ -779,30 +840,61 @@ Contractor::LoadEdgeExpandedGraph(std::string const &edge_based_graph_filename,
|
||||
continue;
|
||||
|
||||
// Get the turn penalty and update to the new value if required
|
||||
const auto &turn_block = turn_penalty_blocks_ptr[edge_index];
|
||||
EdgeWeight new_turn_penalty = turn_block.fixed_penalty;
|
||||
if (auto value = turn_penalty_lookup(turn_block))
|
||||
const auto &turn_index = turn_index_blocks[edge_index];
|
||||
auto turn_weight_penalty = turn_weight_penalties[edge_index];
|
||||
if (auto value = turn_penalty_lookup(turn_index))
|
||||
{
|
||||
new_turn_penalty = static_cast<EdgeWeight>(value->penalty * 10);
|
||||
auto turn_duration_penalty =
|
||||
boost::numeric_cast<TurnPenalty>(std::round(value->duration * 10.));
|
||||
turn_weight_penalty =
|
||||
std::isfinite(value->weight)
|
||||
? boost::numeric_cast<TurnPenalty>(std::round(value->weight * 10))
|
||||
: turn_duration_penalty;
|
||||
|
||||
if (new_weight + new_turn_penalty < static_cast<EdgeWeight>(header->num_osm_nodes))
|
||||
const auto weight_min_value = static_cast<EdgeWeight>(header->num_osm_nodes);
|
||||
if (turn_weight_penalty + new_weight < weight_min_value)
|
||||
{
|
||||
util::Log(logWARNING)
|
||||
<< "turn penalty " << value->penalty << " for turn " << turn_block.from_id
|
||||
<< "," << turn_block.via_id << "," << turn_block.to_id
|
||||
<< " is too negative: clamping turn weight to " << header->num_osm_nodes;
|
||||
util::Log(logWARNING) << "turn penalty " << turn_weight_penalty << " for turn "
|
||||
<< turn_index.from_id << ", " << turn_index.via_id << ", "
|
||||
<< turn_index.to_id
|
||||
<< " is too negative: clamping turn weight to "
|
||||
<< weight_min_value;
|
||||
|
||||
new_turn_penalty = header->num_osm_nodes - new_weight;
|
||||
turn_weight_penalty = weight_min_value - new_weight;
|
||||
}
|
||||
|
||||
turn_duration_penalties[edge_index] = turn_duration_penalty;
|
||||
turn_weight_penalties[edge_index] = turn_weight_penalty;
|
||||
|
||||
// Is fallback of duration to weight values allowed
|
||||
fallback_to_duration &= (turn_duration_penalty == turn_weight_penalty);
|
||||
}
|
||||
|
||||
// Update edge weight
|
||||
inbuffer.weight = new_weight + new_turn_penalty;
|
||||
inbuffer.weight = new_weight + turn_weight_penalty;
|
||||
}
|
||||
|
||||
edge_based_edge_list.emplace_back(std::move(inbuffer));
|
||||
}
|
||||
|
||||
if (update_turn_penalties)
|
||||
{
|
||||
if (fallback_to_duration)
|
||||
{ // Turn duration penalties are identical to turn weight penalties
|
||||
// Save empty data vector, so turn weight penalties will be used by data facade.
|
||||
turn_duration_penalties.clear();
|
||||
}
|
||||
|
||||
const auto save_penalties = [](const auto &filename, const auto &data) -> void {
|
||||
storage::io::FileWriter file(filename, storage::io::FileWriter::HasNoFingerprint);
|
||||
file.SerializeVector(data);
|
||||
};
|
||||
|
||||
tbb::parallel_invoke(
|
||||
[&] { save_penalties(turn_weight_penalties_filename, turn_weight_penalties); },
|
||||
[&] { save_penalties(turn_duration_penalties_filename, turn_duration_penalties); });
|
||||
}
|
||||
|
||||
util::Log() << "Done reading edges";
|
||||
return graph_header.max_edge_id;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ ContractorDijkstra::ContractorDijkstra(const std::size_t heap_size) : heap(heap_
|
||||
|
||||
void ContractorDijkstra::Run(const unsigned number_of_targets,
|
||||
const int node_limit,
|
||||
const int weight_limit,
|
||||
const EdgeWeight weight_limit,
|
||||
const NodeID forbidden_node,
|
||||
const ContractorGraph &graph)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ void ContractorDijkstra::Run(const unsigned number_of_targets,
|
||||
}
|
||||
|
||||
void ContractorDijkstra::RelaxNode(const NodeID node,
|
||||
const int node_weight,
|
||||
const EdgeWeight node_weight,
|
||||
const NodeID forbidden_node,
|
||||
const ContractorGraph &graph)
|
||||
{
|
||||
@@ -60,7 +60,7 @@ void ContractorDijkstra::RelaxNode(const NodeID node,
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int to_weight = node_weight + data.weight;
|
||||
const EdgeWeight to_weight = node_weight + data.weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!heap.WasInserted(to))
|
||||
|
||||
@@ -242,6 +242,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
|
||||
util::json::Object route_step;
|
||||
route_step.values["distance"] = std::round(step.distance * 10) / 10.;
|
||||
route_step.values["duration"] = std::round(step.duration * 10) / 10.;
|
||||
route_step.values["weight"] = step.weight; // We should round to weight_precision here
|
||||
route_step.values["name"] = std::move(step.name);
|
||||
if (!step.ref.empty())
|
||||
route_step.values["ref"] = std::move(step.ref);
|
||||
@@ -275,9 +276,11 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
|
||||
|
||||
util::json::Object makeRoute(const guidance::Route &route,
|
||||
util::json::Array legs,
|
||||
boost::optional<util::json::Value> geometry)
|
||||
boost::optional<util::json::Value> geometry,
|
||||
const char *weight_name)
|
||||
{
|
||||
util::json::Object json_route;
|
||||
json_route.values["weight_name"] = weight_name;
|
||||
json_route.values["distance"] = std::round(route.distance * 10) / 10.;
|
||||
json_route.values["duration"] = std::round(route.duration * 10) / 10.;
|
||||
json_route.values["legs"] = std::move(legs);
|
||||
|
||||
@@ -26,7 +26,7 @@ void AlternativeRouting::operator()(const std::shared_ptr<const datafacade::Base
|
||||
QueryHeap &forward_heap2 = *(engine_working_data.forward_heap_2);
|
||||
QueryHeap &reverse_heap2 = *(engine_working_data.reverse_heap_2);
|
||||
|
||||
int upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||
EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
const EdgeWeight min_edge_offset =
|
||||
std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled
|
||||
@@ -599,7 +599,7 @@ bool AlternativeRouting::ViaNodeCandidatePassesTTest(
|
||||
return false;
|
||||
}
|
||||
const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path);
|
||||
int unpacked_until_weight = 0;
|
||||
EdgeWeight unpacked_until_weight = 0;
|
||||
|
||||
std::stack<SearchSpaceEdge> unpack_stack;
|
||||
// Traverse path s-->v
|
||||
@@ -607,7 +607,7 @@ bool AlternativeRouting::ViaNodeCandidatePassesTTest(
|
||||
{
|
||||
const EdgeID current_edge_id =
|
||||
facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
const int length_of_current_edge = facade->GetEdgeData(current_edge_id).weight;
|
||||
const EdgeWeight length_of_current_edge = facade->GetEdgeData(current_edge_id).weight;
|
||||
if ((length_of_current_edge + unpacked_until_weight) >= T_threshold)
|
||||
{
|
||||
unpack_stack.emplace(packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
@@ -660,7 +660,7 @@ bool AlternativeRouting::ViaNodeCandidatePassesTTest(
|
||||
}
|
||||
}
|
||||
|
||||
int t_test_path_length = unpacked_until_weight;
|
||||
EdgeWeight t_test_path_length = unpacked_until_weight;
|
||||
unpacked_until_weight = 0;
|
||||
// Traverse path s-->v
|
||||
BOOST_ASSERT(!packed_v_t_path.empty());
|
||||
@@ -727,7 +727,7 @@ bool AlternativeRouting::ViaNodeCandidatePassesTTest(
|
||||
|
||||
QueryHeap &forward_heap3 = *engine_working_data.forward_heap_3;
|
||||
QueryHeap &reverse_heap3 = *engine_working_data.reverse_heap_3;
|
||||
int upper_bound = INVALID_EDGE_WEIGHT;
|
||||
EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
forward_heap3.Insert(s_P, 0, s_P);
|
||||
|
||||
@@ -128,7 +128,7 @@ void ManyToManyRouting::ForwardRoutingStep(
|
||||
std::vector<EdgeWeight> &result_table) const
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const int source_weight = query_heap.GetKey(node);
|
||||
const EdgeWeight source_weight = query_heap.GetKey(node);
|
||||
|
||||
// check if each encountered node has an entry
|
||||
const auto bucket_iterator = search_space_with_buckets.find(node);
|
||||
@@ -140,14 +140,14 @@ void ManyToManyRouting::ForwardRoutingStep(
|
||||
{
|
||||
// get target id from bucket entry
|
||||
const unsigned column_idx = current_bucket.target_id;
|
||||
const int target_weight = current_bucket.weight;
|
||||
const EdgeWeight target_weight = current_bucket.weight;
|
||||
auto ¤t_weight = result_table[row_idx * number_of_targets + column_idx];
|
||||
// check if new weight is better
|
||||
const EdgeWeight new_weight = source_weight + target_weight;
|
||||
if (new_weight < 0)
|
||||
{
|
||||
const EdgeWeight loop_weight = super::GetLoopWeight(facade, node);
|
||||
const int new_weight_with_loop = new_weight + loop_weight;
|
||||
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
|
||||
if (loop_weight != INVALID_EDGE_WEIGHT && new_weight_with_loop >= 0)
|
||||
{
|
||||
current_weight = std::min(current_weight, new_weight_with_loop);
|
||||
@@ -173,7 +173,7 @@ void ManyToManyRouting::BackwardRoutingStep(
|
||||
SearchSpaceWithBuckets &search_space_with_buckets) const
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const int target_weight = query_heap.GetKey(node);
|
||||
const EdgeWeight target_weight = query_heap.GetKey(node);
|
||||
|
||||
// store settled nodes in search space bucket
|
||||
search_space_with_buckets[node].emplace_back(column_idx, target_weight);
|
||||
|
||||
@@ -12,19 +12,19 @@ void BasicRoutingInterface::RoutingStep(
|
||||
SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node_id,
|
||||
std::int32_t &upper_bound,
|
||||
std::int32_t min_edge_offset,
|
||||
EdgeWeight &upper_bound,
|
||||
EdgeWeight min_edge_offset,
|
||||
const bool forward_direction,
|
||||
const bool stalling,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse) const
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const std::int32_t weight = forward_heap.GetKey(node);
|
||||
const EdgeWeight weight = forward_heap.GetKey(node);
|
||||
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
const std::int32_t new_weight = reverse_heap.GetKey(node) + weight;
|
||||
const EdgeWeight new_weight = reverse_heap.GetKey(node) + weight;
|
||||
if (new_weight < upper_bound)
|
||||
{
|
||||
// if loops are forced, they are so at the source
|
||||
@@ -45,7 +45,7 @@ void BasicRoutingInterface::RoutingStep(
|
||||
if (to == node)
|
||||
{
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
const std::int32_t loop_weight = new_weight + edge_weight;
|
||||
const EdgeWeight loop_weight = new_weight + edge_weight;
|
||||
if (loop_weight >= 0 && loop_weight < upper_bound)
|
||||
{
|
||||
middle_node_id = node;
|
||||
@@ -109,7 +109,7 @@ void BasicRoutingInterface::RoutingStep(
|
||||
const EdgeWeight edge_weight = data.weight;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_weight = weight + edge_weight;
|
||||
const EdgeWeight to_weight = weight + edge_weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!forward_heap.WasInserted(to))
|
||||
@@ -216,14 +216,14 @@ void BasicRoutingInterface::RetrievePackedPathFromSingleHeap(
|
||||
void BasicRoutingInterface::Search(const std::shared_ptr<const datafacade::BaseDataFacade> facade,
|
||||
SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
std::int32_t &weight,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const int duration_upper_bound) const
|
||||
const EdgeWeight weight_upper_bound) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
weight = duration_upper_bound;
|
||||
weight = weight_upper_bound;
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
||||
@@ -264,7 +264,7 @@ void BasicRoutingInterface::Search(const std::shared_ptr<const datafacade::BaseD
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (duration_upper_bound <= weight || SPECIAL_NODEID == middle)
|
||||
if (weight_upper_bound <= weight || SPECIAL_NODEID == middle)
|
||||
{
|
||||
weight = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
@@ -301,14 +301,14 @@ void BasicRoutingInterface::SearchWithCore(
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
SearchEngineData::QueryHeap &forward_core_heap,
|
||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||
int &weight,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
int duration_upper_bound) const
|
||||
EdgeWeight weight_upper_bound) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
weight = duration_upper_bound;
|
||||
weight = weight_upper_bound;
|
||||
|
||||
using CoreEntryPoint = std::tuple<NodeID, EdgeWeight, NodeID>;
|
||||
std::vector<CoreEntryPoint> forward_entry_points;
|
||||
@@ -328,7 +328,7 @@ void BasicRoutingInterface::SearchWithCore(
|
||||
if (facade->IsCoreNode(forward_heap.Min()))
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int key = forward_heap.GetKey(node);
|
||||
const EdgeWeight key = forward_heap.GetKey(node);
|
||||
forward_entry_points.emplace_back(node, key, forward_heap.GetData(node).parent);
|
||||
}
|
||||
else
|
||||
@@ -350,7 +350,7 @@ void BasicRoutingInterface::SearchWithCore(
|
||||
if (facade->IsCoreNode(reverse_heap.Min()))
|
||||
{
|
||||
const NodeID node = reverse_heap.DeleteMin();
|
||||
const int key = reverse_heap.GetKey(node);
|
||||
const EdgeWeight key = reverse_heap.GetKey(node);
|
||||
reverse_entry_points.emplace_back(node, key, reverse_heap.GetData(node).parent);
|
||||
}
|
||||
else
|
||||
@@ -392,7 +392,7 @@ void BasicRoutingInterface::SearchWithCore(
|
||||
}
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
int min_core_edge_offset = 0;
|
||||
EdgeWeight min_core_edge_offset = 0;
|
||||
if (forward_core_heap.Size() > 0)
|
||||
{
|
||||
min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
|
||||
@@ -432,7 +432,7 @@ void BasicRoutingInterface::SearchWithCore(
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (duration_upper_bound <= weight || SPECIAL_NODEID == middle)
|
||||
if (weight_upper_bound <= weight || SPECIAL_NODEID == middle)
|
||||
{
|
||||
weight = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
@@ -567,7 +567,7 @@ double BasicRoutingInterface::GetNetworkDistanceWithCore(
|
||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
int duration_upper_bound) const
|
||||
EdgeWeight weight_upper_bound) const
|
||||
{
|
||||
BOOST_ASSERT(forward_heap.Empty());
|
||||
BOOST_ASSERT(reverse_heap.Empty());
|
||||
@@ -601,21 +601,21 @@ double BasicRoutingInterface::GetNetworkDistanceWithCore(
|
||||
const bool constexpr DO_NOT_FORCE_LOOPS =
|
||||
false; // prevents forcing of loops, since offsets are set correctly
|
||||
|
||||
int duration = INVALID_EDGE_WEIGHT;
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_path;
|
||||
SearchWithCore(facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
forward_core_heap,
|
||||
reverse_core_heap,
|
||||
duration,
|
||||
weight,
|
||||
packed_path,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
duration_upper_bound);
|
||||
weight_upper_bound);
|
||||
|
||||
double distance = std::numeric_limits<double>::max();
|
||||
if (duration != INVALID_EDGE_WEIGHT)
|
||||
if (weight != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
return GetPathDistance(facade, packed_path, source_phantom, target_phantom);
|
||||
}
|
||||
@@ -631,7 +631,7 @@ double BasicRoutingInterface::GetNetworkDistance(
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
int duration_upper_bound) const
|
||||
EdgeWeight weight_upper_bound) const
|
||||
{
|
||||
BOOST_ASSERT(forward_heap.Empty());
|
||||
BOOST_ASSERT(reverse_heap.Empty());
|
||||
@@ -665,18 +665,18 @@ double BasicRoutingInterface::GetNetworkDistance(
|
||||
const bool constexpr DO_NOT_FORCE_LOOPS =
|
||||
false; // prevents forcing of loops, since offsets are set correctly
|
||||
|
||||
int duration = INVALID_EDGE_WEIGHT;
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_path;
|
||||
Search(facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
duration,
|
||||
weight,
|
||||
packed_path,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
duration_upper_bound);
|
||||
weight_upper_bound);
|
||||
|
||||
if (duration == INVALID_EDGE_WEIGHT)
|
||||
if (weight == INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
@@ -101,6 +101,14 @@ void CompressedEdgeContainer::SerializeInternalVector(const std::string &path) c
|
||||
// write compressed geometry reverse weights
|
||||
geometry_out_stream.write((char *)(m_compressed_geometry_rev_weights.data()),
|
||||
sizeof(EdgeWeight) * m_compressed_geometry_rev_weights.size());
|
||||
|
||||
// write compressed geometry forward durations
|
||||
geometry_out_stream.write((char *)(m_compressed_geometry_fwd_durations.data()),
|
||||
sizeof(EdgeWeight) * m_compressed_geometry_fwd_durations.size());
|
||||
|
||||
// write compressed geometry reverse durations
|
||||
geometry_out_stream.write((char *)(m_compressed_geometry_rev_durations.data()),
|
||||
sizeof(EdgeWeight) * m_compressed_geometry_rev_durations.size());
|
||||
}
|
||||
|
||||
// Adds info for a compressed edge to the container. edge_id_2
|
||||
@@ -111,12 +119,15 @@ void CompressedEdgeContainer::SerializeInternalVector(const std::string &path) c
|
||||
// edge_id_1 edge_id_2
|
||||
// ----------> via_node_id -----------> target_node_id
|
||||
// weight_1 weight_2
|
||||
// duration_1 duration_2
|
||||
void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
|
||||
const EdgeID edge_id_2,
|
||||
const NodeID via_node_id,
|
||||
const NodeID target_node_id,
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2)
|
||||
const EdgeWeight weight2,
|
||||
const EdgeWeight duration1,
|
||||
const EdgeWeight duration2)
|
||||
{
|
||||
// remove super-trivial geometries
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
|
||||
@@ -161,7 +172,7 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
|
||||
// weight1 is the distance to the (currently) last coordinate in the bucket
|
||||
if (edge_bucket_list1.empty())
|
||||
{
|
||||
edge_bucket_list1.emplace_back(OnewayCompressedEdge{via_node_id, weight1});
|
||||
edge_bucket_list1.emplace_back(OnewayCompressedEdge{via_node_id, weight1, duration1});
|
||||
}
|
||||
|
||||
BOOST_ASSERT(0 < edge_bucket_list1.size());
|
||||
@@ -192,13 +203,14 @@ void CompressedEdgeContainer::CompressEdge(const EdgeID edge_id_1,
|
||||
else
|
||||
{
|
||||
// we are certain that the second edge is atomic.
|
||||
edge_bucket_list1.emplace_back(OnewayCompressedEdge{target_node_id, weight2});
|
||||
edge_bucket_list1.emplace_back(OnewayCompressedEdge{target_node_id, weight2, duration2});
|
||||
}
|
||||
}
|
||||
|
||||
void CompressedEdgeContainer::AddUncompressedEdge(const EdgeID edge_id,
|
||||
const NodeID target_node_id,
|
||||
const EdgeWeight weight)
|
||||
const EdgeWeight weight,
|
||||
const EdgeWeight duration)
|
||||
{
|
||||
// remove super-trivial geometries
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != edge_id);
|
||||
@@ -234,7 +246,7 @@ void CompressedEdgeContainer::AddUncompressedEdge(const EdgeID edge_id,
|
||||
// Don't re-add this if it's already in there.
|
||||
if (edge_bucket_list.empty())
|
||||
{
|
||||
edge_bucket_list.emplace_back(OnewayCompressedEdge{target_node_id, weight});
|
||||
edge_bucket_list.emplace_back(OnewayCompressedEdge{target_node_id, weight, duration});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +256,8 @@ void CompressedEdgeContainer::InitializeBothwayVector()
|
||||
m_compressed_geometry_nodes.reserve(m_compressed_oneway_geometries.size());
|
||||
m_compressed_geometry_fwd_weights.reserve(m_compressed_oneway_geometries.size());
|
||||
m_compressed_geometry_rev_weights.reserve(m_compressed_oneway_geometries.size());
|
||||
m_compressed_geometry_fwd_durations.reserve(m_compressed_oneway_geometries.size());
|
||||
m_compressed_geometry_rev_durations.reserve(m_compressed_oneway_geometries.size());
|
||||
}
|
||||
|
||||
unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID r_edge_id)
|
||||
@@ -264,6 +278,8 @@ unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID
|
||||
m_compressed_geometry_nodes.emplace_back(first_node.node_id);
|
||||
m_compressed_geometry_fwd_weights.emplace_back(INVALID_EDGE_WEIGHT);
|
||||
m_compressed_geometry_rev_weights.emplace_back(first_node.weight);
|
||||
m_compressed_geometry_fwd_durations.emplace_back(INVALID_EDGE_WEIGHT);
|
||||
m_compressed_geometry_rev_durations.emplace_back(first_node.duration);
|
||||
|
||||
for (std::size_t i = 0; i < forward_bucket.size() - 1; ++i)
|
||||
{
|
||||
@@ -275,6 +291,8 @@ unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID
|
||||
m_compressed_geometry_nodes.emplace_back(fwd_node.node_id);
|
||||
m_compressed_geometry_fwd_weights.emplace_back(fwd_node.weight);
|
||||
m_compressed_geometry_rev_weights.emplace_back(rev_node.weight);
|
||||
m_compressed_geometry_fwd_durations.emplace_back(fwd_node.duration);
|
||||
m_compressed_geometry_rev_durations.emplace_back(rev_node.duration);
|
||||
}
|
||||
|
||||
const auto &last_node = forward_bucket.back();
|
||||
@@ -282,6 +300,8 @@ unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID
|
||||
m_compressed_geometry_nodes.emplace_back(last_node.node_id);
|
||||
m_compressed_geometry_fwd_weights.emplace_back(last_node.weight);
|
||||
m_compressed_geometry_rev_weights.emplace_back(INVALID_EDGE_WEIGHT);
|
||||
m_compressed_geometry_fwd_durations.emplace_back(last_node.duration);
|
||||
m_compressed_geometry_rev_durations.emplace_back(INVALID_EDGE_WEIGHT);
|
||||
|
||||
return zipped_geometry_id;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
const std::string &original_edge_data_filename,
|
||||
const std::string &turn_lane_data_filename,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_penalty_filename,
|
||||
const std::string &turn_weight_penalties_filename,
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const bool generate_edge_lookup)
|
||||
{
|
||||
TIMER_START(renumber);
|
||||
@@ -207,7 +209,9 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
original_edge_data_filename,
|
||||
turn_lane_data_filename,
|
||||
edge_segment_lookup_filename,
|
||||
edge_penalty_filename,
|
||||
turn_weight_penalties_filename,
|
||||
turn_duration_penalties_filename,
|
||||
turn_penalties_index_filename,
|
||||
generate_edge_lookup);
|
||||
|
||||
TIMER_STOP(generate_edges);
|
||||
@@ -237,11 +241,7 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
continue;
|
||||
}
|
||||
|
||||
// oneway streets always require this self-loop. Other streets only if a u-turn plus
|
||||
// traversal
|
||||
// of the street takes longer than the loop
|
||||
m_edge_based_node_weights.push_back(edge_data.distance +
|
||||
profile_properties.u_turn_penalty);
|
||||
m_edge_based_node_weights.push_back(edge_data.weight);
|
||||
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
|
||||
edge_data.edge_id = numbered_edges_count;
|
||||
@@ -311,7 +311,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const std::string &original_edge_data_filename,
|
||||
const std::string &turn_lane_data_filename,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_fixed_penalties_filename,
|
||||
const std::string &turn_weight_penalties_filename,
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename,
|
||||
const bool generate_edge_lookup)
|
||||
{
|
||||
util::Log() << "Generating edge-expanded edges ";
|
||||
@@ -324,12 +326,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
|
||||
std::ofstream edge_segment_file;
|
||||
std::ofstream edge_penalty_file;
|
||||
std::ofstream turn_penalties_index_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);
|
||||
turn_penalties_index_file.open(turn_penalties_index_filename.c_str(), std::ios::binary);
|
||||
}
|
||||
|
||||
// Writes a dummy value at the front that is updated later with the total length
|
||||
@@ -364,6 +366,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(),
|
||||
std::numeric_limits<std::uint32_t>::max());
|
||||
|
||||
// FIXME these need to be tuned in pre-allocated size
|
||||
std::vector<TurnPenalty> turn_weight_penalties;
|
||||
std::vector<TurnPenalty> turn_duration_penalties;
|
||||
|
||||
const auto weight_multiplier =
|
||||
std::pow(10, scripting_environment.GetProfileProperties().weight_precision);
|
||||
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
|
||||
@@ -474,28 +483,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
BOOST_ASSERT(!edge_data2.reversed);
|
||||
|
||||
// the following is the core of the loop.
|
||||
unsigned distance = edge_data1.distance;
|
||||
if (m_traffic_lights.find(node_at_center_of_intersection) !=
|
||||
m_traffic_lights.end())
|
||||
{
|
||||
distance += profile_properties.traffic_signal_penalty;
|
||||
}
|
||||
|
||||
const int32_t turn_penalty =
|
||||
scripting_environment.GetTurnPenalty(180. - turn.angle);
|
||||
|
||||
const auto turn_instruction = turn.instruction;
|
||||
if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
|
||||
{
|
||||
distance += profile_properties.u_turn_penalty;
|
||||
}
|
||||
|
||||
// don't add turn penalty if it is not an actual turn. This heuristic is
|
||||
// necessary
|
||||
// since OSRM cannot handle looping roads/parallel roads
|
||||
if (turn_instruction.type != guidance::TurnType::NoTurn)
|
||||
distance += turn_penalty;
|
||||
|
||||
const bool is_encoded_forwards =
|
||||
m_compressed_edge_container.HasZippedEntryForForwardID(incoming_edge);
|
||||
const bool is_encoded_backwards =
|
||||
@@ -509,7 +496,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
true},
|
||||
edge_data1.name_id,
|
||||
turn.lane_data_id,
|
||||
turn_instruction,
|
||||
turn.instruction,
|
||||
entry_class_id,
|
||||
edge_data1.travel_mode,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
@@ -523,7 +510,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
false},
|
||||
edge_data1.name_id,
|
||||
turn.lane_data_id,
|
||||
turn_instruction,
|
||||
turn.instruction,
|
||||
entry_class_id,
|
||||
edge_data1.travel_mode,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
@@ -531,26 +518,46 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
|
||||
++original_edges_counter;
|
||||
|
||||
if (original_edge_data_vector.size() > 1024 * 1024 * 10)
|
||||
{
|
||||
FlushVectorToStream(edge_data_file, original_edge_data_vector);
|
||||
}
|
||||
|
||||
// compute weight and duration penalties
|
||||
auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection);
|
||||
ExtractionTurn extracted_turn(turn, is_traffic_light);
|
||||
scripting_environment.ProcessTurn(extracted_turn);
|
||||
|
||||
// turn penalties are limited to [-2^15, 2^15) which roughly
|
||||
// translates to 54 minutes and fits signed 16bit deci-seconds
|
||||
auto weight_penalty =
|
||||
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
||||
auto duration_penalty =
|
||||
boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
||||
|
||||
// NOTE: potential overflow here if we hit 2^32 routable edges
|
||||
BOOST_ASSERT(m_edge_based_edge_list.size() <=
|
||||
std::numeric_limits<NodeID>::max());
|
||||
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
|
||||
edge_data2.edge_id,
|
||||
m_edge_based_edge_list.size(),
|
||||
distance,
|
||||
true,
|
||||
false);
|
||||
auto turn_id = m_edge_based_edge_list.size();
|
||||
auto weight =
|
||||
boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
|
||||
m_edge_based_edge_list.emplace_back(
|
||||
edge_data1.edge_id, edge_data2.edge_id, turn_id, weight, true, false);
|
||||
BOOST_ASSERT(original_edges_counter == m_edge_based_edge_list.size());
|
||||
|
||||
BOOST_ASSERT(turn_weight_penalties.size() == turn_id);
|
||||
turn_weight_penalties.push_back(weight_penalty);
|
||||
|
||||
// the weight and the duration are not the same thing
|
||||
if (!profile_properties.fallback_to_duration)
|
||||
{
|
||||
BOOST_ASSERT(turn_duration_penalties.size() == turn_id);
|
||||
turn_duration_penalties.push_back(duration_penalty);
|
||||
}
|
||||
|
||||
// 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:
|
||||
@@ -618,17 +625,46 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
|
||||
turn.eid)];
|
||||
|
||||
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));
|
||||
lookup::TurnIndexBlock turn_index_block = {
|
||||
from_node.node_id, via_node.node_id, to_node.node_id};
|
||||
BOOST_ASSERT(turn_penalties_index_file.tellp() /
|
||||
(sizeof(turn_index_block)) ==
|
||||
turn_id);
|
||||
turn_penalties_index_file.write(
|
||||
reinterpret_cast<const char *>(&turn_index_block),
|
||||
sizeof(turn_index_block));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write weight penalties per turn
|
||||
std::ofstream turn_weight_penalties_file(turn_weight_penalties_filename.c_str(),
|
||||
std::ios::binary);
|
||||
lookup::TurnPenaltiesHeader turn_weight_penalties_header{turn_weight_penalties.size()};
|
||||
turn_weight_penalties_file.write(reinterpret_cast<const char *>(&turn_weight_penalties_header),
|
||||
sizeof(turn_weight_penalties_header));
|
||||
turn_weight_penalties_file.write(reinterpret_cast<const char *>(turn_weight_penalties.data()),
|
||||
sizeof(decltype(turn_weight_penalties)::value_type) *
|
||||
turn_weight_penalties.size());
|
||||
|
||||
// write duration penalties per turn if we need them
|
||||
BOOST_ASSERT(!profile_properties.fallback_to_duration || turn_duration_penalties.size() == 0);
|
||||
std::ofstream turn_duration_penalties_file(turn_duration_penalties_filename.c_str(),
|
||||
std::ios::binary);
|
||||
lookup::TurnPenaltiesHeader turn_duration_penalties_header{turn_duration_penalties.size()};
|
||||
turn_duration_penalties_file.write(
|
||||
reinterpret_cast<const char *>(&turn_duration_penalties_header),
|
||||
sizeof(turn_duration_penalties_header));
|
||||
if (!profile_properties.fallback_to_duration)
|
||||
{
|
||||
BOOST_ASSERT(turn_weight_penalties.size() == turn_duration_penalties.size());
|
||||
turn_duration_penalties_file.write(
|
||||
reinterpret_cast<const char *>(turn_duration_penalties.data()),
|
||||
sizeof(decltype(turn_duration_penalties)::value_type) * turn_duration_penalties.size());
|
||||
}
|
||||
|
||||
util::Log() << "Created " << entry_class_hash.size() << " entry classes and "
|
||||
<< bearing_class_hash.size() << " Bearing Classes";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "extractor/extraction_containers.hpp"
|
||||
#include "extractor/extraction_segment.hpp"
|
||||
#include "extractor/extraction_way.hpp"
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
@@ -390,6 +391,9 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
const auto all_edges_list_end_ = all_edges_list.end();
|
||||
const auto all_nodes_list_end_ = all_nodes_list.end();
|
||||
|
||||
const auto weight_multiplier =
|
||||
std::pow(10, scripting_environment.GetProfileProperties().weight_precision);
|
||||
|
||||
while (edge_iterator != all_edges_list_end_ && node_iterator != all_nodes_list_end_)
|
||||
{
|
||||
// skip all invalid edges
|
||||
@@ -414,44 +418,28 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
}
|
||||
|
||||
BOOST_ASSERT(edge_iterator->result.osm_target_id == node_iterator->node_id);
|
||||
BOOST_ASSERT(edge_iterator->weight_data.speed >= 0);
|
||||
BOOST_ASSERT(edge_iterator->source_coordinate.lat !=
|
||||
util::FixedLatitude{std::numeric_limits<std::int32_t>::min()});
|
||||
BOOST_ASSERT(edge_iterator->source_coordinate.lon !=
|
||||
util::FixedLongitude{std::numeric_limits<std::int32_t>::min()});
|
||||
|
||||
const util::Coordinate target_coord{node_iterator->lon, node_iterator->lat};
|
||||
const double distance = util::coordinate_calculation::greatCircleDistance(
|
||||
edge_iterator->source_coordinate,
|
||||
util::Coordinate(node_iterator->lon, node_iterator->lat));
|
||||
edge_iterator->source_coordinate, target_coord);
|
||||
|
||||
scripting_environment.ProcessSegment(edge_iterator->source_coordinate,
|
||||
*node_iterator,
|
||||
distance,
|
||||
edge_iterator->weight_data);
|
||||
double weight = static_cast<double>(mapbox::util::apply_visitor(
|
||||
detail::ToValueByEdge(distance), edge_iterator->weight_data));
|
||||
double duration = static_cast<double>(mapbox::util::apply_visitor(
|
||||
detail::ToValueByEdge(distance), edge_iterator->duration_data));
|
||||
|
||||
const double weight = [distance, edge_iterator, node_iterator](
|
||||
const InternalExtractorEdge::WeightData &data) {
|
||||
switch (data.type)
|
||||
{
|
||||
case InternalExtractorEdge::WeightType::EDGE_DURATION:
|
||||
case InternalExtractorEdge::WeightType::WAY_DURATION:
|
||||
return data.duration * 10.;
|
||||
break;
|
||||
case InternalExtractorEdge::WeightType::SPEED:
|
||||
return (distance * 10.) / (data.speed / 3.6);
|
||||
break;
|
||||
case InternalExtractorEdge::WeightType::INVALID:
|
||||
std::stringstream coordstring;
|
||||
coordstring << edge_iterator->source_coordinate << " to " << node_iterator->lon
|
||||
<< "," << node_iterator->lat;
|
||||
util::exception("Encountered invalid weight at segment " + coordstring.str() +
|
||||
SOURCE_REF);
|
||||
}
|
||||
return -1.0;
|
||||
}(edge_iterator->weight_data);
|
||||
ExtractionSegment extracted_segment(
|
||||
edge_iterator->source_coordinate, target_coord, distance, weight, duration);
|
||||
scripting_environment.ProcessSegment(extracted_segment);
|
||||
|
||||
auto &edge = edge_iterator->result;
|
||||
edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
|
||||
edge.weight =
|
||||
std::max<EdgeWeight>(1, std::round(extracted_segment.weight * weight_multiplier));
|
||||
edge.duration = std::max<EdgeWeight>(1, std::round(extracted_segment.duration * 10.));
|
||||
|
||||
// assign new node id
|
||||
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
|
||||
@@ -499,7 +487,7 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
}
|
||||
|
||||
BOOST_ASSERT(all_edges_list.size() > 0);
|
||||
for (unsigned i = 0; i < all_edges_list.size();)
|
||||
for (std::size_t i = 0; i < all_edges_list.size();)
|
||||
{
|
||||
// only invalid edges left
|
||||
if (all_edges_list[i].result.source == SPECIAL_NODEID)
|
||||
@@ -513,42 +501,44 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned start_idx = i;
|
||||
std::size_t start_idx = i;
|
||||
NodeID source = all_edges_list[i].result.source;
|
||||
NodeID target = all_edges_list[i].result.target;
|
||||
|
||||
int min_forward_weight = std::numeric_limits<int>::max();
|
||||
int min_backward_weight = std::numeric_limits<int>::max();
|
||||
unsigned min_forward_idx = std::numeric_limits<unsigned>::max();
|
||||
unsigned min_backward_idx = std::numeric_limits<unsigned>::max();
|
||||
auto min_forward = std::make_pair(std::numeric_limits<EdgeWeight>::max(),
|
||||
std::numeric_limits<EdgeWeight>::max());
|
||||
auto min_backward = std::make_pair(std::numeric_limits<EdgeWeight>::max(),
|
||||
std::numeric_limits<EdgeWeight>::max());
|
||||
std::size_t min_forward_idx = std::numeric_limits<std::size_t>::max();
|
||||
std::size_t min_backward_idx = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
// find minimal edge in both directions
|
||||
while (all_edges_list[i].result.source == source &&
|
||||
while (i < all_edges_list.size() && all_edges_list[i].result.source == source &&
|
||||
all_edges_list[i].result.target == target)
|
||||
{
|
||||
if (all_edges_list[i].result.forward &&
|
||||
all_edges_list[i].result.weight < min_forward_weight)
|
||||
const auto &result = all_edges_list[i].result;
|
||||
const auto value = std::make_pair(result.weight, result.duration);
|
||||
if (result.forward && value < min_forward)
|
||||
{
|
||||
min_forward_idx = i;
|
||||
min_forward_weight = all_edges_list[i].result.weight;
|
||||
min_forward = value;
|
||||
}
|
||||
if (all_edges_list[i].result.backward &&
|
||||
all_edges_list[i].result.weight < min_backward_weight)
|
||||
if (result.backward && value < min_backward)
|
||||
{
|
||||
min_backward_idx = i;
|
||||
min_backward_weight = all_edges_list[i].result.weight;
|
||||
min_backward = value;
|
||||
}
|
||||
|
||||
// this also increments the outer loop counter!
|
||||
i++;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() ||
|
||||
BOOST_ASSERT(min_forward_idx == std::numeric_limits<std::size_t>::max() ||
|
||||
min_forward_idx < i);
|
||||
BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() ||
|
||||
BOOST_ASSERT(min_backward_idx == std::numeric_limits<std::size_t>::max() ||
|
||||
min_backward_idx < i);
|
||||
BOOST_ASSERT(min_backward_idx != std::numeric_limits<unsigned>::max() ||
|
||||
min_forward_idx != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(min_backward_idx != std::numeric_limits<std::size_t>::max() ||
|
||||
min_forward_idx != std::numeric_limits<std::size_t>::max());
|
||||
|
||||
if (min_backward_idx == min_forward_idx)
|
||||
{
|
||||
@@ -558,8 +548,8 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
}
|
||||
else
|
||||
{
|
||||
bool has_forward = min_forward_idx != std::numeric_limits<unsigned>::max();
|
||||
bool has_backward = min_backward_idx != std::numeric_limits<unsigned>::max();
|
||||
bool has_forward = min_forward_idx != std::numeric_limits<std::size_t>::max();
|
||||
bool has_backward = min_backward_idx != std::numeric_limits<std::size_t>::max();
|
||||
if (has_forward)
|
||||
{
|
||||
all_edges_list[min_forward_idx].result.forward = true;
|
||||
@@ -577,7 +567,7 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
}
|
||||
|
||||
// invalidate all unused edges
|
||||
for (unsigned j = start_idx; j < i; j++)
|
||||
for (std::size_t j = start_idx; j < i; j++)
|
||||
{
|
||||
if (j == min_forward_idx || j == min_backward_idx)
|
||||
{
|
||||
|
||||
@@ -126,9 +126,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
}
|
||||
util::Log() << "Threads: " << number_of_threads;
|
||||
|
||||
ExtractionContainers extraction_containers;
|
||||
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(extraction_containers);
|
||||
|
||||
const osmium::io::File input_file(config.input_path.string());
|
||||
|
||||
osmium::io::Reader reader(
|
||||
@@ -144,6 +141,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
util::Log() << "Parsing in progress..";
|
||||
TIMER_START(parsing);
|
||||
|
||||
ExtractionContainers extraction_containers;
|
||||
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(
|
||||
extraction_containers, scripting_environment.GetProfileProperties());
|
||||
|
||||
// setup raster sources
|
||||
scripting_environment.SetupSources();
|
||||
|
||||
@@ -496,7 +497,9 @@ Extractor::BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
config.edge_output_path,
|
||||
config.turn_lane_data_file_name,
|
||||
config.edge_segment_lookup_path,
|
||||
config.edge_penalty_path,
|
||||
config.turn_weight_penalties_path,
|
||||
config.turn_duration_penalties_path,
|
||||
config.turn_penalties_index_path,
|
||||
config.generate_edge_lookup);
|
||||
|
||||
WriteTurnLaneData(config.turn_lane_descriptions_file_name);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "extractor/extraction_node.hpp"
|
||||
#include "extractor/extraction_way.hpp"
|
||||
#include "extractor/guidance/road_classification.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include "util/for_each_pair.hpp"
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
@@ -31,8 +33,9 @@ namespace extractor
|
||||
using TurnLaneDescription = guidance::TurnLaneDescription;
|
||||
namespace TurnLaneType = guidance::TurnLaneType;
|
||||
|
||||
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers)
|
||||
: external_memory(extraction_containers)
|
||||
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers_,
|
||||
const ProfileProperties &properties)
|
||||
: external_memory(extraction_containers_), fallback_to_duration(properties.fallback_to_duration)
|
||||
{
|
||||
// we reserved 0, 1, 2, 3 for the empty case
|
||||
string_map[MapKey("", "", "", "")] = 0;
|
||||
@@ -80,16 +83,18 @@ void ExtractorCallbacks::ProcessRestriction(
|
||||
*/
|
||||
void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const ExtractionWay &parsed_way)
|
||||
{
|
||||
if (((0 >= parsed_way.forward_speed) ||
|
||||
(TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode)) &&
|
||||
((0 >= parsed_way.backward_speed) ||
|
||||
(TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)) &&
|
||||
(0 >= parsed_way.duration))
|
||||
if ((parsed_way.forward_travel_mode == TRAVEL_MODE_INACCESSIBLE &&
|
||||
parsed_way.backward_travel_mode == TRAVEL_MODE_INACCESSIBLE) ||
|
||||
(parsed_way.forward_speed <= 0 && parsed_way.backward_speed <= 0 &&
|
||||
parsed_way.duration <= 0) ||
|
||||
(!fallback_to_duration && parsed_way.forward_rate <= 0 && parsed_way.backward_rate <= 0 &&
|
||||
parsed_way.weight <= 0))
|
||||
{ // Only true if the way is specified by the speed profile
|
||||
return;
|
||||
}
|
||||
|
||||
if (input_way.nodes().size() <= 1)
|
||||
const auto &nodes = input_way.nodes();
|
||||
if (nodes.size() <= 1)
|
||||
{ // safe-guard against broken data
|
||||
return;
|
||||
}
|
||||
@@ -97,46 +102,63 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
if (std::numeric_limits<decltype(input_way.id())>::max() == input_way.id())
|
||||
{
|
||||
util::Log(logDEBUG) << "found bogus way with id: " << input_way.id() << " of size "
|
||||
<< input_way.nodes().size();
|
||||
<< nodes.size();
|
||||
return;
|
||||
}
|
||||
|
||||
InternalExtractorEdge::DurationData forward_duration_data;
|
||||
InternalExtractorEdge::DurationData backward_duration_data;
|
||||
InternalExtractorEdge::WeightData forward_weight_data;
|
||||
InternalExtractorEdge::WeightData backward_weight_data;
|
||||
|
||||
if (0 < parsed_way.duration)
|
||||
{
|
||||
const unsigned num_edges = (input_way.nodes().size() - 1);
|
||||
// FIXME We devide by the numer of nodes here, but should rather consider
|
||||
// the length of each segment. We would eigther have to compute the length
|
||||
// of the whole way here (we can't: no node coordinates) or push that back
|
||||
// to the container and keep a reference to the way.
|
||||
forward_weight_data.duration = parsed_way.duration / num_edges;
|
||||
forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
|
||||
backward_weight_data.duration = parsed_way.duration / num_edges;
|
||||
backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parsed_way.forward_speed > 0 &&
|
||||
parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||
const auto toValueByEdgeOrByMeter =
|
||||
[&nodes](const double by_way, const double by_meter) -> detail::ByEdgeOrByMeterValue {
|
||||
if (by_way > 0)
|
||||
{
|
||||
forward_weight_data.speed = parsed_way.forward_speed;
|
||||
forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
|
||||
// FIXME We divide by the number of edges here, but should rather consider
|
||||
// the length of each segment. We would either have to compute the length
|
||||
// of the whole way here (we can't: no node coordinates) or push that back
|
||||
// to the container and keep a reference to the way.
|
||||
const unsigned num_edges = (nodes.size() - 1);
|
||||
return detail::ValueByEdge{by_way / num_edges};
|
||||
}
|
||||
if (parsed_way.backward_speed > 0 &&
|
||||
parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||
else
|
||||
{
|
||||
backward_weight_data.speed = parsed_way.backward_speed;
|
||||
backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
|
||||
return detail::ValueByMeter{by_meter};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID &&
|
||||
backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
|
||||
if (parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
util::Log(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
|
||||
return;
|
||||
BOOST_ASSERT(parsed_way.duration > 0 || parsed_way.forward_speed > 0);
|
||||
forward_duration_data =
|
||||
toValueByEdgeOrByMeter(parsed_way.duration, parsed_way.forward_speed / 3.6);
|
||||
// fallback to duration as weight
|
||||
if (parsed_way.weight > 0 || parsed_way.forward_rate > 0)
|
||||
{
|
||||
forward_weight_data =
|
||||
toValueByEdgeOrByMeter(parsed_way.weight, parsed_way.forward_rate);
|
||||
}
|
||||
else if (fallback_to_duration)
|
||||
{
|
||||
forward_weight_data = forward_duration_data;
|
||||
}
|
||||
}
|
||||
if (parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
BOOST_ASSERT(parsed_way.duration > 0 || parsed_way.backward_speed > 0);
|
||||
backward_duration_data =
|
||||
toValueByEdgeOrByMeter(parsed_way.duration, parsed_way.backward_speed / 3.6);
|
||||
// fallback to duration as weight
|
||||
if (parsed_way.weight > 0 || parsed_way.backward_rate > 0)
|
||||
{
|
||||
backward_weight_data =
|
||||
toValueByEdgeOrByMeter(parsed_way.weight, parsed_way.backward_rate);
|
||||
}
|
||||
else if (fallback_to_duration)
|
||||
{
|
||||
backward_weight_data = backward_duration_data;
|
||||
}
|
||||
}
|
||||
|
||||
const auto laneStringToDescription = [](const std::string &lane_string) -> TurnLaneDescription {
|
||||
@@ -237,27 +259,23 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
|
||||
const auto road_classification = parsed_way.road_classification;
|
||||
|
||||
const constexpr auto MAX_STRING_LENGTH = 255u;
|
||||
const constexpr std::size_t MAX_STRING_LENGTH = 255u;
|
||||
// Get the unique identifier for the street name, destination, and ref
|
||||
const auto name_iterator = string_map.find(
|
||||
MapKey(parsed_way.name, parsed_way.destinations, parsed_way.ref, parsed_way.pronunciation));
|
||||
unsigned name_id = EMPTY_NAMEID;
|
||||
auto name_id = EMPTY_NAMEID;
|
||||
if (string_map.end() == name_iterator)
|
||||
{
|
||||
const auto name_length = std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.name.size());
|
||||
const auto name_length = std::min(MAX_STRING_LENGTH, parsed_way.name.size());
|
||||
const auto destinations_length =
|
||||
std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.destinations.size());
|
||||
std::min(MAX_STRING_LENGTH, parsed_way.destinations.size());
|
||||
const auto pronunciation_length =
|
||||
std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.pronunciation.size());
|
||||
const auto ref_length = std::min<unsigned>(MAX_STRING_LENGTH, parsed_way.ref.size());
|
||||
std::min(MAX_STRING_LENGTH, parsed_way.pronunciation.size());
|
||||
const auto ref_length = std::min(MAX_STRING_LENGTH, parsed_way.ref.size());
|
||||
|
||||
// name_offsets already has an offset of a new name, take the offset index as the name id
|
||||
name_id = external_memory.name_offsets.size() - 1;
|
||||
|
||||
external_memory.name_char_data.reserve(external_memory.name_char_data.size() + name_length +
|
||||
destinations_length + pronunciation_length +
|
||||
ref_length);
|
||||
|
||||
std::copy(parsed_way.name.c_str(),
|
||||
parsed_way.name.c_str() + name_length,
|
||||
std::back_inserter(external_memory.name_char_data));
|
||||
@@ -288,114 +306,85 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
name_id = name_iterator->second;
|
||||
}
|
||||
|
||||
const bool split_edge = (parsed_way.forward_speed > 0) &&
|
||||
(TRAVEL_MODE_INACCESSIBLE != parsed_way.forward_travel_mode) &&
|
||||
(parsed_way.backward_speed > 0) &&
|
||||
(TRAVEL_MODE_INACCESSIBLE != parsed_way.backward_travel_mode) &&
|
||||
((parsed_way.forward_speed != parsed_way.backward_speed) ||
|
||||
const bool in_forward_direction =
|
||||
(parsed_way.forward_speed > 0 || parsed_way.forward_rate > 0 || parsed_way.duration > 0 ||
|
||||
parsed_way.weight > 0) &&
|
||||
(parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||
|
||||
const bool in_backward_direction =
|
||||
(parsed_way.backward_speed > 0 || parsed_way.backward_rate > 0 || parsed_way.duration > 0 ||
|
||||
parsed_way.weight > 0) &&
|
||||
(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||
|
||||
const bool split_edge = in_forward_direction && in_backward_direction &&
|
||||
((parsed_way.forward_rate != parsed_way.backward_rate) ||
|
||||
(parsed_way.forward_speed != parsed_way.backward_speed) ||
|
||||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode) ||
|
||||
(turn_lane_id_forward != turn_lane_id_backward));
|
||||
|
||||
external_memory.used_node_id_list.reserve(external_memory.used_node_id_list.size() +
|
||||
input_way.nodes().size());
|
||||
|
||||
std::transform(input_way.nodes().begin(),
|
||||
input_way.nodes().end(),
|
||||
std::back_inserter(external_memory.used_node_id_list),
|
||||
[](const osmium::NodeRef &ref) {
|
||||
return OSMNodeID{static_cast<std::uint64_t>(ref.ref())};
|
||||
});
|
||||
|
||||
const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
|
||||
|
||||
// traverse way in reverse in this case
|
||||
if (is_opposite_way)
|
||||
if (in_forward_direction)
|
||||
{
|
||||
BOOST_ASSERT(split_edge == false);
|
||||
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||
util::for_each_pair(
|
||||
input_way.nodes().crbegin(),
|
||||
input_way.nodes().crend(),
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
name_id,
|
||||
backward_weight_data,
|
||||
true,
|
||||
false,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_travel_mode,
|
||||
false,
|
||||
turn_lane_id_backward,
|
||||
road_classification));
|
||||
});
|
||||
|
||||
external_memory.way_start_end_id_list.push_back(
|
||||
{OSMWayID{static_cast<std::uint32_t>(input_way.id())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(input_way.nodes().back().ref())},
|
||||
OSMNodeID{
|
||||
static_cast<std::uint64_t>(input_way.nodes()[input_way.nodes().size() - 2].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[1].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[0].ref())}});
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool forward_only =
|
||||
split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
|
||||
util::for_each_pair(
|
||||
input_way.nodes().cbegin(),
|
||||
input_way.nodes().cend(),
|
||||
nodes.cbegin(),
|
||||
nodes.cend(),
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
name_id,
|
||||
forward_weight_data,
|
||||
forward_duration_data,
|
||||
true,
|
||||
!forward_only,
|
||||
in_backward_direction && !split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.forward_travel_mode,
|
||||
split_edge,
|
||||
turn_lane_id_forward,
|
||||
road_classification));
|
||||
road_classification,
|
||||
{}));
|
||||
});
|
||||
if (split_edge)
|
||||
{
|
||||
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||
util::for_each_pair(
|
||||
input_way.nodes().cbegin(),
|
||||
input_way.nodes().cend(),
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
name_id,
|
||||
backward_weight_data,
|
||||
false,
|
||||
true,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_travel_mode,
|
||||
true,
|
||||
turn_lane_id_backward,
|
||||
road_classification));
|
||||
});
|
||||
}
|
||||
|
||||
external_memory.way_start_end_id_list.push_back(
|
||||
{OSMWayID{static_cast<std::uint32_t>(input_way.id())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(input_way.nodes().back().ref())},
|
||||
OSMNodeID{
|
||||
static_cast<std::uint64_t>(input_way.nodes()[input_way.nodes().size() - 2].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[1].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(input_way.nodes()[0].ref())}});
|
||||
}
|
||||
|
||||
if (in_backward_direction || split_edge)
|
||||
{
|
||||
util::for_each_pair(
|
||||
nodes.cbegin(),
|
||||
nodes.cend(),
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
name_id,
|
||||
backward_weight_data,
|
||||
backward_duration_data,
|
||||
false,
|
||||
true,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_travel_mode,
|
||||
split_edge,
|
||||
turn_lane_id_backward,
|
||||
road_classification,
|
||||
{}));
|
||||
});
|
||||
}
|
||||
|
||||
std::transform(nodes.begin(),
|
||||
nodes.end(),
|
||||
std::back_inserter(external_memory.used_node_id_list),
|
||||
[](const osmium::NodeRef &ref) {
|
||||
return OSMNodeID{static_cast<std::uint64_t>(ref.ref())};
|
||||
});
|
||||
|
||||
external_memory.way_start_end_id_list.push_back(
|
||||
{OSMWayID{static_cast<std::uint32_t>(input_way.id())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(nodes[0].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(nodes[1].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(nodes[nodes.size() - 2].ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(nodes.back().ref())}});
|
||||
}
|
||||
|
||||
guidance::LaneDescriptionMap &&ExtractorCallbacks::moveOutLaneDescriptionMap()
|
||||
|
||||
@@ -119,22 +119,30 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
if (has_node_penalty)
|
||||
continue;
|
||||
|
||||
// Get distances before graph is modified
|
||||
const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
|
||||
const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;
|
||||
// Get weights before graph is modified
|
||||
const EdgeWeight forward_weight1 = fwd_edge_data1.weight;
|
||||
const EdgeWeight forward_weight2 = fwd_edge_data2.weight;
|
||||
const EdgeWeight forward_duration1 = fwd_edge_data1.duration;
|
||||
const EdgeWeight forward_duration2 = fwd_edge_data2.duration;
|
||||
|
||||
BOOST_ASSERT(0 != forward_weight1);
|
||||
BOOST_ASSERT(0 != forward_weight2);
|
||||
|
||||
const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
|
||||
const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;
|
||||
const EdgeWeight reverse_weight1 = rev_edge_data1.weight;
|
||||
const EdgeWeight reverse_weight2 = rev_edge_data2.weight;
|
||||
const EdgeWeight reverse_duration1 = rev_edge_data1.duration;
|
||||
const EdgeWeight reverse_duration2 = rev_edge_data2.duration;
|
||||
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != reverse_weight2);
|
||||
|
||||
// add weight of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
|
||||
graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
|
||||
graph.GetEdgeData(forward_e1).weight += forward_weight2;
|
||||
graph.GetEdgeData(reverse_e1).weight += reverse_weight2;
|
||||
|
||||
// add duration of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).duration += forward_duration2;
|
||||
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
graph.SetTarget(forward_e1, node_w);
|
||||
@@ -196,10 +204,22 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(
|
||||
forward_e1, forward_e2, node_v, node_w, forward_weight1, forward_weight2);
|
||||
geometry_compressor.CompressEdge(
|
||||
reverse_e1, reverse_e2, node_v, node_u, reverse_weight1, reverse_weight2);
|
||||
geometry_compressor.CompressEdge(forward_e1,
|
||||
forward_e2,
|
||||
node_v,
|
||||
node_w,
|
||||
forward_weight1,
|
||||
forward_weight2,
|
||||
forward_duration1,
|
||||
forward_duration2);
|
||||
geometry_compressor.CompressEdge(reverse_e1,
|
||||
reverse_e2,
|
||||
node_v,
|
||||
node_u,
|
||||
reverse_weight1,
|
||||
reverse_weight2,
|
||||
reverse_duration1,
|
||||
reverse_duration2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +235,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
{
|
||||
const EdgeData &data = graph.GetEdgeData(edge_id);
|
||||
const NodeID target = graph.GetTarget(edge_id);
|
||||
geometry_compressor.AddUncompressedEdge(edge_id, target, data.distance);
|
||||
geometry_compressor.AddUncompressedEdge(edge_id, target, data.weight, data.duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ bool findPreviousIntersection(const NodeID node_v,
|
||||
* PREVIOUS_ID. To verify that find, we check the intersection using our PREVIOUS_ID candidate
|
||||
* to check the intersection at NODE for via_edge
|
||||
*/
|
||||
const constexpr double COMBINE_DISTANCE_CUTOFF = 30;
|
||||
const constexpr double COMBINE_WEIGHT_CUTOFF = 30;
|
||||
|
||||
const auto coordinate_extractor = intersection_generator.GetCoordinateExtractor();
|
||||
const auto coordinates_along_via_edge =
|
||||
@@ -53,7 +53,7 @@ bool findPreviousIntersection(const NodeID node_v,
|
||||
|
||||
// we check if via-edge is too short. In this case the previous turn cannot influence the turn
|
||||
// at via_edge and the intersection at NODE_W
|
||||
if (via_edge_length > COMBINE_DISTANCE_CUTOFF)
|
||||
if (via_edge_length > COMBINE_WEIGHT_CUTOFF)
|
||||
return false;
|
||||
|
||||
// Node -> Via_Edge -> Intersection[0 == UTURN] -> reverse_of(via_edge) -> Intersection at
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "extractor/external_memory_node.hpp"
|
||||
#include "extractor/extraction_helper_functions.hpp"
|
||||
#include "extractor/extraction_node.hpp"
|
||||
#include "extractor/extraction_segment.hpp"
|
||||
#include "extractor/extraction_turn.hpp"
|
||||
#include "extractor/extraction_way.hpp"
|
||||
#include "extractor/internal_extractor_edge.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
@@ -140,6 +142,80 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"connectivity",
|
||||
extractor::guidance::RoadPriorityClass::CONNECTIVITY);
|
||||
|
||||
context.state.new_enum("turn_type",
|
||||
"invalid",
|
||||
extractor::guidance::TurnType::Invalid,
|
||||
"new_name",
|
||||
extractor::guidance::TurnType::NewName,
|
||||
"continue",
|
||||
extractor::guidance::TurnType::Continue,
|
||||
"turn",
|
||||
extractor::guidance::TurnType::Turn,
|
||||
"merge",
|
||||
extractor::guidance::TurnType::Merge,
|
||||
"on_ramp",
|
||||
extractor::guidance::TurnType::OnRamp,
|
||||
"off_ramp",
|
||||
extractor::guidance::TurnType::OffRamp,
|
||||
"fork",
|
||||
extractor::guidance::TurnType::Fork,
|
||||
"end_of_road",
|
||||
extractor::guidance::TurnType::EndOfRoad,
|
||||
"notification",
|
||||
extractor::guidance::TurnType::Notification,
|
||||
"enter_roundabout",
|
||||
extractor::guidance::TurnType::EnterRoundabout,
|
||||
"enter_and_exit_roundabout",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundabout,
|
||||
"enter_rotary",
|
||||
extractor::guidance::TurnType::EnterRotary,
|
||||
"enter_and_exit_rotary",
|
||||
extractor::guidance::TurnType::EnterAndExitRotary,
|
||||
"enter_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersection,
|
||||
"enter_and_exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection,
|
||||
"use_lane",
|
||||
extractor::guidance::TurnType::UseLane,
|
||||
"no_turn",
|
||||
extractor::guidance::TurnType::NoTurn,
|
||||
"suppressed",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
"enter_roundabout_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutAtExit,
|
||||
"exit_roundabout",
|
||||
extractor::guidance::TurnType::ExitRoundabout,
|
||||
"enter_rotary_at_exit",
|
||||
extractor::guidance::TurnType::EnterRotaryAtExit,
|
||||
"exit_rotary",
|
||||
extractor::guidance::TurnType::ExitRotary,
|
||||
"enter_roundabout_intersection_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
"exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::ExitRoundaboutIntersection,
|
||||
"stay_on_roundabout",
|
||||
extractor::guidance::TurnType::StayOnRoundabout,
|
||||
"sliproad",
|
||||
extractor::guidance::TurnType::Sliproad);
|
||||
|
||||
context.state.new_enum("direction_modifier",
|
||||
"u_turn",
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
"sharp_right",
|
||||
extractor::guidance::DirectionModifier::SharpRight,
|
||||
"right",
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
"slight_right",
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
"straight",
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
"slight_left",
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
"left",
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
"sharp_left",
|
||||
extractor::guidance::DirectionModifier::SharpLeft);
|
||||
|
||||
context.state.new_usertype<SourceContainer>("sources",
|
||||
"load",
|
||||
&SourceContainer::LoadRasterSource,
|
||||
@@ -156,8 +232,7 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
sol::property(&ProfileProperties::GetTrafficSignalPenalty,
|
||||
&ProfileProperties::SetTrafficSignalPenalty),
|
||||
"u_turn_penalty",
|
||||
sol::property(&ProfileProperties::GetUturnPenalty, //
|
||||
&ProfileProperties::SetUturnPenalty),
|
||||
sol::property(&ProfileProperties::GetUturnPenalty, &ProfileProperties::SetUturnPenalty),
|
||||
"max_speed_for_map_matching",
|
||||
sol::property(&ProfileProperties::GetMaxSpeedForMapMatching,
|
||||
&ProfileProperties::SetMaxSpeedForMapMatching),
|
||||
@@ -166,7 +241,11 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"use_turn_restrictions",
|
||||
&ProfileProperties::use_turn_restrictions,
|
||||
"left_hand_driving",
|
||||
&ProfileProperties::left_hand_driving);
|
||||
&ProfileProperties::left_hand_driving,
|
||||
"weight_precision",
|
||||
&ProfileProperties::weight_precision,
|
||||
"weight_name",
|
||||
sol::property(&ProfileProperties::SetWeightName, &ProfileProperties::GetWeightName));
|
||||
|
||||
context.state.new_usertype<std::vector<std::string>>(
|
||||
"vector",
|
||||
@@ -233,6 +312,10 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
&ExtractionWay::forward_speed,
|
||||
"backward_speed",
|
||||
&ExtractionWay::backward_speed,
|
||||
"forward_rate",
|
||||
&ExtractionWay::forward_rate,
|
||||
"backward_rate",
|
||||
&ExtractionWay::backward_rate,
|
||||
"name",
|
||||
sol::property(&ExtractionWay::GetName, &ExtractionWay::SetName),
|
||||
"ref",
|
||||
@@ -253,6 +336,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
&ExtractionWay::is_startpoint,
|
||||
"duration",
|
||||
&ExtractionWay::duration,
|
||||
"weight",
|
||||
&ExtractionWay::weight,
|
||||
"road_classification",
|
||||
&ExtractionWay::road_classification,
|
||||
"forward_mode",
|
||||
@@ -260,17 +345,45 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"backward_mode",
|
||||
sol::property(&ExtractionWay::get_backward_mode, &ExtractionWay::set_backward_mode));
|
||||
|
||||
context.state.new_usertype<ExtractionSegment>("ExtractionSegment",
|
||||
"source",
|
||||
&ExtractionSegment::source,
|
||||
"target",
|
||||
&ExtractionSegment::target,
|
||||
"distance",
|
||||
&ExtractionSegment::distance,
|
||||
"weight",
|
||||
&ExtractionSegment::weight,
|
||||
"duration",
|
||||
&ExtractionSegment::duration);
|
||||
|
||||
context.state.new_usertype<ExtractionTurn>("ExtractionTurn",
|
||||
"angle",
|
||||
&ExtractionTurn::angle,
|
||||
"turn_type",
|
||||
&ExtractionTurn::turn_type,
|
||||
"direction_modifier",
|
||||
&ExtractionTurn::direction_modifier,
|
||||
"has_traffic_light",
|
||||
&ExtractionTurn::has_traffic_light,
|
||||
"weight",
|
||||
&ExtractionTurn::weight,
|
||||
"duration",
|
||||
&ExtractionTurn::duration);
|
||||
|
||||
// Keep in mind .location is undefined since we're not using libosmium's location cache
|
||||
context.state.new_usertype<osmium::NodeRef>("NodeRef", "id", &osmium::NodeRef::ref);
|
||||
|
||||
context.state.new_usertype<InternalExtractorEdge>("EdgeSource",
|
||||
"source_coordinate",
|
||||
&InternalExtractorEdge::source_coordinate,
|
||||
"weight_data",
|
||||
&InternalExtractorEdge::weight_data);
|
||||
"weight",
|
||||
&InternalExtractorEdge::weight_data,
|
||||
"duration",
|
||||
&InternalExtractorEdge::duration_data);
|
||||
|
||||
context.state.new_usertype<InternalExtractorEdge::WeightData>(
|
||||
"WeightData", "speed", &InternalExtractorEdge::WeightData::speed);
|
||||
// context.state.new_usertype<InternalExtractorEdge::WeightData>(
|
||||
// "WeightData", "weight", &InternalExtractorEdge::WeightData::weight_data);
|
||||
|
||||
context.state.new_usertype<ExternalMemoryNode>("EdgeTarget",
|
||||
"lon",
|
||||
@@ -307,6 +420,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
context.has_node_function = node_function.valid();
|
||||
context.has_way_function = way_function.valid();
|
||||
context.has_segment_function = segment_function.valid();
|
||||
|
||||
// Check profile API version
|
||||
auto maybe_version = context.state.get<sol::optional<int>>("api_version");
|
||||
if (maybe_version)
|
||||
{
|
||||
@@ -321,6 +436,18 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
" to " + std::to_string(SUPPORTED_MAX_API_VERSION) +
|
||||
" are supported." + SOURCE_REF);
|
||||
}
|
||||
|
||||
// Assert that version-dependent properties were not changed by profile
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 1:
|
||||
BOOST_ASSERT(context.properties.GetUturnPenalty() == 0);
|
||||
BOOST_ASSERT(context.properties.GetTrafficSignalPenalty() == 0);
|
||||
break;
|
||||
case 0:
|
||||
BOOST_ASSERT(context.properties.GetWeightName() == "duration");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const ProfileProperties &Sol2ScriptingEnvironment::GetProfileProperties()
|
||||
@@ -437,37 +564,73 @@ void Sol2ScriptingEnvironment::SetupSources()
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Sol2ScriptingEnvironment::GetTurnPenalty(const double angle)
|
||||
void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn)
|
||||
{
|
||||
auto &context = GetSol2Context();
|
||||
|
||||
sol::function turn_function = context.state["turn_function"];
|
||||
|
||||
if (turn_function.valid())
|
||||
switch (context.api_version)
|
||||
{
|
||||
const double penalty = turn_function(angle);
|
||||
case 1:
|
||||
if (context.has_turn_penalty_function)
|
||||
{
|
||||
turn_function(turn);
|
||||
|
||||
BOOST_ASSERT(penalty < std::numeric_limits<int32_t>::max());
|
||||
BOOST_ASSERT(penalty > std::numeric_limits<int32_t>::min());
|
||||
// Turn weight falls back to the duration value in deciseconds
|
||||
// or uses the extracted unit-less weight value
|
||||
if (context.properties.fallback_to_duration)
|
||||
turn.weight = turn.duration;
|
||||
}
|
||||
|
||||
return penalty;
|
||||
break;
|
||||
case 0:
|
||||
if (context.has_turn_penalty_function)
|
||||
{
|
||||
if (turn.turn_type != guidance::TurnType::NoTurn)
|
||||
{
|
||||
// Get turn duration and convert deci-seconds to seconds
|
||||
turn.duration = static_cast<double>(turn_function(turn.angle)) / 10.;
|
||||
BOOST_ASSERT(turn.weight == 0);
|
||||
|
||||
// add U-turn penalty
|
||||
if (turn.direction_modifier == guidance::DirectionModifier::UTurn)
|
||||
turn.duration += context.properties.GetUturnPenalty();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use zero turn penalty if it is not an actual turn. This heuristic is necessary
|
||||
// since OSRM cannot handle looping roads/parallel roads
|
||||
turn.duration = 0.;
|
||||
}
|
||||
}
|
||||
|
||||
// Add traffic light penalty, back-compatibility of api_version=0
|
||||
if (turn.has_traffic_light)
|
||||
turn.duration += context.properties.GetTrafficSignalPenalty();
|
||||
|
||||
// Turn weight falls back to the duration value in deciseconds
|
||||
turn.weight = turn.duration;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sol2ScriptingEnvironment::ProcessSegment(const osrm::util::Coordinate &source,
|
||||
const osrm::util::Coordinate &target,
|
||||
double distance,
|
||||
InternalExtractorEdge::WeightData &weight)
|
||||
void Sol2ScriptingEnvironment::ProcessSegment(ExtractionSegment &segment)
|
||||
{
|
||||
auto &context = GetSol2Context();
|
||||
|
||||
sol::function segment_function = context.state["segment_function"];
|
||||
|
||||
if (segment_function.valid())
|
||||
if (context.has_segment_function)
|
||||
{
|
||||
segment_function(source, target, distance, weight);
|
||||
sol::function segment_function = context.state["segment_function"];
|
||||
switch (context.api_version)
|
||||
{
|
||||
case 1:
|
||||
segment_function(segment);
|
||||
break;
|
||||
case 0:
|
||||
segment_function(segment.source, segment.target, segment.distance, segment.duration);
|
||||
segment.weight = segment.duration; // back-compatibility fallback to duration
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,6 +279,22 @@ void Storage::PopulateLayout(DataLayout &layout)
|
||||
layout.SetBlockSize<unsigned>(DataLayout::CORE_MARKER, number_of_core_markers);
|
||||
}
|
||||
|
||||
// load turn weight penalties
|
||||
{
|
||||
io::FileReader turn_weight_penalties_file(config.turn_weight_penalties_path,
|
||||
io::FileReader::HasNoFingerprint);
|
||||
const auto number_of_penalties = turn_weight_penalties_file.ReadElementCount64();
|
||||
layout.SetBlockSize<TurnPenalty>(DataLayout::TURN_WEIGHT_PENALTIES, number_of_penalties);
|
||||
}
|
||||
|
||||
// load turn duration penalties
|
||||
{
|
||||
io::FileReader turn_duration_penalties_file(config.turn_duration_penalties_path,
|
||||
io::FileReader::HasNoFingerprint);
|
||||
const auto number_of_penalties = turn_duration_penalties_file.ReadElementCount64();
|
||||
layout.SetBlockSize<TurnPenalty>(DataLayout::TURN_DURATION_PENALTIES, number_of_penalties);
|
||||
}
|
||||
|
||||
// load coordinate size
|
||||
{
|
||||
io::FileReader node_file(config.nodes_data_path, io::FileReader::HasNoFingerprint);
|
||||
@@ -307,6 +323,10 @@ void Storage::PopulateLayout(DataLayout &layout)
|
||||
number_of_compressed_geometries);
|
||||
layout.SetBlockSize<EdgeWeight>(DataLayout::GEOMETRIES_REV_WEIGHT_LIST,
|
||||
number_of_compressed_geometries);
|
||||
layout.SetBlockSize<EdgeWeight>(DataLayout::GEOMETRIES_FWD_DURATION_LIST,
|
||||
number_of_compressed_geometries);
|
||||
layout.SetBlockSize<EdgeWeight>(DataLayout::GEOMETRIES_REV_DURATION_LIST,
|
||||
number_of_compressed_geometries);
|
||||
}
|
||||
|
||||
// load datasource sizes. This file is optional, and it's non-fatal if it doesn't
|
||||
@@ -582,6 +602,18 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
|
||||
BOOST_ASSERT(geometry_node_lists_count ==
|
||||
layout.num_entries[DataLayout::GEOMETRIES_REV_WEIGHT_LIST]);
|
||||
geometry_input_file.ReadInto(geometries_rev_weight_list_ptr, geometry_node_lists_count);
|
||||
|
||||
const auto geometries_fwd_duration_list_ptr = layout.GetBlockPtr<EdgeWeight, true>(
|
||||
memory_ptr, DataLayout::GEOMETRIES_FWD_DURATION_LIST);
|
||||
BOOST_ASSERT(geometry_node_lists_count ==
|
||||
layout.num_entries[DataLayout::GEOMETRIES_FWD_DURATION_LIST]);
|
||||
geometry_input_file.ReadInto(geometries_fwd_duration_list_ptr, geometry_node_lists_count);
|
||||
|
||||
const auto geometries_rev_duration_list_ptr = layout.GetBlockPtr<EdgeWeight, true>(
|
||||
memory_ptr, DataLayout::GEOMETRIES_REV_DURATION_LIST);
|
||||
BOOST_ASSERT(geometry_node_lists_count ==
|
||||
layout.num_entries[DataLayout::GEOMETRIES_REV_DURATION_LIST]);
|
||||
geometry_input_file.ReadInto(geometries_rev_duration_list_ptr, geometry_node_lists_count);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -666,6 +698,26 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
|
||||
layout.num_entries[DataLayout::COORDINATE_LIST]);
|
||||
}
|
||||
|
||||
// load turn weight penalties
|
||||
{
|
||||
io::FileReader turn_weight_penalties_file(config.turn_weight_penalties_path,
|
||||
io::FileReader::HasNoFingerprint);
|
||||
const auto number_of_penalties = turn_weight_penalties_file.ReadElementCount64();
|
||||
const auto turn_weight_penalties_ptr =
|
||||
layout.GetBlockPtr<TurnPenalty, true>(memory_ptr, DataLayout::TURN_WEIGHT_PENALTIES);
|
||||
turn_weight_penalties_file.ReadInto(turn_weight_penalties_ptr, number_of_penalties);
|
||||
}
|
||||
|
||||
// load turn duration penalties
|
||||
{
|
||||
io::FileReader turn_duration_penalties_file(config.turn_duration_penalties_path,
|
||||
io::FileReader::HasNoFingerprint);
|
||||
const auto number_of_penalties = turn_duration_penalties_file.ReadElementCount64();
|
||||
const auto turn_duration_penalties_ptr =
|
||||
layout.GetBlockPtr<TurnPenalty, true>(memory_ptr, DataLayout::TURN_DURATION_PENALTIES);
|
||||
turn_duration_penalties_file.ReadInto(turn_duration_penalties_ptr, number_of_penalties);
|
||||
}
|
||||
|
||||
// store timestamp
|
||||
{
|
||||
io::FileReader timestamp_file(config.timestamp_path, io::FileReader::HasNoFingerprint);
|
||||
|
||||
@@ -13,6 +13,8 @@ StorageConfig::StorageConfig(const boost::filesystem::path &base)
|
||||
hsgr_data_path{base.string() + ".hsgr"}, nodes_data_path{base.string() + ".nodes"},
|
||||
edges_data_path{base.string() + ".edges"}, core_data_path{base.string() + ".core"},
|
||||
geometries_path{base.string() + ".geometry"}, timestamp_path{base.string() + ".timestamp"},
|
||||
turn_weight_penalties_path{base.string() + ".turn_weight_penalties"},
|
||||
turn_duration_penalties_path{base.string() + ".turn_duration_penalties"},
|
||||
datasource_names_path{base.string() + ".datasource_names"},
|
||||
datasource_indexes_path{base.string() + ".datasource_indexes"},
|
||||
names_data_path{base.string() + ".names"}, properties_path{base.string() + ".properties"},
|
||||
@@ -23,7 +25,7 @@ StorageConfig::StorageConfig(const boost::filesystem::path &base)
|
||||
|
||||
bool StorageConfig::IsValid() const
|
||||
{
|
||||
const constexpr auto num_files = 13;
|
||||
const constexpr auto num_files = 15;
|
||||
const boost::filesystem::path paths[num_files] = {ram_index_path,
|
||||
file_index_path,
|
||||
hsgr_data_path,
|
||||
@@ -32,6 +34,8 @@ bool StorageConfig::IsValid() const
|
||||
core_data_path,
|
||||
geometries_path,
|
||||
timestamp_path,
|
||||
turn_weight_penalties_path,
|
||||
turn_duration_penalties_path,
|
||||
datasource_indexes_path,
|
||||
datasource_indexes_path,
|
||||
names_data_path,
|
||||
|
||||
Reference in New Issue
Block a user