Consider acceleration profile of vehicle travelling - particularly affects very short routes.

This commit is contained in:
Kevin Kreiser 2019-02-07 10:24:58 -05:00 committed by Daniel Patterson
parent 23c69f4c3d
commit 3d4d51d6b7
No known key found for this signature in database
GPG Key ID: 19C12BE1725A028B
9 changed files with 373 additions and 8 deletions

View File

@ -0,0 +1,168 @@
@routing @maxspeed @testbot
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.1 | 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.1 | 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 - With 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
| acceleration_profile | car |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | b |
| a | 0 | 1.1 | 1.7 | 2.1 | 2.4 | 2.6 | 2.9 | 3.1 | 3.4 | 3.5 | 3.7 |
| 1 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.3 | 2.6 | 2.8 | 3.1 | 3.3 | 3.5 |
| 2 | 1.7 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.4 | 2.6 | 2.9 | 3.1 | 3.3 |
| 3 | 2 | 1.5 | 1.1 | 0 | 1.1 | 1.5 | 2 | 2.3 | 2.6 | 2.8 | 3 |
| 4 | 2.3 | 1.9 | 1.5 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.4 | 2.6 | 2.8 |
| 5 | 2.5 | 2.2 | 1.9 | 1.5 | 1.1 | 0 | 1.1 | 1.7 | 2.1 | 2.4 | 2.6 |
| 6 | 2.8 | 2.5 | 2.3 | 2 | 1.7 | 1.1 | 0 | 1.1 | 1.7 | 2 | 2.3 |
| 7 | 3 | 2.8 | 2.5 | 2.3 | 2 | 1.7 | 1.1 | 0 | 1.1 | 1.7 | 2 |
| 8 | 3.2 | 3 | 2.8 | 2.5 | 2.3 | 2 | 1.5 | 1.1 | 0 | 1.1 | 1.5 |
| 9 | 3.4 | 3.2 | 3 | 2.8 | 2.5 | 2.3 | 1.9 | 1.5 | 1.1 | 0 | 1.1 |
| b | 3.6 | 3.4 | 3.2 | 3 | 2.8 | 2.5 | 2.2 | 1.9 | 1.5 | 1.1 | 0 |
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
"""
And the ways
| nodes | highway | maxspeed:forward | maxspeed:backward |
| ab | trunk | 60 | 45 |
And the query options
| acceleration_profile | car |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | b |
| a | 0 | 3.7 | 5.3 | 6.5 | 7.5 | 8.4 | 9.1 |
| 1 | 3.6 | 0 | 3.7 | 5.3 | 6.5 | 7.5 | 8.3 |
| 2 | 5.1 | 3.6 | 0 | 3.7 | 5.3 | 6.5 | 7.5 |
| 3 | 6.3 | 5.1 | 3.6 | 0 | 3.7 | 5.3 | 6.4 |
| 4 | 7.2 | 6.3 | 5.1 | 3.6 | 0 | 3.7 | 5.2 |
| 5 | 8.1 | 7.2 | 6.3 | 5.1 | 3.6 | 0 | 3.7 |
| b | 8.9 | 8.1 | 7.2 | 6.2 | 5.1 | 3.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
| acceleration_profile | car |
When I request a travel time matrix I should get
| | a | 1 | 2 | 3 | 4 | 5 | b |
| a | 0 | 65.1 | 125.1 | 185.1 | 245.1 | 305.1 | 365.1 |
| 1 | 83.7 | 0 | 65.2 | 125.2 | 185.2 | 245.2 | 305.2 |
| 2 | 163.7 | 83.8 | 0 | 65.2 | 125.2 | 185.2 | 245.2 |
| 3 | 243.7 | 163.8 | 83.8 | 0 | 65.2 | 125.2 | 185.2 |
| 4 | 323.7 | 243.8 | 163.8 | 83.8 | 0 | 65.2 | 125.2 |
| 5 | 403.7 | 323.8 | 243.8 | 163.8 | 83.8 | 0 | 65.2 |
| b | 483.7 | 403.8 | 323.8 | 243.8 | 163.8 | 83.8 | 0 |

View File

@ -81,6 +81,8 @@ struct BaseParameters
bool generate_hints = true; bool generate_hints = true;
SnappingType snapping = SnappingType::Default; SnappingType snapping = SnappingType::Default;
// Whether or not to add acceleration/decelleration penalties at waypoints
double waypoint_acceleration_factor = 0.;
BaseParameters(const std::vector<util::Coordinate> coordinates_ = {}, BaseParameters(const std::vector<util::Coordinate> coordinates_ = {},
const std::vector<boost::optional<Hint>> hints_ = {}, const std::vector<boost::optional<Hint>> hints_ = {},
@ -89,10 +91,11 @@ struct BaseParameters
std::vector<boost::optional<Approach>> approaches_ = {}, std::vector<boost::optional<Approach>> approaches_ = {},
bool generate_hints_ = true, bool generate_hints_ = true,
std::vector<std::string> exclude = {}, std::vector<std::string> exclude = {},
const SnappingType snapping_ = SnappingType::Default) const SnappingType snapping_ = SnappingType::Default,
bool waypoint_acceleration_factor_ = 0.)
: coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_), : coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_),
approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_), approaches(approaches_), exclude(std::move(exclude)), generate_hints(generate_hints_),
snapping(snapping_) snapping(snapping_), waypoint_acceleration_factor(waypoint_acceleration_factor_)
{ {
} }

View File

@ -721,6 +721,48 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo<v8::Value> &arg
} }
} }
if (obj->Has(Nan::New("acceleration_profile").ToLocalChecked()))
{
v8::Local<v8::Value> acceleration_profile =
obj->Get(Nan::New("acceleration_profile").ToLocalChecked());
if (acceleration_profile.IsEmpty())
return false;
if (!acceleration_profile->IsNumber() || !acceleration_profile->IsString())
{
Nan::ThrowError("acceleration_profile must be a decimal number or one of 'car', 'fast_car', 'slow_car', 'truck', or 'tractor_trailer'");
return false;
}
if (acceleration_profile->IsString()) {
std::string ssaf = *v8::String::Utf8Value(acceleration_profile);
// If they say 'yes', they get the default
if (ssaf == "car") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_CAR;
} else if (ssaf == "fast_car") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_FAST_CAR;
} else if (ssaf == "slow_car") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_SLOW_CAR;
} else if (ssaf == "truck") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_TRUCK;
} else if (ssaf == "tractor_trailer") {
params->waypoint_acceleration_factor = ACCELERATION_ALPHA_TRACTOR_TRAILER;
} else {
Nan::ThrowError("acceleration_profile must be a decimal number or one of 'car', 'fast_car', 'slow_car', 'truck', or 'tractor_trailer'");
return false;
}
return true;
}
const auto value = acceleration_profile->NumberValue();
if (value < 0) {
Nan::ThrowError("acceleration_profile cannot be negative");
return false;
}
params->waypoint_acceleration_factor = value;
}
return true; return true;
} }

View File

@ -135,6 +135,19 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
}, },
qi::_1)]; qi::_1)];
acceleration_alpha_defaults_rule =
qi::lit("car")[qi::_val = ACCELERATION_ALPHA_CAR] |
qi::lit("fast_car")[qi::_val = ACCELERATION_ALPHA_FAST_CAR] |
qi::lit("slow_car")[qi::_val = ACCELERATION_ALPHA_SLOW_CAR] |
qi::lit("truck")[qi::_val = ACCELERATION_ALPHA_TRUCK] |
qi::lit("tractor_trailer")[qi::_val = ACCELERATION_ALPHA_TRACTOR_TRAILER];
acceleration_profile_rule =
qi::lit("acceleration_profile=") >
(qi::double_ | acceleration_alpha_defaults_rule)
[ph::bind(&engine::api::BaseParameters::waypoint_acceleration_factor, qi::_r1) =
qi::_1];
query_rule = query_rule =
((location_rule % ';') | polyline_rule | ((location_rule % ';') | polyline_rule |
polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1]; polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1];
@ -179,7 +192,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
| generate_hints_rule(qi::_r1) // | generate_hints_rule(qi::_r1) //
| approach_rule(qi::_r1) // | approach_rule(qi::_r1) //
| exclude_rule(qi::_r1) // | exclude_rule(qi::_r1) //
| snapping_rule(qi::_r1); | snapping_rule(qi::_r1) //
| acceleration_profile_rule(qi::_r1);//
} }
protected: protected:
@ -196,6 +210,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, Signature> generate_hints_rule; qi::rule<Iterator, Signature> generate_hints_rule;
qi::rule<Iterator, Signature> approach_rule; qi::rule<Iterator, Signature> approach_rule;
qi::rule<Iterator, Signature> exclude_rule; qi::rule<Iterator, Signature> exclude_rule;
qi::rule<Iterator, Signature> acceleration_profile_rule;
qi::rule<Iterator, osrm::engine::Bearing()> bearing_rule; qi::rule<Iterator, osrm::engine::Bearing()> bearing_rule;
qi::rule<Iterator, osrm::util::Coordinate()> location_rule; qi::rule<Iterator, osrm::util::Coordinate()> location_rule;
@ -207,6 +222,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, double()> unlimited_rule; qi::rule<Iterator, double()> unlimited_rule;
qi::rule<Iterator, Signature> snapping_rule; qi::rule<Iterator, Signature> snapping_rule;
qi::rule<Iterator, double()> acceleration_alpha_defaults_rule;
qi::symbols<char, engine::Approach> approach_type; qi::symbols<char, engine::Approach> approach_type;
qi::symbols<char, engine::api::BaseParameters::SnappingType> snapping_type; qi::symbols<char, engine::api::BaseParameters::SnappingType> snapping_type;
}; };

View File

@ -488,8 +488,8 @@ inline void Prettify(char *buffer, int length, int k)
inline void dtoa_milo(double value, char *buffer) inline void dtoa_milo(double value, char *buffer)
{ {
// Not handling NaN and inf // Not handling NaN and inf
assert(!isnan(value)); assert(!std::isnan(value));
assert(!isinf(value)); assert(!std::isinf(value));
if (value == 0) if (value == 0)
{ {

View File

@ -118,6 +118,14 @@ static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>
static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max(); static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
static const EdgeDistance INVALID_FALLBACK_SPEED = std::numeric_limits<double>::max(); static const EdgeDistance INVALID_FALLBACK_SPEED = std::numeric_limits<double>::max();
// Recommended value for passenger vehicles from
// https://fdotwww.blob.core.windows.net/sitefinity/docs/default-source/content/rail/publications/studies/safety/accelerationresearch.pdf?sfvrsn=716a4bb1_0
static const double ACCELERATION_ALPHA_CAR = 6.0;
static const double ACCELERATION_ALPHA_FAST_CAR = 18;
static const double ACCELERATION_ALPHA_SLOW_CAR = 2;
static const double ACCELERATION_ALPHA_TRUCK = 1.5;
static const double ACCELERATION_ALPHA_TRACTOR_TRAILER = 0.5;
// FIXME the bitfields we use require a reduced maximal duration, this should be kept consistent // FIXME the bitfields we use require a reduced maximal duration, this should be kept consistent
// within the code base. For now we have to ensure that we don't case 30 bit to -1 and break any // within the code base. For now we have to ensure that we don't case 30 bit to -1 and break any
// min() / operator< checks due to the invalid truncation. In addition, using signed and unsigned // min() / operator< checks due to the invalid truncation. In addition, using signed and unsigned

View File

@ -86,8 +86,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance; bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration; bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
// Because of the Short Trip ETA adjustments below, we need distances every time
const bool distances_required = request_distance || params.waypoint_acceleration_factor > 0.;
auto result_tables_pair = algorithms.ManyToManySearch( auto result_tables_pair = algorithms.ManyToManySearch(
snapped_phantoms, params.sources, params.destinations, request_distance); snapped_phantoms, params.sources, params.destinations, distances_required);
if ((request_duration && result_tables_pair.first.empty()) || if ((request_duration && result_tables_pair.first.empty()) ||
(request_distance && result_tables_pair.second.empty())) (request_distance && result_tables_pair.second.empty()))
@ -97,8 +100,71 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
std::vector<api::TableAPI::TableCellRef> estimated_pairs; std::vector<api::TableAPI::TableCellRef> 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 &acceleration_alpha,
const EdgeDuration &duration,
const EdgeDistance &distance) -> EdgeDuration {
// 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
// The following reference has a nice model (equations 9 through 12)
// for vehicle acceleration
// https://fdotwww.blob.core.windows.net/sitefinity/docs/default-source/content/rail/publications/studies/safety/accelerationresearch.pdf?sfvrsn=716a4bb1_0
// We solve euqation 10 for time to figure out how long it'll take
// to get up to the desired speed
// Because Equation 10 is asymptotic on v_des, we need to pick a target speed
// that's slighly less so the equation can actually get there. 1m/s less than
// target seems like a reasonable value to aim for
const auto target_speed = std::max(average_speed - 1, 0.1);
const auto initial_speed = 0.;
// Equation 9
const auto beta = acceleration_alpha / average_speed;
// Equation 10 solved for time
const auto time_to_full_speed = std::log( (average_speed - initial_speed) / (average_speed - target_speed) ) / beta;
BOOST_ASSERT(time_to_full_speed >= 0);
// Equation 11
const auto distance_to_full_speed =
average_speed * time_to_full_speed -
average_speed * (1 - std::exp(-1 * beta * time_to_full_speed)) / beta;
BOOST_ASSERT(distance_to_full_speed >= 0);
if (distance_to_full_speed > distance / 2)
{
// Because equation 12 requires velocity at halfway, and
// solving equation 11 for t requires a Lambert W function,
// we'll approximate here by assuming constant acceleration
// over distance_to_full_speed using s = ut + 1/2at^2
const auto average_acceleration =
2 * distance_to_full_speed / (time_to_full_speed * time_to_full_speed);
const auto time_to_halfway = std::sqrt(distance / average_acceleration);
BOOST_ASSERT(time_to_halfway >= 0);
return (2 * time_to_halfway) * 10; // result is in deciseconds
}
else
{
const auto cruising_distance = distance - 2 * distance_to_full_speed;
const auto cruising_time = cruising_distance / average_speed;
BOOST_ASSERT(cruising_time >= 0);
return (cruising_time + 2 * time_to_full_speed) * 10; // result is in deciseconds
}
};
// Scan table for null results - if any exist, replace with distance estimates // Scan table for null results - if any exist, replace with distance estimates
if (params.fallback_speed != INVALID_FALLBACK_SPEED || params.scale_factor != 1) if (params.fallback_speed != INVALID_FALLBACK_SPEED || params.scale_factor != 1 ||
params.waypoint_acceleration_factor != 0.)
{ {
for (std::size_t row = 0; row < num_sources; row++) for (std::size_t row = 0; row < num_sources; row++)
{ {
@ -106,6 +172,16 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
{ {
const auto &table_index = row * num_destinations + column; const auto &table_index = row * num_destinations + column;
BOOST_ASSERT(table_index < result_tables_pair.first.size()); BOOST_ASSERT(table_index < result_tables_pair.first.size());
// apply an accel/deceleration penalty to the duration
if (result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION &&
row != column && params.waypoint_acceleration_factor != 0.)
{
result_tables_pair.first[table_index] =
adjust_for_startstop(params.waypoint_acceleration_factor,
result_tables_pair.first[table_index],
result_tables_pair.second[table_index]);
}
// Estimate null results based on fallback_speed (if valid) and distance
if (params.fallback_speed != INVALID_FALLBACK_SPEED && params.fallback_speed > 0 && if (params.fallback_speed != INVALID_FALLBACK_SPEED && params.fallback_speed > 0 &&
result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION) result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION)
{ {
@ -132,6 +208,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
estimated_pairs.emplace_back(row, column); estimated_pairs.emplace_back(row, column);
} }
// Apply a scale factor to non-null result if requested
if (params.scale_factor > 0 && params.scale_factor != 1 && if (params.scale_factor > 0 && params.scale_factor != 1 &&
result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION && result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION &&
result_tables_pair.first[table_index] != 0) result_tables_pair.first[table_index] != 0)
@ -153,6 +230,14 @@ 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<EdgeDistance> empty;
result_tables_pair.second.swap(empty);
}
api::TableAPI table_api{facade, params}; api::TableAPI table_api{facade, params};
table_api.MakeResponse(result_tables_pair, snapped_phantoms, estimated_pairs, result); table_api.MakeResponse(result_tables_pair, snapped_phantoms, estimated_pairs, result);

View File

@ -143,7 +143,8 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
middle_nodes_table[row_index * number_of_targets + column_index] = node; middle_nodes_table[row_index * number_of_targets + column_index] = node;
} }
} }
else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration)) else if (std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration) &&
new_distance >= 0)
{ {
current_weight = new_weight; current_weight = new_weight;
current_duration = new_duration; current_duration = new_duration;

View File

@ -318,5 +318,46 @@ tables.forEach(function(annotation) {
assert.throws(()=>osrm.table(options, (err, res) => {}), /scale_factor must be > 0/, "should throw on invalid scale_factor value"); assert.throws(()=>osrm.table(options, (err, res) => {}), /scale_factor must be > 0/, "should throw on invalid scale_factor value");
}); });
test('table: ' + annotation + ' table in Monaco with start_stop_acceleration_factor values', function(assert) {
assert.plan(12);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
annotations: [annotation.slice(0,-1)],
start_stop_acceleration_factor: []
};
assert.throws(()=>osrm.table(options, (err, res) => {}), /start_stop_acceleration_factor must be a decimal number or one of/, "should throw on empty array");
options.start_stop_acceleration_factor = 'a';
assert.throws(()=>osrm.table(options, (err, res) => {}), /start_stop_acceleration_factor must be a decimal number or one of/, "should throw on non-numeric value");
options.start_stop_acceleration_factor = [1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /start_stop_acceleration_factor must be a decimal number or one of/, "should throw on non-numeric value");
options.start_stop_acceleration_factor = -0.1;
assert.throws(()=>osrm.table(options, (err, res) => {}), /start_stop_acceleration_factor must be a decimal number or one of/, "should throw on non-numeric value");
options.start_stop_acceleration_factor = 0.;
assert.ok(()=>osrm.table(options, (err, res) => {}), "should work with zero");
options.start_stop_acceleration_factor = 2.0;
assert.ok(()=>osrm.table(options, (err, res) => {}), "Should work with positive numeric values");
options.start_stop_acceleration_factor = 'car';
assert.ok(()=>osrm.table(options, (err, res) => {}), "Should work with car defaults");
options.start_stop_acceleration_factor = 'fast_car';
assert.ok(()=>osrm.table(options, (err, res) => {}), "Should work with fast car defaults");
options.start_stop_acceleration_factor = 'slow_car';
assert.ok(()=>osrm.table(options, (err, res) => {}), "Should work with slow car defaults");
options.start_stop_acceleration_factor = 'truck';
assert.ok(()=>osrm.table(options, (err, res) => {}), "Should work with truck defaults");
options.start_stop_acceleration_factor = 'tractor_trailer';
assert.ok(()=>osrm.table(options, (err, res) => {}), "Should work with tractor trailer defaults");
options.start_stop_acceleration_factor = 'yes';
assert.throws(()=>osrm.table(options, (err, res) => {}), /start_stop_acceleration_factor must be a decimal number or one of/, "should throw on non-recognized string");
});
}); });