Add source phantom weight to first segment when merging legs (#4949)
Fix annotation values for annotations on edges where phantom nodes are snapped.
This commit is contained in:
parent
b7af6eb2a4
commit
f7775f5e0b
@ -4,6 +4,7 @@
|
||||
- fix deduplication of route steps when waypoints are used [#4909](https://github.com/Project-OSRM/osrm-backend/issues/4909)
|
||||
- FIXED #4920: Use smaller range for U-turn angles in map-matching [#4920](https://github.com/Project-OSRM/osrm-backend/pull/4920)
|
||||
- FIXED: Remove the last short annotation segment in `trimShortSegments`
|
||||
- FIXED: Properly calculate annotations for speeds, durations and distances when waypoints are used with mapmatching [#4949](https://github.com/Project-OSRM/osrm-backend/pull/4949)
|
||||
- Profile:
|
||||
- CHANGED #4929: Handle oneways in get_forward_backward_by_key [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929)
|
||||
- Guidance:
|
||||
|
@ -718,3 +718,78 @@ Feature: Basic Map Matching
|
||||
| abe | 1,0.99973,1.00027,0.99973,1.00027,1 | depart,turn left,arrive | Ok |
|
||||
| ahd | 1,0.99973,1.00027,0.99973,1.00027,0.999461 | depart,turn right,arrive | Ok |
|
||||
| ahe | 1,0.99973,1.00027,0.99973,1.00027,1 | depart,turn left,arrive | Ok |
|
||||
|
||||
@match @testbot
|
||||
Scenario: Regression test - add source phantoms properly (one phantom on one edge)
|
||||
Given the profile "testbot"
|
||||
Given a grid size of 10 meters
|
||||
Given the node map
|
||||
"""
|
||||
a--1-b2-cd3--e
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bcd |
|
||||
| de |
|
||||
Given the query options
|
||||
| geometries | geojson |
|
||||
| overview | full |
|
||||
| steps | true |
|
||||
| waypoints | 0;2 |
|
||||
| annotations | duration,weight |
|
||||
| generate_hints | false |
|
||||
When I match I should get
|
||||
| trace | geometry | a:duration | a:weight | duration |
|
||||
| 123 | 1.000135,1,1.000225,1,1.00036,1,1.000405,1,1.00045,1 | 1:1.5:0.5:0.5 | 1:1.5:0.5:0.5 | 3.5 |
|
||||
| 321 | 1.00045,1,1.000405,1,1.00036,1,1.000225,1,1.000135,1 | 0.5:0.5:1.5:1 | 0.5:0.5:1.5:1 | 3.5 |
|
||||
|
||||
@match @testbot
|
||||
Scenario: Regression test - add source phantom properly (two phantoms on one edge)
|
||||
Given the profile "testbot"
|
||||
Given a grid size of 10 meters
|
||||
Given the node map
|
||||
"""
|
||||
a--1-b23-c4--d
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
| cd |
|
||||
Given the query options
|
||||
| geometries | geojson |
|
||||
| overview | full |
|
||||
| steps | true |
|
||||
| waypoints | 0;3 |
|
||||
| annotations | duration,weight |
|
||||
| generate_hints | false |
|
||||
When I match I should get
|
||||
| trace | geometry | a:duration | a:weight | duration |
|
||||
| 1234 | 1.000135,1,1.000225,1,1.000405,1,1.00045,1 | 1:2:0.5 | 1:2:0.5 | 3.5 |
|
||||
| 4321 | 1.00045,1,1.000405,1,1.000225,1,1.000135,1 | 0.5:2:1 | 0.5:2:1 | 3.5 |
|
||||
|
||||
@match @testbot
|
||||
Scenario: Regression test - add source phantom properly (two phantoms on one edge)
|
||||
Given the profile "testbot"
|
||||
Given a grid size of 10 meters
|
||||
Given the node map
|
||||
"""
|
||||
a--12345-b
|
||||
"""
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
Given the query options
|
||||
| geometries | geojson |
|
||||
| overview | full |
|
||||
| steps | true |
|
||||
| waypoints | 0;3 |
|
||||
| annotations | duration,weight,distance |
|
||||
| generate_hints | false |
|
||||
|
||||
# These should have the same weights/duration in either direction
|
||||
When I match I should get
|
||||
| trace | geometry | a:distance | a:duration | a:weight | duration |
|
||||
| 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
|
||||
| 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
|
@ -136,13 +136,13 @@ Feature: Traffic - speeds
|
||||
|
||||
When I route I should get
|
||||
| from | to | route | speed | weights | a:datasources | a:speed | a:nodes|
|
||||
| a | b | fb,fb | 36 km/h | 329.4,0 | 0 | 7 | 6:2 |
|
||||
| a | b | fb,fb | 36 km/h | 329.4,0 | 0 | 10 | 6:2 |
|
||||
| a | c | fb,bc,bc | 30 km/h | 329.4,741.5,0 | 0:1 | 10:7.5 | 6:2:3 |
|
||||
| b | c | bc,bc | 27 km/h | 741.5,0 | 1 | 7.5 | 2:3 |
|
||||
| a | d | fb,df,df | 36 km/h | 140,487.5,0 | 0:0 | 10:10 | 2:6:4 |
|
||||
| d | c | dc,dc | 36 km/h | 956.8,0 | 0 | 10 | 4:3 |
|
||||
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 | 3.5 | 6:2 |
|
||||
| a | g | fb,fb | 36 km/h | 164.7,0 | 0 | 5.4 | 6:2 |
|
||||
| g | b | fb,fb | 36 km/h | 164.7,0 | 0 | 10 | 6:2 |
|
||||
| a | g | fb,fb | 36 km/h | 164.7,0 | 0 | 10 | 6:2 |
|
||||
|
||||
|
||||
Scenario: Verify that negative values cause an error, they're not valid at all
|
||||
|
@ -53,8 +53,8 @@ Feature: Weight tests
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | distances | weights | times | a:distance | a:duration | a:weight | a:speed |
|
||||
| s,t | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 3 | 3 | 6.7 |
|
||||
| t,s | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 3.1 | 3.1 | 6.5 |
|
||||
| s,t | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 2.1 | 2.1 | 9.5 |
|
||||
| t,s | abc,abc | 20m,0m | 2.1,0 | 2.1s,0s | 20.017685 | 2.1 | 2.1 | 9.5 |
|
||||
| s,e | abc,abc | 40m,0m | 4.1,0 | 4.1s,0s | 30.026527:10.008842 | 3.1:1 | 3.1:1 | 9.7:10 |
|
||||
| e,s | abc,abc | 40m,0m | 4.1,0 | 4.1s,0s | 10.008842:30.026527 | 1:3.1 | 1:3.1 | 10:9.7 |
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -113,15 +114,39 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
const std::vector<DatasourceID> forward_datasources =
|
||||
facade.GetUncompressedForwardDatasources(target_geometry_id);
|
||||
|
||||
// FIXME if source and target phantoms are on the same segment then duration and weight
|
||||
// will be from one projected point till end of segment
|
||||
// testbot/weight.feature:Start and target on the same and adjacent edge
|
||||
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
||||
current_distance,
|
||||
(reversed_target ? target_node.reverse_duration : target_node.forward_duration) / 10.,
|
||||
(reversed_target ? target_node.reverse_weight : target_node.forward_weight) /
|
||||
facade.GetWeightMultiplier(),
|
||||
forward_datasources[target_node.fwd_segment_position]});
|
||||
// This happens when the source/target are on the same edge-based-node
|
||||
// There will be no entries in the unpacked path, thus no annotations.
|
||||
// We will need to calculate the lone annotation by looking at the position
|
||||
// of the source/target nodes, and calculating their differences.
|
||||
if (geometry.annotations.empty())
|
||||
{
|
||||
auto duration =
|
||||
std::abs(
|
||||
(reversed_target ? target_node.reverse_duration : target_node.forward_duration) -
|
||||
(reversed_source ? source_node.reverse_duration : source_node.forward_duration)) /
|
||||
10.;
|
||||
BOOST_ASSERT(duration >= 0);
|
||||
auto weight =
|
||||
std::abs((reversed_target ? target_node.reverse_weight : target_node.forward_weight) -
|
||||
(reversed_source ? source_node.reverse_weight : source_node.forward_weight)) /
|
||||
facade.GetWeightMultiplier();
|
||||
BOOST_ASSERT(weight >= 0);
|
||||
|
||||
geometry.annotations.emplace_back(
|
||||
LegGeometry::Annotation{current_distance,
|
||||
duration,
|
||||
weight,
|
||||
forward_datasources[target_node.fwd_segment_position]});
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
||||
current_distance,
|
||||
(reversed_target ? target_node.reverse_duration : target_node.forward_duration) / 10.,
|
||||
(reversed_target ? target_node.reverse_weight : target_node.forward_weight) /
|
||||
facade.GetWeightMultiplier(),
|
||||
forward_datasources[target_node.fwd_segment_position]});
|
||||
}
|
||||
|
||||
geometry.segment_offsets.push_back(geometry.locations.size());
|
||||
geometry.locations.push_back(target_node.location);
|
||||
|
@ -145,11 +145,32 @@ inline InternalRouteResult CollapseInternalRouteResult(const InternalRouteResult
|
||||
collapsed.target_traversed_in_reverse.back() =
|
||||
leggy_result.target_traversed_in_reverse[i];
|
||||
// copy path segments into current leg
|
||||
last_segment.insert(last_segment.end(),
|
||||
leggy_result.unpacked_path_segments[i].begin(),
|
||||
leggy_result.unpacked_path_segments[i].end());
|
||||
if (!leggy_result.unpacked_path_segments[i].empty())
|
||||
{
|
||||
auto old_size = last_segment.size();
|
||||
last_segment.insert(last_segment.end(),
|
||||
leggy_result.unpacked_path_segments[i].begin(),
|
||||
leggy_result.unpacked_path_segments[i].end());
|
||||
|
||||
// The first segment of the unpacked path is missing the weight of the
|
||||
// source phantom. We need to add those values back so that the total
|
||||
// edge weight is correct
|
||||
last_segment[old_size].weight_until_turn +=
|
||||
|
||||
leggy_result.source_traversed_in_reverse[i]
|
||||
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_weight
|
||||
: leggy_result.segment_end_coordinates[i].source_phantom.forward_weight;
|
||||
|
||||
last_segment[old_size].duration_until_turn +=
|
||||
leggy_result.source_traversed_in_reverse[i]
|
||||
? leggy_result.segment_end_coordinates[i].source_phantom.reverse_duration
|
||||
: leggy_result.segment_end_coordinates[i].source_phantom.forward_duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(collapsed.segment_end_coordinates.size() ==
|
||||
collapsed.unpacked_path_segments.size());
|
||||
return collapsed;
|
||||
}
|
||||
}
|
||||
|
@ -407,12 +407,20 @@ BOOST_AUTO_TEST_CASE(speed_annotation_matches_duration_and_distance)
|
||||
const auto &durations = annotation.values.at("duration").get<json::Array>().values;
|
||||
const auto &distances = annotation.values.at("distance").get<json::Array>().values;
|
||||
int length = speeds.size();
|
||||
|
||||
BOOST_CHECK_EQUAL(length, 1);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
auto speed = speeds[i].get<json::Number>().value;
|
||||
auto duration = durations[i].get<json::Number>().value;
|
||||
auto distance = distances[i].get<json::Number>().value;
|
||||
BOOST_CHECK_EQUAL(speed, std::round(distance / duration * 10.) / 10.);
|
||||
auto calc = std::round(distance / duration * 10.) / 10.;
|
||||
BOOST_CHECK_EQUAL(speed, std::isnan(calc) ? 0 : calc);
|
||||
|
||||
// Because we route from/to the same location, all annotations should be 0;
|
||||
BOOST_CHECK_EQUAL(speed, 0);
|
||||
BOOST_CHECK_EQUAL(distance, 0);
|
||||
BOOST_CHECK_EQUAL(duration, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user