Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions docs/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ In addition to the [general options](#general-options) the following options are
|------------|---------------------------------------------|-------------------------------------------------------------------------------|
|alternatives|`true`, `false` (default), or Number |Search for alternative routes. Passing a number `alternatives=n` searches for up to `n` alternative routes.\* |
|steps |`true`, `false` (default) |Returned route steps for each route leg |
|annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed` |Returns additional metadata for each coordinate along the route geometry. |
|annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed`, `way_ids` |Returns additional metadata for each coordinate along the route geometry. |
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|overview |`simplified` (default), `full`, `false`, `by_legs` |Add overview geometry either full, simplified according to highest zoom level it could be displayed on, not at all, or split by leg.|
|continue\_straight |`default` (default), `true`, `false` |Forces the route to keep going straight at waypoints constraining uturns there even if it would be faster. Default value depends on the profile. |
Expand Down Expand Up @@ -431,7 +431,7 @@ In addition to the [general options](#general-options) the following options are
|------------|------------------------------------------------|------------------------------------------------------------------------------------------|
|steps |`true`, `false` (default) |Returned route steps for each route |
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed` |Returns additional metadata for each coordinate along the route geometry. |
|annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed`, `way_ids` |Returns additional metadata for each coordinate along the route geometry. |
|overview |`simplified` (default), `full`, `false`, `by_legs` |Add overview geometry either full, simplified according to highest zoom level it could be displayed on, not at all, or split by leg.|
|timestamps |`{timestamp};{timestamp}[;{timestamp} ...]` |Timestamps for the input locations in seconds since UNIX epoch. Timestamps need to be monotonically increasing. |
|radiuses |`{radius};{radius}[;{radius} ...]` |Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy.|
Expand Down Expand Up @@ -487,7 +487,7 @@ In addition to the [general options](#general-options) the following options are
|source |`any` (default), `first` |Returned route starts at `any` or `first` coordinate |
|destination |`any` (default), `last` |Returned route ends at `any` or `last` coordinate |
|steps |`true`, `false` (default) |Returned route instructions for each trip |
|annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed` |Returns additional metadata for each coordinate along the route geometry. |
|annotations |`true`, `false` (default), `nodes`, `distance`, `duration`, `datasources`, `weight`, `speed`, `way_ids` |Returns additional metadata for each coordinate along the route geometry. |
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|overview |`simplified` (default), `full`, `false`, `by_legs` |Add overview geometry either full, simplified according to highest zoom level it could be displayed on, not at all, or split by leg.|

Expand Down Expand Up @@ -667,7 +667,7 @@ Represents a route between two waypoints.

| annotations | |
|--------------|-------------------------------------------------------------------------------|
| true | An `Annotation` object containing node ids, durations, distances, and weights. |
| true | An `Annotation` object containing the requested per-segment values, including node ids, way ids, durations, distances, and weights. |
| false | `undefined` |

#### Example
Expand All @@ -686,7 +686,8 @@ With `steps=false` and `annotations=true`:
"datasources": [1,0,0,0,1],
"metadata": { "datasource_names": ["traffic","lua profile","lua profile","lua profile","traffic"] },
"nodes": [49772551,49772552,49786799,49786800,49786801,49786802],
"speed": [0.3, 0.3, 0.3, 0.3, 0.3]
"speed": [0.3, 0.3, 0.3, 0.3, 0.3],
"way_ids": [111,111,222,222,333]
}
}
```
Expand All @@ -703,6 +704,7 @@ Annotation of the whole route leg with fine-grained information about each segme
- `nodes`: The OSM node ID for each coordinate along the route, excluding the first/last user-supplied coordinates
- `weight`: The weights between each pair of coordinates. Does not include any turn costs.
- `speed`: Convenience field, calculation of `distance / duration` rounded to one decimal place
- `way_ids`: The OSM way ID for each traversed segment along the route leg
- `metadata`: Metadata related to other annotations
- `datasource_names`: The names of the data sources used for the speed between each pair of coordinates. `lua profile` is the default profile, other values are the filenames supplied via `--segment-speed-file` to `osrm-contract` or `osrm-customize`

Expand All @@ -715,7 +717,8 @@ Annotation of the whole route leg with fine-grained information about each segme
"datasources": [1,0,0,0,1],
"metadata": { "datasource_names": ["traffic","lua profile","lua profile","lua profile","traffic"] },
"nodes": [49772551,49772552,49786799,49786800,49786801,49786802],
"weight": [15,15,40,15,15]
"weight": [15,15,40,15,15],
"way_ids": [111,111,222,222,333]
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/nodejs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Returns the fastest route between two or more coordinates while visiting the way
* `options.alternatives` **[Number][6]** Search for up to this many alternative routes.
*Please note that even if alternative routes are requested, a result cannot be guaranteed.* (optional, default `0`)
* `options.steps` **[Boolean][4]** Return route steps for each route leg. (optional, default `false`)
* `options.annotations` **([Array][5] | [Boolean][4])** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
* `options.annotations` **([Array][5] | [Boolean][4])** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed`, `way_ids` or boolean for enabling/disabling all. (optional, default `false`)
* `options.geometries` **[String][3]** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
* `options.overview` **[String][3]** Add overview geometry either `full`, `simplified` according to highest zoom level it could be displayed on, or not at all (`false`). If you want the overview for each leg, you can use `by_legs`. (optional, default `simplified`)
* `options.continue_straight` **[Boolean][4]?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile.
Expand Down Expand Up @@ -227,7 +227,7 @@ if they can not be matched successfully.
* `options.hints` **[Array][5]?** Hints for the coordinate snapping. Array of base64 encoded strings.
* `options.generate_hints` **[Boolean][4]** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`)
* `options.steps` **[Boolean][4]** Return route steps for each route. (optional, default `false`)
* `options.annotations` **([Array][5] | [Boolean][4])** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
* `options.annotations` **([Array][5] | [Boolean][4])** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed`, `way_ids` or boolean for enabling/disabling all. (optional, default `false`)
* `options.geometries` **[String][3]** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
* `options.overview` **[String][3]** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`)
* `options.timestamps` **[Array][5]<[Number][6]>?** Timestamp of the input location (integers, UNIX-like timestamp).
Expand Down Expand Up @@ -298,7 +298,7 @@ Right now, the following combinations are possible:
* `options.hints` **[Array][5]?** Hints for the coordinate snapping. Array of base64 encoded strings.
* `options.generate_hints` **[Boolean][4]** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`)
* `options.steps` **[Boolean][4]** Return route steps for each route. (optional, default `false`)
* `options.annotations` **([Array][5] | [Boolean][4])** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed` or boolean for enabling/disabling all. (optional, default `false`)
* `options.annotations` **([Array][5] | [Boolean][4])** An array with strings of `duration`, `nodes`, `distance`, `weight`, `datasources`, `speed`, `way_ids` or boolean for enabling/disabling all. (optional, default `false`)
* `options.geometries` **[String][3]** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`)
* `options.overview` **[String][3]** Add overview geometry either `full`, `simplified`, `false` or `by_legs`. (optional, default `simplified`)
* `options.roundtrip` **[Boolean][4]** Return route is a roundtrip. (optional, default `true`)
Expand Down
2 changes: 2 additions & 0 deletions features/step_definitions/matching.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ When(/^I match I should get$/, async function (table) {
'datasources',
'nodes',
'weight',
'speed',
'way_ids',
];
if (k.match(/^a:/)) {
const a_type = k.slice(2);
Expand Down
1 change: 1 addition & 0 deletions features/support/shared_steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export default class SharedSteps {
'nodes',
'weight',
'speed',
'way_ids',
];
const metadata_whitelist = ['datasource_names'];
if (k.match(/^a:/)) {
Expand Down
25 changes: 25 additions & 0 deletions features/testbot/way_ids.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@routing @testbot
Feature: Route annotations - way ids

Background:
Given the profile "testbot"
Given a grid size of 10 meters
Given the node map
"""
a--1-b--2-c--3-d
"""
And the ways
| nodes |
| ab |
| bc |
| cd |

Scenario: Route annotations expose traversed OSM way ids per segment
Given the query options
| steps | false |
| annotations | way_ids |

When I route I should get
| from | to | a:way_ids |
| 1 | 3 | 5:6:7 |
| 3 | 1 | 7:6:5 |
3 changes: 2 additions & 1 deletion include/engine/api/flatbuffers/route.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ table Annotation {
nodes: [uint];
weight: [uint];
speed: [float];
way_ids: [ulong];
metadata: Metadata;
}

Expand Down Expand Up @@ -109,4 +110,4 @@ table RouteObject {
polyline: string;
coordinates: [Position];
legs: [Leg];
}
}
18 changes: 18 additions & 0 deletions include/engine/api/route_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,15 @@ class RouteAPI : public BaseAPI
[](const guidance::LegGeometry::Annotation &anno)
{ return anno.datasource; });
}

flatbuffers::Offset<flatbuffers::Vector<uint64_t>> way_ids;
if (requested_annotations & RouteParameters::AnnotationsType::WayIds)
{
way_ids = GetAnnotations<uint64_t>(fb_result,
leg_geometry,
[](const guidance::LegGeometry::Annotation &anno)
{ return static_cast<std::uint64_t>(anno.way_id); });
}
std::vector<uint32_t> nodes;
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
{
Expand Down Expand Up @@ -557,6 +566,7 @@ class RouteAPI : public BaseAPI
annotation.add_weight(weight);
annotation.add_datasources(datasources);
annotation.add_nodes(nodes_vector);
annotation.add_way_ids(way_ids);
if (use_metadata)
{
annotation.add_metadata(metadata_buffer);
Expand Down Expand Up @@ -872,6 +882,14 @@ class RouteAPI : public BaseAPI
[](const guidance::LegGeometry::Annotation &anno)
{ return anno.datasource; }));
}
if (requested_annotations & RouteParameters::AnnotationsType::WayIds)
{
annotation.values.emplace(
"way_ids",
GetAnnotations(leg_geometry,
[](const guidance::LegGeometry::Annotation &anno)
{ return static_cast<std::uint64_t>(anno.way_id); }));
}
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
{
util::json::Array nodes;
Expand Down
3 changes: 2 additions & 1 deletion include/engine/api/route_parameters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ struct RouteParameters : public BaseParameters
Weight = 0x08,
Datasources = 0x10,
Speed = 0x20,
All = Duration | Nodes | Distance | Weight | Datasources | Speed
WayIds = 0x40,
All = Duration | Nodes | Distance | Weight | Datasources | Speed | WayIds
};

RouteParameters() = default;
Expand Down
15 changes: 15 additions & 0 deletions include/engine/datafacade/contiguous_internalmem_datafacade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
return m_osmnodeid_list[node_based_node_id];
}

OSMWayID GetOSMWayID(const NodeID edge_based_node_id) const override final
{
return edge_based_node_data.GetWayID(edge_based_node_id);
}

NodeForwardRange GetUncompressedForwardGeometry(const PackedGeometryID id) const override final
{
return segment_data.GetForwardGeometry(id);
Expand Down Expand Up @@ -337,6 +342,16 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
return segment_data.GetReverseDatasources(id);
}

WayIDForwardRange GetUncompressedForwardWayIDs(const PackedGeometryID id) const override final
{
return segment_data.GetForwardWayIDs(id);
}

WayIDReverseRange GetUncompressedReverseWayIDs(const PackedGeometryID id) const override final
{
return segment_data.GetReverseWayIDs(id);
}

TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID edge_based_edge_id) const override final
{
BOOST_ASSERT(m_turn_weight_penalties.size() > edge_based_edge_id);
Expand Down
9 changes: 9 additions & 0 deletions include/engine/datafacade/datafacade_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class BaseDataFacade
std::ranges::subrange<extractor::SegmentDataView::SegmentDatasourceVector::const_iterator>;
using DatasourceReverseRange = std::ranges::reverse_view<DatasourceForwardRange>;

using WayIDForwardRange =
std::ranges::subrange<extractor::SegmentDataView::SegmentWayIDVector::const_iterator>;
using WayIDReverseRange = std::ranges::reverse_view<WayIDForwardRange>;

BaseDataFacade() {}
virtual ~BaseDataFacade() {}

Expand All @@ -75,6 +79,8 @@ class BaseDataFacade

virtual OSMNodeID GetOSMNodeIDOfNode(const NodeID node_based_node_id) const = 0;

virtual OSMWayID GetOSMWayID(const NodeID edge_based_node_id) const = 0;
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the new pure-virtual BaseDataFacade::GetOSMWayID requires updating every BaseDataFacade implementation. In the current tree there is at least unit_tests/engine/offline_facade.cpp (ContiguousInternalMemoryDataFacadeoffline::Algorithm) that still derives from BaseDataFacade but does not implement GetOSMWayID, which will break compilation of unit tests. Either add the override there (and any other derived facades), or provide a non-pure default implementation if appropriate.

Suggested change
virtual OSMWayID GetOSMWayID(const NodeID edge_based_node_id) const = 0;
virtual OSMWayID GetOSMWayID(const NodeID /*edge_based_node_id*/) const
{
throw util::exception("GetOSMWayID is not implemented for this data facade");
}

Copilot uses AI. Check for mistakes.

virtual GeometryID GetGeometryIndex(const NodeID edge_based_node_id) const = 0;

virtual ComponentID GetComponentID(const NodeID edge_based_node_id) const = 0;
Expand Down Expand Up @@ -105,6 +111,9 @@ class BaseDataFacade
virtual DatasourceReverseRange
GetUncompressedReverseDatasources(const PackedGeometryID id) const = 0;

virtual WayIDForwardRange GetUncompressedForwardWayIDs(const PackedGeometryID id) const = 0;
virtual WayIDReverseRange GetUncompressedReverseWayIDs(const PackedGeometryID id) const = 0;

// Gets the name of a datasource
virtual std::string_view GetDatasourceName(const DatasourceID id) const = 0;

Expand Down
10 changes: 7 additions & 3 deletions include/engine/guidance/assemble_geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
10.,
from_alias<double>(path_point.weight_until_turn - path_point.weight_of_turn) /
facade.GetWeightMultiplier(),
path_point.datasource_id});
path_point.datasource_id,
path_point.way_id});
geometry.locations.push_back(coordinate);
geometry.node_ids.push_back(node_id);
}
Expand All @@ -117,6 +118,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
reversed_target ? target_node.reverse_segment_id.id : target_node.forward_segment_id.id;
const auto target_geometry_id = facade.GetGeometryIndex(target_node_id).id;
const auto forward_datasources = facade.GetUncompressedForwardDatasources(target_geometry_id);
const auto forward_way_ids = facade.GetUncompressedForwardWayIDs(target_geometry_id);

// 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.
Expand All @@ -141,7 +143,8 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
LegGeometry::Annotation{current_distance,
duration,
weight,
forward_datasources[target_node.fwd_segment_position]});
forward_datasources[target_node.fwd_segment_position],
forward_way_ids[target_node.fwd_segment_position]});
}
else
{
Expand All @@ -153,7 +156,8 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
from_alias<double>(reversed_target ? target_node.reverse_weight
: target_node.forward_weight) /
facade.GetWeightMultiplier(),
forward_datasources[target_node.fwd_segment_position]});
forward_datasources[target_node.fwd_segment_position],
forward_way_ids[target_node.fwd_segment_position]});
}

geometry.segment_offsets.push_back(geometry.locations.size());
Expand Down
1 change: 1 addition & 0 deletions include/engine/guidance/leg_geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct LegGeometry
double weight; // weight value, NOT including the turn weight

DatasourceID datasource;
OSMWayID way_id;
};
std::vector<Annotation> annotations;

Expand Down
Loading