Include datasources for each segment in route annotation.

This commit is contained in:
Daniel Patterson 2016-07-20 14:59:16 +02:00
parent fb4834458e
commit 280b000f07
11 changed files with 71 additions and 20 deletions

View File

@ -414,11 +414,23 @@ With `steps=false` and `annotations=true`:
"annotation": {
"distance": [5,5,10,5,5],
"duration": [15,15,40,15,15],
"datasources": [1,0,0,0,1],
"nodes": [49772551,49772552,49786799,49786800,49786801,49786802]
}
}
```
#### Annotation data
Several fields are available as annotations. They are:
| field | description |
|-------------|---------------------------------------------------------------------------------------------------------|
| distance | the distance, in metres, between each pair of coordinates |
| duration | the duration between each pair of coordinates, in seconds |
| datasources | the index of the datasource for the speed between each pair of coordinates. `0` is the default profile, other values are supplied via `--segment-speed-file` to `osrm-contract` |
| nodes | the OSM node ID for each coordinate along the route, excluding the first/last user-supplied coordinates |
### RouteStep
A step consists of a maneuver such as a turn or merge, followed

View File

@ -152,15 +152,15 @@ module.exports = function () {
};
this.annotationList = (instructions) => {
function zip(list_1, list_2)
function zip(list_1, list_2, list_3)
{
let pairs = [];
let tuples = [];
for (let i = 0; i < list_1.length; ++i) {
pairs.push([list_1[i], list_2[i]]);
tuples.push([list_1[i], list_2[i], list_3[i]]);
}
return pairs;
return tuples;
}
return instructions.legs.map(l => {return zip(l.annotation.duration, l.annotation.distance).map(p => { return p.join(':'); }).join(','); }).join(',');
return instructions.legs.map(l => {return zip(l.annotation.duration, l.annotation.distance, l.annotation.datasources).map(p => { return p.join(':'); }).join(','); }).join(',');
};
this.OSMIDList = (instructions) => {

View File

@ -4,6 +4,7 @@ Feature: Basic Map Matching
Background:
Given the profile "testbot"
Given a grid size of 10 meters
Given the extract extra arguments "--generate-edge-lookup"
Scenario: Testbot - Map matching with outlier that has no candidate
Given a grid size of 100 meters
@ -118,10 +119,17 @@ Feature: Basic Map Matching
| abcdegh | no |
| ci | no |
And the speed file
"""
1,2,36
"""
And the contract extra arguments "--segment-speed-file speeds.csv"
When I match I should get
| trace | matchings | annotation |
| abeh | abcedgh | 1:9.897633,0:0,1:10.008842,1:10.008842,1:10.008842,0:0,2:20.017685,1:10.008842 |
| abci | abc,ci | 1:9.897633,0:0,1:10.008842,0:0.111209,1:10.010367 |
| trace | matchings | annotation |
| abeh | abcedgh | 1:9.897633:1,0:0:0,1:10.008842:0,1:10.008842:0,1:10.008842:0,0:0:0,2:20.017685:0,1:10.008842:0 |
| abci | abc,ci | 1:9.897633:1,0:0:0,1:10.008842:0,0:0.111209:0,1:10.010367:0 |
# The following is the same as the above, but separated for readability (line length)
When I match I should get

View File

@ -207,18 +207,21 @@ class RouteAPI : public BaseAPI
util::json::Array durations;
util::json::Array distances;
util::json::Array nodes;
util::json::Array datasources;
auto &leg_geometry = leg_geometries[idx];
durations.values.reserve(leg_geometry.annotations.size());
distances.values.reserve(leg_geometry.annotations.size());
nodes.values.reserve(leg_geometry.osm_node_ids.size());
datasources.values.reserve(leg_geometry.annotations.size());
std::for_each(
leg_geometry.annotations.begin(),
leg_geometry.annotations.end(),
[this, &durations, &distances](const guidance::LegGeometry::Annotation &step) {
[this, &durations, &distances, &datasources](const guidance::LegGeometry::Annotation &step) {
durations.values.push_back(step.duration);
distances.values.push_back(step.distance);
datasources.values.push_back(step.datasource);
});
std::for_each(leg_geometry.osm_node_ids.begin(),
leg_geometry.osm_node_ids.end(),
@ -229,6 +232,7 @@ class RouteAPI : public BaseAPI
annotation.values["distance"] = std::move(distances);
annotation.values["duration"] = std::move(durations);
annotation.values["nodes"] = std::move(nodes);
annotation.values["datasources"] = std::move(datasources);
annotations.push_back(std::move(annotation));
}
}

View File

@ -50,6 +50,10 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(
reverse_geometry[reverse_geometry.size() - source_node.fwd_segment_position - 1]));
std::vector<uint8_t> forward_datasource_vector;
facade.GetUncompressedDatasources(source_node.forward_packed_geometry_id, forward_datasource_vector);
auto cumulative_distance = 0.;
auto current_distance = 0.;
auto prev_coordinate = geometry.locations.front();
@ -70,7 +74,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
prev_coordinate = coordinate;
geometry.annotations.emplace_back(
LegGeometry::Annotation{current_distance, path_point.duration_until_turn / 10.});
LegGeometry::Annotation{current_distance, path_point.duration_until_turn / 10., path_point.datasource_id});
geometry.locations.push_back(std::move(coordinate));
geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(path_point.turn_via_node));
}
@ -79,8 +83,12 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
cumulative_distance += current_distance;
// segment leading to the target node
geometry.segment_distances.push_back(cumulative_distance);
std::vector<DatasourceID> forward_datasources;
facade.GetUncompressedDatasources(target_node.forward_packed_geometry_id, forward_datasources);
geometry.annotations.emplace_back(
LegGeometry::Annotation{current_distance, target_node.forward_weight / 10.});
LegGeometry::Annotation{current_distance, target_node.forward_weight / 10., forward_datasources[target_node.fwd_segment_position]});
geometry.segment_offsets.push_back(geometry.locations.size());
geometry.locations.push_back(target_node.location);
@ -91,6 +99,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
geometry.osm_node_ids.push_back(
facade.GetOSMNodeIDOfNode(forward_geometry[target_node.fwd_segment_position]));
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
BOOST_ASSERT(geometry.annotations.size() == geometry.locations.size() - 1);

View File

@ -39,6 +39,7 @@ struct LegGeometry
{
double distance;
double duration;
DatasourceID datasource;
};
std::vector<Annotation> annotations;

View File

@ -33,6 +33,9 @@ struct PathData
extractor::TravelMode travel_mode : 4;
// entry class of the turn, indicating possibility of turns
EntryClassID entry_classid;
// Source of the speed value on this road segment
DatasourceID datasource_id;
};
struct InternalRouteResult

View File

@ -294,16 +294,18 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
? phantom_node_pair.source_phantom.backward_travel_mode
: facade->GetTravelModeForEdgeID(ed.id);
const auto geometry_index = facade->GetGeometryIndexForEdgeID(ed.id);
std::vector<NodeID> id_vector;
facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
id_vector);
facade->GetUncompressedGeometry(geometry_index, id_vector);
BOOST_ASSERT(id_vector.size() > 0);
std::vector<EdgeWeight> weight_vector;
facade->GetUncompressedWeights(facade->GetGeometryIndexForEdgeID(ed.id),
weight_vector);
facade->GetUncompressedWeights(geometry_index, weight_vector);
BOOST_ASSERT(weight_vector.size() > 0);
std::vector<DatasourceID> datasource_vector;
facade->GetUncompressedDatasources(geometry_index, datasource_vector);
auto total_weight = std::accumulate(weight_vector.begin(), weight_vector.end(), 0);
BOOST_ASSERT(weight_vector.size() == id_vector.size());
@ -329,7 +331,8 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
extractor::guidance::TurnInstruction::NO_TURN(),
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
travel_mode,
INVALID_ENTRY_CLASSID});
INVALID_ENTRY_CLASSID,
datasource_vector[i]});
}
BOOST_ASSERT(unpacked_path.size() > 0);
if (facade->hasLaneData(ed.id))
@ -343,6 +346,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
std::size_t start_index = 0, end_index = 0;
std::vector<unsigned> id_vector;
std::vector<EdgeWeight> weight_vector;
std::vector<DatasourceID> datasource_vector;
const bool is_local_path = (phantom_node_pair.source_phantom.forward_packed_geometry_id ==
phantom_node_pair.target_phantom.forward_packed_geometry_id) &&
unpacked_path.empty();
@ -355,6 +359,9 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
facade->GetUncompressedWeights(
phantom_node_pair.target_phantom.reverse_packed_geometry_id, weight_vector);
facade->GetUncompressedDatasources(
phantom_node_pair.target_phantom.reverse_packed_geometry_id, datasource_vector);
if (is_local_path)
{
start_index =
@ -375,6 +382,9 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
facade->GetUncompressedWeights(
phantom_node_pair.target_phantom.forward_packed_geometry_id, weight_vector);
facade->GetUncompressedDatasources(
phantom_node_pair.target_phantom.forward_packed_geometry_id, datasource_vector);
}
// Given the following compressed geometry:
@ -396,7 +406,8 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode
: phantom_node_pair.target_phantom.forward_travel_mode,
INVALID_ENTRY_CLASSID});
INVALID_ENTRY_CLASSID,
datasource_vector[i]});
}
if (unpacked_path.size() > 0)

View File

@ -83,6 +83,8 @@ static const NameID EMPTY_NAMEID = 0;
static const unsigned INVALID_COMPONENTID = 0;
static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<EdgeWeight>::max();
using DatasourceID = std::uint8_t;
struct SegmentID
{
SegmentID(const NodeID id_, const bool enabled_) : id{id_}, enabled{enabled_}

View File

@ -335,7 +335,7 @@ Status TilePlugin::HandleRequest(const api::TileParameters &parameters, std::str
&used_weights](const detail::FixedLine &tile_line,
const std::uint32_t speed_kmh,
const std::size_t duration,
const std::uint8_t datasource,
const DatasourceID datasource,
const std::size_t name,
std::int32_t &start_x,
std::int32_t &start_y) {

View File

@ -293,11 +293,12 @@ int Storage::Run()
throw util::exception("Could not open " + config.datasource_indexes_path.string() +
" for reading.");
}
std::size_t number_of_compressed_datasources = 0;
std::uint64_t number_of_compressed_datasources = 0;
if (geometry_datasource_input_stream)
{
geometry_datasource_input_stream.read(
reinterpret_cast<char *>(&number_of_compressed_datasources), sizeof(std::size_t));
reinterpret_cast<char *>(&number_of_compressed_datasources),
sizeof(number_of_compressed_datasources));
}
shared_layout_ptr->SetBlockSize<uint8_t>(SharedDataLayout::DATASOURCES_LIST,
number_of_compressed_datasources);