295 lines
11 KiB
C++
295 lines
11 KiB
C++
#ifndef ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_
|
|
#define ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_
|
|
|
|
#include "guidance/segment_list.hpp"
|
|
#include "guidance/textual_route_annotation.hpp"
|
|
|
|
#include "engine/douglas_peucker.hpp"
|
|
#include "engine/internal_route_result.hpp"
|
|
#include "engine/object_encoder.hpp"
|
|
#include "engine/phantom_node.hpp"
|
|
#include "engine/polyline_formatter.hpp"
|
|
#include "engine/route_name_extraction.hpp"
|
|
#include "engine/segment_information.hpp"
|
|
#include "extractor/turn_instructions.hpp"
|
|
#include "osrm/coordinate.hpp"
|
|
#include "osrm/json_container.hpp"
|
|
#include "osrm/route_parameters.hpp"
|
|
#include "util/integer_range.hpp"
|
|
#include "util/typedefs.hpp"
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
#include <cmath>
|
|
|
|
#include <limits>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace osrm
|
|
{
|
|
namespace engine
|
|
{
|
|
namespace detail
|
|
{
|
|
struct Segment
|
|
{
|
|
uint32_t name_id;
|
|
int32_t length;
|
|
std::size_t position;
|
|
};
|
|
} // namespace detail
|
|
|
|
template <typename DataFacadeT> class ApiResponseGenerator
|
|
{
|
|
public:
|
|
using DataFacade = DataFacadeT;
|
|
using Segments = guidance::SegmentList<DataFacade>;
|
|
using Segment = detail::Segment;
|
|
using RouteNameExtractor = ExtractRouteNames<DataFacade, Segment>;
|
|
|
|
ApiResponseGenerator(DataFacade *facade);
|
|
|
|
// This runs a full annotation, according to config.
|
|
// The output is tailored to the viaroute plugin.
|
|
void DescribeRoute(const RouteParameters &config,
|
|
const InternalRouteResult &raw_route,
|
|
util::json::Object &json_result);
|
|
|
|
// The following functions allow access to the different parts of the Describe Route
|
|
// functionality.
|
|
// For own responses, they can be used to generate only subsets of the information.
|
|
// In the normal situation, Describe Route is the desired usecase.
|
|
|
|
// generate an overview of a raw route
|
|
util::json::Object SummarizeRoute(const InternalRouteResult &raw_route,
|
|
const Segments &segment_list) const;
|
|
|
|
// create an array containing all via-points/-indices used in the query
|
|
util::json::Array ListViaPoints(const InternalRouteResult &raw_route) const;
|
|
util::json::Array ListViaIndices(const Segments &segment_list) const;
|
|
|
|
util::json::Value GetGeometry(const bool return_encoded, const Segments &segments) const;
|
|
|
|
// TODO this dedicated creation seems unnecessary? Only used for route names
|
|
std::vector<Segment> BuildRouteSegments(const Segments &segment_list) const;
|
|
|
|
// adds checksum and locations
|
|
util::json::Object BuildHintData(const InternalRouteResult &raw_route) const;
|
|
|
|
private:
|
|
// data access to translate ids back into names
|
|
DataFacade *facade;
|
|
};
|
|
|
|
template <typename DataFacadeT>
|
|
ApiResponseGenerator<DataFacadeT>::ApiResponseGenerator(DataFacadeT *facade_)
|
|
: facade(facade_)
|
|
{
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
void ApiResponseGenerator<DataFacadeT>::DescribeRoute(const RouteParameters &config,
|
|
const InternalRouteResult &raw_route,
|
|
util::json::Object &json_result)
|
|
{
|
|
if( not raw_route.is_valid() ){
|
|
return;
|
|
}
|
|
const constexpr bool ALLOW_SIMPLIFICATION = true;
|
|
const constexpr bool EXTRACT_ROUTE = false;
|
|
const constexpr bool EXTRACT_ALTERNATIVE = true;
|
|
Segments segment_list(raw_route, EXTRACT_ROUTE, config.zoom_level, ALLOW_SIMPLIFICATION,
|
|
facade);
|
|
json_result.values["route_summary"] = SummarizeRoute(raw_route, segment_list);
|
|
json_result.values["via_points"] = ListViaPoints(raw_route);
|
|
json_result.values["via_indices"] = ListViaIndices(segment_list);
|
|
|
|
if (config.geometry)
|
|
{
|
|
json_result.values["route_geometry"] = GetGeometry(config.compression, segment_list);
|
|
}
|
|
|
|
if (config.print_instructions)
|
|
{
|
|
json_result.values["route_instructions"] =
|
|
guidance::AnnotateRoute(segment_list.Get(), facade);
|
|
}
|
|
|
|
RouteNames route_names;
|
|
RouteNameExtractor generate_route_names;
|
|
|
|
if (raw_route.has_alternative())
|
|
{
|
|
Segments alternate_segment_list(raw_route, EXTRACT_ALTERNATIVE, config.zoom_level,
|
|
ALLOW_SIMPLIFICATION, facade);
|
|
|
|
// Alternative Route Summaries are stored in an array to (down the line) allow multiple
|
|
// alternatives
|
|
util::json::Array json_alternate_route_summary_array;
|
|
json_alternate_route_summary_array.values.emplace_back(
|
|
SummarizeRoute(raw_route, alternate_segment_list));
|
|
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
|
|
json_result.values["alternative_indices"] = ListViaIndices(alternate_segment_list);
|
|
|
|
if (config.geometry)
|
|
{
|
|
auto alternate_geometry_string =
|
|
GetGeometry(config.compression, alternate_segment_list);
|
|
util::json::Array json_alternate_geometries_array;
|
|
json_alternate_geometries_array.values.emplace_back(std::move(alternate_geometry_string));
|
|
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
|
|
}
|
|
|
|
if (config.print_instructions)
|
|
{
|
|
util::json::Array json_alternate_annotations_array;
|
|
json_alternate_annotations_array.values.emplace_back(
|
|
guidance::AnnotateRoute(alternate_segment_list.Get(), facade));
|
|
json_result.values["alternative_instructions"] = json_alternate_annotations_array;
|
|
}
|
|
|
|
// generate names for both the main path and the alternative route
|
|
auto path_segments = BuildRouteSegments(segment_list);
|
|
auto alternate_segments = BuildRouteSegments(alternate_segment_list);
|
|
route_names = generate_route_names(path_segments, alternate_segments, facade);
|
|
|
|
util::json::Array json_alternate_names_array;
|
|
util::json::Array json_alternate_names;
|
|
json_alternate_names.values.push_back(route_names.alternative_path_name_1);
|
|
json_alternate_names.values.push_back(route_names.alternative_path_name_2);
|
|
json_alternate_names_array.values.emplace_back(std::move(json_alternate_names));
|
|
json_result.values["alternative_names"] = json_alternate_names_array;
|
|
json_result.values["found_alternative"] = util::json::True();
|
|
}
|
|
else
|
|
{
|
|
json_result.values["found_alternative"] = util::json::False();
|
|
// generate names for the main route on its own
|
|
auto path_segments = BuildRouteSegments(segment_list);
|
|
std::vector<detail::Segment> alternate_segments;
|
|
route_names = generate_route_names(path_segments, alternate_segments, facade);
|
|
}
|
|
|
|
util::json::Array json_route_names;
|
|
json_route_names.values.push_back(route_names.shortest_path_name_1);
|
|
json_route_names.values.push_back(route_names.shortest_path_name_2);
|
|
json_result.values["route_name"] = json_route_names;
|
|
|
|
json_result.values["hint_data"] = BuildHintData(raw_route);
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
util::json::Object
|
|
ApiResponseGenerator<DataFacadeT>::SummarizeRoute(const InternalRouteResult &raw_route,
|
|
const Segments &segment_list) const
|
|
{
|
|
util::json::Object json_route_summary;
|
|
if (not raw_route.segment_end_coordinates.empty())
|
|
{
|
|
const auto start_name_id = raw_route.segment_end_coordinates.front().source_phantom.name_id;
|
|
json_route_summary.values["start_point"] = facade->get_name_for_id(start_name_id);
|
|
const auto destination_name_id = raw_route.segment_end_coordinates.back().target_phantom.name_id;
|
|
json_route_summary.values["end_point"] = facade->get_name_for_id(destination_name_id);
|
|
}
|
|
json_route_summary.values["total_time"] = segment_list.GetDuration();
|
|
json_route_summary.values["total_distance"] = segment_list.GetDistance();
|
|
return json_route_summary;
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
util::json::Array
|
|
ApiResponseGenerator<DataFacadeT>::ListViaPoints(const InternalRouteResult &raw_route) const
|
|
{
|
|
util::json::Array json_via_points_array;
|
|
util::json::Array json_first_coordinate;
|
|
json_first_coordinate.values.emplace_back(
|
|
raw_route.segment_end_coordinates.front().source_phantom.location.lat /
|
|
COORDINATE_PRECISION);
|
|
json_first_coordinate.values.emplace_back(
|
|
raw_route.segment_end_coordinates.front().source_phantom.location.lon /
|
|
COORDINATE_PRECISION);
|
|
json_via_points_array.values.emplace_back(std::move(json_first_coordinate));
|
|
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
|
{
|
|
std::string tmp;
|
|
util::json::Array json_coordinate;
|
|
json_coordinate.values.emplace_back(nodes.target_phantom.location.lat / COORDINATE_PRECISION);
|
|
json_coordinate.values.emplace_back(nodes.target_phantom.location.lon / COORDINATE_PRECISION);
|
|
json_via_points_array.values.emplace_back(std::move(json_coordinate));
|
|
}
|
|
return json_via_points_array;
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
util::json::Array
|
|
ApiResponseGenerator<DataFacadeT>::ListViaIndices(const Segments &segment_list) const
|
|
{
|
|
util::json::Array via_indices;
|
|
via_indices.values.insert(via_indices.values.end(), segment_list.GetViaIndices().begin(),
|
|
segment_list.GetViaIndices().end());
|
|
return via_indices;
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
util::json::Value ApiResponseGenerator<DataFacadeT>::GetGeometry(const bool return_encoded, const Segments &segments) const
|
|
{
|
|
if (return_encoded)
|
|
return PolylineFormatter().printEncodedString(segments.Get());
|
|
else
|
|
return PolylineFormatter().printUnencodedString(segments.Get());
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
std::vector<detail::Segment>
|
|
ApiResponseGenerator<DataFacadeT>::BuildRouteSegments(const Segments &segment_list) const
|
|
{
|
|
std::vector<detail::Segment> result;
|
|
for (const auto &segment : segment_list.Get())
|
|
{
|
|
const auto current_turn = segment.turn_instruction;
|
|
if (extractor::TurnInstructionsClass::TurnIsNecessary(current_turn) and
|
|
(extractor::TurnInstruction::EnterRoundAbout != current_turn))
|
|
{
|
|
|
|
detail::Segment seg = {segment.name_id, static_cast<int32_t>(segment.length),
|
|
static_cast<std::size_t>(result.size())};
|
|
result.emplace_back(std::move(seg));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
util::json::Object
|
|
ApiResponseGenerator<DataFacadeT>::BuildHintData(const InternalRouteResult &raw_route) const
|
|
{
|
|
util::json::Object json_hint_object;
|
|
json_hint_object.values["checksum"] = facade->GetCheckSum();
|
|
util::json::Array json_location_hint_array;
|
|
std::string hint;
|
|
for (const auto i : util::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
|
|
{
|
|
ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
|
|
json_location_hint_array.values.push_back(hint);
|
|
}
|
|
ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
|
|
json_location_hint_array.values.emplace_back(std::move(hint));
|
|
json_hint_object.values["locations"] = json_location_hint_array;
|
|
|
|
return json_hint_object;
|
|
}
|
|
|
|
template <typename DataFacadeT>
|
|
ApiResponseGenerator<DataFacadeT> MakeApiResponseGenerator(DataFacadeT *facade){
|
|
return ApiResponseGenerator<DataFacadeT>(facade);
|
|
}
|
|
|
|
} // namespace engine
|
|
} // namespace osrm
|
|
|
|
#endif //ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_
|