Refactor guidance generation
This commit is contained in:
parent
fa4ba42f15
commit
efd33b295a
294
include/engine/api_response_generator.hpp
Normal file
294
include/engine/api_response_generator.hpp
Normal file
@ -0,0 +1,294 @@
|
||||
#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,
|
||||
osrm::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
|
||||
osrm::json::Object SummarizeRoute(const InternalRouteResult &raw_route,
|
||||
const Segments &segment_list) const;
|
||||
|
||||
// create an array containing all via-points/-indices used in the query
|
||||
osrm::json::Array ListViaPoints(const InternalRouteResult &raw_route) const;
|
||||
osrm::json::Array ListViaIndices(const Segments &segment_list) const;
|
||||
|
||||
osrm::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
|
||||
osrm::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,
|
||||
osrm::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
|
||||
osrm::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);
|
||||
osrm::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)
|
||||
{
|
||||
osrm::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);
|
||||
|
||||
osrm::json::Array json_alternate_names_array;
|
||||
osrm::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"] = osrm::json::True();
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["found_alternative"] = osrm::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);
|
||||
}
|
||||
|
||||
osrm::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>
|
||||
osrm::json::Object
|
||||
ApiResponseGenerator<DataFacadeT>::SummarizeRoute(const InternalRouteResult &raw_route,
|
||||
const Segments &segment_list) const
|
||||
{
|
||||
osrm::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>
|
||||
osrm::json::Array
|
||||
ApiResponseGenerator<DataFacadeT>::ListViaPoints(const InternalRouteResult &raw_route) const
|
||||
{
|
||||
osrm::json::Array json_via_points_array;
|
||||
osrm::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;
|
||||
osrm::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>
|
||||
osrm::json::Array
|
||||
ApiResponseGenerator<DataFacadeT>::ListViaIndices(const Segments &segment_list) const
|
||||
{
|
||||
osrm::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>
|
||||
osrm::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 (TurnInstructionsClass::TurnIsNecessary(current_turn) and
|
||||
(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>
|
||||
osrm::json::Object
|
||||
ApiResponseGenerator<DataFacadeT>::BuildHintData(const InternalRouteResult &raw_route) const
|
||||
{
|
||||
osrm::json::Object json_hint_object;
|
||||
json_hint_object.values["checksum"] = facade->GetCheckSum();
|
||||
osrm::json::Array json_location_hint_array;
|
||||
std::string hint;
|
||||
for (const auto i : osrm::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_
|
@ -1,69 +0,0 @@
|
||||
#ifndef DESCRIPTION_FACTORY_HPP
|
||||
#define DESCRIPTION_FACTORY_HPP
|
||||
|
||||
#include "engine/douglas_peucker.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "engine/segment_information.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
struct PathData;
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
class DescriptionFactory
|
||||
{
|
||||
DouglasPeucker polyline_generalizer;
|
||||
PhantomNode start_phantom, target_phantom;
|
||||
|
||||
double DegreeToRadian(const double degree) const;
|
||||
double RadianToDegree(const double degree) const;
|
||||
|
||||
std::vector<unsigned> via_indices;
|
||||
|
||||
double entire_length;
|
||||
|
||||
public:
|
||||
struct RouteSummary
|
||||
{
|
||||
unsigned distance;
|
||||
EdgeWeight duration;
|
||||
unsigned source_name_id;
|
||||
unsigned target_name_id;
|
||||
RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
|
||||
|
||||
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
|
||||
{
|
||||
// compute distance/duration for route summary
|
||||
distance = static_cast<unsigned>(std::round(raw_distance));
|
||||
duration = static_cast<EdgeWeight>(std::round(raw_duration / 10.));
|
||||
}
|
||||
} summary;
|
||||
|
||||
// I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector<SegmentInformation> path_description;
|
||||
DescriptionFactory();
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
|
||||
void SetEndSegment(const PhantomNode &start_phantom,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_location = false);
|
||||
osrm::json::Value AppendGeometryString(const bool return_encoded);
|
||||
std::vector<unsigned> const &GetViaIndices() const;
|
||||
|
||||
double get_entire_length() const { return entire_length; }
|
||||
|
||||
void Run(const unsigned zoom_level);
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTION_FACTORY_HPP */
|
@ -1,60 +0,0 @@
|
||||
#ifndef DESCRIPTOR_BASE_HPP
|
||||
#define DESCRIPTOR_BASE_HPP
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct DescriptorTable : public std::unordered_map<std::string, unsigned>
|
||||
{
|
||||
unsigned get_id(const std::string &key)
|
||||
{
|
||||
auto iter = find(key);
|
||||
if (iter != end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct DescriptorConfig
|
||||
{
|
||||
DescriptorConfig() : instructions(true), geometry(true), encode_geometry(true), zoom_level(18)
|
||||
{
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
DescriptorConfig(const OtherT &other)
|
||||
: instructions(other.print_instructions), geometry(other.geometry),
|
||||
encode_geometry(other.compression), zoom_level(other.zoom_level)
|
||||
{
|
||||
BOOST_ASSERT(zoom_level >= 0);
|
||||
}
|
||||
|
||||
bool instructions;
|
||||
bool geometry;
|
||||
bool encode_geometry;
|
||||
short zoom_level;
|
||||
};
|
||||
|
||||
template <class DataFacadeT> class BaseDescriptor
|
||||
{
|
||||
public:
|
||||
BaseDescriptor() {}
|
||||
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() {}
|
||||
virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig &c) = 0;
|
||||
};
|
||||
|
||||
#endif // DESCRIPTOR_BASE_HPP
|
@ -1,78 +0,0 @@
|
||||
#ifndef GPX_DESCRIPTOR_HPP
|
||||
#define GPX_DESCRIPTOR_HPP
|
||||
|
||||
#include "engine/descriptors/descriptor_base.hpp"
|
||||
#include "util/xml_renderer.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
DataFacadeT *facade;
|
||||
|
||||
template<std::size_t digits>
|
||||
void fixedIntToString(const int value, std::string &output)
|
||||
{
|
||||
char buffer[digits];
|
||||
buffer[digits-1] = 0; // zero termination
|
||||
output = printInt<11, 6>(buffer, value);
|
||||
}
|
||||
|
||||
void AddRoutePoint(const FixedPointCoordinate &coordinate, osrm::json::Array &json_route)
|
||||
{
|
||||
osrm::json::Object json_lat;
|
||||
osrm::json::Object json_lon;
|
||||
osrm::json::Array json_row;
|
||||
|
||||
std::string tmp;
|
||||
|
||||
fixedIntToString<12>(coordinate.lat, tmp);
|
||||
json_lat.values["_lat"] = tmp;
|
||||
|
||||
fixedIntToString<12>(coordinate.lon, tmp);
|
||||
json_lon.values["_lon"] = tmp;
|
||||
|
||||
json_row.values.push_back(json_lat);
|
||||
json_row.values.push_back(json_lon);
|
||||
osrm::json::Object entry;
|
||||
entry.values["rtept"] = json_row;
|
||||
json_route.values.push_back(entry);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
|
||||
|
||||
virtual void SetConfig(const DescriptorConfig &c) final { config = c; }
|
||||
|
||||
virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) final
|
||||
{
|
||||
osrm::json::Array json_route;
|
||||
if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
|
||||
json_route);
|
||||
|
||||
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
|
||||
{
|
||||
for (const PathData &path_data : path_data_vector)
|
||||
{
|
||||
const FixedPointCoordinate current_coordinate =
|
||||
facade->GetCoordinateOfNode(path_data.node);
|
||||
AddRoutePoint(current_coordinate, json_route);
|
||||
}
|
||||
}
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
|
||||
json_route);
|
||||
}
|
||||
// osrm::json::gpx_render(reply.content, json_route);
|
||||
json_result.values["route"] = json_route;
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_HPP
|
@ -1,379 +0,0 @@
|
||||
#ifndef JSON_DESCRIPTOR_HPP
|
||||
#define JSON_DESCRIPTOR_HPP
|
||||
|
||||
#include "engine/descriptors/descriptor_base.hpp"
|
||||
#include "engine/descriptors/description_factory.hpp"
|
||||
#include "engine/object_encoder.hpp"
|
||||
#include "engine/route_name_extraction.hpp"
|
||||
#include "engine/segment_information.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/cast.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory, alternate_description_factory;
|
||||
FixedPointCoordinate current;
|
||||
|
||||
public:
|
||||
struct Segment
|
||||
{
|
||||
Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
|
||||
Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
|
||||
unsigned name_id;
|
||||
int length;
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
|
||||
|
||||
public:
|
||||
explicit JSONDescriptor(DataFacadeT *facade) : facade(facade) {}
|
||||
|
||||
virtual void SetConfig(const DescriptorConfig &c) override final { config = c; }
|
||||
|
||||
unsigned DescribeLeg(const std::vector<PathData> &route_leg,
|
||||
const PhantomNodes &leg_phantoms,
|
||||
const bool target_traversed_in_reverse,
|
||||
const bool is_via_leg)
|
||||
{
|
||||
unsigned added_element_count = 0;
|
||||
// Get all the coordinates for the computed route
|
||||
FixedPointCoordinate current_coordinate;
|
||||
for (const PathData &path_data : route_leg)
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
description_factory.AppendSegment(current_coordinate, path_data);
|
||||
++added_element_count;
|
||||
}
|
||||
description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse,
|
||||
is_via_leg);
|
||||
++added_element_count;
|
||||
BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
virtual void Run(const InternalRouteResult &raw_route,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
return;
|
||||
}
|
||||
|
||||
// check if first segment is non-zero
|
||||
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const int added_segments =
|
||||
#endif
|
||||
DescribeLeg(raw_route.unpacked_path_segments[i],
|
||||
raw_route.segment_end_coordinates[i],
|
||||
raw_route.target_traversed_in_reverse[i], raw_route.is_via_leg(i));
|
||||
BOOST_ASSERT(0 < added_segments);
|
||||
}
|
||||
description_factory.Run(config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
osrm::json::Value route_geometry =
|
||||
description_factory.AppendGeometryString(config.encode_geometry);
|
||||
json_result.values["route_geometry"] = route_geometry;
|
||||
}
|
||||
if (config.instructions)
|
||||
{
|
||||
osrm::json::Array json_route_instructions =
|
||||
BuildTextualDescription(description_factory, shortest_path_segments);
|
||||
json_result.values["route_instructions"] = json_route_instructions;
|
||||
}
|
||||
description_factory.BuildRouteSummary(description_factory.get_entire_length(),
|
||||
raw_route.shortest_path_length);
|
||||
osrm::json::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = description_factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = description_factory.summary.duration;
|
||||
json_route_summary.values["start_point"] =
|
||||
facade->get_name_for_id(description_factory.summary.source_name_id);
|
||||
json_route_summary.values["end_point"] =
|
||||
facade->get_name_for_id(description_factory.summary.target_name_id);
|
||||
json_result.values["route_summary"] = json_route_summary;
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
osrm::json::Array json_via_points_array;
|
||||
osrm::json::Array json_first_coordinate;
|
||||
json_first_coordinate.values.push_back(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_first_coordinate.values.push_back(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_first_coordinate);
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
std::string tmp;
|
||||
osrm::json::Array json_coordinate;
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_coordinate);
|
||||
}
|
||||
json_result.values["via_points"] = json_via_points_array;
|
||||
|
||||
osrm::json::Array json_via_indices_array;
|
||||
|
||||
std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
|
||||
json_via_indices_array.values.insert(json_via_indices_array.values.end(),
|
||||
shortest_leg_end_indices.begin(),
|
||||
shortest_leg_end_indices.end());
|
||||
json_result.values["via_indices"] = json_via_indices_array;
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
json_result.values["found_alternative"] = osrm::json::True();
|
||||
BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
|
||||
alternate_description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.front());
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_description_factory.AppendSegment(current, path_data);
|
||||
}
|
||||
alternate_description_factory.SetEndSegment(
|
||||
raw_route.segment_end_coordinates.back().target_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.back());
|
||||
alternate_description_factory.Run(config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
osrm::json::Value alternate_geometry_string =
|
||||
alternate_description_factory.AppendGeometryString(config.encode_geometry);
|
||||
osrm::json::Array json_alternate_geometries_array;
|
||||
json_alternate_geometries_array.values.push_back(alternate_geometry_string);
|
||||
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
|
||||
}
|
||||
// Generate instructions for each alternative (simulated here)
|
||||
osrm::json::Array json_alt_instructions;
|
||||
osrm::json::Array json_current_alt_instructions;
|
||||
if (config.instructions)
|
||||
{
|
||||
json_current_alt_instructions = BuildTextualDescription(
|
||||
alternate_description_factory, alternative_path_segments);
|
||||
json_alt_instructions.values.push_back(json_current_alt_instructions);
|
||||
json_result.values["alternative_instructions"] = json_alt_instructions;
|
||||
}
|
||||
alternate_description_factory.BuildRouteSummary(
|
||||
alternate_description_factory.get_entire_length(),
|
||||
raw_route.alternative_path_length);
|
||||
|
||||
osrm::json::Object json_alternate_route_summary;
|
||||
osrm::json::Array json_alternate_route_summary_array;
|
||||
json_alternate_route_summary.values["total_distance"] =
|
||||
alternate_description_factory.summary.distance;
|
||||
json_alternate_route_summary.values["total_time"] =
|
||||
alternate_description_factory.summary.duration;
|
||||
json_alternate_route_summary.values["start_point"] =
|
||||
facade->get_name_for_id(alternate_description_factory.summary.source_name_id);
|
||||
json_alternate_route_summary.values["end_point"] =
|
||||
facade->get_name_for_id(alternate_description_factory.summary.target_name_id);
|
||||
json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
|
||||
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
|
||||
|
||||
std::vector<unsigned> const &alternate_leg_end_indices =
|
||||
alternate_description_factory.GetViaIndices();
|
||||
osrm::json::Array json_altenative_indices_array;
|
||||
json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
|
||||
alternate_leg_end_indices.begin(),
|
||||
alternate_leg_end_indices.end());
|
||||
json_result.values["alternative_indices"] = json_altenative_indices_array;
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["found_alternative"] = osrm::json::False();
|
||||
}
|
||||
|
||||
// Get Names for both routes
|
||||
RouteNames route_names =
|
||||
GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
|
||||
osrm::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;
|
||||
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
osrm::json::Array json_alternate_names_array;
|
||||
osrm::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.push_back(json_alternate_names);
|
||||
json_result.values["alternative_names"] = json_alternate_names_array;
|
||||
}
|
||||
|
||||
json_result.values["hint_data"] = BuildHintData(raw_route);
|
||||
}
|
||||
|
||||
inline osrm::json::Object BuildHintData(const InternalRouteResult &raw_route) const
|
||||
{
|
||||
osrm::json::Object json_hint_object;
|
||||
json_hint_object.values["checksum"] = facade->GetCheckSum();
|
||||
osrm::json::Array json_location_hint_array;
|
||||
std::string hint;
|
||||
for (const auto i : osrm::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.push_back(hint);
|
||||
json_hint_object.values["locations"] = json_location_hint_array;
|
||||
|
||||
return json_hint_object;
|
||||
}
|
||||
|
||||
inline osrm::json::Array
|
||||
BuildTextualDescription(const DescriptionFactory &description_factory,
|
||||
std::vector<Segment> &route_segments_list) const
|
||||
{
|
||||
osrm::json::Array json_instruction_array;
|
||||
// Segment information has following format:
|
||||
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
unsigned necessary_segments_running_index = 0;
|
||||
|
||||
struct RoundAbout
|
||||
{
|
||||
RoundAbout()
|
||||
: start_index(std::numeric_limits<int>::max()), name_id(INVALID_NAMEID),
|
||||
leave_at_exit(std::numeric_limits<int>::max())
|
||||
{
|
||||
}
|
||||
int start_index;
|
||||
unsigned name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
// Fetch data from Factory and generate a string from it.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
osrm::json::Array json_instruction_row;
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
{
|
||||
if (TurnInstruction::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string current_turn_instruction;
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
temp_instruction = std::to_string(
|
||||
cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
|
||||
current_turn_instruction += temp_instruction;
|
||||
current_turn_instruction += "-";
|
||||
temp_instruction = std::to_string(round_about.leave_at_exit + 1);
|
||||
current_turn_instruction += temp_instruction;
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(current_instruction));
|
||||
current_turn_instruction += temp_instruction;
|
||||
}
|
||||
json_instruction_row.values.push_back(current_turn_instruction);
|
||||
|
||||
json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id));
|
||||
json_instruction_row.values.push_back(std::round(segment.length));
|
||||
json_instruction_row.values.push_back(necessary_segments_running_index);
|
||||
json_instruction_row.values.push_back(std::round(segment.duration / 10.));
|
||||
json_instruction_row.values.push_back(
|
||||
std::to_string(static_cast<unsigned>(segment.length)) + "m");
|
||||
|
||||
// post turn bearing
|
||||
const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
|
||||
json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<unsigned>(round(post_turn_bearing_value)));
|
||||
|
||||
json_instruction_row.values.push_back(segment.travel_mode);
|
||||
|
||||
// pre turn bearing
|
||||
const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
|
||||
json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<unsigned>(round(pre_turn_bearing_value)));
|
||||
|
||||
json_instruction_array.values.push_back(json_instruction_row);
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
segment.name_id, static_cast<int>(segment.length),
|
||||
static_cast<unsigned>(route_segments_list.size()));
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
|
||||
osrm::json::Array json_last_instruction_row;
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
|
||||
json_last_instruction_row.values.push_back(temp_instruction);
|
||||
json_last_instruction_row.values.push_back("");
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back("0m");
|
||||
json_last_instruction_row.values.push_back(bearing::get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_last_instruction_row.values.push_back(bearing::get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_instruction_array.values.push_back(json_last_instruction_row);
|
||||
|
||||
return json_instruction_array;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
66
include/engine/guidance/segment_compression.hpp
Normal file
66
include/engine/guidance/segment_compression.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
||||
#define ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
||||
|
||||
#include "engine/segment_inforamtion.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
/*
|
||||
Simplify turn instructions
|
||||
Input :
|
||||
10. Turn left on B 36 for 20 km
|
||||
11. Continue on B 35; B 36 for 2 km
|
||||
12. Continue on B 36 for 13 km
|
||||
|
||||
Output:
|
||||
10. Turn left on B 36 for 35 km
|
||||
*/
|
||||
|
||||
inline void CombineSimilarSegments(std::vector<SegmentInformation> &segments)
|
||||
{
|
||||
// TODO: rework to check only end and start of string.
|
||||
// stl string is way to expensive
|
||||
// unsigned lastTurn = 0;
|
||||
// for(unsigned i = 1; i < path_description.size(); ++i) {
|
||||
// string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
|
||||
// if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
|
||||
// if(std::string::npos != string0.find(string1+";")
|
||||
// || std::string::npos != string0.find(";"+string1)
|
||||
// || std::string::npos != string0.find(string1+" ;")
|
||||
// || std::string::npos != string0.find("; "+string1)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
|
||||
// string1;
|
||||
// for(; lastTurn != i; ++lastTurn)
|
||||
// path_description[lastTurn].name_id = path_description[i].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// } else if(std::string::npos != string1.find(string0+";")
|
||||
// || std::string::npos != string1.find(";"+string0)
|
||||
// || std::string::npos != string1.find(string0+" ;")
|
||||
// || std::string::npos != string1.find("; "+string0)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
|
||||
// string0;
|
||||
// path_description[i].name_id = path_description[i-1].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
//
|
||||
}
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif //ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
326
include/engine/guidance/segment_list.hpp
Normal file
326
include/engine/guidance/segment_list.hpp
Normal file
@ -0,0 +1,326 @@
|
||||
#ifndef ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
|
||||
#define ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
|
||||
#include "engine/douglas_peucker.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "engine/segment_information.hpp"
|
||||
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
// transfers the internal edge based data structures to a more useable format
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
template <typename DataFacadeT> class SegmentList
|
||||
{
|
||||
public:
|
||||
using DataFacade = DataFacadeT;
|
||||
SegmentList(const InternalRouteResult &raw_route,
|
||||
const bool extract_alternative,
|
||||
const unsigned zoom_level,
|
||||
const bool allow_simplification,
|
||||
const DataFacade *facade);
|
||||
|
||||
const std::vector<std::uint32_t> &GetViaIndices() const;
|
||||
std::uint32_t GetDistance() const;
|
||||
std::uint32_t GetDuration() const;
|
||||
|
||||
const std::vector<SegmentInformation> &Get() const;
|
||||
|
||||
private:
|
||||
void InitRoute(const PhantomNode &phantom_node, const bool traversed_in_reverse);
|
||||
void AddLeg(const std::vector<PathData> &leg_data,
|
||||
const PhantomNode &target_node,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_leg,
|
||||
const DataFacade *facade);
|
||||
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &path_point);
|
||||
void Finalize(const bool extract_alternative,
|
||||
const InternalRouteResult &raw_route,
|
||||
const unsigned zoom_level,
|
||||
const bool allow_simplification);
|
||||
|
||||
// journey length in tenth of a second
|
||||
std::uint32_t total_distance;
|
||||
// journey distance in meter (TODO: verify)
|
||||
std::uint32_t total_duration;
|
||||
|
||||
// segments that are required to keep
|
||||
std::vector<std::uint32_t> via_indices;
|
||||
|
||||
// a list of node based segments
|
||||
std::vector<SegmentInformation> segments;
|
||||
};
|
||||
|
||||
template <typename DataFacadeT>
|
||||
SegmentList<DataFacadeT>::SegmentList(const InternalRouteResult &raw_route,
|
||||
const bool extract_alternative,
|
||||
const unsigned zoom_level,
|
||||
const bool allow_simplification,
|
||||
const DataFacade *facade)
|
||||
: total_distance(0), total_duration(0)
|
||||
{
|
||||
if (not raw_route.is_valid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (extract_alternative)
|
||||
{
|
||||
BOOST_ASSERT(raw_route.has_alternative());
|
||||
InitRoute(raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.front());
|
||||
AddLeg(raw_route.unpacked_alternative,
|
||||
raw_route.segment_end_coordinates.back().target_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.back(), false, facade);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitRoute(raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
for (std::size_t raw_index = 0; raw_index < raw_route.segment_end_coordinates.size();
|
||||
++raw_index)
|
||||
{
|
||||
AddLeg(raw_route.unpacked_path_segments[raw_index],
|
||||
raw_route.segment_end_coordinates[raw_index].target_phantom,
|
||||
raw_route.target_traversed_in_reverse[raw_index],
|
||||
raw_route.is_via_leg(raw_index), facade);
|
||||
}
|
||||
}
|
||||
|
||||
if (not allow_simplification)
|
||||
{
|
||||
// to prevent any simplifications, we mark all segments as necessary
|
||||
for (auto &segment : segments)
|
||||
{
|
||||
segment.necessary = true;
|
||||
}
|
||||
}
|
||||
|
||||
Finalize(extract_alternative, raw_route, zoom_level, allow_simplification);
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
void SegmentList<DataFacadeT>::InitRoute(const PhantomNode &node, const bool traversed_in_reverse)
|
||||
{
|
||||
const auto segment_duration =
|
||||
(traversed_in_reverse ? node.reverse_weight : node.forward_weight);
|
||||
const auto travel_mode =
|
||||
(traversed_in_reverse ? node.backward_travel_mode : node.forward_travel_mode);
|
||||
|
||||
AppendSegment(node.location, PathData(0, node.name_id, TurnInstruction::HeadOn,
|
||||
segment_duration, travel_mode));
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
void SegmentList<DataFacadeT>::AddLeg(const std::vector<PathData> &leg_data,
|
||||
const PhantomNode &target_node,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_leg,
|
||||
const DataFacade *facade)
|
||||
{
|
||||
for (const PathData &path_data : leg_data)
|
||||
{
|
||||
AppendSegment(facade->GetCoordinateOfNode(path_data.node), path_data);
|
||||
}
|
||||
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight);
|
||||
const TravelMode travel_mode =
|
||||
(traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode);
|
||||
segments.emplace_back(target_node.location, target_node.name_id, segment_duration, 0.f,
|
||||
is_via_leg ? TurnInstruction::ReachViaLocation : TurnInstruction::NoTurn,
|
||||
true, true, travel_mode);
|
||||
}
|
||||
|
||||
template <typename DataFacadeT> std::uint32_t SegmentList<DataFacadeT>::GetDistance() const
|
||||
{
|
||||
return total_distance;
|
||||
}
|
||||
template <typename DataFacadeT> std::uint32_t SegmentList<DataFacadeT>::GetDuration() const
|
||||
{
|
||||
return total_duration;
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
std::vector<std::uint32_t> const &SegmentList<DataFacadeT>::GetViaIndices() const
|
||||
{
|
||||
return via_indices;
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
std::vector<SegmentInformation> const &SegmentList<DataFacadeT>::Get() const
|
||||
{
|
||||
return segments;
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
void SegmentList<DataFacadeT>::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
const PathData &path_point)
|
||||
{
|
||||
// if the start location is on top of a node, the first movement might be zero-length,
|
||||
// in which case we dont' add a new description, but instead update the existing one
|
||||
if ((1 == segments.size()) and (segments.front().location == coordinate))
|
||||
{
|
||||
if (path_point.segment_duration > 0)
|
||||
{
|
||||
segments.front().name_id = path_point.name_id;
|
||||
segments.front().travel_mode = path_point.travel_mode;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure mode changes are announced, even when there otherwise is no turn
|
||||
const auto getTurn = [](const PathData &path_point, const TravelMode previous_mode)
|
||||
{
|
||||
if (TurnInstruction::NoTurn == path_point.turn_instruction and
|
||||
previous_mode != path_point.travel_mode and path_point.segment_duration > 0)
|
||||
{
|
||||
return TurnInstruction::GoStraight;
|
||||
}
|
||||
return path_point.turn_instruction;
|
||||
};
|
||||
|
||||
// TODO check why we require .front() here
|
||||
const auto turn = segments.size() ? getTurn(path_point, segments.front().travel_mode)
|
||||
: path_point.turn_instruction;
|
||||
|
||||
segments.emplace_back(coordinate, path_point.name_id, path_point.segment_duration, 0.f, turn,
|
||||
path_point.travel_mode);
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
void SegmentList<DataFacadeT>::Finalize(const bool extract_alternative,
|
||||
const InternalRouteResult &raw_route,
|
||||
const unsigned zoom_level,
|
||||
const bool allow_simplification)
|
||||
{
|
||||
if (segments.empty())
|
||||
return;
|
||||
|
||||
segments[0].length = 0.f;
|
||||
for (const auto i : osrm::irange<std::size_t>(1, segments.size()))
|
||||
{
|
||||
// move down names by one, q&d hack
|
||||
segments[i - 1].name_id = segments[i].name_id;
|
||||
segments[i].length = coordinate_calculation::greatCircleDistance(segments[i - 1].location,
|
||||
segments[i].location);
|
||||
}
|
||||
|
||||
float segment_length = 0.;
|
||||
EdgeWeight segment_duration = 0;
|
||||
std::size_t segment_start_index = 0;
|
||||
|
||||
double path_length = 0;
|
||||
|
||||
for (const auto i : osrm::irange<std::size_t>(1, segments.size()))
|
||||
{
|
||||
path_length += segments[i].length;
|
||||
segment_length += segments[i].length;
|
||||
segment_duration += segments[i].duration;
|
||||
segments[segment_start_index].length = segment_length;
|
||||
segments[segment_start_index].duration = segment_duration;
|
||||
|
||||
if (TurnInstruction::NoTurn != segments[i].turn_instruction)
|
||||
{
|
||||
BOOST_ASSERT(segments[i].necessary);
|
||||
segment_length = 0;
|
||||
segment_duration = 0;
|
||||
segment_start_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
total_distance = static_cast<std::uint32_t>(std::round(path_length));
|
||||
total_duration = static_cast<std::uint32_t>(std::round(
|
||||
(extract_alternative ? raw_route.alternative_path_length : raw_route.shortest_path_length) /
|
||||
10.));
|
||||
|
||||
auto start_phantom = raw_route.segment_end_coordinates.front().source_phantom;
|
||||
auto target_phantom = raw_route.segment_end_coordinates.back().target_phantom;
|
||||
|
||||
// Post-processing to remove empty or nearly empty path segments
|
||||
if (segments.size() > 2 && std::numeric_limits<float>::epsilon() > segments.back().length &&
|
||||
!(segments.end() - 2)->is_via_location)
|
||||
{
|
||||
segments.pop_back();
|
||||
segments.back().necessary = true;
|
||||
segments.back().turn_instruction = TurnInstruction::NoTurn;
|
||||
target_phantom.name_id =
|
||||
(segments.end() - 2)
|
||||
->name_id; // TODO check whether this -2 is desired after the pop-back
|
||||
}
|
||||
|
||||
if (segments.size() > 2 && std::numeric_limits<float>::epsilon() > segments.front().length &&
|
||||
!(segments.begin() + 1)->is_via_location)
|
||||
{
|
||||
segments.erase(segments.begin());
|
||||
segments.front().turn_instruction = TurnInstruction::HeadOn;
|
||||
segments.front().necessary = true;
|
||||
start_phantom.name_id = segments.front().name_id;
|
||||
}
|
||||
|
||||
if (allow_simplification)
|
||||
{
|
||||
DouglasPeucker polyline_generalizer;
|
||||
polyline_generalizer.Run(segments.begin(), segments.end(), zoom_level);
|
||||
}
|
||||
|
||||
std::uint32_t necessary_segments = 0; // a running index that counts the necessary pieces
|
||||
via_indices.push_back(0);
|
||||
const auto markNecessarySegments = [this, &necessary_segments](SegmentInformation &first,
|
||||
const SegmentInformation &second)
|
||||
{
|
||||
if (!first.necessary)
|
||||
return;
|
||||
|
||||
// mark the end of a leg (of several segments)
|
||||
if (first.is_via_location)
|
||||
via_indices.push_back(necessary_segments);
|
||||
|
||||
const double post_turn_bearing =
|
||||
coordinate_calculation::bearing(first.location, second.location);
|
||||
const double pre_turn_bearing =
|
||||
coordinate_calculation::bearing(second.location, first.location);
|
||||
first.post_turn_bearing = static_cast<short>(post_turn_bearing * 10);
|
||||
first.pre_turn_bearing = static_cast<short>(pre_turn_bearing * 10);
|
||||
|
||||
++necessary_segments;
|
||||
};
|
||||
|
||||
// calculate which segments are necessary and update segments for bearings
|
||||
osrm::for_each_pair(segments, markNecessarySegments);
|
||||
via_indices.push_back(necessary_segments);
|
||||
|
||||
BOOST_ASSERT(via_indices.size() >= 2);
|
||||
}
|
||||
|
||||
template <typename DataFacadeT>
|
||||
SegmentList<DataFacadeT> MakeSegmentList(const InternalRouteResult &raw_route,
|
||||
const bool extract_alternative,
|
||||
const unsigned zoom_level,
|
||||
const bool allow_simplification,
|
||||
const DataFacadeT *facade)
|
||||
{
|
||||
return SegmentList<DataFacadeT>(raw_route, extract_alternative, zoom_level,
|
||||
allow_simplification, facade);
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
|
134
include/engine/guidance/textual_route_annotation.hpp
Normal file
134
include/engine/guidance/textual_route_annotation.hpp
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef ENGINE_GUIDANCE_TEXTUAL_ROUTE_ANNOTATIONS_HPP_
|
||||
#define ENGINE_GUIDANCE_TEXTUAL_ROUTE_ANNOTATIONS_HPP_
|
||||
|
||||
#include "engine/segment_information.hpp"
|
||||
#include "engine/guidance/segment_list.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "osrm/json_container.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/cast.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
template< typename DataFacadeT >
|
||||
inline osrm::json::Array
|
||||
AnnotateRoute(const std::vector<SegmentInformation> &route_segments, DataFacadeT* facade)
|
||||
{
|
||||
osrm::json::Array json_instruction_array;
|
||||
if( route_segments.empty() )
|
||||
return json_instruction_array;
|
||||
// Segment information has following format:
|
||||
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
std::int32_t necessary_segments_running_index = 0;
|
||||
|
||||
struct RoundAbout
|
||||
{
|
||||
std::int32_t start_index;
|
||||
std::uint32_t name_id;
|
||||
std::int32_t leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
round_about = {std::numeric_limits<std::int32_t>::max(), 0, 0};
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
//Generate annotations for every segment
|
||||
for (const SegmentInformation &segment : route_segments)
|
||||
{
|
||||
osrm::json::Array json_instruction_row;
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
{
|
||||
if (TurnInstruction::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string current_turn_instruction;
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
|
||||
current_turn_instruction += temp_instruction;
|
||||
current_turn_instruction += "-";
|
||||
temp_instruction = std::to_string(round_about.leave_at_exit + 1);
|
||||
current_turn_instruction += temp_instruction;
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(current_instruction));
|
||||
current_turn_instruction += temp_instruction;
|
||||
}
|
||||
json_instruction_row.values.emplace_back(std::move(current_turn_instruction));
|
||||
|
||||
json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id));
|
||||
json_instruction_row.values.push_back(std::round(segment.length));
|
||||
json_instruction_row.values.push_back(necessary_segments_running_index);
|
||||
json_instruction_row.values.push_back(std::round(segment.duration / 10.));
|
||||
json_instruction_row.values.push_back(
|
||||
std::to_string(static_cast<std::uint32_t>(segment.length)) + "m");
|
||||
|
||||
// post turn bearing
|
||||
const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
|
||||
json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<std::uint32_t>(std::round(post_turn_bearing_value)));
|
||||
|
||||
json_instruction_row.values.push_back(segment.travel_mode);
|
||||
|
||||
// pre turn bearing
|
||||
const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
|
||||
json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<std::uint32_t>(std::round(pre_turn_bearing_value)));
|
||||
|
||||
json_instruction_array.values.push_back(json_instruction_row);
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
|
||||
osrm::json::Array json_last_instruction_row;
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
|
||||
json_last_instruction_row.values.emplace_back( std::move(temp_instruction));
|
||||
json_last_instruction_row.values.push_back("");
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back("0m");
|
||||
json_last_instruction_row.values.push_back(bearing::get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_last_instruction_row.values.push_back(bearing::get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_instruction_array.values.emplace_back(std::move(json_last_instruction_row));
|
||||
|
||||
return json_instruction_array;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif
|
@ -46,6 +46,10 @@ struct InternalRouteResult
|
||||
int shortest_path_length;
|
||||
int alternative_path_length;
|
||||
|
||||
bool is_valid() const { return INVALID_EDGE_WEIGHT != shortest_path_length; }
|
||||
|
||||
bool has_alternative() const { return INVALID_EDGE_WEIGHT != alternative_path_length; }
|
||||
|
||||
bool is_via_leg(const std::size_t leg) const
|
||||
{
|
||||
return (leg != unpacked_path_segments.size() - 1);
|
||||
|
@ -4,21 +4,15 @@
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
|
||||
#include "engine/object_encoder.hpp"
|
||||
#include "contractor/query_edge.hpp"
|
||||
#include "engine/search_engine.hpp"
|
||||
#include "engine/descriptors/descriptor_base.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
#include "util/make_unique.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
|
||||
#include "util/json_renderer.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <string>
|
||||
|
@ -6,8 +6,9 @@
|
||||
#include "engine/map_matching/bayes_classifier.hpp"
|
||||
#include "engine/object_encoder.hpp"
|
||||
#include "engine/search_engine.hpp"
|
||||
#include "engine/descriptors/descriptor_base.hpp"
|
||||
#include "engine/descriptors/json_descriptor.hpp"
|
||||
#include "engine/guidance/textual_route_annotation.hpp"
|
||||
#include "engine/guidance/segment_list.hpp"
|
||||
#include "engine/api_response_generator.hpp"
|
||||
#include "engine/routing_algorithms/map_matching.hpp"
|
||||
#include "util/compute_angle.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
@ -185,55 +186,37 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
||||
subtrace.values["confidence"] = sub.confidence;
|
||||
}
|
||||
|
||||
JSONDescriptor<DataFacadeT> json_descriptor(facade);
|
||||
json_descriptor.SetConfig(route_parameters);
|
||||
auto response_generator = osrm::engine::MakeApiResponseGenerator(facade);
|
||||
|
||||
subtrace.values["hint_data"] = json_descriptor.BuildHintData(raw_route);
|
||||
subtrace.values["hint_data"] = response_generator.BuildHintData(raw_route);
|
||||
|
||||
if (route_parameters.geometry || route_parameters.print_instructions)
|
||||
{
|
||||
DescriptionFactory factory;
|
||||
FixedPointCoordinate current_coordinate;
|
||||
factory.SetStartSegment(raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
for (const auto i :
|
||||
osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
|
||||
{
|
||||
for (const PathData &path_data : raw_route.unpacked_path_segments[i])
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
factory.AppendSegment(current_coordinate, path_data);
|
||||
}
|
||||
factory.SetEndSegment(raw_route.segment_end_coordinates[i].target_phantom,
|
||||
raw_route.target_traversed_in_reverse[i],
|
||||
raw_route.is_via_leg(i));
|
||||
}
|
||||
|
||||
factory.Run(route_parameters.zoom_level);
|
||||
|
||||
// we need because we don't run path simplification
|
||||
for (auto &segment : factory.path_description)
|
||||
{
|
||||
segment.necessary = true;
|
||||
}
|
||||
using SegmentList = osrm::engine::guidance::SegmentList<DataFacadeT>;
|
||||
//Passing false to extract_alternative extracts the route.
|
||||
const constexpr bool EXTRACT_ROUTE = false;
|
||||
// by passing false to segment_list, we skip the douglas peucker simplification
|
||||
// and mark all segments as necessary within the generation process
|
||||
const constexpr bool NO_ROUTE_SIMPLIFICATION = false;
|
||||
SegmentList segment_list(raw_route, EXTRACT_ROUTE, route_parameters.zoom_level,
|
||||
NO_ROUTE_SIMPLIFICATION, facade);
|
||||
|
||||
if (route_parameters.geometry)
|
||||
{
|
||||
subtrace.values["geometry"] =
|
||||
factory.AppendGeometryString(route_parameters.compression);
|
||||
response_generator.GetGeometry(route_parameters.compression, segment_list);
|
||||
}
|
||||
|
||||
if (route_parameters.print_instructions)
|
||||
{
|
||||
std::vector<typename JSONDescriptor<DataFacadeT>::Segment> temp_segments;
|
||||
subtrace.values["instructions"] =
|
||||
json_descriptor.BuildTextualDescription(factory, temp_segments);
|
||||
osrm::engine::guidance::AnnotateRoute<DataFacadeT>(
|
||||
segment_list.Get(), facade);
|
||||
}
|
||||
|
||||
factory.BuildRouteSummary(factory.get_entire_length(), raw_route.shortest_path_length);
|
||||
osrm::json::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = factory.summary.duration;
|
||||
json_route_summary.values["total_distance"] = segment_list.GetDistance();
|
||||
json_route_summary.values["total_time"] = segment_list.GetDuration();
|
||||
subtrace.values["route_summary"] = json_route_summary;
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,8 @@
|
||||
#define NEAREST_HPP
|
||||
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <string>
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
|
||||
#include "util/json_renderer.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <string>
|
||||
|
@ -9,17 +9,12 @@
|
||||
#include "engine/trip/trip_farthest_insertion.hpp"
|
||||
#include "engine/trip/trip_brute_force.hpp"
|
||||
#include "engine/search_engine.hpp"
|
||||
#include "util/matrix_graph_wrapper.hpp" // wrapper to use tarjan
|
||||
// scc on dist table
|
||||
#include "engine/descriptors/descriptor_base.hpp" // to make json output
|
||||
#include "engine/descriptors/json_descriptor.hpp" // to make json output
|
||||
#include "util/matrix_graph_wrapper.hpp" // wrapper to use tarjan scc on dist table
|
||||
#include "engine/api_response_generator.hpp"
|
||||
#include "util/make_unique.hpp"
|
||||
#include "util/timing_util.hpp" // to time runtime
|
||||
//#include "util/simple_logger.hpp" // for logging output
|
||||
#include "util/dist_table_wrapper.hpp" // to access the dist
|
||||
// table more easily
|
||||
|
||||
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
@ -284,7 +279,6 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
|
||||
std::vector<std::vector<NodeID>> route_result;
|
||||
route_result.reserve(scc.GetNumberOfComponents());
|
||||
TIMER_START(TRIP_TIMER);
|
||||
// run Trip computation for every SCC
|
||||
for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
|
||||
{
|
||||
@ -337,24 +331,20 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
comp_route.push_back(ComputeRoute(phantom_node_list, route_parameters, elem));
|
||||
}
|
||||
|
||||
TIMER_STOP(TRIP_TIMER);
|
||||
|
||||
// prepare JSON output
|
||||
// create a json object for every trip
|
||||
osrm::json::Array trip;
|
||||
for (std::size_t i = 0; i < route_result.size(); ++i)
|
||||
{
|
||||
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor =
|
||||
osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
|
||||
descriptor->SetConfig(route_parameters);
|
||||
|
||||
osrm::json::Object scc_trip;
|
||||
|
||||
// annotate comp_route[i] as a json trip
|
||||
auto generator = osrm::engine::MakeApiResponseGenerator(facade);
|
||||
generator.DescribeRoute(route_parameters, comp_route[i], scc_trip);
|
||||
|
||||
// set permutation output
|
||||
SetLocPermutationOutput(route_result[i], scc_trip);
|
||||
// set viaroute output
|
||||
descriptor->Run(comp_route[i], scc_trip);
|
||||
|
||||
trip.values.push_back(std::move(scc_trip));
|
||||
}
|
||||
|
||||
|
@ -3,17 +3,14 @@
|
||||
|
||||
#include "engine/plugins/plugin_base.hpp"
|
||||
|
||||
#include "engine/api_response_generator.hpp"
|
||||
#include "engine/object_encoder.hpp"
|
||||
#include "engine/search_engine.hpp"
|
||||
#include "engine/descriptors/descriptor_base.hpp"
|
||||
#include "engine/descriptors/gpx_descriptor.hpp"
|
||||
#include "engine/descriptors/json_descriptor.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_renderer.hpp"
|
||||
#include "util/make_unique.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
@ -26,7 +23,6 @@
|
||||
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
DescriptorTable descriptor_table;
|
||||
std::string descriptor_string;
|
||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
DataFacadeT *facade;
|
||||
@ -38,10 +34,6 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
max_locations_viaroute(max_locations_viaroute)
|
||||
{
|
||||
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
|
||||
|
||||
descriptor_table.emplace("json", 0);
|
||||
descriptor_table.emplace("gpx", 1);
|
||||
// descriptor_table.emplace("geojson", 2);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
@ -139,22 +131,8 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
|
||||
bool no_route = INVALID_EDGE_WEIGHT == raw_route.shortest_path_length;
|
||||
|
||||
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
|
||||
switch (descriptor_table.get_id(route_parameters.output_format))
|
||||
{
|
||||
case 1:
|
||||
descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
// case 2:
|
||||
// descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
default:
|
||||
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
}
|
||||
|
||||
descriptor->SetConfig(route_parameters);
|
||||
descriptor->Run(raw_route, json_result);
|
||||
auto generator = osrm::engine::MakeApiResponseGenerator(facade);
|
||||
generator.DescribeRoute(route_parameters, raw_route, json_result);
|
||||
|
||||
// we can only know this after the fact, different SCC ids still
|
||||
// allow for connection in one direction.
|
||||
|
@ -23,6 +23,7 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
|
||||
const unsigned blocked_name_id) const
|
||||
{
|
||||
SegmentT result_segment;
|
||||
result_segment.name_id = blocked_name_id; //make sure we get a valid name
|
||||
result_segment.length = 0;
|
||||
|
||||
for (const SegmentT &segment : segment_list)
|
||||
@ -123,11 +124,13 @@ template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
|
||||
route_names.shortest_path_name_1 = facade->get_name_for_id(shortest_segment_1.name_id);
|
||||
route_names.shortest_path_name_2 = facade->get_name_for_id(shortest_segment_2.name_id);
|
||||
|
||||
route_names.alternative_path_name_1 =
|
||||
facade->get_name_for_id(alternative_segment_1.name_id);
|
||||
route_names.alternative_path_name_2 =
|
||||
facade->get_name_for_id(alternative_segment_2.name_id);
|
||||
|
||||
if (not alternative_path_segments.empty())
|
||||
{
|
||||
route_names.alternative_path_name_1 =
|
||||
facade->get_name_for_id(alternative_segment_1.name_id);
|
||||
route_names.alternative_path_name_2 =
|
||||
facade->get_name_for_id(alternative_segment_2.name_id);
|
||||
}
|
||||
return route_names;
|
||||
}
|
||||
};
|
||||
|
@ -1,224 +0,0 @@
|
||||
#include "engine/descriptors/description_factory.hpp"
|
||||
|
||||
#include "engine/polyline_formatter.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "util/container.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
DescriptionFactory::DescriptionFactory() : entire_length(0) { via_indices.push_back(0); }
|
||||
|
||||
std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
|
||||
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
|
||||
{
|
||||
start_phantom = source;
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? source.reverse_weight : source.forward_weight);
|
||||
const TravelMode travel_mode =
|
||||
(traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
|
||||
AppendSegment(source.location, PathData(0, source.name_id, TurnInstruction::HeadOn,
|
||||
segment_duration, travel_mode));
|
||||
BOOST_ASSERT(path_description.back().duration == segment_duration);
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode &target,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_location)
|
||||
{
|
||||
target_phantom = target;
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? target.reverse_weight : target.forward_weight);
|
||||
const TravelMode travel_mode =
|
||||
(traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
|
||||
path_description.emplace_back(target.location, target.name_id, segment_duration, 0.f,
|
||||
is_via_location ? TurnInstruction::ReachViaLocation
|
||||
: TurnInstruction::NoTurn,
|
||||
true, true, travel_mode);
|
||||
BOOST_ASSERT(path_description.back().duration == segment_duration);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
const PathData &path_point)
|
||||
{
|
||||
// if the start location is on top of a node, the first movement might be zero-length,
|
||||
// in which case we dont' add a new description, but instead update the existing one
|
||||
if ((1 == path_description.size()) && (path_description.front().location == coordinate))
|
||||
{
|
||||
if (path_point.segment_duration > 0)
|
||||
{
|
||||
path_description.front().name_id = path_point.name_id;
|
||||
path_description.front().travel_mode = path_point.travel_mode;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure mode changes are announced, even when there otherwise is no turn
|
||||
const TurnInstruction turn = [&]() -> TurnInstruction
|
||||
{
|
||||
if (TurnInstruction::NoTurn == path_point.turn_instruction &&
|
||||
path_description.front().travel_mode != path_point.travel_mode &&
|
||||
path_point.segment_duration > 0)
|
||||
{
|
||||
return TurnInstruction::GoStraight;
|
||||
}
|
||||
return path_point.turn_instruction;
|
||||
}();
|
||||
|
||||
path_description.emplace_back(coordinate, path_point.name_id, path_point.segment_duration, 0.f,
|
||||
turn, path_point.travel_mode);
|
||||
}
|
||||
|
||||
osrm::json::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
|
||||
{
|
||||
if (return_encoded)
|
||||
{
|
||||
return PolylineFormatter().printEncodedString(path_description);
|
||||
}
|
||||
return PolylineFormatter().printUnencodedString(path_description);
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
|
||||
{
|
||||
summary.source_name_id = start_phantom.name_id;
|
||||
summary.target_name_id = target_phantom.name_id;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
|
||||
void DescriptionFactory::Run(const unsigned zoom_level)
|
||||
{
|
||||
if (path_description.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/** starts at index 1 */
|
||||
path_description[0].length = 0.f;
|
||||
for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
|
||||
{
|
||||
// move down names by one, q&d hack
|
||||
path_description[i - 1].name_id = path_description[i].name_id;
|
||||
path_description[i].length = coordinate_calculation::greatCircleDistance(
|
||||
path_description[i - 1].location, path_description[i].location);
|
||||
}
|
||||
|
||||
/*Simplify turn instructions
|
||||
Input :
|
||||
10. Turn left on B 36 for 20 km
|
||||
11. Continue on B 35; B 36 for 2 km
|
||||
12. Continue on B 36 for 13 km
|
||||
|
||||
becomes:
|
||||
10. Turn left on B 36 for 35 km
|
||||
*/
|
||||
// TODO: rework to check only end and start of string.
|
||||
// stl string is way to expensive
|
||||
|
||||
// unsigned lastTurn = 0;
|
||||
// for(unsigned i = 1; i < path_description.size(); ++i) {
|
||||
// string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
|
||||
// if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
|
||||
// if(std::string::npos != string0.find(string1+";")
|
||||
// || std::string::npos != string0.find(";"+string1)
|
||||
// || std::string::npos != string0.find(string1+" ;")
|
||||
// || std::string::npos != string0.find("; "+string1)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
|
||||
// string1;
|
||||
// for(; lastTurn != i; ++lastTurn)
|
||||
// path_description[lastTurn].name_id = path_description[i].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// } else if(std::string::npos != string1.find(string0+";")
|
||||
// || std::string::npos != string1.find(";"+string0)
|
||||
// || std::string::npos != string1.find(string0+" ;")
|
||||
// || std::string::npos != string1.find("; "+string0)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
|
||||
// string0;
|
||||
// path_description[i].name_id = path_description[i-1].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
//
|
||||
|
||||
float segment_length = 0.;
|
||||
EdgeWeight segment_duration = 0;
|
||||
std::size_t segment_start_index = 0;
|
||||
|
||||
for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
|
||||
{
|
||||
entire_length += path_description[i].length;
|
||||
segment_length += path_description[i].length;
|
||||
segment_duration += path_description[i].duration;
|
||||
path_description[segment_start_index].length = segment_length;
|
||||
path_description[segment_start_index].duration = segment_duration;
|
||||
|
||||
if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
|
||||
{
|
||||
BOOST_ASSERT(path_description[i].necessary);
|
||||
segment_length = 0;
|
||||
segment_duration = 0;
|
||||
segment_start_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Post-processing to remove empty or nearly empty path segments
|
||||
if (path_description.size() > 2 &&
|
||||
std::numeric_limits<float>::epsilon() > path_description.back().length &&
|
||||
!(path_description.end() - 2)->is_via_location)
|
||||
{
|
||||
path_description.pop_back();
|
||||
path_description.back().necessary = true;
|
||||
path_description.back().turn_instruction = TurnInstruction::NoTurn;
|
||||
target_phantom.name_id = (path_description.end() - 2)->name_id;
|
||||
}
|
||||
|
||||
if (path_description.size() > 2 &&
|
||||
std::numeric_limits<float>::epsilon() > path_description.front().length &&
|
||||
!(path_description.begin() + 1)->is_via_location)
|
||||
{
|
||||
path_description.erase(path_description.begin());
|
||||
path_description.front().turn_instruction = TurnInstruction::HeadOn;
|
||||
path_description.front().necessary = true;
|
||||
start_phantom.name_id = path_description.front().name_id;
|
||||
}
|
||||
|
||||
// Generalize poly line
|
||||
polyline_generalizer.Run(path_description.begin(), path_description.end(), zoom_level);
|
||||
|
||||
// fix what needs to be fixed else
|
||||
unsigned necessary_segments = 0; // a running index that counts the necessary pieces
|
||||
osrm::for_each_pair(path_description,
|
||||
[&](SegmentInformation &first, const SegmentInformation &second)
|
||||
{
|
||||
if (!first.necessary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (first.is_via_location)
|
||||
{ // mark the end of a leg (of several segments)
|
||||
via_indices.push_back(necessary_segments);
|
||||
}
|
||||
|
||||
const double post_turn_bearing =
|
||||
coordinate_calculation::bearing(first.location, second.location);
|
||||
const double pre_turn_bearing =
|
||||
coordinate_calculation::bearing(second.location, first.location);
|
||||
first.post_turn_bearing = static_cast<short>(post_turn_bearing * 10);
|
||||
first.pre_turn_bearing = static_cast<short>(pre_turn_bearing * 10);
|
||||
|
||||
++necessary_segments;
|
||||
});
|
||||
|
||||
via_indices.push_back(necessary_segments);
|
||||
BOOST_ASSERT(via_indices.size() >= 2);
|
||||
return;
|
||||
}
|
Loading…
Reference in New Issue
Block a user