diff --git a/docs/http.md b/docs/http.md index f3d033fbd..d6ae028cb 100644 --- a/docs/http.md +++ b/docs/http.md @@ -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 diff --git a/features/support/route.js b/features/support/route.js index a453ca484..56e5c9e1e 100644 --- a/features/support/route.js +++ b/features/support/route.js @@ -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) => { diff --git a/features/testbot/matching.feature b/features/testbot/matching.feature index 2de39f5ad..9c7faa01f 100644 --- a/features/testbot/matching.feature +++ b/features/testbot/matching.feature @@ -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 diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index 631bb5199..df7cb2ee2 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -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)); } } diff --git a/include/engine/guidance/assemble_geometry.hpp b/include/engine/guidance/assemble_geometry.hpp index 991a3e4a3..fe6e139d3 100644 --- a/include/engine/guidance/assemble_geometry.hpp +++ b/include/engine/guidance/assemble_geometry.hpp @@ -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 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 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); diff --git a/include/engine/guidance/leg_geometry.hpp b/include/engine/guidance/leg_geometry.hpp index 72b0e6570..3c6fb8189 100644 --- a/include/engine/guidance/leg_geometry.hpp +++ b/include/engine/guidance/leg_geometry.hpp @@ -39,6 +39,7 @@ struct LegGeometry { double distance; double duration; + DatasourceID datasource; }; std::vector annotations; diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index 6f1076975..b87b143ca 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -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 diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 4f77c0975..172acad1a 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -294,16 +294,18 @@ template class BasicRoutingInterface ? phantom_node_pair.source_phantom.backward_travel_mode : facade->GetTravelModeForEdgeID(ed.id); + const auto geometry_index = facade->GetGeometryIndexForEdgeID(ed.id); std::vector id_vector; - facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id), - id_vector); + facade->GetUncompressedGeometry(geometry_index, id_vector); BOOST_ASSERT(id_vector.size() > 0); std::vector weight_vector; - facade->GetUncompressedWeights(facade->GetGeometryIndexForEdgeID(ed.id), - weight_vector); + facade->GetUncompressedWeights(geometry_index, weight_vector); BOOST_ASSERT(weight_vector.size() > 0); + std::vector 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 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 BasicRoutingInterface std::size_t start_index = 0, end_index = 0; std::vector id_vector; std::vector weight_vector; + std::vector 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 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 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 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) diff --git a/include/util/typedefs.hpp b/include/util/typedefs.hpp index f4440c423..36797eea0 100644 --- a/include/util/typedefs.hpp +++ b/include/util/typedefs.hpp @@ -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::max(); +using DatasourceID = std::uint8_t; + struct SegmentID { SegmentID(const NodeID id_, const bool enabled_) : id{id_}, enabled{enabled_} diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp index 3877b0702..67ebc93d5 100644 --- a/src/engine/plugins/tile.cpp +++ b/src/engine/plugins/tile.cpp @@ -335,7 +335,7 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, 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) { diff --git a/src/storage/storage.cpp b/src/storage/storage.cpp index 3f27284aa..c89ee631d 100644 --- a/src/storage/storage.cpp +++ b/src/storage/storage.cpp @@ -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(&number_of_compressed_datasources), sizeof(std::size_t)); + reinterpret_cast(&number_of_compressed_datasources), + sizeof(number_of_compressed_datasources)); } shared_layout_ptr->SetBlockSize(SharedDataLayout::DATASOURCES_LIST, number_of_compressed_datasources);