Allow specifing a weight for routing that is independent of duration

This commit is contained in:
Patrick Niklaus
2016-05-12 18:50:10 +02:00
committed by Patrick Niklaus
parent e463733138
commit 279f8aabfb
85 changed files with 2100 additions and 853 deletions
+172 -80
View File
@@ -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;
}
+3 -3
View File
@@ -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))
+4 -1
View File
@@ -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 &current_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);
+27 -27
View File
@@ -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();
}
+25 -5
View File
@@ -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;
}
+82 -46
View File
@@ -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";
+38 -48
View File
@@ -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)
{
+7 -4
View File
@@ -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);
+123 -134
View File
@@ -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()
+32 -12
View File
@@ -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);
}
}
}
+2 -2
View File
@@ -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
+187 -24
View File
@@ -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;
}
}
}
+52
View File
@@ -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);
+5 -1
View File
@@ -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,