1 #ifndef ENGINE_API_TRIP_HPP
2 #define ENGINE_API_TRIP_HPP
3 
4 #include "engine/api/route_api.hpp"
5 #include "engine/api/trip_parameters.hpp"
6 
7 #include "engine/datafacade/datafacade_base.hpp"
8 
9 #include "engine/internal_route_result.hpp"
10 
11 #include "util/integer_range.hpp"
12 
13 namespace osrm
14 {
15 namespace engine
16 {
17 namespace api
18 {
19 
20 class TripAPI final : public RouteAPI
21 {
22   public:
TripAPI(const datafacade::BaseDataFacade & facade_,const TripParameters & parameters_)23     TripAPI(const datafacade::BaseDataFacade &facade_, const TripParameters &parameters_)
24         : RouteAPI(facade_, parameters_), parameters(parameters_)
25     {
26     }
MakeResponse(const std::vector<std::vector<NodeID>> & sub_trips,const std::vector<InternalRouteResult> & sub_routes,const std::vector<PhantomNode> & phantoms,osrm::engine::api::ResultT & response) const27     void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
28                       const std::vector<InternalRouteResult> &sub_routes,
29                       const std::vector<PhantomNode> &phantoms,
30                       osrm::engine::api::ResultT &response) const
31     {
32         BOOST_ASSERT(sub_trips.size() == sub_routes.size());
33 
34         if (response.is<flatbuffers::FlatBufferBuilder>())
35         {
36             auto &fb_result = response.get<flatbuffers::FlatBufferBuilder>();
37             MakeResponse(sub_trips, sub_routes, phantoms, fb_result);
38         }
39         else
40         {
41             auto &json_result = response.get<util::json::Object>();
42             MakeResponse(sub_trips, sub_routes, phantoms, json_result);
43         }
44     }
MakeResponse(const std::vector<std::vector<NodeID>> & sub_trips,const std::vector<InternalRouteResult> & sub_routes,const std::vector<PhantomNode> & phantoms,flatbuffers::FlatBufferBuilder & fb_result) const45     void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
46                       const std::vector<InternalRouteResult> &sub_routes,
47                       const std::vector<PhantomNode> &phantoms,
48                       flatbuffers::FlatBufferBuilder &fb_result) const
49     {
50         auto data_timestamp = facade.GetTimestamp();
51         flatbuffers::Offset<flatbuffers::String> data_version_string;
52         if (!data_timestamp.empty())
53         {
54             data_version_string = fb_result.CreateString(data_timestamp);
55         }
56 
57         auto response =
58             MakeFBResponse(sub_routes, fb_result, [this, &fb_result, &sub_trips, &phantoms]() {
59                 return MakeWaypoints(fb_result, sub_trips, phantoms);
60             });
61 
62         if (!data_timestamp.empty())
63         {
64             response->add_data_version(data_version_string);
65         }
66         fb_result.Finish(response->Finish());
67     }
MakeResponse(const std::vector<std::vector<NodeID>> & sub_trips,const std::vector<InternalRouteResult> & sub_routes,const std::vector<PhantomNode> & phantoms,util::json::Object & response) const68     void MakeResponse(const std::vector<std::vector<NodeID>> &sub_trips,
69                       const std::vector<InternalRouteResult> &sub_routes,
70                       const std::vector<PhantomNode> &phantoms,
71                       util::json::Object &response) const
72     {
73         auto number_of_routes = sub_trips.size();
74         util::json::Array routes;
75         routes.values.reserve(number_of_routes);
76         for (auto index : util::irange<std::size_t>(0UL, sub_trips.size()))
77         {
78             auto route = MakeRoute(sub_routes[index].segment_end_coordinates,
79                                    sub_routes[index].unpacked_path_segments,
80                                    sub_routes[index].source_traversed_in_reverse,
81                                    sub_routes[index].target_traversed_in_reverse);
82             routes.values.push_back(std::move(route));
83         }
84         if (!parameters.skip_waypoints)
85         {
86             response.values["waypoints"] = MakeWaypoints(sub_trips, phantoms);
87         }
88         response.values["trips"] = std::move(routes);
89         response.values["code"] = "Ok";
90     }
91 
92   protected:
93     // FIXME this logic is a little backwards. We should change the output format of the
94     // trip plugin routing algorithm to be easier to consume here.
95 
96     struct TripIndex
97     {
98         TripIndex() = default;
99 
TripIndexosrm::engine::api::TripAPI::TripIndex100         TripIndex(unsigned sub_trip_index_, unsigned point_index_)
101             : sub_trip_index(sub_trip_index_), point_index(point_index_)
102         {
103         }
104 
105         unsigned sub_trip_index = std::numeric_limits<unsigned>::max();
106         unsigned point_index = std::numeric_limits<unsigned>::max();
107 
NotUsedosrm::engine::api::TripAPI::TripIndex108         bool NotUsed()
109         {
110             return sub_trip_index == std::numeric_limits<unsigned>::max() &&
111                    point_index == std::numeric_limits<unsigned>::max();
112         }
113     };
114 
115     flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
MakeWaypoints(flatbuffers::FlatBufferBuilder & fb_result,const std::vector<std::vector<NodeID>> & sub_trips,const std::vector<PhantomNode> & phantoms) const116     MakeWaypoints(flatbuffers::FlatBufferBuilder &fb_result,
117                   const std::vector<std::vector<NodeID>> &sub_trips,
118                   const std::vector<PhantomNode> &phantoms) const
119     {
120         std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
121         waypoints.reserve(parameters.coordinates.size());
122 
123         auto input_idx_to_trip_idx = MakeTripIndices(sub_trips);
124 
125         for (auto input_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
126         {
127             auto trip_index = input_idx_to_trip_idx[input_index];
128             BOOST_ASSERT(!trip_index.NotUsed());
129 
130             auto waypoint = BaseAPI::MakeWaypoint(&fb_result, phantoms[input_index]);
131             waypoint->add_waypoint_index(trip_index.point_index);
132             waypoint->add_trips_index(trip_index.sub_trip_index);
133             waypoints.push_back(waypoint->Finish());
134         }
135 
136         return fb_result.CreateVector(waypoints);
137     }
138 
MakeWaypoints(const std::vector<std::vector<NodeID>> & sub_trips,const std::vector<PhantomNode> & phantoms) const139     util::json::Array MakeWaypoints(const std::vector<std::vector<NodeID>> &sub_trips,
140                                     const std::vector<PhantomNode> &phantoms) const
141     {
142         util::json::Array waypoints;
143         waypoints.values.reserve(parameters.coordinates.size());
144 
145         auto input_idx_to_trip_idx = MakeTripIndices(sub_trips);
146 
147         for (auto input_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
148         {
149             auto trip_index = input_idx_to_trip_idx[input_index];
150             BOOST_ASSERT(!trip_index.NotUsed());
151 
152             auto waypoint = BaseAPI::MakeWaypoint(phantoms[input_index]);
153             waypoint.values["trips_index"] = trip_index.sub_trip_index;
154             waypoint.values["waypoint_index"] = trip_index.point_index;
155             waypoints.values.push_back(std::move(waypoint));
156         }
157 
158         return waypoints;
159     }
160 
MakeTripIndices(const std::vector<std::vector<NodeID>> & sub_trips) const161     std::vector<TripIndex> MakeTripIndices(const std::vector<std::vector<NodeID>> &sub_trips) const
162     {
163         std::vector<TripIndex> input_idx_to_trip_idx(parameters.coordinates.size());
164         for (auto sub_trip_index : util::irange<unsigned>(0u, sub_trips.size()))
165         {
166             for (auto point_index : util::irange<unsigned>(0u, sub_trips[sub_trip_index].size()))
167             {
168                 input_idx_to_trip_idx[sub_trips[sub_trip_index][point_index]] =
169                     TripIndex{sub_trip_index, point_index};
170             }
171         }
172         return input_idx_to_trip_idx;
173     }
174 
175     const TripParameters &parameters;
176 };
177 
178 } // namespace api
179 } // namespace engine
180 } // namespace osrm
181 
182 #endif
183