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
+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;
}
}
}