Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option for country specific toll factor #4289

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
12 changes: 11 additions & 1 deletion proto/options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ message Contour {
}

message Ring {
repeated LatLng coords = 1;
repeated LatLng coords = 1 ;
}

enum ShapeMatch {
Expand Down Expand Up @@ -311,6 +311,11 @@ message Costing {
uint32 axle_count = 81;
float use_lit = 82;
bool disable_hierarchy_pruning = 83;
repeated string country_code = 84;
}

message Multioptions {
repeated Options cost_per_country = 1;
}

oneof has_options {
Expand All @@ -325,6 +330,11 @@ message Costing {
oneof has_filter_closures {
bool filter_closures = 4;
}

oneof has_multioptions {
Multioptions multi_options = 5;
}

}

message Options {
Expand Down
88 changes: 87 additions & 1 deletion src/sif/autocost.cc
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,38 @@
return DynamicCost::Allowed(edge, tile, disallow_mask) && !edge->bss_connection() &&
(allow_closures || !tile->IsClosed(edge)) && IsHOVAllowed(edge);
}
// returns toll factor for a given toll value
float get_toll_factor(float use_tolls) {
auto toll_factor = use_tolls < 0.5f ? (4.0f - 8 * use_tolls) : // ranges from 4 to 0
(0.5f - use_tolls) * 0.03f; // ranges from 0 to -0.15
return toll_factor;
}

// set toll factor that will be finally applied
void set_toll_factor(float toll_factor_value) override {
this->toll_factor_ = toll_factor_value;
}

/**
* Return default toll factor
*/
float get_default_toll_factor() override {
return this->default_toll_factor_;
}

/**
* Return toll factor per country map
*/
std::map<std::string, float> get_toll_factor_per_country() override {
return this->toll_factor_per_country_;
}

/**
* Return true if multiple cost options is present in request
*/
bool get_multi_cost_flag() override {
return this->multi_options_flag_;
}

// Hidden in source file so we don't need it to be protected
// We expose it within the source file for testing purposes
Expand All @@ -329,10 +361,15 @@
float density_factor_[16]; // Density factor
float highway_factor_; // Factor applied when road is a motorway or trunk
float alley_factor_; // Avoid alleys factor.
float toll_factor_; // Factor applied when road has a toll
float default_toll_factor_; // Factor applied when road has a toll for all countries except
// specified otherwise
float toll_factor_; // Final factor applied when road has a toll
float surface_factor_; // How much the surface factors are applied.
float distance_factor_; // How much distance factors in overall favorability
float inv_distance_factor_; // How much time factors in overall favorability
std::map<std::string, float>
toll_factor_per_country_; // Factor applied when road has a toll for a specific country
bool multi_options_flag_; // set to true when "/cost_per_country" is present in the input

// Vehicle attributes (used for special restrictions and costing)
float height_; // Vehicle height in meters
Expand Down Expand Up @@ -370,6 +407,25 @@
// Get the base transition costs
get_base_costs(costing);

// Get the multiple options if present and store it in the country based mapping for options
if (costing.has_multi_options()) {
multi_options_flag_ = true;
const auto& multiple_costing_options = costing.multi_options();
const auto& cost_per_country = multiple_costing_options.cost_per_country();
for (const auto& cost_option_per_country : cost_per_country) {
if (cost_option_per_country.has_use_tolls_case()) {
float toll_value = cost_option_per_country.use_tolls();
auto country_based_use_toll_factor = get_toll_factor(toll_value);
auto country_list = cost_option_per_country.country_code();
if (!country_list.empty()) {
for (const auto& country : country_list) {
toll_factor_per_country_[country] = country_based_use_toll_factor;

Check warning on line 422 in src/sif/autocost.cc

View check run for this annotation

Codecov / codecov/patch

src/sif/autocost.cc#L416-L422

Added lines #L416 - L422 were not covered by tests
}
}
}

Check warning on line 425 in src/sif/autocost.cc

View check run for this annotation

Codecov / codecov/patch

src/sif/autocost.cc#L425

Added line #L425 was not covered by tests
}
}

// Get alley factor from costing options.
alley_factor_ = costing_options.alley_factor();

Expand Down Expand Up @@ -398,6 +454,7 @@
float use_tolls = costing_options.use_tolls();
toll_factor_ = use_tolls < 0.5f ? (4.0f - 8 * use_tolls) : // ranges from 4 to 0
(0.5f - use_tolls) * 0.03f; // ranges from 0 to -0.15
default_toll_factor_ = get_toll_factor(use_tolls);

include_hot_ = costing_options.include_hot();
include_hov2_ = costing_options.include_hov2();
Expand Down Expand Up @@ -686,6 +743,34 @@
return c;
}

void ParseMultiOptions(const rapidjson::Document& doc,
const std::string& costing_options_key,
Costing* c) {
std::string options_per_country_key = costing_options_key + "/cost_per_country";
auto* cmo = c->mutable_multi_options();
auto* cpc = cmo->mutable_cost_per_country();
auto multi_option_json =
rapidjson::get_optional<rapidjson::Value::ConstArray>(doc, options_per_country_key.c_str());
if (multi_option_json) {
for (const auto& option_arr : *multi_option_json) {
auto* cost_opt_country = cpc->Add();
auto toll_value = rapidjson::get_optional<float>(option_arr, "/use_tolls");
if (toll_value) {
cost_opt_country->set_use_tolls(*toll_value);

Check warning on line 759 in src/sif/autocost.cc

View check run for this annotation

Codecov / codecov/patch

src/sif/autocost.cc#L755-L759

Added lines #L755 - L759 were not covered by tests
} else {
cost_opt_country->set_use_tolls(kDefaultUseTolls);

Check warning on line 761 in src/sif/autocost.cc

View check run for this annotation

Codecov / codecov/patch

src/sif/autocost.cc#L761

Added line #L761 was not covered by tests
}
auto country_list =
rapidjson::get_optional<rapidjson::Value::ConstArray>(option_arr, "/country_code");
if (country_list) {
for (const auto& country : *country_list) {
cost_opt_country->add_country_code(country.GetString());

Check warning on line 767 in src/sif/autocost.cc

View check run for this annotation

Codecov / codecov/patch

src/sif/autocost.cc#L764-L767

Added lines #L764 - L767 were not covered by tests
}
}
}

Check warning on line 770 in src/sif/autocost.cc

View check run for this annotation

Codecov / codecov/patch

src/sif/autocost.cc#L770

Added line #L770 was not covered by tests
}
}

void ParseAutoCostOptions(const rapidjson::Document& doc,
const std::string& costing_options_key,
Costing* c) {
Expand All @@ -696,6 +781,7 @@
rapidjson::Value dummy;
const auto& json = rapidjson::get_child(doc, costing_options_key.c_str(), dummy);

ParseMultiOptions(doc, costing_options_key, c);
ParseBaseCostOptions(json, c, kBaseCostOptsConfig);
JSON_PBF_DEFAULT(co, kDefaultAutoType, json, "/type", transport_type);
JSON_PBF_RANGED_DEFAULT(co, kAlleyFactorRange, json, "/alley_factor", alley_factor);
Expand Down
64 changes: 63 additions & 1 deletion src/thor/bidirectional_astar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,34 @@
}
}

