diff --git a/features/car/stoppage.feature b/features/car/stoppage.feature new file mode 100644 index 000000000..762cca14f --- /dev/null +++ b/features/car/stoppage.feature @@ -0,0 +1,36 @@ +@routing @maxspeed @car +Feature: Car - Acceleration profiles + + Background: Use specific speeds + Given the profile "car" + Given a grid size of 1000 meters + + Scenario: Car - Use stoppage penalty at waypoints + Given the node map + """ + a 1 2 3 4 5 b + """ + + And the ways + | nodes | highway | maxspeed:forward | maxspeed:backward | + | ab | trunk | 60 | 45 | + + And the query options + | stoppage_penalty | 5,100 | + + When I route I should get + | from | to | route | time | + | a | b | ab,ab | 481.1s | + + When I route I should get + | from | to | route | time | + | b | a | ab,ab | 609.9s | + + When I route I should get + | from | to | route | time | + | a | a | ab,ab | 0s | + + When I request a travel time matrix I should get + | | a | b | + | a | 0 | 481.1 | + | b | 609.9 | 0 | diff --git a/features/testbot/stoppage.feature b/features/testbot/stoppage.feature index 39ddc5964..34a874c13 100644 --- a/features/testbot/stoppage.feature +++ b/features/testbot/stoppage.feature @@ -3,102 +3,9 @@ Feature: Testbot - Acceleration profiles Background: Use specific speeds Given the profile "testbot" - - Scenario: Testbot - No stoppage penalties - Given a grid size of 10 meters - Given the node map - """ - a 1 2 3 4 5 b - """ - - And the ways - | nodes | highway | maxspeed:forward | maxspeed:backward | - | ab | trunk | 60 | 45 | - - When I route I should get - | from | to | route | time | distance | - | a | b | ab,ab | 3.6s | 59.9m | - | a | 1 | ab,ab | 0.6s | 10m | - | a | 2 | ab,ab | 1.2s | 20m | - | a | 3 | ab,ab | 1.8s | 30m | - | a | 4 | ab,ab | 2.4s | 40m | - | a | 5 | ab,ab | 3s | 50m | - | 5 | b | ab,ab | 0.6s | 9.9m | - | 4 | b | ab,ab | 1.2s | 19.9m | - | 3 | b | ab,ab | 1.8s | 29.9m | - | 2 | b | ab,ab | 2.4s | 39.9m | - | 1 | b | ab,ab | 3s | 49.9m | - | 1 | 2 | ab,ab | 0.6s | 10m | - | 1 | 3 | ab,ab | 1.2s | 20m | - | 1 | 4 | ab,ab | 1.8s | 30m | - | 1 | 5 | ab,ab | 2.4s | 40m | - - When I request a travel time matrix I should get - | | a | 1 | 2 | 3 | 4 | 5 | b | - | a | 0 | 0.6 | 1.2 | 1.8 | 2.4 | 3 | 3.6 | - | 1 | 0.8 | 0 | 0.6 | 1.2 | 1.8 | 2.4 | 3 | - | 2 | 1.6 | 0.8 | 0 | 0.6 | 1.2 | 1.8 | 2.4 | - | 3 | 2.4 | 1.6 | 0.8 | 0 | 0.6 | 1.2 | 1.8 | - | 4 | 3.2 | 2.4 | 1.6 | 0.8 | 0 | 0.6 | 1.2 | - | 5 | 4 | 3.2 | 2.4 | 1.6 | 0.8 | 0 | 0.6 | - | b | 4.8 | 4 | 3.2 | 2.4 | 1.6 | 0.8 | 0 | - - Scenario: Testbot - No stoppage points, tiny grid size - Given a grid size of 1 meters - Given the node map - """ - a 1 2 3 4 5 6 7 8 9 b - """ - - And the ways - | nodes | highway | maxspeed:forward | maxspeed:backward | - | ab | trunk | 60 | 45 | - - When I request a travel time matrix I should get - | | a | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | b | - | a | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 | 0.3 | 0.4 | 0.4 | 0.5 | 0.6 | - | 1 | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 | 0.3 | 0.4 | 0.4 | 0.5 | 0.6 | - | 2 | 0.1 | 0.1 | 0 | 0 | 0.1 | 0.2 | 0.2 | 0.3 | 0.3 | 0.4 | 0.5 | - | 3 | 0.2 | 0.2 | 0 | 0 | 0.1 | 0.2 | 0.2 | 0.3 | 0.3 | 0.4 | 0.5 | - | 4 | 0.3 | 0.3 | 0.2 | 0.1 | 0 | 0.1 | 0.1 | 0.2 | 0.2 | 0.3 | 0.4 | - | 5 | 0.4 | 0.4 | 0.3 | 0.2 | 0.1 | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 | - | 6 | 0.4 | 0.4 | 0.3 | 0.2 | 0.1 | 0 | 0 | 0.1 | 0.1 | 0.2 | 0.3 | - | 7 | 0.5 | 0.5 | 0.4 | 0.3 | 0.2 | 0.1 | 0.1 | 0 | 0 | 0.1 | 0.2 | - | 8 | 0.6 | 0.6 | 0.5 | 0.4 | 0.3 | 0.2 | 0.2 | 0 | 0 | 0.1 | 0.2 | - | 9 | 0.7 | 0.7 | 0.6 | 0.5 | 0.4 | 0.3 | 0.3 | 0.2 | 0.1 | 0 | 0.1 | - | b | 0.8 | 0.8 | 0.7 | 0.6 | 0.5 | 0.4 | 0.4 | 0.3 | 0.2 | 0.1 | 0 | - - Scenario: Testbot - No stoppage points, tiny grid size - Given a grid size of 1 meters - Given the node map - """ - a 1 2 3 4 5 6 7 8 9 b - """ - - And the ways - | nodes | highway | maxspeed:forward | maxspeed:backward | - | ab | trunk | 60 | 45 | - - And the query options - | stoppage_penalty | 1.85,15 | - - When I request a travel time matrix I should get - | | a | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | b | - | a | 0 | 1.4 | 2 | 2.5 | 2.9 | 3.2 | 3.6 | 3.8 | 4.1 | 4.4 | 4.6 | - | 1 | 1.4 | 0 | 1.4 | 2 | 2.5 | 2.9 | 3.2 | 3.6 | 3.8 | 4.1 | 4.4 | - | 2 | 2 | 1.4 | 0 | 1.4 | 2 | 2.5 | 2.9 | 3.2 | 3.6 | 3.8 | 4.1 | - | 3 | 2.5 | 2 | 1.4 | 0 | 1.4 | 2 | 2.5 | 2.9 | 3.2 | 3.6 | 3.8 | - | 4 | 2.9 | 2.5 | 2 | 1.4 | 0 | 1.4 | 2 | 2.5 | 2.9 | 3.2 | 3.6 | - | 5 | 3.2 | 2.9 | 2.5 | 2 | 1.4 | 0 | 1.4 | 2 | 2.5 | 2.9 | 3.2 | - | 6 | 3.6 | 3.2 | 2.9 | 2.5 | 2 | 1.4 | 0 | 1.4 | 2 | 2.5 | 2.9 | - | 7 | 3.8 | 3.6 | 3.2 | 2.9 | 2.5 | 2 | 1.4 | 0 | 1.4 | 2 | 2.5 | - | 8 | 4.1 | 3.8 | 3.6 | 3.2 | 2.9 | 2.5 | 2 | 1.4 | 0 | 1.4 | 2 | - | 9 | 4.4 | 4.1 | 3.8 | 3.6 | 3.2 | 2.9 | 2.5 | 2 | 1.4 | 0 | 1.4 | - | b | 4.6 | 4.4 | 4.1 | 3.8 | 3.6 | 3.2 | 2.9 | 2.5 | 2 | 1.4 | 0 | - + Given a grid size of 1000 meters Scenario: Testbot - Use stoppage penalty at waypoints - Given a grid size of 10 meters Given the node map """ a 1 2 3 4 5 b @@ -109,60 +16,21 @@ Feature: Testbot - Acceleration profiles | ab | trunk | 60 | 45 | And the query options - | stoppage_penalty | 1.85,15 | + | stoppage_penalty | 5,100 | + + When I route I should get + | from | to | route | time | + | a | b | ab,ab | 412.3s | + + When I route I should get + | from | to | route | time | + | b | a | ab,ab | 505.9s | + + When I route I should get + | from | to | route | time | + | a | a | ab,ab | 0s | When I request a travel time matrix I should get - | | a | 1 | 2 | 3 | 4 | 5 | b | - | a | 0 | 4.6 | 6.5 | 8 | 9.3 | 10.4 | 11.3 | - | 1 | 4.6 | 0 | 4.6 | 6.5 | 8 | 9.3 | 10.3 | - | 2 | 6.5 | 4.6 | 0 | 4.6 | 6.5 | 8 | 9.2 | - | 3 | 8 | 6.5 | 4.6 | 0 | 4.6 | 6.5 | 8 | - | 4 | 9.3 | 8 | 6.5 | 4.6 | 0 | 4.6 | 6.5 | - | 5 | 10.4 | 9.3 | 8 | 6.5 | 4.6 | 0 | 4.6 | - | b | 11.3 | 10.3 | 9.2 | 8 | 6.5 | 4.6 | 0 | - - - Scenario: Long distance grid with no penalty - Given a grid size of 1000 meters - Given the node map - """ - a 1 2 3 4 5 b - """ - - And the ways - | nodes | highway | maxspeed:forward | maxspeed:backward | - | ab | trunk | 60 | 45 | - - When I request a travel time matrix I should get - | | a | 1 | 2 | 3 | 4 | 5 | b | - | a | 0 | 59.9 | 119.9 | 179.9 | 239.9 | 299.9 | 359.9 | - | 1 | 79.9 | 0 | 60 | 120 | 180 | 240 | 300 | - | 2 | 159.9 | 80 | 0 | 60 | 120 | 180 | 240 | - | 3 | 239.9 | 160 | 80 | 0 | 60 | 120 | 180 | - | 4 | 319.9 | 240 | 160 | 80 | 0 | 60 | 120 | - | 5 | 399.9 | 320 | 240 | 160 | 80 | 0 | 60 | - | b | 479.9 | 400 | 320 | 240 | 160 | 80 | 0 | - - Scenario: Long distance grid - Given a grid size of 1000 meters - Given the node map - """ - a 1 2 3 4 5 b - """ - - And the ways - | nodes | highway | maxspeed:forward | maxspeed:backward | - | ab | trunk | 60 | 45 | - - And the query options - | stoppage_penalty | 1.85,15 | - - When I request a travel time matrix I should get - | | a | 1 | 2 | 3 | 4 | 5 | b | - | a | 0 | 68.9 | 128.9 | 188.9 | 248.9 | 308.9 | 368.9 | - | 1 | 86.6 | 0 | 69 | 129 | 189 | 249 | 309 | - | 2 | 166.6 | 86.7 | 0 | 69 | 129 | 189 | 249 | - | 3 | 246.6 | 166.7 | 86.7 | 0 | 69 | 129 | 189 | - | 4 | 326.6 | 246.7 | 166.7 | 86.7 | 0 | 69 | 129 | - | 5 | 406.6 | 326.7 | 246.7 | 166.7 | 86.7 | 0 | 69 | - | b | 486.6 | 406.7 | 326.7 | 246.7 | 166.7 | 86.7 | 0 | \ No newline at end of file + | | a | b | + | a | 0 | 412.3 | + | b | 505.9 | 0 | diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp index 973cc9f64..23490e007 100644 --- a/src/engine/plugins/table.cpp +++ b/src/engine/plugins/table.cpp @@ -86,10 +86,8 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance; bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration; - constexpr bool always_calculate_distance = true; - auto result_tables_pair = algorithms.ManyToManySearch( - snapped_phantoms, params.sources, params.destinations, always_calculate_distance); + snapped_phantoms, params.sources, params.destinations, request_distance); if ((request_duration && result_tables_pair.first.empty()) || (request_distance && result_tables_pair.second.empty())) @@ -99,55 +97,20 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, std::vector estimated_pairs; - // Adds some time to adjust for getting up to speed and slowing down to a stop - // Returns a new `duration` - auto adjust_for_startstop = [](const double &comfortable_acceleration, - const EdgeDuration &duration, - const EdgeDistance &distance) -> EdgeDuration { - - // Assume linear acceleration from 0 to velocity - // auto comfortable_acceleration = 1.85; // m/s^2 - - // Very short paths can end up with 0 duration. That'll lead to a divide - // by zero, so instead, we'll assume the travel speed is 10m/s (36km/h). - // Typically, the distance is also short, so we're quibbling at tiny numbers - // here, but tiny numbers is what this adjustment lambda is all about, - // so we do try to be reasonable. - const auto average_speed = - duration == 0 ? 10 : distance / - (duration / 10.); // duration is in deciseconds, we need m/sec - - // Using the equations of motion as a simple approximation, assuming constant acceleration - // https://en.wikipedia.org/wiki/Equations_of_motion#Constant_translational_acceleration_in_a_straight_line - const auto distance_to_full_speed = - (average_speed * average_speed) / (2 * comfortable_acceleration); - - /* - std::cout << "Comfortable accel is " << comfortable_acceleration << std::endl; - std::cout << "Average speed is " << average_speed << " duration is " << duration - << std::endl; - std::cout << "Distance is " << distance << " distance to full speed is " - << distance_to_full_speed << std::endl; - */ - - if (distance_to_full_speed > distance / 2) - { - // std::cout << "Distance was too short, so only using half" << std::endl; - const auto time_to_halfway = std::sqrt(distance / comfortable_acceleration); - return (2 * time_to_halfway) * 10; // result is in deciseconds - } - else - { - // std::cout << "Distance was long, using cruising speed" << std::endl; - const auto cruising_distance = distance - 2 * distance_to_full_speed; - const auto cruising_time = cruising_distance / average_speed; - const auto acceleration_time = average_speed / comfortable_acceleration; - - // std::cout << "Cruising distance is " << cruising_distance << std::endl; - // std::cout << "Cruising time is " << cruising_time << std::endl; - // std::cout << "Acceleration time is " << acceleration_time << std::endl; - return (cruising_time + 2 * acceleration_time) * 10; // result is in deciseconds - } + auto penalize = [¶ms](float speed, EdgeDuration duration) -> EdgeDuration { + // this is the penalty before adjusting for the length of the route + auto speed_ratio = speed * MAXIMAL_ACCEL_DECEL_PENALIZABLE_SPEED_INVERSE; + auto penalty = speed_ratio * (params.max_stoppage_penalty - params.min_stoppage_penalty) + + params.min_stoppage_penalty; + // how much distance would we cover if we took half of it at this speed + // scale the penalty based on this distance, if its small we dont get much + // of the penalty, buf if its large we get up to the whole penalty + // .05 is to scale the duration to second and cut it in half + // .005 is like / 200m, so the estimated distance as a ratio of 200m + // so you get the full penalty if your route is 200m or more + auto distance_ratio = (speed * duration * .05) * 0.008; + return static_cast( + (distance_ratio < 1.f ? distance_ratio * penalty : penalty) * 10.); }; // Scan table for null results - if any exist, replace with distance estimates @@ -164,17 +127,16 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, // apply an accel/deceleration penalty to the duration if (result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION && row != column) { - /* const auto &source = snapped_phantoms[params.sources.empty() ? row : params.sources[row]]; const auto &destination = snapped_phantoms[params.destinations.empty() ? column : params.destinations[column]]; - */ - result_tables_pair.first[table_index] = - adjust_for_startstop(params.min_stoppage_penalty, - result_tables_pair.first[table_index], - result_tables_pair.second[table_index]); + result_tables_pair.first[table_index] += + penalize(source.speed_approximation, + result_tables_pair.first[table_index]) + + penalize(destination.speed_approximation, + result_tables_pair.first[table_index]); } // Estimate null results based on fallback_speed (if valid) and distance if (params.fallback_speed != INVALID_FALLBACK_SPEED && params.fallback_speed > 0 && @@ -225,14 +187,6 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, } } - // If distances weren't requested, delete them from the result so they don't - // get rendered. - if (!request_distance) - { - std::vector empty; - result_tables_pair.second.swap(empty); - } - api::TableAPI table_api{facade, params}; table_api.MakeResponse(result_tables_pair, snapped_phantoms, estimated_pairs, result);