Add viaroute suport for new API

This commit is contained in:
Patrick Niklaus
2016-01-28 16:28:44 +01:00
parent 2f3b4373f9
commit 68eeb20c5c
87 changed files with 3352 additions and 2098 deletions
+70
View File
@@ -0,0 +1,70 @@
#ifndef ENGINE_API_BASE_API_HPP
#define ENGINE_API_BASE_API_HPP
#include "engine/api/base_parameters.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/api/json_factory.hpp"
#include "engine/hint.hpp"
#include <boost/assert.hpp>
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
namespace detail
{
template <typename ChildT> class BaseAPI_
{
public:
BaseAPI_(const datafacade::BaseDataFacade &facade_, const BaseParameters &parameters_)
: facade(facade_), parameters(parameters_)
{
}
virtual util::json::Array
MakeWaypoints(const std::vector<PhantomNodes> &segment_end_coordinates) const
{
BOOST_ASSERT(parameters.coordinates.size() > 0);
BOOST_ASSERT(parameters.coordinates.size() == segment_end_coordinates.size() + 1);
util::json::Array waypoints;
waypoints.values.resize(parameters.coordinates.size());
waypoints.values[0] = MakeWaypoint(parameters.coordinates.front(),
segment_end_coordinates.front().source_phantom);
auto coord_iter = std::next(parameters.coordinates.begin());
auto out_iter = std::next(waypoints.values.begin());
for (const auto &phantoms : segment_end_coordinates)
{
*out_iter++ = MakeWaypoint(*coord_iter++, phantoms.target_phantom);
}
return waypoints;
}
protected:
virtual util::json::Object MakeWaypoint(const util::FixedPointCoordinate input_coordinate,
const PhantomNode &phantom) const
{
return json::makeWaypoint(phantom.location, facade.get_name_for_id(phantom.name_id),
Hint{input_coordinate, phantom, facade.GetCheckSum()});
}
const datafacade::BaseDataFacade &facade;
const BaseParameters &parameters;
};
}
// Only expose non-templated version
using BaseAPI = detail::BaseAPI_<std::true_type>;
}
}
}
#endif
+51
View File
@@ -0,0 +1,51 @@
#ifndef ENGINE_API_BASE_PARAMETERS_HPP
#define ENGINE_API_BASE_PARAMETERS_HPP
#include "engine/hint.hpp"
#include "util/coordinate.hpp"
#include <boost/optional.hpp>
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
struct BaseParameters
{
struct Bearing
{
short bearing;
short range;
};
std::vector<util::FixedPointCoordinate> coordinates;
std::vector<boost::optional<Hint>> hints;
std::vector<boost::optional<double>> radiuses;
std::vector<boost::optional<Bearing>> bearings;
// FIXME add validation for invalid bearing values
bool IsValid() const
{
return (hints.empty() || hints.size() == coordinates.size()) &&
(bearings.empty() || bearings.size() == coordinates.size()) &&
(radiuses.empty() || radiuses.size() == coordinates.size());
}
};
inline bool operator==(const BaseParameters::Bearing lhs, const BaseParameters::Bearing rhs)
{
return lhs.bearing == rhs.bearing && lhs.range == rhs.range;
}
inline bool operator!=(const BaseParameters::Bearing lhs, const BaseParameters::Bearing rhs)
{
return !(lhs == rhs);
}
}
}
}
#endif // ROUTE_PARAMETERS_HPP
+90
View File
@@ -0,0 +1,90 @@
#ifndef ENGINE_RESPONSE_OBJECTS_HPP_
#define ENGINE_RESPONSE_OBJECTS_HPP_
#include "extractor/turn_instructions.hpp"
#include "extractor/travel_mode.hpp"
#include "engine/polyline_compressor.hpp"
#include "util/coordinate.hpp"
#include "util/json_container.hpp"
#include <boost/optional.hpp>
#include <string>
#include <algorithm>
#include <vector>
namespace osrm
{
namespace engine
{
struct Hint;
namespace guidance
{
class RouteLeg;
class RouteStep;
class StepManeuver;
class Route;
class LegGeometry;
}
namespace api
{
namespace json
{
namespace detail
{
std::string instructionToString(extractor::TurnInstruction instruction);
util::json::Array coordinateToLonLat(const FixedPointCoordinate &coordinate);
std::string modeToString(const extractor::TravelMode mode);
} // namespace detail
template <typename ForwardIter> util::json::String makePolyline(ForwardIter begin, ForwardIter end)
{
util::json::String polyline;
polyline.value = encodePolyline(begin, end);
return polyline;
}
template <typename ForwardIter>
util::json::Object makeGeoJSONLineString(ForwardIter begin, ForwardIter end)
{
util::json::Object geojson;
geojson.values["type"] = "LineString";
util::json::Array coordinates;
std::transform(begin, end, std::back_inserter(coordinates.values),
[](const util::FixedPointCoordinate loc)
{
return detail::coordinateToLonLat(loc);
});
geojson.values["coordinates"] = std::move(coordinates);
return geojson;
}
util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver);
util::json::Object makeRouteStep(guidance::RouteStep &&step,
boost::optional<util::json::Value> geometry);
util::json::Object makeRoute(const guidance::Route &route,
util::json::Array &&legs,
boost::optional<util::json::Value> geometry);
util::json::Object
makeWaypoint(const FixedPointCoordinate location, std::string &&way_name, const Hint &hint);
util::json::Object makeRouteLeg(guidance::RouteLeg &&leg, util::json::Array &&steps);
util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> &&legs,
const std::vector<guidance::LegGeometry> &leg_geometries);
}
}
} // namespace engine
} // namespace osrm
#endif // ENGINE_GUIDANCE_API_RESPONSE_GENERATOR_HPP_
+25
View File
@@ -0,0 +1,25 @@
#ifndef ENGINE_API_MATCH_PARAMETERS_HPP
#define ENGINE_API_MATCH_PARAMETERS_HPP
#include "engine/api/route_parameters.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
struct MatchParameters : public RouteParameters
{
std::vector<unsigned> timestamps;
bool IsValid() const;
};
}
}
}
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef ENGINE_API_NEAREST_PARAMETERS_HPP
#define ENGINE_API_NEAREST_PARAMETERS_HPP
#include "engine/api/base_parameters.hpp"
namespace osrm
{
namespace engine
{
namespace api
{
struct NearestParameters : public BaseParameters
{
unsigned number_of_results;
bool IsValid() const;
};
}
}
}
#endif // ROUTE_PARAMETERS_HPP
+135
View File
@@ -0,0 +1,135 @@
#ifndef ENGINE_API_ROUTE_HPP
#define ENGINE_API_ROUTE_HPP
#include "engine/api/base_api.hpp"
#include "engine/api/route_parameters.hpp"
#include "engine/api/json_factory.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/guidance/assemble_leg.hpp"
#include "engine/guidance/assemble_route.hpp"
#include "engine/guidance/assemble_geometry.hpp"
#include "engine/guidance/assemble_overview.hpp"
#include "engine/guidance/assemble_steps.hpp"
#include "engine/internal_route_result.hpp"
#include "util/integer_range.hpp"
namespace osrm
{
namespace engine
{
namespace api
{
namespace detail
{
template <typename ChildT> class RouteAPI_ : public BaseAPI_<RouteAPI_<ChildT>>
{
using BaseT = BaseAPI_<RouteAPI_<ChildT>>;
public:
RouteAPI_(const datafacade::BaseDataFacade &facade_, const RouteParameters &parameters_)
: BaseT(facade_, parameters_), parameters(parameters_)
{
}
virtual void MakeResponse(const InternalRouteResult &raw_route,
util::json::Object &response) const
{
auto number_of_routes = raw_route.has_alternative() ? 2UL : 1UL;
util::json::Array routes;
routes.values.resize(number_of_routes);
routes.values[0] =
MakeRoute(raw_route.segment_end_coordinates, raw_route.unpacked_path_segments,
raw_route.source_traversed_in_reverse, raw_route.target_traversed_in_reverse);
if (raw_route.has_alternative())
{
std::vector<std::vector<PathData>> wrapped_leg(1);
wrapped_leg.front() = std::move(raw_route.unpacked_alternative);
routes.values[1] = MakeRoute(raw_route.segment_end_coordinates, wrapped_leg,
raw_route.alt_source_traversed_in_reverse,
raw_route.alt_target_traversed_in_reverse);
}
response.values["waypoints"] = BaseT::MakeWaypoints(raw_route.segment_end_coordinates);
response.values["routes"] = std::move(routes);
response.values["code"] = "ok";
}
protected:
template <typename ForwardIter>
util::json::Value MakeGeometry(ForwardIter begin, ForwardIter end) const
{
if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
{
return json::makePolyline(begin, end);
}
BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
return json::makeGeoJSONLineString(begin, end);
}
virtual util::json::Object
MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates,
const std::vector<std::vector<PathData>> &unpacked_path_segments,
const std::vector<bool> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const
{
std::vector<guidance::RouteLeg> legs;
std::vector<guidance::LegGeometry> leg_geometries;
auto number_of_legs = segment_end_coordinates.size();
legs.reserve(number_of_legs);
leg_geometries.reserve(number_of_legs);
for (auto idx : util::irange(0UL, number_of_legs))
{
const auto &phantoms = segment_end_coordinates[idx];
const auto &path_data = unpacked_path_segments[idx];
const bool reversed_source = source_traversed_in_reverse[idx];
const bool reversed_target = target_traversed_in_reverse[idx];
auto leg_geometry = guidance::assembleGeometry(
BaseT::facade, path_data, phantoms.source_phantom, phantoms.target_phantom);
auto leg = guidance::assembleLeg(BaseT::facade, path_data, leg_geometry, phantoms.source_phantom,
phantoms.target_phantom, reversed_source, reversed_target);
if (parameters.steps)
{
leg.steps = guidance::assembleSteps(BaseT::facade,
path_data, leg_geometry, phantoms.source_phantom, phantoms.target_phantom,
reversed_source, reversed_target);
}
leg_geometries.push_back(std::move(leg_geometry));
legs.push_back(std::move(leg));
}
auto route = guidance::assembleRoute(legs);
boost::optional<util::json::Value> json_overview;
if (parameters.overview != RouteParameters::OverviewType::False)
{
const auto use_simplification =
parameters.overview == RouteParameters::OverviewType::Simplified;
BOOST_ASSERT(use_simplification ||
parameters.overview == RouteParameters::OverviewType::Full);
auto overview = guidance::assembleOverview(leg_geometries, use_simplification);
json_overview = MakeGeometry(overview.begin(), overview.end());
}
return json::makeRoute(route, json::makeRouteLegs(std::move(legs), leg_geometries),
std::move(json_overview));
}
const RouteParameters &parameters;
};
}
// Expose non-templated version
using RouteAPI = detail::RouteAPI_<std::true_type>;
}
}
}
#endif
+58
View File
@@ -0,0 +1,58 @@
#ifndef ENGINE_API_ROUTE_PARAMETERS_HPP
#define ENGINE_API_ROUTE_PARAMETERS_HPP
#include "engine/api/base_parameters.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
struct RouteParameters : public BaseParameters
{
enum class GeometriesType
{
Polyline,
GeoJSON
};
enum class OverviewType
{
Simplified,
Full,
False
};
RouteParameters() = default;
template<typename... Args>
RouteParameters(const bool steps_,
const bool alternative_,
const GeometriesType geometries_,
const OverviewType overview_,
std::vector<boost::optional<bool>> uturns_, Args... args_)
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternative{alternative_}, geometries{geometries_},
overview{overview_}, uturns{std::move(uturns_)}
{
}
bool steps = true;
bool alternative = true;
GeometriesType geometries = GeometriesType::Polyline;
OverviewType overview = OverviewType::Simplified;
std::vector<boost::optional<bool>> uturns;
bool IsValid() const
{
return coordinates.size() >= 2 && BaseParameters::IsValid() &&
(uturns.empty() || uturns.size() == coordinates.size());
}
};
}
}
}
#endif
+27
View File
@@ -0,0 +1,27 @@
#ifndef ENGINE_API_TABLE_PARAMETERS_HPP
#define ENGINE_API_TABLE_PARAMETERS_HPP
#include "engine/api/base_parameters.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
struct TableParameters : public BaseParameters
{
std::vector<bool> is_source;
std::vector<bool> is_destination;
bool IsValid() const;
};
}
}
}
#endif // ROUTE_PARAMETERS_HPP
+24
View File
@@ -0,0 +1,24 @@
#ifndef ENGINE_API_TRIP_PARAMETERS_HPP
#define ENGINE_API_TRIP_PARAMETERS_HPP
#include "engine/api/route_parameters.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
struct TripParameters : public RouteParameters
{
bool IsValid() const;
};
}
}
}
#endif
-299
View File
@@ -1,299 +0,0 @@
#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/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;
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 (!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;
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 = extractRouteNames(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 = extractRouteNames(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 (!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 polylineEncodeAsJSON(segments.Get());
else
return polylineUnencodedAsJSON(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::isTurnNecessary(current_turn) &&
(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()))
{
hint = encodeBase64(raw_route.segment_end_coordinates[i].source_phantom);
json_location_hint_array.values.push_back(std::move(hint));
}
hint = encodeBase64(raw_route.segment_end_coordinates.back().target_phantom);
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_
+18 -5
View File
@@ -5,6 +5,7 @@
#include "extractor/edge_based_node.hpp"
#include "extractor/external_memory_node.hpp"
#include "contractor/query_edge.hpp"
#include "engine/phantom_node.hpp"
#include "extractor/turn_instructions.hpp"
#include "util/integer_range.hpp"
@@ -29,11 +30,11 @@ namespace datafacade
using EdgeRange = util::range<EdgeID>;
template <class EdgeDataT> class BaseDataFacade
class BaseDataFacade
{
public:
using EdgeData = contractor::QueryEdge::EdgeData;
using RTreeLeaf = extractor::EdgeBasedNode;
using EdgeData = EdgeDataT;
BaseDataFacade() {}
virtual ~BaseDataFacade() {}
@@ -46,7 +47,7 @@ template <class EdgeDataT> class BaseDataFacade
virtual NodeID GetTarget(const EdgeID e) const = 0;
virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
virtual EdgeID BeginEdges(const NodeID n) const = 0;
@@ -94,10 +95,22 @@ template <class EdgeDataT> class BaseDataFacade
const int bearing = 0,
const int bearing_range = 180) = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate) = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate, const double max_distance) = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing = 0,
const int bearing_range = 180) = 0;
const double max_distance,
const int bearing,
const int bearing_range) = 0;
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing,
const int bearing_range) = 0;
virtual unsigned GetCheckSum() const = 0;
@@ -46,17 +46,17 @@ namespace engine
namespace datafacade
{
template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT>
class InternalDataFacade final : public BaseDataFacade
{
private:
using super = BaseDataFacade<EdgeDataT>;
using super = BaseDataFacade;
using QueryGraph = util::StaticGraph<typename super::EdgeData>;
using InputEdge = typename QueryGraph::InputEdge;
using RTreeLeaf = typename super::RTreeLeaf;
using InternalRTree =
util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, false>::vector, false>;
using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade<EdgeDataT>>;
using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>;
InternalDataFacade() {}
@@ -293,7 +293,7 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad
NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
EdgeDataT &GetEdgeData(const EdgeID e) const override final
EdgeData &GetEdgeData(const EdgeID e) const override final
{
return m_query_graph->GetEdgeData(e);
}
@@ -386,10 +386,52 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad
bearing_range);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate, const double max_distance) override final
{
if (!m_static_rtree.get())
{
LoadRTree();
BOOST_ASSERT(m_geospatial_query.get());
}
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate) override final
{
if (!m_static_rtree.get())
{
LoadRTree();
BOOST_ASSERT(m_geospatial_query.get());
}
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing = 0,
const int bearing_range = 180) override final
const double max_distance,
const int bearing,
const int bearing_range) override final
{
if (!m_static_rtree.get())
{
LoadRTree();
BOOST_ASSERT(m_geospatial_query.get());
}
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing,
const int bearing_range) override final
{
if (!m_static_rtree.get())
{
@@ -36,12 +36,11 @@ namespace engine
namespace datafacade
{
template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT>
class SharedDataFacade final : public BaseDataFacade
{
private:
using EdgeData = EdgeDataT;
using super = BaseDataFacade<EdgeData>;
using super = BaseDataFacade;
using QueryGraph = util::StaticGraph<EdgeData, true>;
using GraphNode = typename QueryGraph::NodeArrayEntry;
using GraphEdge = typename QueryGraph::EdgeArrayEntry;
@@ -50,7 +49,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
using RTreeLeaf = typename super::RTreeLeaf;
using SharedRTree =
util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, true>::vector, true>;
using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade<EdgeDataT>>;
using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
using RTreeNode = typename SharedRTree::TreeNode;
@@ -333,7 +332,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
EdgeDataT &GetEdgeData(const EdgeID e) const override final
EdgeData &GetEdgeData(const EdgeID e) const override final
{
return m_query_graph->GetEdgeData(e);
}
@@ -454,10 +453,52 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
bearing_range);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate) override final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
LoadRTree();
BOOST_ASSERT(m_geospatial_query.get());
}
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate, const double max_distance) override final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
LoadRTree();
BOOST_ASSERT(m_geospatial_query.get());
}
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing = 0,
const int bearing_range = 180) override final
const double max_distance,
const int bearing,
const int bearing_range) override final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
LoadRTree();
BOOST_ASSERT(m_geospatial_query.get());
}
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
input_coordinate, max_distance, bearing, bearing_range);
}
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing,
const int bearing_range) override final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
@@ -469,6 +510,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
input_coordinate, bearing, bearing_range);
}
unsigned GetCheckSum() const override final { return m_check_sum; }
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
+8 -6
View File
@@ -1,7 +1,7 @@
#ifndef DOUGLAS_PEUCKER_HPP_
#define DOUGLAS_PEUCKER_HPP_
#include "engine/segment_information.hpp"
#include "util/coordinate.hpp"
#include <vector>
#include <iterator>
@@ -44,14 +44,16 @@ const constexpr auto DOUGLAS_PEUCKER_THRESHOLDS_SIZE =
// Input is vector of pairs. Each pair consists of the point information and a
// bit indicating if the points is present in the generalization.
// Note: points may also be pre-selected*/
void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
std::vector<SegmentInformation>::iterator end,
const unsigned zoom_level);
std::vector<util::FixedPointCoordinate>
douglasPeucker(std::vector<util::FixedPointCoordinate>::const_iterator begin,
std::vector<util::FixedPointCoordinate>::const_iterator end,
const unsigned zoom_level);
// Convenience range-based function
inline void douglasPeucker(std::vector<SegmentInformation> &geometry, const unsigned zoom_level)
inline std::vector<util::FixedPointCoordinate>
douglasPeucker(const std::vector<util::FixedPointCoordinate> &geometry, const unsigned zoom_level)
{
douglasPeucker(begin(geometry), end(geometry), zoom_level);
return douglasPeucker(begin(geometry), end(geometry), zoom_level);
}
}
}
+22 -26
View File
@@ -1,10 +1,9 @@
#ifndef ENGINE_HPP
#define ENGINE_HPP
#include "contractor/query_edge.hpp"
#include "osrm/json_container.hpp"
#include "osrm/osrm.hpp"
#include "engine/status.hpp"
#include "storage/shared_barriers.hpp"
#include "util/json_container.hpp"
#include <memory>
#include <unordered_map>
@@ -13,11 +12,6 @@
namespace osrm
{
namespace storage
{
struct SharedBarriers;
}
namespace util
{
namespace json
@@ -29,41 +23,43 @@ struct Object;
namespace engine
{
struct EngineConfig;
namespace api
{
struct RouteParameters;
}
namespace plugins
{
class BasePlugin;
class ViaRoutePlugin;
}
namespace datafacade
{
template <class EdgeDataT> class BaseDataFacade;
class BaseDataFacade;
}
class Engine final
{
private:
using PluginMap = std::unordered_map<std::string, std::unique_ptr<plugins::BasePlugin>>;
public:
struct EngineLock
{
// will only be initialized if shared memory is used
storage::SharedBarriers barrier;
// decrease number of concurrent queries
void DecreaseQueryCount();
// increase number of concurrent queries
void IncreaseQueryCount();
};
Engine(EngineConfig &config_);
Engine(const Engine &) = delete;
Engine &operator=(const Engine &) = delete;
int RunQuery(const RouteParameters &route_parameters, util::json::Object &json_result);
Status Route(const api::RouteParameters &route_parameters, util::json::Object &json_result);
private:
void RegisterPlugin(plugins::BasePlugin *plugin);
PluginMap plugin_map;
// will only be initialized if shared memory is used
std::unique_ptr<storage::SharedBarriers> barrier;
// base class pointer to the objects
datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData> *query_data_facade;
// decrease number of concurrent queries
void decrease_concurrent_query_count();
// increase number of concurrent queries
void increase_concurrent_query_count();
std::unique_ptr<EngineLock> lock;
std::unique_ptr<plugins::ViaRoutePlugin> route_plugin;
std::unique_ptr<datafacade::BaseDataFacade> query_data_facade;
};
}
}
+121 -5
View File
@@ -84,16 +84,86 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing = 0,
const int bearing_range = 180)
const util::FixedPointCoordinate input_coordinate, const double max_distance)
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this, bearing, bearing_range, &has_big_component, &has_small_component](
const EdgeData &data)
[&has_big_component, &has_small_component](const EdgeData &data)
{
auto use_segment =
(!has_small_component || (!has_big_component && !data.component.is_tiny));
auto use_directions = std::make_pair(use_segment, use_segment);
has_big_component = has_big_component || !data.component.is_tiny;
has_small_component = has_small_component || data.component.is_tiny;
return use_directions;
},
[&has_big_component, max_distance](const std::size_t num_results, const double min_dist)
{
return (num_results > 0 && has_big_component) || min_dist > max_distance;
});
if (results.size() == 0)
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate)
{
bool has_small_component = false;
bool has_big_component = false;
auto results =
rtree.Nearest(input_coordinate,
[&has_big_component, &has_small_component](const EdgeData &data)
{
auto use_segment = (!has_small_component ||
(!has_big_component && !data.component.is_tiny));
auto use_directions = std::make_pair(use_segment, use_segment);
has_big_component = has_big_component || !data.component.is_tiny;
has_small_component = has_small_component || data.component.is_tiny;
return use_directions;
},
[&has_big_component](const std::size_t num_results, const double)
{
return num_results > 0 && has_big_component;
});
if (results.size() == 0)
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() == 1 || results.size() == 2);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const int bearing,
const int bearing_range)
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this, bearing, bearing_range, &has_big_component,
&has_small_component](const EdgeData &data)
{
auto use_segment =
(!has_small_component || (!has_big_component && !data.component.is_tiny));
@@ -126,6 +196,52 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
// Returns the nearest phantom node. If this phantom node is not from a big component
// a second phantom node is return that is the nearest coordinate in a big component.
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::FixedPointCoordinate input_coordinate,
const double max_distance,
const int bearing,
const int bearing_range)
{
bool has_small_component = false;
bool has_big_component = false;
auto results = rtree.Nearest(
input_coordinate,
[this, bearing, bearing_range, &has_big_component,
&has_small_component](const EdgeData &data)
{
auto use_segment =
(!has_small_component || (!has_big_component && !data.component.is_tiny));
auto use_directions = std::make_pair(use_segment, use_segment);
if (use_segment)
{
use_directions = checkSegmentBearing(data, bearing, bearing_range);
if (use_directions.first || use_directions.second)
{
has_big_component = has_big_component || !data.component.is_tiny;
has_small_component = has_small_component || data.component.is_tiny;
}
}
return use_directions;
},
[&has_big_component, max_distance](const std::size_t num_results, const double min_dist)
{
return (num_results > 0 && has_big_component) || min_dist > max_distance;
});
if (results.size() == 0)
{
return std::make_pair(PhantomNode{}, PhantomNode{});
}
BOOST_ASSERT(results.size() > 0);
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
MakePhantomNode(input_coordinate, results.back()).phantom_node);
}
private:
std::vector<PhantomNodeWithDistance>
MakePhantomNodes(const util::FixedPointCoordinate input_coordinate,
@@ -0,0 +1,78 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_GEOMETRY_HPP
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp"
#include "extractor/travel_mode.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
// Extracts the geometry for each segment and calculates the traveled distance
// Combines the geometry form the phantom node with the PathData
// to the full route geometry.
//
// turn 0 1 2 3 4
// s...x...y...z...t
// |---|segment 0
// |---| segment 1
// |---| segment 2
// |---| segment 3
template <typename DataFacadeT>
LegGeometry assembleGeometry(const DataFacadeT &facade,
const std::vector<PathData> &leg_data,
const PhantomNode &source_node,
const PhantomNode &target_node)
{
LegGeometry geometry;
// segment 0 first and last
geometry.segment_offsets.push_back(0);
geometry.locations.push_back(source_node.location);
auto current_distance = 0.;
auto prev_coordinate = geometry.locations.front();
for (const auto &path_point : leg_data)
{
auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node);
current_distance +=
util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate);
if (path_point.turn_instruction != extractor::TurnInstruction::NoTurn)
{
geometry.segment_distances.push_back(current_distance);
geometry.segment_offsets.push_back(geometry.locations.size());
current_distance = 0.;
}
prev_coordinate = coordinate;
geometry.locations.push_back(std::move(coordinate));
}
current_distance +=
util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location);
// segment leading to the target node
geometry.segment_distances.push_back(current_distance);
geometry.segment_offsets.push_back(geometry.locations.size());
geometry.locations.push_back(target_node.location);
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
return geometry;
}
}
}
}
#endif
+165
View File
@@ -0,0 +1,165 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
#define ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_
#include "engine/guidance/route_leg.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/internal_route_result.hpp"
#include <vector>
#include <array>
#include <algorithm>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
const constexpr std::size_t MAX_USED_SEGMENTS = 2;
struct NamedSegment
{
double duration;
std::uint32_t position;
std::uint32_t name_id;
};
template <std::size_t SegmentNumber>
std::array<std::uint32_t, SegmentNumber> summarizeRoute(const std::vector<PathData> &route_data)
{
// merges segments with same name id
const auto collapse_segments = [](std::vector<NamedSegment> &segments)
{
auto out = segments.begin();
auto end = segments.end();
for (auto in = segments.begin(); in != end; ++in)
{
if (in->name_id == out->name_id)
{
out->duration += in->duration;
}
else
{
++out;
BOOST_ASSERT(out != end);
*out = *in;
}
}
return out;
};
std::vector<NamedSegment> segments(route_data.size());
std::uint32_t index = 0;
std::transform(
route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point)
{
return NamedSegment{point.duration_until_turn / 10.0, index++, point.name_id};
});
// this makes sure that the segment with the lowest position comes first
std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
{
return lhs.name_id < rhs.name_id ||
(lhs.name_id == rhs.name_id && lhs.position < rhs.position);
});
auto new_end = collapse_segments(segments);
segments.resize(new_end - segments.begin());
// sort descending
std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
{
return lhs.duration > rhs.duration;
});
// make sure the segments are sorted by position
segments.resize(std::min(segments.size(), SegmentNumber));
std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs)
{
return lhs.position < rhs.position;
});
std::array<std::uint32_t, SegmentNumber> summary;
std::fill(summary.begin(), summary.end(), 0);
std::transform(segments.begin(), segments.end(), summary.begin(),
[](const NamedSegment &segment)
{
return segment.name_id;
});
return summary;
}
}
template <typename DataFacadeT>
RouteLeg assembleLeg(const DataFacadeT &facade,
const std::vector<PathData> &route_data,
const LegGeometry &leg_geometry,
const PhantomNode &source_node,
const PhantomNode &target_node,
const bool source_traversed_in_reverse,
const bool target_traversed_in_reverse)
{
const auto source_duration =
(source_traversed_in_reverse ? source_node.GetReverseWeightPlusOffset()
: source_node.GetForwardWeightPlusOffset()) /
10.;
const auto target_duration =
(target_traversed_in_reverse ? target_node.GetReverseWeightPlusOffset()
: target_node.GetForwardWeightPlusOffset()) /
10.;
auto distance = std::accumulate(leg_geometry.segment_distances.begin(),
leg_geometry.segment_distances.end(), 0.);
auto duration = std::accumulate(route_data.begin(), route_data.end(), 0.,
[](const double sum, const PathData &data)
{
return sum + data.duration_until_turn;
}) /
10.;
// s
// |
// Given a route a---b---c where there is a right turn at b.
// |
// d
// |--t
// e
// (a, b, c) gets compressed to (a,c)
// (c, d, e) gets compressed to (c,e)
// The duration of the turn (a,c) -> (c,e) will be the duration of (a,c) (e.g. the duration
// of (a,b,c)).
// The phantom node of s will contain:
// `forward_weight`: duration of (a,s)
// `forward_offset`: 0 (its the first segment)
// The phantom node of t will contain:
// `forward_weight`: duration of (d,t)
// `forward_offset`: duration of (c, d)
//
// The PathData will contain entries of b, c and d. But only c will contain
// a duration value since its the only point associated with a turn.
// As such we want to slice of the duration for (a,s) and add the duration for
// (c,d,t)
duration = duration - source_duration + target_duration;
auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(route_data);
BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
BOOST_ASSERT(summary_array.begin() != summary_array.end());
std::string summary =
std::accumulate(std::next(summary_array.begin()), summary_array.end(),
facade.get_name_for_id(summary_array.front()),
[&facade](std::string previous, const std::uint32_t name_id)
{
if (name_id != 0)
{
previous += ", " + facade.get_name_for_id(name_id);
}
return previous;
});
return RouteLeg{duration, distance, summary, {}};
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
@@ -0,0 +1,22 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
#include "engine/guidance/leg_geometry.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
std::vector<util::FixedPointCoordinate>
assembleOverview(const std::vector<LegGeometry> &leg_geometries, const bool use_simplification);
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif
@@ -0,0 +1,37 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_ROUTE_HPP
#include "engine/guidance/route_leg.hpp"
#include "engine/guidance/route.hpp"
#include <vector>
#include <algorithm>
namespace osrm
{
namespace engine
{
namespace guidance
{
inline Route assembleRoute(const std::vector<RouteLeg> &route_legs)
{
auto distance = std::accumulate(route_legs.begin(),
route_legs.end(), 0.,
[](const double sum, const RouteLeg &leg)
{
return sum + leg.distance;
});
auto duration = std::accumulate(route_legs.begin(), route_legs.end(), 0.,
[](const double sum, const RouteLeg &leg)
{
return sum + leg.duration;
});
return Route{duration, distance};
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif
+135
View File
@@ -0,0 +1,135 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
#define ENGINE_GUIDANCE_ASSEMBLE_STEPS_HPP_
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp"
#include "extractor/travel_mode.hpp"
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
// FIXME move implementation to cpp
inline StepManeuver stepManeuverFromGeometry(const extractor::TurnInstruction instruction,
const LegGeometry &leg_geometry,
std::size_t segment_index)
{
auto turn_index = leg_geometry.BackIndex(segment_index);
BOOST_ASSERT(turn_index > 0);
BOOST_ASSERT(turn_index < leg_geometry.locations.size() - 1);
// TODO chose a bigger look-a-head to smooth complex geometry
const auto pre_turn_coordinate = leg_geometry.locations[turn_index - 1];
const auto turn_coordinate = leg_geometry.locations[turn_index];
const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
const double pre_turn_heading =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
const double post_turn_heading =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
return StepManeuver{turn_coordinate, pre_turn_heading, post_turn_heading, instruction};
}
}
template <typename DataFacadeT>
std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
const std::vector<PathData> &leg_data,
const LegGeometry &leg_geometry,
const PhantomNode &source_node,
const PhantomNode &target_node,
const bool source_traversed_in_reverse,
const bool target_traversed_in_reverse)
{
const auto source_duration =
(source_traversed_in_reverse ? source_node.GetReverseWeightPlusOffset()
: source_node.GetForwardWeightPlusOffset()) /
10.;
const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode
: source_node.forward_travel_mode;
const auto target_duration =
(target_traversed_in_reverse ? target_node.GetReverseWeightPlusOffset()
: target_node.GetForwardWeightPlusOffset()) /
10.;
const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode
: target_node.forward_travel_mode;
const auto number_of_segments = leg_geometry.GetNumberOfSegments();
std::vector<RouteStep> steps;
steps.reserve(number_of_segments);
auto segment_index = 0;
if (leg_data.size() > 0)
{
StepManeuver maneuver = detail::stepManeuverFromGeometry(extractor::TurnInstruction::StartAtEndOfStreet,
leg_geometry, segment_index);
// PathData saves the information we need of the segment _before_ the turn,
// but a RouteStep is with regard to the segment after the turn.
// We need to skip the first segment because it is already covered by the
for (const auto &path_point : leg_data)
{
if (path_point.turn_instruction != extractor::TurnInstruction::NoTurn)
{
auto name = facade.get_name_for_id(path_point.name_id);
const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{path_point.name_id, std::move(name),
path_point.duration_until_turn / 10.0, distance,
path_point.travel_mode, maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
leg_geometry, segment_index);
segment_index++;
}
}
const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{target_node.name_id, facade.get_name_for_id(target_node.name_id),
target_duration, distance, target_mode, maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
}
else
{
//
// |-----s source_duration
// |-------------t target_duration
// x---*---*---*---z compressed edge
// |-------| duration
steps.push_back(RouteStep{
source_node.name_id, facade.get_name_for_id(source_node.name_id),
target_duration - source_duration, leg_geometry.segment_distances[segment_index],
source_mode,
StepManeuver{source_node.location, 0., 0., extractor::TurnInstruction::StartAtEndOfStreet},
leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1});
}
BOOST_ASSERT(segment_index == number_of_segments - 1);
// This step has length zero, the only reason we need it is the target location
steps.push_back(RouteStep{
target_node.name_id, facade.get_name_for_id(target_node.name_id), 0., 0., target_mode,
StepManeuver{target_node.location, 0., 0., extractor::TurnInstruction::ReachedYourDestination},
leg_geometry.locations.size(), leg_geometry.locations.size()});
return steps;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // ENGINE_GUIDANCE_SEGMENT_LIST_HPP_
+54
View File
@@ -0,0 +1,54 @@
#ifndef ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
#define ENGINE_GUIDANCE_LEG_GEOMETRY_HPP
#include "util/coordinate.hpp"
#include "util/integer_range.hpp"
#include <boost/assert.hpp>
#include <boost/range/iterator_range.hpp>
#include <vector>
#include <cstdlib>
namespace osrm
{
namespace engine
{
namespace guidance
{
// locations 0---1---2-...-n-1---n
// turns s x y t
// segment | 0 | 1 | 2 | senitel
// offsets 0 2 n-1 n
struct LegGeometry
{
std::vector<util::FixedPointCoordinate> locations;
// segment_offset[i] .. segment_offset[i+1] (inclusive)
// contains the geometry of segment i
std::vector<std::size_t> segment_offsets;
// length of the segment in meters
std::vector<double> segment_distances;
std::size_t FrontIndex(std::size_t segment_index) const
{
return segment_offsets[segment_index];
}
std::size_t BackIndex(std::size_t segment_index) const
{
return segment_offsets[segment_index + 1];
}
std::size_t GetNumberOfSegments() const
{
BOOST_ASSERT(segment_offsets.size() > 0);
return segment_offsets.size() - 1;
}
};
}
}
}
#endif
+18
View File
@@ -0,0 +1,18 @@
#ifndef ROUTE_HPP
#define ROUTE_HPP
namespace osrm {
namespace engine {
namespace guidance {
struct Route
{
double duration;
double distance;
};
}
}
}
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef ROUTE_LEG_HPP
#define ROUTE_LEG_HPP
#include "engine/guidance/route_step.hpp"
#include <boost/optional.hpp>
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
struct RouteLeg
{
double duration;
double distance;
std::string summary;
std::vector<RouteStep> steps;
};
}
}
}
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef ROUTE_STEP_HPP
#define ROUTE_STEP_HPP
#include "extractor/travel_mode.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
// Given the following turn from a,b to b,c over b:
// a --> b --> c
// this struct saves the information of the segment b,c.
// Notable exceptions are Departure and Arrival steps.
// Departue: s --> a --> b. Represents the segment s,a with location being s.
// Arrive: a --> b --> t. The segment (b,t) is already covered by the previous segment.
struct RouteStep
{
unsigned name_id;
std::string way_name;
double duration;
double distance;
extractor::TravelMode mode;
StepManeuver maneuver;
// indices into the locations array stored the LegGeometry
std::size_t geometry_begin;
std::size_t geometry_end;
};
}
}
}
#endif
-347
View File
@@ -1,347 +0,0 @@
#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 "util/integer_range.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/for_each_pair.hpp"
#include "extractor/turn_instructions.hpp"
#include <boost/assert.hpp>
#include <cmath>
#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 (!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 (raw_route.is_via_leg(raw_index))
{
const auto &source_phantom =
raw_route.segment_end_coordinates[raw_index].target_phantom;
if (raw_route.target_traversed_in_reverse[raw_index] !=
raw_route.source_traversed_in_reverse[raw_index + 1])
{
bool traversed_in_reverse = raw_route.target_traversed_in_reverse[raw_index];
const extractor::TravelMode travel_mode =
(traversed_in_reverse ? source_phantom.backward_travel_mode
: source_phantom.forward_travel_mode);
const bool constexpr IS_NECESSARY = true;
const bool constexpr IS_VIA_LOCATION = true;
segments.emplace_back(source_phantom.location, source_phantom.name_id, 0, 0.f,
extractor::TurnInstruction::UTurn, IS_NECESSARY,
IS_VIA_LOCATION, travel_mode);
}
}
}
}
if (!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, extractor::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 auto &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 extractor::TravelMode travel_mode =
(traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode);
const bool constexpr IS_NECESSARY = true;
const bool constexpr IS_VIA_LOCATION = true;
segments.emplace_back(target_node.location, target_node.name_id, segment_duration, 0.f,
is_via_leg ? extractor::TurnInstruction::ReachViaLocation
: extractor::TurnInstruction::NoTurn,
IS_NECESSARY, IS_VIA_LOCATION, 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)
{
const auto turn = 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;
// check if first two segments can be merged
BOOST_ASSERT(segments.size() >= 2);
if (segments[0].location == segments[1].location &&
segments[1].turn_instruction == extractor::TurnInstruction::NoTurn)
{
segments[0].travel_mode = segments[1].travel_mode;
segments[0].name_id = segments[1].name_id;
// Other data??
segments.erase(segments.begin() + 1);
}
// announce mode changes
for (std::size_t i = 0; i + 1 < segments.size(); ++i)
{
auto &segment = segments[i];
const auto next_mode = segments[i + 1].travel_mode;
if (segment.travel_mode != next_mode &&
segment.turn_instruction == extractor::TurnInstruction::NoTurn)
{
segment.turn_instruction = extractor::TurnInstruction::GoStraight;
segment.necessary = true;
}
}
segments[0].length = 0.f;
for (const auto i : util::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 = util::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 : util::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 (extractor::TurnInstruction::NoTurn != segments[i].turn_instruction)
{
BOOST_ASSERT(segments[i].necessary);
segment_length = 0;
segment_duration = 0;
segment_start_index = i;
if (segments[i].turn_instruction == extractor::TurnInstruction::NameChanges)
{
segments[i].turn_instruction =
extractor::TurnInstruction::GoStraight; // to not break the api
}
}
}
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.));
// 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 = extractor::TurnInstruction::NoTurn;
}
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 = extractor::TurnInstruction::HeadOn;
segments.front().necessary = true;
}
if (allow_simplification)
{
douglasPeucker(segments, 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 =
util::coordinate_calculation::bearing(first.location, second.location);
const double pre_turn_bearing =
util::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
util::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_
+26
View File
@@ -0,0 +1,26 @@
#ifndef ENGINE_GUIDANCE_STEP_MANEUVER_HPP
#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
#include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp"
namespace osrm
{
namespace engine
{
namespace guidance
{
struct StepManeuver
{
util::FixedPointCoordinate location;
double heading_before;
double heading_after;
extractor::TurnInstruction instruction;
};
}
}
}
#endif
@@ -1,147 +0,0 @@
#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 util::json::Array AnnotateRoute(const std::vector<SegmentInformation> &route_segments,
DataFacadeT *facade)
{
util::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;
extractor::TravelMode last_travel_mode = TRAVEL_MODE_DEFAULT;
// Generate annotations for every segment
for (std::size_t i = 0; i < route_segments.size(); ++i)
{
const auto &segment = route_segments[i];
util::json::Array json_instruction_row;
extractor::TurnInstruction current_instruction = segment.turn_instruction;
if (extractor::isTurnNecessary(current_instruction))
{
if (extractor::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 (extractor::TurnInstruction::LeaveRoundAbout == current_instruction)
{
temp_instruction = std::to_string(util::cast::enum_to_underlying(
extractor::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(util::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(util::bearing::get(post_turn_bearing_value));
json_instruction_row.values.push_back(
static_cast<std::uint32_t>(std::round(post_turn_bearing_value)));
if (i + 1 < route_segments.size())
{
// anounce next travel mode with turn
json_instruction_row.values.push_back(route_segments[i + 1].travel_mode);
last_travel_mode = segment.travel_mode;
}
else
{
json_instruction_row.values.push_back(segment.travel_mode);
last_travel_mode = segment.travel_mode;
}
// pre turn bearing
const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
json_instruction_row.values.push_back(util::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 (extractor::TurnInstruction::StayOnRoundAbout == current_instruction)
{
++round_about.leave_at_exit;
}
if (segment.necessary)
{
++necessary_segments_running_index;
}
}
util::json::Array json_last_instruction_row;
temp_instruction = std::to_string(
util::cast::enum_to_underlying(extractor::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(util::bearing::get(0.0));
json_last_instruction_row.values.push_back(0.);
json_last_instruction_row.values.push_back(last_travel_mode);
json_last_instruction_row.values.push_back(util::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
+61
View File
@@ -0,0 +1,61 @@
#ifndef ENGINE_HINT_HPP
#define ENGINE_HINT_HPP
#include "engine/object_encoder.hpp"
#include "engine/phantom_node.hpp"
#include <boost/assert.hpp>
#include <cmath>
namespace osrm
{
namespace engine
{
// Is returned as a temporary identifier for snapped coodinates
struct Hint
{
FixedPointCoordinate input_coordinate;
PhantomNode phantom;
std::uint32_t data_checksum;
template <typename DataFacadeT>
bool IsValid(const FixedPointCoordinate new_input_coordinates, DataFacadeT &facade) const
{
auto is_same_input_coordinate = new_input_coordinates.lat == input_coordinate.lat &&
new_input_coordinates.lon == input_coordinate.lon;
return is_same_input_coordinate && phantom.IsValid(facade.GetNumberOfNodes()) &&
facade.GetCheckSum() == data_checksum;
}
std::string ToBase64() const
{
std::string encoded = encodeBase64(*this);
return encoded;
}
static Hint FromBase64(const std::string &base64Hint)
{
BOOST_ASSERT_MSG(base64Hint.size() ==
static_cast<std::size_t>(std::ceil(sizeof(Hint) / 3.) * 4),
"Hint has invalid size");
auto decoded = decodeBase64<Hint>(base64Hint);
return decoded;
}
};
#ifndef _MSC_VER
constexpr std::size_t ENCODED_HINT_SIZE = 88;
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
"ENCODED_HINT_SIZE does not match size of Hint");
#else
// PhantomNode is bigger under windows because MSVC does not support bit packing
constexpr std::size_t ENCODED_HINT_SIZE = 84;
static_assert(ENCODED_HINT_SIZE / 4 * 3 >= sizeof(Hint),
"ENCODED_HINT_SIZE does not match size of Hint");
#endif
}
}
#endif
+7 -18
View File
@@ -17,26 +17,15 @@ namespace engine
struct PathData
{
PathData()
: node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT),
turn_instruction(extractor::TurnInstruction::NoTurn),
travel_mode(TRAVEL_MODE_INACCESSIBLE)
{
}
PathData(NodeID node,
unsigned name_id,
extractor::TurnInstruction turn_instruction,
EdgeWeight segment_duration,
extractor::TravelMode travel_mode)
: node(node), name_id(name_id), segment_duration(segment_duration),
turn_instruction(turn_instruction), travel_mode(travel_mode)
{
}
NodeID node;
// id of via node of the turn
NodeID turn_via_node;
// name of the street that leads to the turn
unsigned name_id;
EdgeWeight segment_duration;
// duration that is traveled on the segment until the turn is reached
EdgeWeight duration_until_turn;
// instruction to execute at the turn
extractor::TurnInstruction turn_instruction;
// travel mode of the street that leads to the turn
extractor::TravelMode travel_mode : 4;
};
+1 -1
View File
@@ -94,7 +94,7 @@ struct PhantomNode
bool operator==(const PhantomNode &other) const { return location == other.location; }
template <class OtherT>
PhantomNode(const OtherT &other, int forward_weight_, int forward_offset_, int reverse_weight_, int reverse_offset_, const util::FixedPointCoordinate foot_point)
explicit PhantomNode(const OtherT &other, int forward_weight_, int forward_offset_, int reverse_weight_, int reverse_offset_, const util::FixedPointCoordinate foot_point)
{
forward_node_id = other.forward_edge_based_node_id;
reverse_node_id = other.reverse_edge_based_node_id;
+89 -29
View File
@@ -1,11 +1,14 @@
#ifndef BASE_PLUGIN_HPP
#define BASE_PLUGIN_HPP
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/api/base_parameters.hpp"
#include "engine/phantom_node.hpp"
#include "engine/status.hpp"
#include "osrm/coordinate.hpp"
#include "osrm/json_container.hpp"
#include "osrm/route_parameters.hpp"
#include "util/coordinate.hpp"
#include "util/json_container.hpp"
#include "util/integer_range.hpp"
#include <algorithm>
#include <string>
@@ -20,38 +23,32 @@ namespace plugins
class BasePlugin
{
public:
enum class Status : int
{
Ok = 200,
EmptyResult = 207,
NoSegment = 208,
Error = 400
};
protected:
datafacade::BaseDataFacade &facade;
BasePlugin(datafacade::BaseDataFacade &facade_) : facade(facade_) {}
BasePlugin() {}
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BasePlugin() {}
virtual const std::string GetDescriptor() const = 0;
virtual Status HandleRequest(const RouteParameters &, util::json::Object &) = 0;
virtual bool check_all_coordinates(const std::vector<util::FixedPointCoordinate> &coordinates,
const unsigned min = 2) const final
bool CheckAllCoordinates(const std::vector<util::FixedPointCoordinate> &coordinates)
{
if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
[](const util::FixedPointCoordinate coordinate)
{
return !coordinate.IsValid();
}))
{
return false;
}
return true;
return !std::any_of(std::begin(coordinates), std::end(coordinates),
[](const util::FixedPointCoordinate &coordinate)
{
return !coordinate.IsValid();
});
}
Status Error(const std::string &code,
const std::string &message,
util::json::Object &json_result) const
{
json_result.values["code"] = code;
json_result.values["message"] = message;
return Status::Error;
}
// Decides whether to use the phantom node from a big or small component if both are found.
// Returns true if all phantom nodes are in the same component after snapping.
std::vector<PhantomNode> snapPhantomNodes(
const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
std::vector<PhantomNode>
SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
{
const auto check_component_id_is_tiny =
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
@@ -111,6 +108,69 @@ class BasePlugin
return snapped_phantoms;
}
std::vector<PhantomNodePair> GetPhantomNodes(const api::BaseParameters &parameters)
{
std::vector<PhantomNodePair> phantom_node_pairs(parameters.coordinates.size());
const bool use_hints = !parameters.hints.empty();
const bool use_bearings = !parameters.bearings.empty();
const bool use_radiuses = !parameters.radiuses.empty();
BOOST_ASSERT(parameters.IsValid());
for (const auto i : util::irange<std::size_t>(0, parameters.coordinates.size()))
{
if (use_hints && parameters.hints[i] &&
parameters.hints[i]->IsValid(parameters.coordinates[i], facade))
{
phantom_node_pairs[i].first = parameters.hints[i]->phantom;
// we don't set the second one - it will be marked as invalid
continue;
}
if (use_bearings && parameters.bearings[i])
{
if (use_radiuses && parameters.radiuses[i])
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], *parameters.radiuses[i],
parameters.bearings[i]->bearing, parameters.bearings[i]->range);
}
else
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], parameters.bearings[i]->bearing,
parameters.bearings[i]->range);
{
}
}
else
{
if (use_radiuses && parameters.radiuses[i])
{
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i], *parameters.radiuses[i]);
}
else
phantom_node_pairs[i] =
facade.NearestPhantomNodeWithAlternativeFromBigComponent(
parameters.coordinates[i]);
{
}
}
// we didn't found a fitting node, return error
if (!phantom_node_pairs[i].first.IsValid(facade.GetNumberOfNodes()))
{
break;
}
BOOST_ASSERT(phantom_node_pairs[i].first.IsValid(facade.GetNumberOfNodes()));
BOOST_ASSERT(phantom_node_pairs[i].second.IsValid(facade.GetNumberOfNodes()));
}
return phantom_node_pairs;
}
};
}
}
+15 -142
View File
@@ -1,17 +1,16 @@
#ifndef VIA_ROUTE_HPP
#define VIA_ROUTE_HPP
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/plugins/plugin_base.hpp"
#include "engine/api/route_api.hpp"
#include "engine/api_response_generator.hpp"
#include "engine/object_encoder.hpp"
#include "engine/search_engine.hpp"
#include "util/for_each_pair.hpp"
#include "util/integer_range.hpp"
#include "util/make_unique.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
#include "osrm/json_container.hpp"
#include "engine/search_engine_data.hpp"
#include "engine/routing_algorithms/shortest_path.hpp"
#include "engine/routing_algorithms/alternative_path.hpp"
#include "engine/routing_algorithms/direct_shortest_path.hpp"
#include "util/json_container.hpp"
#include <cstdlib>
@@ -27,146 +26,20 @@ namespace engine
namespace plugins
{
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
class ViaRoutePlugin final : public BasePlugin
{
private:
std::string descriptor_string;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
DataFacadeT *facade;
SearchEngineData heaps;
routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
routing_algorithms::AlternativeRouting<datafacade::BaseDataFacade> alternative_path;
routing_algorithms::DirectShortestPathRouting<datafacade::BaseDataFacade> direct_shortest_path;
int max_locations_viaroute;
public:
explicit ViaRoutePlugin(DataFacadeT *facade, int max_locations_viaroute)
: descriptor_string("viaroute"), facade(facade),
max_locations_viaroute(max_locations_viaroute)
{
search_engine_ptr = util::make_unique<SearchEngine<DataFacadeT>>(facade);
}
explicit ViaRoutePlugin(datafacade::BaseDataFacade &facade, int max_locations_viaroute);
virtual ~ViaRoutePlugin() {}
const std::string GetDescriptor() const override final { return descriptor_string; }
Status HandleRequest(const RouteParameters &route_parameters,
util::json::Object &json_result) override final
{
if (max_locations_viaroute > 0 &&
(static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
{
json_result.values["status_message"] =
"Number of entries " + std::to_string(route_parameters.coordinates.size()) +
" is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")";
return Status::Error;
}
if (!check_all_coordinates(route_parameters.coordinates))
{
json_result.values["status_message"] = "Invalid coordinates";
return Status::Error;
}
const auto &input_bearings = route_parameters.bearings;
if (input_bearings.size() > 0 &&
route_parameters.coordinates.size() != input_bearings.size())
{
json_result.values["status_message"] =
"Number of bearings does not match number of coordinate";
return Status::Error;
}
std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size());
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
for (const auto i : util::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
phantom_node_pair_list[i].first =
decodeBase64<PhantomNode>(route_parameters.hints[i]);
if (phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes()))
{
continue;
}
}
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
const int range = input_bearings.size() > 0
? (input_bearings[i].second ? *input_bearings[i].second : 10)
: 180;
phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(
route_parameters.coordinates[i], bearing, range);
// we didn't found a fitting node, return error
if (!phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes()))
{
json_result.values["status_message"] =
std::string("Could not find a matching segment for coordinate ") +
std::to_string(i);
return Status::NoSegment;
}
BOOST_ASSERT(phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes()));
BOOST_ASSERT(phantom_node_pair_list[i].second.IsValid(facade->GetNumberOfNodes()));
}
auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
InternalRouteResult raw_route;
auto build_phantom_pairs =
[&raw_route](const PhantomNode &first_node, const PhantomNode &second_node)
{
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
};
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
if (1 == raw_route.segment_end_coordinates.size())
{
if (route_parameters.alternate_route && facade->GetCoreSize() == 0)
{
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route);
}
else
{
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
}
else
{
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
// we can only know this after the fact, different SCC ids still
// allow for connection in one direction.
if (raw_route.is_valid())
{
auto generator = MakeApiResponseGenerator(facade);
generator.DescribeRoute(route_parameters, raw_route, json_result);
json_result.values["status_message"] = "Found route between points";
}
else
{
auto first_component_id = snapped_phantoms.front().component.id;
auto not_in_same_component =
std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
[first_component_id](const PhantomNode &node)
{
return node.component.id != first_component_id;
});
if (not_in_same_component)
{
json_result.values["status_message"] = "Impossible route between points";
return Status::EmptyResult;
}
else
{
json_result.values["status_message"] = "No route found between points";
return Status::Error;
}
}
return Status::Ok;
}
Status HandleRequest(const api::RouteParameters &route_parameters,
util::json::Object &json_result);
};
}
}
+10 -3
View File
@@ -2,7 +2,6 @@
#define POLYLINECOMPRESSOR_H_
#include "osrm/coordinate.hpp"
#include "engine/segment_information.hpp"
#include <string>
#include <vector>
@@ -11,13 +10,21 @@ namespace osrm
{
namespace engine
{
namespace detail
{
constexpr double POLYLINE_PECISION = 1e5;
constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PECISION / COORDINATE_PRECISION;
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PECISION;
}
using CoordVectorForwardIter = std::vector<FixedPointCoordinate>::const_iterator;
// Encodes geometry into polyline format.
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
std::string polylineEncode(const std::vector<SegmentInformation> &geometry);
std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end);
// Decodes geometry from polyline format
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
std::vector<util::FixedPointCoordinate> polylineDecode(const std::string &polyline);
std::vector<util::FixedPointCoordinate> decodePolyline(const std::string &polyline);
}
}
-24
View File
@@ -1,24 +0,0 @@
#ifndef POLYLINE_FORMATTER_HPP
#define POLYLINE_FORMATTER_HPP
#include "engine/segment_information.hpp"
#include "osrm/json_container.hpp"
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
// Encodes geometry into polyline format, returning an encoded JSON object
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
util::json::String polylineEncodeAsJSON(const std::vector<SegmentInformation> &geometry);
// Does not encode the geometry in polyline format, instead returning an unencoded JSON object
util::json::Array polylineUnencodedAsJSON(const std::vector<SegmentInformation> &geometry);
}
}
#endif /* POLYLINE_FORMATTER_HPP */
-149
View File
@@ -1,149 +0,0 @@
#ifndef EXTRACT_ROUTE_NAMES_H
#define EXTRACT_ROUTE_NAMES_H
#include <boost/assert.hpp>
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
namespace osrm
{
namespace engine
{
struct RouteNames
{
std::string shortest_path_name_1;
std::string shortest_path_name_2;
std::string alternative_path_name_1;
std::string alternative_path_name_2;
};
namespace detail
{
template <class SegmentT>
SegmentT pickNextLongestSegment(const std::vector<SegmentT> &segment_list,
const unsigned blocked_name_id)
{
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)
{
if (segment.name_id != blocked_name_id && segment.length > result_segment.length &&
segment.name_id != 0)
{
result_segment = segment;
}
}
return result_segment;
}
} // ns detail
template <class DataFacadeT, class SegmentT>
RouteNames extractRouteNames(std::vector<SegmentT> &shortest_path_segments,
std::vector<SegmentT> &alternative_path_segments,
const DataFacadeT *facade)
{
RouteNames route_names;
if (shortest_path_segments.empty())
{
return route_names;
}
SegmentT shortest_segment_1, shortest_segment_2;
SegmentT alternative_segment_1, alternative_segment_2;
const auto length_comperator = [](const SegmentT &a, const SegmentT &b)
{
return a.length > b.length;
};
const auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
{
return a.name_id < b.name_id;
};
// pick the longest segment for the shortest path.
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
shortest_segment_1 = shortest_path_segments[0];
if (!alternative_path_segments.empty())
{
std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
length_comperator);
// also pick the longest segment for the alternative path
alternative_segment_1 = alternative_path_segments[0];
}
// compute the set difference (for shortest path) depending on names between shortest and
// alternative
std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
name_id_comperator);
std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(),
alternative_path_segments.begin(), alternative_path_segments.end(),
shortest_path_set_difference.begin(), name_id_comperator);
std::sort(shortest_path_set_difference.begin(), shortest_path_set_difference.end(),
length_comperator);
shortest_segment_2 =
pickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
// compute the set difference (for alternative path) depending on names between shortest and
// alternative
// vectors are still sorted, no need to do again
BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(), shortest_path_segments.end(),
name_id_comperator));
BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(), alternative_path_segments.end(),
name_id_comperator));
std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(),
shortest_path_segments.begin(), shortest_path_segments.end(),
alternative_path_set_difference.begin(), name_id_comperator);
std::sort(alternative_path_set_difference.begin(), alternative_path_set_difference.end(),
length_comperator);
if (!alternative_path_segments.empty())
{
alternative_segment_2 =
pickNextLongestSegment(alternative_path_set_difference, alternative_segment_1.name_id);
}
// move the segments into the order in which they occur.
if (shortest_segment_1.position > shortest_segment_2.position)
{
std::swap(shortest_segment_1, shortest_segment_2);
}
if (alternative_segment_1.position > alternative_segment_2.position)
{
std::swap(alternative_segment_1, alternative_segment_2);
}
// fetching names for the selected segments
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);
if (!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;
}
}
}
#endif // EXTRACT_ROUTE_NAMES_H
-129
View File
@@ -1,129 +0,0 @@
/*
Copyright (c) 2016, Project OSRM contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ROUTE_PARAMETERS_HPP
#define ROUTE_PARAMETERS_HPP
#include "osrm/coordinate.hpp"
#include <boost/optional/optional.hpp>
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
struct RouteParameters
{
RouteParameters();
void SetZoomLevel(const short level);
void SetNumberOfResults(const short number);
void SetAlternateRouteFlag(const bool flag);
void SetUTurn(const bool flag);
void SetAllUTurns(const bool flag);
void SetClassify(const bool classify);
void SetMatchingBeta(const double beta);
void SetGPSPrecision(const double precision);
void SetDeprecatedAPIFlag(const std::string &);
void SetChecksum(const unsigned check_sum);
void SetInstructionFlag(const bool flag);
void SetService(const std::string &service);
void SetOutputFormat(const std::string &format);
void SetJSONpParameter(const std::string &parameter);
void AddHint(const std::string &hint);
void AddTimestamp(const unsigned timestamp);
bool AddBearing(int bearing, boost::optional<int> range);
void SetLanguage(const std::string &language);
void SetGeometryFlag(const bool flag);
void SetCompressionFlag(const bool flag);
void AddCoordinate(const double latitude, const double longitude);
void AddDestination(const double latitude, const double longitude);
void AddSource(const double latitude, const double longitude);
void SetCoordinatesFromGeometry(const std::string &geometry_string);
bool SetX(const int x);
bool SetZ(const int z);
bool SetY(const int y);
short zoom_level;
bool print_instructions;
bool alternate_route;
bool geometry;
bool compression;
bool deprecatedAPI;
bool uturn_default;
bool classify;
double matching_beta;
double gps_precision;
unsigned check_sum;
short num_results;
std::string service;
std::string output_format;
std::string jsonp_parameter;
std::string language;
std::vector<std::string> hints;
std::vector<unsigned> timestamps;
std::vector<std::pair<const int, const boost::optional<int>>> bearings;
std::vector<bool> uturns;
std::vector<FixedPointCoordinate> coordinates;
std::vector<bool> is_destination;
std::vector<bool> is_source;
int z;
int x;
int y;
};
}
}
#endif // ROUTE_PARAMETERS_HPP
@@ -40,11 +40,8 @@ class DirectShortestPathRouting final
~DirectShortestPathRouting() {}
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<bool> &uturn_indicators,
InternalRouteResult &raw_route_data) const
{
(void)uturn_indicators; // unused
// Get distance to next pair of target nodes.
BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
"Direct Shortest Path Query only accepts a single source and target pair. "
@@ -24,13 +24,6 @@ namespace osrm
namespace engine
{
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1;
SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1;
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2;
SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2;
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3;
SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3;
namespace routing_algorithms
{
@@ -327,13 +320,13 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
BOOST_ASSERT(start_index < end_index);
for (std::size_t i = start_index; i < end_index; ++i)
{
unpacked_path.emplace_back(id_vector[i], name_index,
extractor::TurnInstruction::NoTurn, weight_vector[i],
travel_mode);
unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i],
extractor::TurnInstruction::NoTurn,
travel_mode});
}
BOOST_ASSERT(unpacked_path.size() > 0);
unpacked_path.back().turn_instruction = turn_instruction;
unpacked_path.back().segment_duration += (ed.distance - total_weight);
unpacked_path.back().duration_until_turn += (ed.distance - total_weight);
}
}
std::vector<unsigned> id_vector;
@@ -373,7 +366,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
unpacked_path.emplace_back(
PathData{id_vector[i], phantom_node_pair.target_phantom.name_id,
extractor::TurnInstruction::NoTurn, 0,
0, extractor::TurnInstruction::NoTurn,
target_traversed_in_reverse
? phantom_node_pair.target_phantom.backward_travel_mode
: phantom_node_pair.target_phantom.forward_travel_mode});
@@ -392,7 +385,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
// looks like a trivially true check but tests for underflow
BOOST_ASSERT(last_index > second_to_last_index);
if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
if (unpacked_path[last_index].turn_via_node == unpacked_path[second_to_last_index].turn_via_node)
{
unpacked_path.pop_back();
}
@@ -755,7 +748,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
double distance = 0;
for (const auto &p : unpacked_path)
{
current_coordinate = facade->GetCoordinateOfNode(p.node);
current_coordinate = facade->GetCoordinateOfNode(p.turn_via_node);
distance += util::coordinate_calculation::haversineDistance(previous_coordinate,
current_coordinate);
previous_coordinate = current_coordinate;
@@ -9,6 +9,7 @@
#include "util/integer_range.hpp"
#include <boost/assert.hpp>
#include <boost/optional.hpp>
namespace osrm
{
@@ -236,11 +237,13 @@ class ShortestPathRouting final
}
}
static const constexpr bool UTURN_DEFAULT = false;
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
const std::vector<bool> &uturn_indicators,
const std::vector<boost::optional<bool>> &uturn_indicators,
InternalRouteResult &raw_route_data) const
{
BOOST_ASSERT(uturn_indicators.size() == phantom_nodes_vector.size() + 1);
BOOST_ASSERT(uturn_indicators.empty() || uturn_indicators.size() == phantom_nodes_vector.size() + 1);
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
@@ -266,6 +269,8 @@ class ShortestPathRouting final
std::vector<NodeID> total_packed_path_to_reverse;
std::vector<std::size_t> packed_leg_to_reverse_begin;
const bool use_uturn_indicators = !uturn_indicators.empty();
std::size_t current_leg = 0;
// this implements a dynamic program that finds the shortest route through
// a list of vias
@@ -280,8 +285,8 @@ class ShortestPathRouting final
const auto &source_phantom = phantom_node_pair.source_phantom;
const auto &target_phantom = phantom_node_pair.target_phantom;
BOOST_ASSERT(current_leg + 1 < uturn_indicators.size());
const bool allow_u_turn_at_via = uturn_indicators[current_leg + 1];
const bool use_uturn_default = !use_uturn_indicators || !uturn_indicators[current_leg + 1];
const bool allow_u_turn_at_via = (use_uturn_default && UTURN_DEFAULT) || (!use_uturn_default && *uturn_indicators[current_leg + 1]);
bool search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
-47
View File
@@ -1,47 +0,0 @@
#ifndef SEARCH_ENGINE_HPP
#define SEARCH_ENGINE_HPP
#include "engine/search_engine_data.hpp"
#include "engine/routing_algorithms/alternative_path.hpp"
#include "engine/routing_algorithms/many_to_many.hpp"
#include "engine/routing_algorithms/map_matching.hpp"
#include "engine/routing_algorithms/shortest_path.hpp"
#include "engine/routing_algorithms/direct_shortest_path.hpp"
#include <type_traits>
namespace osrm
{
namespace engine
{
template <class DataFacadeT> class SearchEngine
{
private:
DataFacadeT *facade;
SearchEngineData engine_working_data;
public:
routing_algorithms::ShortestPathRouting<DataFacadeT> shortest_path;
routing_algorithms::DirectShortestPathRouting<DataFacadeT> direct_shortest_path;
routing_algorithms::AlternativeRouting<DataFacadeT> alternative_path;
routing_algorithms::ManyToManyRouting<DataFacadeT> distance_table;
routing_algorithms::MapMatching<DataFacadeT> map_matching;
explicit SearchEngine(DataFacadeT *facade)
: facade(facade), shortest_path(facade, engine_working_data),
direct_shortest_path(facade, engine_working_data),
alternative_path(facade, engine_working_data),
distance_table(facade, engine_working_data), map_matching(facade, engine_working_data)
{
static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
static_assert(std::is_object<DataFacadeT>::value,
"don't instantiate with void, function, or reference");
}
~SearchEngine() {}
};
}
}
#endif // SEARCH_ENGINE_HPP
-60
View File
@@ -1,60 +0,0 @@
#ifndef SEGMENT_INFORMATION_HPP
#define SEGMENT_INFORMATION_HPP
#include "extractor/turn_instructions.hpp"
#include "extractor/travel_mode.hpp"
#include "util/typedefs.hpp"
#include "osrm/coordinate.hpp"
#include <utility>
namespace osrm
{
namespace engine
{
// Struct fits everything in one cache line
struct SegmentInformation
{
util::FixedPointCoordinate location;
NodeID name_id;
EdgeWeight duration;
float length;
short pre_turn_bearing; // more than enough [0..3600] fits into 12 bits
short post_turn_bearing;
extractor::TurnInstruction turn_instruction;
extractor::TravelMode travel_mode;
bool necessary;
bool is_via_location;
explicit SegmentInformation(util::FixedPointCoordinate location,
const NodeID name_id,
const EdgeWeight duration,
const float length,
const extractor::TurnInstruction turn_instruction,
const bool necessary,
const bool is_via_location,
const extractor::TravelMode travel_mode)
: location(std::move(location)), name_id(name_id), duration(duration), length(length),
pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction),
travel_mode(travel_mode), necessary(necessary), is_via_location(is_via_location)
{
}
explicit SegmentInformation(util::FixedPointCoordinate location,
const NodeID name_id,
const EdgeWeight duration,
const float length,
const extractor::TurnInstruction turn_instruction,
const extractor::TravelMode travel_mode)
: location(std::move(location)), name_id(name_id), duration(duration), length(length),
pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction),
travel_mode(travel_mode),
necessary(turn_instruction != extractor::TurnInstruction::NoTurn), is_via_location(false)
{
}
};
}
}
#endif /* SEGMENT_INFORMATION_HPP */
+18
View File
@@ -0,0 +1,18 @@
#ifndef ENGINE_STATUS_HPP
#define ENGINE_STATUS_HPP
namespace osrm
{
namespace engine
{
enum class Status
{
Ok,
Error
};
}
}
#endif