// Apply country specific toll factor
if (costing_->get_multi_cost_flag()) {
auto country_toll_map = costing_->get_toll_factor_per_country();
std::string admin_endnode;
if (FORWARD) {
auto endtile = graphreader.GetGraphTile(meta.edge->endnode());
if (endtile != nullptr) {
auto endnode_admin_idx = graphreader.GetEndNode(meta.edge, endtile)->admin_index();
admin_endnode = endtile->admin(endnode_admin_idx)->country_iso();
}
} else {
auto endtile = graphreader.GetGraphTile(opp_edge->endnode());
if (endtile != nullptr) {
auto endnode_admin_idx = graphreader.GetEndNode(opp_edge, endtile)->admin_index();
admin_endnode = endtile->admin(endnode_admin_idx)->country_iso();
}
}
auto it = country_toll_map.find(admin_endnode);
if (it != country_toll_map.end()) {
auto toll_factor_val = it->second;
costing_->set_toll_factor(toll_factor_val);

Check warning on line 294 in src/thor/bidirectional_astar.cc

View check run for this annotation

Codecov / codecov/patch

src/thor/bidirectional_astar.cc#L293-L294

Added lines #L293 - L294 were not covered by tests
} else {
costing_->set_toll_factor(costing_->get_default_toll_factor());
}
} else {
costing_->set_toll_factor(costing_->get_default_toll_factor());
}

