Compare commits

...

7 Commits

21 changed files with 742 additions and 184 deletions
+168
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 | 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 |
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
| stoppage_penalty | 1.85,15 |
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 |
+14 -5
View File
@@ -81,6 +81,8 @@ struct BaseParameters
bool generate_hints = true; bool generate_hints = true;
SnappingType snapping = SnappingType::Default; SnappingType snapping = SnappingType::Default;
double min_stoppage_penalty = INVALID_MINIMUM_STOPPAGE_PENALTY;
double max_stoppage_penalty = INVALID_MAXIMUM_STOPPAGE_PENALTY;
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,16 +91,23 @@ 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,
double min_stoppage_penalty_ = INVALID_MINIMUM_STOPPAGE_PENALTY,
double max_stoppage_penalty_ = INVALID_MAXIMUM_STOPPAGE_PENALTY)
: 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_), min_stoppage_penalty(min_stoppage_penalty_),
max_stoppage_penalty(max_stoppage_penalty_)
{ {
} }
// FIXME add validation for invalid bearing values // FIXME add validation for invalid bearing values
bool IsValid() const bool IsValid() const
{ {
if (min_stoppage_penalty <= 0 || max_stoppage_penalty <= 0 ||
min_stoppage_penalty > max_stoppage_penalty)
return false;
return (hints.empty() || hints.size() == coordinates.size()) && return (hints.empty() || hints.size() == coordinates.size()) &&
(bearings.empty() || bearings.size() == coordinates.size()) && (bearings.empty() || bearings.size() == coordinates.size()) &&
(radiuses.empty() || radiuses.size() == coordinates.size()) && (radiuses.empty() || radiuses.size() == coordinates.size()) &&
@@ -114,8 +123,8 @@ struct BaseParameters
}); });
} }
}; };
} } // namespace api
} } // namespace engine
} } // namespace osrm
#endif // ROUTE_PARAMETERS_HPP #endif // ROUTE_PARAMETERS_HPP
+3 -5
View File
@@ -78,7 +78,6 @@ struct TableParameters : public BaseParameters
}; };
AnnotationsType annotations = AnnotationsType::Duration; AnnotationsType annotations = AnnotationsType::Duration;
double scale_factor = 1; double scale_factor = 1;
TableParameters() = default; TableParameters() = default;
@@ -113,7 +112,6 @@ struct TableParameters : public BaseParameters
destinations{std::move(destinations_)}, fallback_speed{fallback_speed_}, destinations{std::move(destinations_)}, fallback_speed{fallback_speed_},
fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_}, fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_},
scale_factor{scale_factor_} scale_factor{scale_factor_}
{ {
} }
@@ -166,8 +164,8 @@ inline TableParameters::AnnotationsType &operator|=(TableParameters::Annotations
{ {
return lhs = lhs | rhs; return lhs = lhs | rhs;
} }
} } // namespace api
} } // namespace engine
} } // namespace osrm
#endif // ENGINE_API_TABLE_PARAMETERS_HPP #endif // ENGINE_API_TABLE_PARAMETERS_HPP
@@ -384,54 +384,84 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
input_coordinate, max_results, max_distance, bearing, bearing_range, approach); input_coordinate, max_results, max_distance, bearing, bearing_range, approach);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const util::Coordinate input_coordinate,
const Approach approach, const Approach approach,
const bool use_all_edges) const override final const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, approach, use_all_edges); input_coordinate,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach, const Approach approach,
const bool use_all_edges) const override final const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, approach, use_all_edges); input_coordinate,
max_distance,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach, const Approach approach,
const bool use_all_edges) const override final const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range, approach, use_all_edges); input_coordinate,
max_distance,
bearing,
bearing_range,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const util::Coordinate input_coordinate,
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach, const Approach approach,
const bool use_all_edges) const override final const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const override final
{ {
BOOST_ASSERT(m_geospatial_query.get()); BOOST_ASSERT(m_geospatial_query.get());
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, bearing, bearing_range, approach, use_all_edges); input_coordinate,
bearing,
bearing_range,
approach,
use_all_edges,
minimum_stoppage_penalty,
maximum_stoppage_penalty);
} }
std::uint32_t GetCheckSum() const override final { return m_check_sum; } std::uint32_t GetCheckSum() const override final { return m_check_sum; }
+30 -22
View File
@@ -157,28 +157,36 @@ class BaseDataFacade
const double max_distance, const double max_distance,
const Approach approach) const = 0; const Approach approach) const = 0;
virtual std::pair<PhantomNode, PhantomNode> virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const util::Coordinate input_coordinate,
const Approach approach, const Approach approach,
const bool use_all_edges) const = 0; const bool use_all_edges,
virtual std::pair<PhantomNode, PhantomNode> const double minimum_stoppage_penalty,
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const double maximum_stoppage_penalty) const = 0;
const double max_distance, virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const Approach approach, const util::Coordinate input_coordinate,
const bool use_all_edges) const = 0; const double max_distance,
virtual std::pair<PhantomNode, PhantomNode> const Approach approach,
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const bool use_all_edges,
const double max_distance, const double minimum_stoppage_penalty,
const int bearing, const double maximum_stoppage_penalty) const = 0;
const int bearing_range, virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const Approach approach, const util::Coordinate input_coordinate,
const bool use_all_edges) const = 0; const double max_distance,
virtual std::pair<PhantomNode, PhantomNode> const int bearing,
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const int bearing_range,
const int bearing, const Approach approach,
const int bearing_range, const bool use_all_edges,
const Approach approach, const double minimum_stoppage_penalty,
const bool use_all_edges = false) const = 0; const double maximum_stoppage_penalty) const = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate,
const int bearing,
const int bearing_range,
const Approach approach,
const bool use_all_edges,
const double minimum_stoppage_penalty,
const double maximum_stoppage_penalty) const = 0;
virtual bool HasLaneData(const EdgeID id) const = 0; virtual bool HasLaneData(const EdgeID id) const = 0;
virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0; virtual util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const = 0;
+92 -35
View File
@@ -206,7 +206,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance, const double max_distance,
const Approach approach, const Approach approach,
const bool use_all_edges) const const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@@ -248,8 +250,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
} }
BOOST_ASSERT(results.size() == 1 || results.size() == 2); BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, return std::make_pair(
MakePhantomNode(input_coordinate, results.back()).phantom_node); MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
} }
// Returns the nearest phantom node. If this phantom node is not from a big component // Returns the nearest phantom node. If this phantom node is not from a big component
@@ -257,7 +264,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const Approach approach, const Approach approach,
const bool use_all_edges) const const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@@ -298,8 +307,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
} }
BOOST_ASSERT(results.size() == 1 || results.size() == 2); BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, return std::make_pair(
MakePhantomNode(input_coordinate, results.back()).phantom_node); MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
} }
// Returns the nearest phantom node. If this phantom node is not from a big component // Returns the nearest phantom node. If this phantom node is not from a big component
@@ -309,7 +323,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach, const Approach approach,
const bool use_all_edges) const const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@@ -357,8 +373,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
} }
BOOST_ASSERT(results.size() > 0); BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, return std::make_pair(
MakePhantomNode(input_coordinate, results.back()).phantom_node); MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
} }
// Returns the nearest phantom node. If this phantom node is not from a big component // Returns the nearest phantom node. If this phantom node is not from a big component
@@ -369,7 +390,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const int bearing, const int bearing,
const int bearing_range, const int bearing_range,
const Approach approach, const Approach approach,
const bool use_all_edges) const const bool use_all_edges,
const double min_stoppage_penalty,
const double max_stoppage_penalty) const
{ {
bool has_small_component = false; bool has_small_component = false;
bool has_big_component = false; bool has_big_component = false;
@@ -419,8 +442,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
} }
BOOST_ASSERT(results.size() > 0); BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, return std::make_pair(
MakePhantomNode(input_coordinate, results.back()).phantom_node); MakePhantomNode(
input_coordinate, results.front(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node,
MakePhantomNode(
input_coordinate, results.back(), min_stoppage_penalty, max_stoppage_penalty)
.phantom_node);
} }
private: private:
@@ -438,8 +466,11 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
return distance_and_phantoms; return distance_and_phantoms;
} }
// TODO: remove stoppage penalty as its not needed here anymore
PhantomNodeWithDistance MakePhantomNode(const util::Coordinate input_coordinate, PhantomNodeWithDistance MakePhantomNode(const util::Coordinate input_coordinate,
const EdgeData &data) const const EdgeData &data,
const double min_stoppage_penalty = 0,
const double max_stoppage_penalty = 0) const
{ {
util::Coordinate point_on_segment; util::Coordinate point_on_segment;
double ratio; double ratio;
@@ -478,16 +509,21 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
forward_durations.begin() + data.fwd_segment_position, forward_durations.begin() + data.fwd_segment_position,
EdgeDuration{0}); EdgeDuration{0});
EdgeDistance forward_distance_offset = 0; // For measuring distance from begin up to end
// Sum up the distance from the start to the fwd_segment_position const auto appx_distance = [this](decltype(forward_geometry.begin()) begin,
for (auto current = forward_geometry.begin(); decltype(forward_geometry.begin()) end) {
current < forward_geometry.begin() + data.fwd_segment_position; EdgeDistance dist = 0;
++current) for (; begin != end; ++begin)
{ {
forward_distance_offset += util::coordinate_calculation::fccApproximateDistance( dist += util::coordinate_calculation::fccApproximateDistance(
datafacade.GetCoordinateOfNode(*current), datafacade.GetCoordinateOfNode(*begin),
datafacade.GetCoordinateOfNode(*std::next(current))); datafacade.GetCoordinateOfNode(*std::next(begin)));
} }
return dist;
};
EdgeDistance forward_distance_offset = appx_distance(
forward_geometry.begin(), forward_geometry.begin() + data.fwd_segment_position);
BOOST_ASSERT(data.fwd_segment_position < BOOST_ASSERT(data.fwd_segment_position <
std::distance(forward_durations.begin(), forward_durations.end())); std::distance(forward_durations.begin(), forward_durations.end()));
@@ -508,16 +544,9 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_durations.end() - data.fwd_segment_position - 1, reverse_durations.end() - data.fwd_segment_position - 1,
EdgeDuration{0}); EdgeDuration{0});
EdgeDistance reverse_distance_offset = 0; EdgeDistance reverse_distance_offset =
// Sum up the distance from just after the fwd_segment_position to the end appx_distance(forward_geometry.begin() + data.fwd_segment_position + 1,
for (auto current = forward_geometry.begin() + data.fwd_segment_position + 1; std::prev(forward_geometry.end()));
current != std::prev(forward_geometry.end());
++current)
{
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
datafacade.GetCoordinateOfNode(*current),
datafacade.GetCoordinateOfNode(*std::next(current)));
}
EdgeWeight reverse_weight = EdgeWeight reverse_weight =
reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1]; reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
@@ -527,16 +556,43 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
point_on_segment, point_on_segment,
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1))); datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1)));
// We may end up adding a stoppage penalty
double forward_speed = 0;
double reverse_speed = 0;
auto total_distance = 0;
auto penalty_range = max_stoppage_penalty - min_stoppage_penalty;
ratio = std::min(1.0, std::max(0.0, ratio)); ratio = std::min(1.0, std::max(0.0, ratio));
if (data.forward_segment_id.id != SPECIAL_SEGMENTID) if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
{ {
forward_weight = static_cast<EdgeWeight>(forward_weight * ratio); forward_weight = static_cast<EdgeWeight>(forward_weight * ratio);
forward_duration = static_cast<EdgeDuration>(forward_duration * ratio); forward_duration = static_cast<EdgeDuration>(forward_duration * ratio);
// Stoppage penalty based on speed
if (data.forward_segment_id.enabled && penalty_range > 0)
{
total_distance =
appx_distance(forward_geometry.begin(), std::prev(forward_geometry.end()));
const auto total_duration = std::accumulate(
forward_durations.begin(), forward_durations.end(), EdgeDuration{0});
forward_speed = total_distance / (total_duration * 0.1);
reverse_speed = forward_speed;
}
} }
if (data.reverse_segment_id.id != SPECIAL_SEGMENTID) if (data.reverse_segment_id.id != SPECIAL_SEGMENTID)
{ {
reverse_weight -= static_cast<EdgeWeight>(reverse_weight * ratio); reverse_weight -= static_cast<EdgeWeight>(reverse_weight * ratio);
reverse_duration -= static_cast<EdgeDuration>(reverse_duration * ratio); reverse_duration -= static_cast<EdgeDuration>(reverse_duration * ratio);
// Stoppage penalty based on speed
if (data.reverse_segment_id.enabled && penalty_range > 0)
{
if (total_distance == 0)
total_distance =
appx_distance(forward_geometry.begin(), std::prev(forward_geometry.end()));
const auto total_duration = std::accumulate(
reverse_durations.begin(), reverse_durations.end(), EdgeDuration{0});
reverse_speed = total_distance / (total_duration * 0.1);
if (forward_speed == 0)
forward_speed = reverse_speed;
}
} }
// check phantom node segments validity // check phantom node segments validity
@@ -567,6 +623,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
reverse_duration, reverse_duration,
forward_duration_offset, forward_duration_offset,
reverse_duration_offset, reverse_duration_offset,
static_cast<float>((forward_speed + reverse_speed) / 2.0),
is_forward_valid_source, is_forward_valid_source,
is_forward_valid_target, is_forward_valid_target,
is_reverse_valid_source, is_reverse_valid_source,
@@ -717,7 +774,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const CoordinateList &coordinates; const CoordinateList &coordinates;
DataFacadeT &datafacade; DataFacadeT &datafacade;
}; };
} } // namespace engine
} } // namespace osrm
#endif #endif
+5 -2
View File
@@ -122,7 +122,7 @@ std::array<std::uint32_t, SegmentNumber> summarizeRoute(const datafacade::BaseDa
[](const NamedSegment &segment) { return segment.name_id; }); [](const NamedSegment &segment) { return segment.name_id; });
return summary; return summary;
} }
} } // namespace detail
inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade, inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
const std::vector<PathData> &route_data, const std::vector<PathData> &route_data,
@@ -166,7 +166,7 @@ inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
// `forward_duration`: duration of (d,t) // `forward_duration`: duration of (d,t)
// `forward_offset`: duration of (c, d) // `forward_offset`: duration of (c, d)
// path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only // path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only
// caputed by the phantom node. So we need to add the target duration here. // captured by the phantom node. So we need to add the target duration here.
// On local segments, the target duration is already part of the duration, however. // On local segments, the target duration is already part of the duration, however.
duration = duration + target_duration; duration = duration + target_duration;
@@ -182,6 +182,9 @@ inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
duration = std::max(0, duration); duration = std::max(0, duration);
} }
// TODO: Add start and stop penalties to the duration to simulate accel/deceleration
//
std::string summary; std::string summary;
if (needs_summary) if (needs_summary)
{ {
+4 -4
View File
@@ -63,11 +63,11 @@ struct Hint
friend std::ostream &operator<<(std::ostream &, const Hint &); friend std::ostream &operator<<(std::ostream &, const Hint &);
}; };
static_assert(sizeof(Hint) == 80 + 4, "Hint is bigger than expected"); static_assert(sizeof(Hint) == sizeof(PhantomNode) + 4, "Hint is bigger than expected");
constexpr std::size_t ENCODED_HINT_SIZE = 112; constexpr std::size_t ENCODED_HINT_SIZE = 120;
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint), static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
"ENCODED_HINT_SIZE does not match size of Hint"); "ENCODED_HINT_SIZE does not match size of Hint");
} } // namespace engine
} } // namespace osrm
#endif #endif
+28 -22
View File
@@ -44,14 +44,15 @@ namespace engine
struct PhantomNode struct PhantomNode
{ {
PhantomNode() PhantomNode()
: forward_segment_id{SPECIAL_SEGMENTID, false}, : forward_segment_id{SPECIAL_SEGMENTID, false}, reverse_segment_id{SPECIAL_SEGMENTID,
reverse_segment_id{SPECIAL_SEGMENTID, false}, forward_weight(INVALID_EDGE_WEIGHT), false},
reverse_weight(INVALID_EDGE_WEIGHT), forward_weight_offset(0), reverse_weight_offset(0), forward_weight(INVALID_EDGE_WEIGHT), reverse_weight(INVALID_EDGE_WEIGHT),
forward_weight_offset(0), reverse_weight_offset(0),
forward_distance(INVALID_EDGE_DISTANCE), reverse_distance(INVALID_EDGE_DISTANCE), forward_distance(INVALID_EDGE_DISTANCE), reverse_distance(INVALID_EDGE_DISTANCE),
forward_distance_offset(0), reverse_distance_offset(0), forward_distance_offset(0), reverse_distance_offset(0),
forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION), forward_duration(MAXIMAL_EDGE_DURATION), reverse_duration(MAXIMAL_EDGE_DURATION),
forward_duration_offset(0), reverse_duration_offset(0), fwd_segment_position(0), forward_duration_offset(0), reverse_duration_offset(0), speed_approximation(0),
is_valid_forward_source{false}, is_valid_forward_target{false}, fwd_segment_position(0), is_valid_forward_source{false}, is_valid_forward_target{false},
is_valid_reverse_source{false}, is_valid_reverse_target{false}, bearing(0) is_valid_reverse_source{false}, is_valid_reverse_target{false}, bearing(0)
{ {
@@ -69,13 +70,13 @@ struct PhantomNode
return reverse_weight_offset + reverse_weight; return reverse_weight_offset + reverse_weight;
} }
EdgeWeight GetForwardDuration() const EdgeDuration GetForwardDuration() const
{ {
BOOST_ASSERT(forward_segment_id.enabled); BOOST_ASSERT(forward_segment_id.enabled);
return forward_duration + forward_duration_offset; return forward_duration + forward_duration_offset;
} }
EdgeWeight GetReverseDuration() const EdgeDuration GetReverseDuration() const
{ {
BOOST_ASSERT(reverse_segment_id.enabled); BOOST_ASSERT(reverse_segment_id.enabled);
return reverse_duration + reverse_duration_offset; return reverse_duration + reverse_duration_offset;
@@ -109,8 +110,9 @@ struct PhantomNode
bool IsValid(const unsigned number_of_nodes) const bool IsValid(const unsigned number_of_nodes) const
{ {
return location.IsValid() && ((forward_segment_id.id < number_of_nodes) || return location.IsValid() &&
(reverse_segment_id.id < number_of_nodes)) && ((forward_segment_id.id < number_of_nodes) ||
(reverse_segment_id.id < number_of_nodes)) &&
((forward_weight != INVALID_EDGE_WEIGHT) || ((forward_weight != INVALID_EDGE_WEIGHT) ||
(reverse_weight != INVALID_EDGE_WEIGHT)) && (reverse_weight != INVALID_EDGE_WEIGHT)) &&
((forward_duration != MAXIMAL_EDGE_DURATION) || ((forward_duration != MAXIMAL_EDGE_DURATION) ||
@@ -163,10 +165,11 @@ struct PhantomNode
EdgeDistance reverse_distance, EdgeDistance reverse_distance,
EdgeDistance forward_distance_offset, EdgeDistance forward_distance_offset,
EdgeDistance reverse_distance_offset, EdgeDistance reverse_distance_offset,
EdgeWeight forward_duration, EdgeDuration forward_duration,
EdgeWeight reverse_duration, EdgeDuration reverse_duration,
EdgeWeight forward_duration_offset, EdgeDuration forward_duration_offset,
EdgeWeight reverse_duration_offset, EdgeDuration reverse_duration_offset,
EdgeDistance speed_approximation,
bool is_valid_forward_source, bool is_valid_forward_source,
bool is_valid_forward_target, bool is_valid_forward_target,
bool is_valid_reverse_source, bool is_valid_reverse_source,
@@ -182,8 +185,9 @@ struct PhantomNode
reverse_distance_offset{reverse_distance_offset}, forward_duration{forward_duration}, reverse_distance_offset{reverse_distance_offset}, forward_duration{forward_duration},
reverse_duration{reverse_duration}, forward_duration_offset{forward_duration_offset}, reverse_duration{reverse_duration}, forward_duration_offset{forward_duration_offset},
reverse_duration_offset{reverse_duration_offset}, reverse_duration_offset{reverse_duration_offset},
component{component.id, component.is_tiny}, location{location}, speed_approximation{speed_approximation}, component{component.id, component.is_tiny},
input_location{input_location}, fwd_segment_position{other.fwd_segment_position}, location{location}, input_location{input_location},
fwd_segment_position{other.fwd_segment_position},
is_valid_forward_source{is_valid_forward_source}, is_valid_forward_source{is_valid_forward_source},
is_valid_forward_target{is_valid_forward_target}, is_valid_forward_target{is_valid_forward_target},
is_valid_reverse_source{is_valid_reverse_source}, is_valid_reverse_source{is_valid_reverse_source},
@@ -201,10 +205,12 @@ struct PhantomNode
EdgeDistance reverse_distance; EdgeDistance reverse_distance;
EdgeDistance forward_distance_offset; // TODO: try to remove -> requires path unpacking changes EdgeDistance forward_distance_offset; // TODO: try to remove -> requires path unpacking changes
EdgeDistance reverse_distance_offset; // TODO: try to remove -> requires path unpacking changes EdgeDistance reverse_distance_offset; // TODO: try to remove -> requires path unpacking changes
EdgeWeight forward_duration; EdgeDuration forward_duration;
EdgeWeight reverse_duration; EdgeDuration reverse_duration;
EdgeWeight forward_duration_offset; // TODO: try to remove -> requires path unpacking changes EdgeDuration forward_duration_offset; // TODO: try to remove -> requires path unpacking changes
EdgeWeight reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes EdgeDuration reverse_duration_offset; // TODO: try to remove -> requires path unpacking changes
EdgeDistance speed_approximation; // m/s
ComponentID component; ComponentID component;
util::Coordinate location; // this is the coordinate of x util::Coordinate location; // this is the coordinate of x
@@ -219,7 +225,7 @@ struct PhantomNode
unsigned short bearing : 12; unsigned short bearing : 12;
}; };
static_assert(sizeof(PhantomNode) == 80, "PhantomNode has more padding then expected"); static_assert(sizeof(PhantomNode) == 84, "PhantomNode has more padding then expected");
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>; using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
@@ -234,7 +240,7 @@ struct PhantomNodes
PhantomNode source_phantom; PhantomNode source_phantom;
PhantomNode target_phantom; PhantomNode target_phantom;
}; };
} } // namespace engine
} } // namespace osrm
#endif // PHANTOM_NODES_H #endif // PHANTOM_NODES_H
+14 -4
View File
@@ -298,7 +298,9 @@ class BasePlugin
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach, approach,
use_all_edges); use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
} }
else else
{ {
@@ -308,7 +310,9 @@ class BasePlugin
parameters.bearings[i]->bearing, parameters.bearings[i]->bearing,
parameters.bearings[i]->range, parameters.bearings[i]->range,
approach, approach,
use_all_edges); use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
} }
} }
else else
@@ -320,13 +324,19 @@ class BasePlugin
parameters.coordinates[i], parameters.coordinates[i],
*parameters.radiuses[i], *parameters.radiuses[i],
approach, approach,
use_all_edges); use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
} }
else else
{ {
phantom_node_pairs[i] = phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent( facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], approach, use_all_edges); parameters.coordinates[i],
approach,
use_all_edges,
parameters.min_stoppage_penalty,
parameters.max_stoppage_penalty);
} }
} }
+81
View File
@@ -0,0 +1,81 @@
#include "util/typedefs.h"
namespace osrm
{
namespace extractor
{
namespace
{
constexpr int 5_MINUTE_BUCKETS_PER_WEEK = 2016;
constexpr int 1_HOUR_BUCKETS_PER_WEEK = 168;
} // namespace
/**
* Represents a simple piecewise linear function
* (https://en.wikipedia.org/wiki/Piecewise_linear_function)
* in the form of a regularly spaced set of buckets.
* Assumes that the spacing between buckets is equal.
*/
template <typename DataType, int BUCKETCOUNT> struct PiecewiseLinearFunction
{
std::array<DataType, BUCKETCOUNT> sample;
inline DataType getAt(float position)
{
// Range check
assert(position >= 0);
assert(position < BUCKETCOUNT - 1);
}
PiecewiseLinearFunction<DataType, BUCKETCOUNT>
merge(PiecewiseLinearFunction<DataType, BUCKETCOUNT> &other, float offset)
{
PiecewiseLinearFunction result;
for (int i = 0; i < BUCKETCOUNT; i++)
{
for (int j = offset; j < BUCKETCOUNT + offset; j++)
{
result.sample[i] = sample[i] + other.sample[j % BUCKETCOUNT];
}
}
return std::move(result);
}
}
/**
* Represents variances in the default `.duration` of an edge
* over the space of a week.
*/
struct WeeklySpeedProfile
{
using Multiplier = std::uint8_t;
private:
PiecewiseLinearFunction<Multiplier, 1_HOUR_BUCKETS_PER_WEEK> fn;
public:
SpeedProfile() : min(0), max(0) { multipliers.fill(0); }
SpeedProfile(const std::array<Multiplier, BUCKETS> &other)
{
fn.samples = other;
min = std::min(samples);
max = std::max(samples);
}
inline EdgeDuration adjust(const EdgeDuration &original, const int bucket) const
{
// Treat Multiplier as an 8-bit fixed-point value.
EdgeDuration new_value = (original * multipliers[bucket]);
}
inline EdgeDuration min(const EdgeDuration original) const {}
inline EdgeDuration max(const EdgeDuration original) const {}
duration = m * e1 + m2 * e2
};
} // namespace extractor
} // namespace osrm
+45
View File
@@ -721,6 +721,51 @@ inline bool argumentsToParameter(const Nan::FunctionCallbackInfo<v8::Value> &arg
} }
} }
if (obj->Has(Nan::New("stoppage_penalty").ToLocalChecked()))
{
v8::Local<v8::Value> stoppage_penalty =
obj->Get(Nan::New("stoppage_penalty").ToLocalChecked());
if (stoppage_penalty.IsEmpty())
return false;
if (!stoppage_penalty->IsArray())
{
Nan::ThrowError("Stoppage penalty must be an array of 2 numbers [min,max]");
return false;
}
auto stoppage_penalty_array = v8::Local<v8::Array>::Cast(stoppage_penalty);
if (stoppage_penalty_array->Length() != 2)
{
Nan::ThrowError("Stoppage penalty must be an array of 2 numbers [min,max]");
return false;
}
if (!stoppage_penalty_array->Get(0)->IsNumber() ||
!stoppage_penalty_array->Get(1)->IsNumber())
{
Nan::ThrowError("Stoppage penalty must be an array of 2 numbers [min,max]");
return false;
}
const auto min = static_cast<short>(stoppage_penalty_array->Get(0)->NumberValue());
const auto max = static_cast<short>(stoppage_penalty_array->Get(1)->NumberValue());
if (min < 0 || max < 0)
{
Nan::ThrowError("Stoppage penalty min/max can't be less than zero");
return false;
}
if (max < min)
{
Nan::ThrowError("Stoppage penalty max must be larger than min");
return false;
}
params->max_stoppage_penalty = max;
params->min_stoppage_penalty = min;
}
return true; return true;
} }
+17 -5
View File
@@ -25,7 +25,7 @@ namespace
{ {
namespace ph = boost::phoenix; namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi; namespace qi = boost::spirit::qi;
} } // namespace
template <typename T, char... Fmt> struct no_trailing_dot_policy : qi::real_policies<T> template <typename T, char... Fmt> struct no_trailing_dot_policy : qi::real_policies<T>
{ {
@@ -135,6 +135,16 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
}, },
qi::_1)]; qi::_1)];
stoppage_rule = qi::lit("stoppage_penalty=") >
(qi::double_ > ',' > qi::double_)[ph::bind(
[](engine::api::BaseParameters &params, double min, double max) {
params.min_stoppage_penalty = min;
params.max_stoppage_penalty = max;
},
qi::_r1,
qi::_1,
qi::_2)];
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 +189,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) //
| stoppage_rule(qi::_r1); //
} }
protected: protected:
@@ -196,6 +207,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> stoppage_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;
@@ -210,8 +222,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
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;
}; };
} } // namespace api
} } // namespace server
} } // namespace osrm
#endif #endif
@@ -18,7 +18,7 @@ namespace
{ {
namespace ph = boost::phoenix; namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi; namespace qi = boost::spirit::qi;
} } // namespace
template <typename Iterator = std::string::iterator, template <typename Iterator = std::string::iterator,
typename Signature = void(engine::api::TableParameters &)> typename Signature = void(engine::api::TableParameters &)>
@@ -106,8 +106,8 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
fallback_coordinate_type; fallback_coordinate_type;
qi::real_parser<double, json_policy> double_; qi::real_parser<double, json_policy> double_;
}; };
} } // namespace api
} } // namespace server
} } // namespace osrm
#endif #endif
+2 -2
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)
{ {
+5 -2
View File
@@ -48,7 +48,7 @@ struct osm_way_id
struct duplicated_node struct duplicated_node
{ {
}; };
} } // namespace tag
using OSMNodeID = osrm::Alias<std::uint64_t, tag::osm_node_id>; using OSMNodeID = osrm::Alias<std::uint64_t, tag::osm_node_id>;
static_assert(std::is_pod<OSMNodeID>(), "OSMNodeID is not a valid alias"); static_assert(std::is_pod<OSMNodeID>(), "OSMNodeID is not a valid alias");
using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>; using OSMWayID = osrm::Alias<std::uint64_t, tag::osm_way_id>;
@@ -116,7 +116,10 @@ static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDurati
static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max(); static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max(); static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max();
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<EdgeDistance>::max();
constexpr EdgeDuration INVALID_MINIMUM_STOPPAGE_PENALTY = std::numeric_limits<EdgeDuration>::max();
constexpr EdgeDuration INVALID_MAXIMUM_STOPPAGE_PENALTY = std::numeric_limits<EdgeDuration>::max();
constexpr float MAXIMAL_ACCEL_DECEL_PENALIZABLE_SPEED_INVERSE = 40.f; // seconds/metre
// 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
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "osrm", "name": "osrm",
"version": "5.21.0-customsnapping.2", "version": "5.21.0-customsnapping.6",
"private": false, "private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.", "description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": { "dependencies": {
+85 -5
View File
@@ -86,8 +86,10 @@ 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;
constexpr bool always_calculate_distance = true;
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, always_calculate_distance);
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 +99,61 @@ 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 &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
}
};
// 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.min_stoppage_penalty != INVALID_MINIMUM_STOPPAGE_PENALTY &&
params.max_stoppage_penalty != INVALID_MAXIMUM_STOPPAGE_PENALTY))
{ {
for (std::size_t row = 0; row < num_sources; row++) for (std::size_t row = 0; row < num_sources; row++)
{ {
@@ -106,6 +161,22 @@ 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)
{
/*
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]);
}
// 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 +203,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,11 +225,19 @@ 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);
return Status::Ok; return Status::Ok;
} }
} } // namespace plugins
} } // namespace engine
} } // namespace osrm
+28
View File
@@ -318,5 +318,33 @@ 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 stoppage_penalty values', function(assert) {
assert.plan(6);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
annotations: [annotation.slice(0,-1)],
stoppage_penalty: [],
};
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on empty array");
options.stoppage_penalty = ['a',1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on non-numeric value");
options.stoppage_penalty = [1,2,3];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on too many values");
options.stoppage_penalty = [1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty must be an array of 2 numbers/, "should throw on not enough values");
options.stoppage_penalty = [2,1];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty max must be larger than min/, "should throw on max < min");
options.stoppage_penalty = [-1,2];
assert.throws(()=>osrm.table(options, (err, res) => {}), /Stoppage penalty min\/max can't be less than zero/, "should throw on negative value");
});
}); });
+30 -22
View File
@@ -282,40 +282,48 @@ class ContiguousInternalMemoryDataFacade<routing_algorithms::offline::Algorithm>
return {}; return {};
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, const util::Coordinate /*input_coordinate*/,
const Approach /*approach*/, const Approach /*approach*/,
const bool /* use_all_edges */) const override const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/, const double /*max_distance*/,
const Approach /*approach*/, const Approach /*approach*/,
const bool /* use_all_edges */) const override const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, const util::Coordinate /*input_coordinate*/,
const double /*max_distance*/, const double /*max_distance*/,
const int /*bearing*/, const int /*bearing*/,
const int /*bearing_range*/, const int /*bearing_range*/,
const Approach /*approach*/, const Approach /*approach*/,
const bool /* use_all_edges */) const override const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
std::pair<PhantomNode, PhantomNode> std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, const util::Coordinate /*input_coordinate*/,
const int /*bearing*/, const int /*bearing*/,
const int /*bearing_range*/, const int /*bearing_range*/,
const Approach /*approach*/, const Approach /*approach*/,
const bool /* use_all_edges */) const override const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
+30 -18
View File
@@ -167,39 +167,51 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
} }
std::pair<engine::PhantomNode, engine::PhantomNode> std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, NearestPhantomNodeWithAlternativeFromBigComponent(
const engine::Approach /*approach*/, const util::Coordinate /*input_coordinate*/,
const bool /* use_all_edges */) const override const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
std::pair<engine::PhantomNode, engine::PhantomNode> std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, NearestPhantomNodeWithAlternativeFromBigComponent(
const double /*max_distance*/, const util::Coordinate /*input_coordinate*/,
const engine::Approach /*approach*/, const double /*max_distance*/,
const bool /* use_all_edges */) const override const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
std::pair<engine::PhantomNode, engine::PhantomNode> std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, NearestPhantomNodeWithAlternativeFromBigComponent(
const double /*max_distance*/, const util::Coordinate /*input_coordinate*/,
const int /*bearing*/, const double /*max_distance*/,
const int /*bearing_range*/, const int /*bearing*/,
const engine::Approach /*approach*/, const int /*bearing_range*/,
const bool /* use_all_edges */) const override const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }
std::pair<engine::PhantomNode, engine::PhantomNode> std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate /*input_coordinate*/, NearestPhantomNodeWithAlternativeFromBigComponent(
const int /*bearing*/, const util::Coordinate /*input_coordinate*/,
const int /*bearing_range*/, const int /*bearing*/,
const engine::Approach /*approach*/, const int /*bearing_range*/,
const bool /* use_all_edges */) const override const engine::Approach /*approach*/,
const bool /* use_all_edges */,
const double /* min_stoppage_penalty */,
const double /* max_stoppage_penalty */) const override
{ {
return {}; return {};
} }