osrm-backend/include/engine/api/trip_api.hpp
2024-06-15 18:57:26 +02:00

182 lines
6.9 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::engine::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 (std::holds_alternative<flatbuffers::FlatBufferBuilder>(response))
{
auto &fb_result = std::get<flatbuffers::FlatBufferBuilder>(response);
MakeResponse(sub_trips, sub_routes, candidates, fb_result);
}
else
{
auto &json_result = std::get<util::json::Object>(response);
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.emplace("waypoints", MakeWaypoints(sub_trips, candidates));
}
response.values.emplace("trips", std::move(routes));
response.values.emplace("code", "Ok");
auto data_timestamp = facade.GetTimestamp();
if (!data_timestamp.empty())
{
response.values.emplace("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.emplace("trips_index", trip_index.sub_trip_index);
waypoint.values.emplace("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 osrm::engine::api
#endif