// Get cost
uint8_t flow_sources;
sif::Cost newcost =
Expand Down Expand Up @@ -969,13 +997,28 @@
// Get the tile at the end node. Skip if tile not found as we won't be
// able to expand from this origin edge.
graph_tile_ptr endtile = graphreader.GetGraphTile(directededge->endnode());
if (!endtile) {
if (endtile == nullptr) {
continue;
}

// Get cost and sort cost (based on distance from endnode of this edge
// to the destination
nodeinfo = endtile->node(directededge->endnode());
if (costing_->get_multi_cost_flag()) {
auto country_toll_map = costing_->get_toll_factor_per_country();
auto endnode_admin_idx = nodeinfo->admin_index();
auto admin_endnode = endtile->admin(endnode_admin_idx)->country_iso();
auto it = country_toll_map.find(admin_endnode);
if (it != country_toll_map.end()) {
auto toll_factor_val = it->second;
costing_->set_toll_factor(toll_factor_val);

Check warning on line 1014 in src/thor/bidirectional_astar.cc

View check run for this annotation

Codecov / codecov/patch

src/thor/bidirectional_astar.cc#L1013-L1014

Added lines #L1013 - L1014 were not covered by tests
} else {
auto toll_factor_val = costing_->get_default_toll_factor();
costing_->set_toll_factor(toll_factor_val);
}
} else {
costing_->set_toll_factor(costing_->get_default_toll_factor());
}
uint8_t flow_sources;
Cost cost = costing_->EdgeCost(directededge, tile, time_info, flow_sources) *
(1.0f - edge.percent_along());
Expand Down Expand Up @@ -1073,6 +1116,25 @@
// directed edge for costing, as this is the forward direction along the
// destination edge. Note that the end node of the opposing edge is in the
// same tile as the directed edge.
graph_tile_ptr endtile = graphreader.GetGraphTile(directededge->endnode());
if (endtile == nullptr) {
continue;
}
if (costing_->get_multi_cost_flag()) {
auto country_toll_map = costing_->get_toll_factor_per_country();
auto endnode_admin_idx = endtile->node(directededge->endnode())->admin_index();
auto admin_endnode = endtile->admin(endnode_admin_idx)->country_iso();
auto it = country_toll_map.find(admin_endnode);
if (it != country_toll_map.end()) {
auto toll_factor_val = it->second;
costing_->set_toll_factor(toll_factor_val);

Check warning on line 1130 in src/thor/bidirectional_astar.cc

View check run for this annotation

Codecov / codecov/patch

src/thor/bidirectional_astar.cc#L1129-L1130

Added lines #L1129 - L1130 were not covered by tests
} else {
auto toll_factor_val = costing_->get_default_toll_factor();
costing_->set_toll_factor(toll_factor_val);
}
} else {
costing_->set_toll_factor(costing_->get_default_toll_factor());
}
uint8_t flow_sources;
Cost cost =
costing_->EdgeCost(directededge, tile, time_info, flow_sources) * edge.percent_along();
Expand Down
12 changes: 12 additions & 0 deletions valhalla/sif/autocost.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ void ParseTaxiCostOptions(const rapidjson::Document& doc,
*/
cost_ptr_t CreateTaxiCost(const Costing& costing);

/**
* Parses the multiple cost options from json and stores values in pbf.
* @param doc The json request represented as a DOM tree.
* @param costing_options_key A string representing the location in the DOM tree where the multiple
* costing options are stored.
* @param co A mutable protocol buffer where the parsed json values will be stored.
*/

void ParseMultiOptions(const rapidjson::Document& doc,
const std::string& costing_options_key,
Costing* c);

} // namespace sif
} // namespace valhalla

Expand Down
30 changes: 30 additions & 0 deletions valhalla/sif/dynamiccost.h
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,36 @@
return speed_penalty;
}

/**
* Override this in autocost Class.
* @param toll_factor_value set the toll_factor for edge cost calculations.
*/
virtual void set_toll_factor(float toll_factor_value) {
static_cast<void>(toll_factor_value);
}

/**
* Return default toll factor
*/
virtual float get_default_toll_factor() {
return 0;
}

/**
* Return toll factor per country map
*/
virtual std::map<std::string, float> get_toll_factor_per_country() {
std::map<std::string, float> default_toll_factor_per_country;
return default_toll_factor_per_country;

Check warning on line 919 in valhalla/sif/dynamiccost.h

View check run for this annotation

Codecov / codecov/patch

valhalla/sif/dynamiccost.h#L917-L919

Added lines #L917 - L919 were not covered by tests
}

/**
* Return true if multiple cost options is present in request
*/
virtual bool get_multi_cost_flag() {
return false;
}

protected:
/**
* Calculate `track` costs based on tracks preference.
Expand Down