2016-02-20 22:27:26 -05:00
|
|
|
#ifndef ENGINE_API_MATCH_HPP
|
|
|
|
#define ENGINE_API_MATCH_HPP
|
|
|
|
|
|
|
|
#include "engine/api/match_parameters.hpp"
|
2017-03-20 11:49:50 -04:00
|
|
|
#include "engine/api/match_parameters_tidy.hpp"
|
2016-05-27 15:05:04 -04:00
|
|
|
#include "engine/api/route_api.hpp"
|
2016-02-20 22:27:26 -05:00
|
|
|
|
|
|
|
#include "engine/datafacade/datafacade_base.hpp"
|
|
|
|
|
|
|
|
#include "engine/internal_route_result.hpp"
|
|
|
|
#include "engine/map_matching/sub_matching.hpp"
|
|
|
|
|
|
|
|
#include "util/integer_range.hpp"
|
|
|
|
|
2022-12-11 04:10:26 -05:00
|
|
|
namespace osrm::engine::api
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
|
|
|
|
|
|
|
class MatchAPI final : public RouteAPI
|
|
|
|
{
|
|
|
|
public:
|
2017-03-20 11:49:50 -04:00
|
|
|
MatchAPI(const datafacade::BaseDataFacade &facade_,
|
|
|
|
const MatchParameters ¶meters_,
|
|
|
|
const tidy::Result &tidy_result_)
|
|
|
|
: RouteAPI(facade_, parameters_), parameters(parameters_), tidy_result(tidy_result_)
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-08-08 11:20:03 -04:00
|
|
|
void MakeResponse(const std::vector<map_matching::SubMatching> &sub_matchings,
|
|
|
|
const std::vector<InternalRouteResult> &sub_routes,
|
|
|
|
osrm::engine::api::ResultT &response) const
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(sub_matchings.size() == sub_routes.size());
|
2024-05-28 12:52:49 -04:00
|
|
|
if (std::holds_alternative<flatbuffers::FlatBufferBuilder>(response))
|
2019-08-15 04:40:23 -04:00
|
|
|
{
|
2024-05-28 12:52:49 -04:00
|
|
|
auto &fb_result = std::get<flatbuffers::FlatBufferBuilder>(response);
|
2019-08-08 11:20:03 -04:00
|
|
|
MakeResponse(sub_matchings, sub_routes, fb_result);
|
2019-08-15 04:40:23 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-05-28 12:52:49 -04:00
|
|
|
auto &json_result = std::get<util::json::Object>(response);
|
2019-08-08 11:20:03 -04:00
|
|
|
MakeResponse(sub_matchings, sub_routes, json_result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void MakeResponse(const std::vector<map_matching::SubMatching> &sub_matchings,
|
|
|
|
const std::vector<InternalRouteResult> &sub_routes,
|
|
|
|
flatbuffers::FlatBufferBuilder &fb_result) const
|
|
|
|
{
|
2019-08-23 05:20:56 -04:00
|
|
|
auto data_timestamp = facade.GetTimestamp();
|
2019-09-30 09:33:32 -04:00
|
|
|
flatbuffers::Offset<flatbuffers::String> data_version_string;
|
2019-08-23 05:20:56 -04:00
|
|
|
if (!data_timestamp.empty())
|
|
|
|
{
|
|
|
|
data_version_string = fb_result.CreateString(data_timestamp);
|
|
|
|
}
|
|
|
|
|
2024-05-06 03:14:46 -04:00
|
|
|
auto response = MakeFBResponse(sub_routes,
|
|
|
|
fb_result,
|
|
|
|
[this, &fb_result, &sub_matchings]()
|
|
|
|
{ return MakeTracepoints(fb_result, sub_matchings); });
|
2019-08-08 11:20:03 -04:00
|
|
|
|
2019-09-30 09:33:32 -04:00
|
|
|
if (!data_timestamp.empty())
|
2019-08-23 05:20:56 -04:00
|
|
|
{
|
2019-09-30 09:33:32 -04:00
|
|
|
response->add_data_version(data_version_string);
|
2019-08-23 05:20:56 -04:00
|
|
|
}
|
|
|
|
|
2019-09-26 03:36:31 -04:00
|
|
|
fb_result.Finish(response->Finish());
|
2019-08-08 11:20:03 -04:00
|
|
|
}
|
2016-02-20 22:27:26 -05:00
|
|
|
void MakeResponse(const std::vector<map_matching::SubMatching> &sub_matchings,
|
|
|
|
const std::vector<InternalRouteResult> &sub_routes,
|
|
|
|
util::json::Object &response) const
|
|
|
|
{
|
|
|
|
auto number_of_routes = sub_matchings.size();
|
|
|
|
util::json::Array routes;
|
|
|
|
routes.values.reserve(number_of_routes);
|
|
|
|
for (auto index : util::irange<std::size_t>(0UL, sub_matchings.size()))
|
|
|
|
{
|
2022-08-27 06:36:20 -04:00
|
|
|
auto route = MakeRoute(sub_routes[index].leg_endpoints,
|
2016-02-20 22:27:26 -05:00
|
|
|
sub_routes[index].unpacked_path_segments,
|
|
|
|
sub_routes[index].source_traversed_in_reverse,
|
2016-03-07 12:59:39 -05:00
|
|
|
sub_routes[index].target_traversed_in_reverse);
|
2024-06-14 10:04:19 -04:00
|
|
|
route.values.emplace("confidence", sub_matchings[index].confidence);
|
|
|
|
routes.values.emplace_back(std::move(route));
|
2016-02-20 22:27:26 -05:00
|
|
|
}
|
2019-09-16 10:13:33 -04:00
|
|
|
if (!parameters.skip_waypoints)
|
|
|
|
{
|
2024-06-14 10:04:19 -04:00
|
|
|
response.values.emplace("tracepoints", MakeTracepoints(sub_matchings));
|
2019-09-16 06:54:25 -04:00
|
|
|
}
|
2024-06-14 10:04:19 -04:00
|
|
|
response.values.emplace("matchings", std::move(routes));
|
|
|
|
response.values.emplace("code", "Ok");
|
2022-08-22 15:07:32 -04:00
|
|
|
auto data_timestamp = facade.GetTimestamp();
|
|
|
|
if (!data_timestamp.empty())
|
|
|
|
{
|
2024-06-14 10:04:19 -04:00
|
|
|
response.values.emplace("data_version", data_timestamp);
|
2022-08-22 15:07:32 -04:00
|
|
|
}
|
2016-02-20 22:27:26 -05:00
|
|
|
}
|
|
|
|
|
2016-12-15 09:28:54 -05:00
|
|
|
protected:
|
2016-02-20 22:27:26 -05:00
|
|
|
// FIXME this logic is a little backwards. We should change the output format of the
|
|
|
|
// map_matching
|
|
|
|
// routing algorithm to be easier to consume here.
|
2019-08-08 11:20:03 -04:00
|
|
|
struct MatchingIndex
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
2019-08-08 11:20:03 -04:00
|
|
|
MatchingIndex() = default;
|
|
|
|
MatchingIndex(unsigned sub_matching_index_, unsigned point_index_)
|
2019-08-15 04:40:23 -04:00
|
|
|
: sub_matching_index(sub_matching_index_), point_index(point_index_)
|
2019-08-08 11:20:03 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned sub_matching_index = std::numeric_limits<unsigned>::max();
|
|
|
|
unsigned point_index = std::numeric_limits<unsigned>::max();
|
2016-02-20 22:27:26 -05:00
|
|
|
|
2019-08-08 11:20:03 -04:00
|
|
|
bool NotMatched()
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
2019-08-08 11:20:03 -04:00
|
|
|
return sub_matching_index == std::numeric_limits<unsigned>::max() &&
|
|
|
|
point_index == std::numeric_limits<unsigned>::max();
|
|
|
|
}
|
|
|
|
};
|
2016-02-20 22:27:26 -05:00
|
|
|
|
2019-08-08 12:12:27 -04:00
|
|
|
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<fbresult::Waypoint>>>
|
2019-08-15 04:40:23 -04:00
|
|
|
MakeTracepoints(flatbuffers::FlatBufferBuilder &fb_result,
|
|
|
|
const std::vector<map_matching::SubMatching> &sub_matchings) const
|
2019-08-08 11:20:03 -04:00
|
|
|
{
|
|
|
|
std::vector<flatbuffers::Offset<fbresult::Waypoint>> waypoints;
|
|
|
|
waypoints.reserve(parameters.coordinates.size());
|
2016-02-20 22:27:26 -05:00
|
|
|
|
2019-08-08 11:20:03 -04:00
|
|
|
auto trace_idx_to_matching_idx = MakeMatchingIndices(sub_matchings);
|
2016-02-20 22:27:26 -05:00
|
|
|
|
2019-08-08 11:20:03 -04:00
|
|
|
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
|
|
|
|
|
|
|
|
std::size_t was_waypoint_idx = 0;
|
|
|
|
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
2019-08-08 11:20:03 -04:00
|
|
|
|
|
|
|
if (tidy_result.can_be_removed[trace_index])
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish());
|
2019-08-08 11:20:03 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto matching_index = trace_idx_to_matching_idx[trace_index];
|
|
|
|
if (matching_index.NotMatched())
|
|
|
|
{
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish());
|
2019-08-08 11:20:03 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto &phantom =
|
2019-08-15 04:40:23 -04:00
|
|
|
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
2022-08-27 06:36:20 -04:00
|
|
|
auto waypoint = BaseAPI::MakeWaypoint(&fb_result, {phantom});
|
2019-09-26 03:36:31 -04:00
|
|
|
waypoint->add_matchings_index(matching_index.sub_matching_index);
|
|
|
|
waypoint->add_alternatives_count(sub_matchings[matching_index.sub_matching_index]
|
|
|
|
.alternatives_count[matching_index.point_index]);
|
2019-08-08 11:20:03 -04:00
|
|
|
// waypoint indices need to be adjusted if route legs were collapsed
|
|
|
|
// waypoint parameter assumes there is only one match object
|
|
|
|
if (!parameters.waypoints.empty())
|
|
|
|
{
|
|
|
|
if (tidy_result.was_waypoint[trace_index])
|
|
|
|
{
|
2019-09-26 03:36:31 -04:00
|
|
|
waypoint->add_waypoint_index(was_waypoint_idx);
|
2019-08-08 11:20:03 -04:00
|
|
|
was_waypoint_idx++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-26 03:36:31 -04:00
|
|
|
waypoint->add_waypoint_index(0);
|
2019-08-08 11:20:03 -04:00
|
|
|
}
|
2019-08-15 04:40:23 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-26 03:36:31 -04:00
|
|
|
waypoint->add_waypoint_index(matching_index.point_index);
|
2016-02-20 22:27:26 -05:00
|
|
|
}
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoints.emplace_back(waypoint->Finish());
|
2016-02-20 22:27:26 -05:00
|
|
|
}
|
|
|
|
|
2019-08-08 12:12:27 -04:00
|
|
|
return fb_result.CreateVector(waypoints);
|
2019-08-08 11:20:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
util::json::Array
|
|
|
|
MakeTracepoints(const std::vector<map_matching::SubMatching> &sub_matchings) const
|
|
|
|
{
|
|
|
|
util::json::Array waypoints;
|
|
|
|
waypoints.values.reserve(parameters.coordinates.size());
|
|
|
|
|
|
|
|
auto trace_idx_to_matching_idx = MakeMatchingIndices(sub_matchings);
|
|
|
|
|
2018-01-19 05:22:23 -05:00
|
|
|
BOOST_ASSERT(parameters.waypoints.empty() || sub_matchings.size() == 1);
|
|
|
|
|
2017-12-07 10:36:30 -05:00
|
|
|
std::size_t was_waypoint_idx = 0;
|
2016-04-12 09:14:13 -04:00
|
|
|
for (auto trace_index : util::irange<std::size_t>(0UL, parameters.coordinates.size()))
|
2016-02-20 22:27:26 -05:00
|
|
|
{
|
2017-03-20 11:49:50 -04:00
|
|
|
if (tidy_result.can_be_removed[trace_index])
|
|
|
|
{
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoints.values.emplace_back(util::json::Null());
|
2017-03-20 11:49:50 -04:00
|
|
|
continue;
|
|
|
|
}
|
2016-02-20 22:27:26 -05:00
|
|
|
auto matching_index = trace_idx_to_matching_idx[trace_index];
|
|
|
|
if (matching_index.NotMatched())
|
|
|
|
{
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoints.values.emplace_back(util::json::Null());
|
2016-02-20 22:27:26 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto &phantom =
|
|
|
|
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
2022-08-27 06:36:20 -04:00
|
|
|
auto waypoint = BaseAPI::MakeWaypoint({phantom});
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoint.values.emplace("matchings_index", matching_index.sub_matching_index);
|
|
|
|
waypoint.values.emplace("waypoint_index", matching_index.point_index);
|
|
|
|
waypoint.values.emplace("alternatives_count",
|
|
|
|
sub_matchings[matching_index.sub_matching_index]
|
|
|
|
.alternatives_count[matching_index.point_index]);
|
2018-01-15 09:55:24 -05:00
|
|
|
// waypoint indices need to be adjusted if route legs were collapsed
|
2018-01-15 12:38:14 -05:00
|
|
|
// waypoint parameter assumes there is only one match object
|
2018-01-15 09:55:24 -05:00
|
|
|
if (!parameters.waypoints.empty())
|
2017-12-07 10:36:30 -05:00
|
|
|
{
|
2018-01-15 09:55:24 -05:00
|
|
|
if (tidy_result.was_waypoint[trace_index])
|
|
|
|
{
|
|
|
|
waypoint.values["waypoint_index"] = was_waypoint_idx;
|
|
|
|
was_waypoint_idx++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
waypoint.values["waypoint_index"] = util::json::Null();
|
|
|
|
}
|
2017-12-07 10:36:30 -05:00
|
|
|
}
|
2024-06-14 10:04:19 -04:00
|
|
|
waypoints.values.emplace_back(std::move(waypoint));
|
2016-02-20 22:27:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return waypoints;
|
|
|
|
}
|
|
|
|
|
2019-08-15 04:40:23 -04:00
|
|
|
std::vector<MatchingIndex>
|
|
|
|
MakeMatchingIndices(const std::vector<map_matching::SubMatching> &sub_matchings) const
|
|
|
|
{
|
2019-08-08 11:20:03 -04:00
|
|
|
std::vector<MatchingIndex> trace_idx_to_matching_idx(parameters.coordinates.size());
|
|
|
|
for (auto sub_matching_index :
|
2019-08-15 04:40:23 -04:00
|
|
|
util::irange(0u, static_cast<unsigned>(sub_matchings.size())))
|
|
|
|
{
|
2019-08-08 11:20:03 -04:00
|
|
|
for (auto point_index : util::irange(
|
2019-08-15 04:40:23 -04:00
|
|
|
0u, static_cast<unsigned>(sub_matchings[sub_matching_index].indices.size())))
|
|
|
|
{
|
2019-08-08 11:20:03 -04:00
|
|
|
// tidied_to_original: index of the input coordinate that a tidied coordinate
|
|
|
|
// corresponds to.
|
|
|
|
// sub_matching indices: index of the coordinate passed to map matching plugin that
|
|
|
|
// a matched node corresponds to.
|
|
|
|
trace_idx_to_matching_idx[tidy_result
|
2019-08-15 04:40:23 -04:00
|
|
|
.tidied_to_original[sub_matchings[sub_matching_index]
|
|
|
|
.indices[point_index]]] =
|
|
|
|
MatchingIndex{sub_matching_index, point_index};
|
2019-08-08 11:20:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return trace_idx_to_matching_idx;
|
|
|
|
}
|
|
|
|
|
2016-02-20 22:27:26 -05:00
|
|
|
const MatchParameters ¶meters;
|
2017-03-20 11:49:50 -04:00
|
|
|
const tidy::Result &tidy_result;
|
2016-02-20 22:27:26 -05:00
|
|
|
};
|
|
|
|
|
2022-12-20 12:00:11 -05:00
|
|
|
} // namespace osrm::engine::api
|
2016-02-20 22:27:26 -05:00
|
|
|
|
|
|
|
#endif
|