osrm-backend/include/engine/api/trip_api.hpp
Michael Bell d74e7b66bd
Support snapping to multiple ways at an input location ()
This PR improves routing results by adding support for snapping to
multiple ways at input locations.

This means all edges at the snapped location can act as source/target
candidates for routing search, ensuring we always find the best route,
and not the one dependent on the edge selected.
2022-08-27 11:36:20 +01:00

188 lines
6.8 KiB
C++

#ifndef ENGINE_API_TRIP_HPP
#define ENGINE_API_TRIP_HPP
#include "engine/api/route_api.hpp"
#include "engine/api/trip_parameters.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/internal_route_result.hpp"
#include "util/integer_range.hpp"
namespace osrm
{
namespace engine
{
namespace api
{
class TripAPI final : public RouteAPI
{
public:
TripAPI(const datafacade::BaseDataFacade &facade_, const TripParameters &parameters_)
: RouteAPI(facade_, parameters_), parameters(parameters_)
{
}
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<InternalRouteResult> &sub_routes,
const std::vector<PhantomNodeCandidates> &candidates,
osrm::engine::api::ResultT &response) const
{
BOOST_ASSERT(sub_trips.size() == sub_routes.size());
if (response.is<flatbuffers::FlatBufferBuilder>())
{
auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
MakeResponse(sub_trips, sub_routes, candidates, fb_result);
}
else
{
auto &json_result = response.get<util::json::Object>();
MakeResponse(sub_trips, sub_routes, candidates, json_result);
}
}
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<InternalRouteResult> &sub_routes,
const std::vector<PhantomNodeCandidates> &candidates,
flatbuffers::FlatBufferBuilder &fb_result) const
{
auto data_timestamp = facade.GetTimestamp();
flatbuffers::Offset<flatbuffers::String> data_version_string;
if (!data_timestamp.empty())
{
data_version_string = fb_result.CreateString(data_timestamp);
}
auto response =
MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &candidates]() {
return MakeWaypoints(fb_result, sub_trips, candidates);
});
if (!data_timestamp.empty())
{
response->add_data_version(data_version_string);
}
fb_result.Finish(response->Finish());
}
void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<InternalRouteResult> &sub_routes,
const std::vector<PhantomNodeCandidates> &candidates,
util::json::Object &response) const
{
auto number_of_routes = sub_trips.size();
util::json::Array routes;
routes.values.reserve(number_of_routes);
for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
{
auto route = MakeRoute(sub_routes[index].leg_endpoints,
sub_routes[index].unpacked_path_segments,
sub_routes[index].source_traversed_in_reverse,
sub_routes[index].target_traversed_in_reverse);
routes.values.push_back(std::move(route));
}
if (!parameters.skip_waypoints)
{
response.values["waypoints"] = MakeWaypoints(sub_trips, candidates);
}
response.values["trips"] = std::move(routes);
response.values["code"] = "Ok";
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values["data_version"] = data_timestamp;
}
}
protected:
// FIXME this logic is a little backwards. We should change the output format of the
// trip plugin routing algorithm to be easier to consume here.
struct TripIndex
{
TripIndex() = default;
TripIndex(unsigned sub_trip_index_, unsigned point_index_)
: sub_trip_index(sub_trip_index_), point_index(point_index_)
{
}
unsigned sub_trip_index = std::numeric_limits<unsigned>::max();
unsigned point_index = std::numeric_limits<unsigned>::max();
bool NotUsed()
{
return sub_trip_index == std::numeric_limits<unsigned>::max() &&
point_index == std::numeric_limits<unsigned>::max();
}
};
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result,
const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<PhantomNodeCandidates> &candidates) const
{
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
waypoints.reserve(parameters.coordinates.size());
auto input_idx_to_trip_idx = MakeTripIndices(sub_trips);
for (auto input_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
auto trip_index = input_idx_to_trip_idx[input_index];
BOOST_ASSERT(!trip_index.NotUsed());
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, candidates[input_index]);
waypoint->add_waypoint_index(trip_index.point_index);
waypoint->add_trips_index(trip_index.sub_trip_index);
waypoints.push_back(waypoint->Finish());
}
return fb_result.CreateVector(waypoints);
}
util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
const std::vector<PhantomNodeCandidates> &candidates) const
{
util::json::Array waypoints;
waypoints.values.reserve(parameters.coordinates.size());
auto input_idx_to_trip_idx = MakeTripIndices(sub_trips);
for (auto input_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
{
auto trip_index = input_idx_to_trip_idx[input_index];
BOOST_ASSERT(!trip_index.NotUsed());
auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]);
waypoint.values["trips_index"] = trip_index.sub_trip_index;
waypoint.values["waypoint_index"] = trip_index.point_index;
waypoints.values.push_back(std::move(waypoint));
}
return waypoints;
}
std::vector<TripIndex> MakeTripIndices(const std::vector<std::vector<NodeID>> &sub_trips) const
{
std::vector<TripIndex> input_idx_to_trip_idx(parameters.coordinates.size());
for (auto sub_trip_index : util::irange<unsigned>(0u, sub_trips.size()))
{
for (auto point_index : util::irange<unsigned>(0u, sub_trips[sub_trip_index].size()))
{
input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] =
TripIndex{sub_trip_index, point_index};
}
}
return input_idx_to_trip_idx;
}
const TripParameters &parameters;
};
} // namespace api
} // namespace engine
} // namespace osrm
#endif