Add viaroute suport for new API
This commit is contained in:
parent
54ee76bcef
commit
f3e72623e9
@ -45,7 +45,7 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND}
|
|||||||
COMMENT "Configuring revision fingerprint"
|
COMMENT "Configuring revision fingerprint"
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests)
|
add_custom_target(tests DEPENDS engine-tests extractor-tests util-tests server-tests)
|
||||||
add_custom_target(benchmarks DEPENDS rtree-bench)
|
add_custom_target(benchmarks DEPENDS rtree-bench)
|
||||||
|
|
||||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
|
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
|
||||||
@ -63,6 +63,7 @@ file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
|
|||||||
file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
|
file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
|
||||||
file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
|
file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
|
||||||
file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
|
file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
|
||||||
|
file(GLOB ServerTestsGlob unit_tests/server/*.cpp)
|
||||||
file(GLOB IOTestsGlob unit_tests/io/*.cpp)
|
file(GLOB IOTestsGlob unit_tests/io/*.cpp)
|
||||||
|
|
||||||
add_library(UTIL OBJECT ${UtilGlob})
|
add_library(UTIL OBJECT ${UtilGlob})
|
||||||
@ -88,6 +89,7 @@ add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)
|
|||||||
add_executable(engine-tests EXCLUDE_FROM_ALL unit_tests/engine_tests.cpp ${EngineTestsGlob} $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL>)
|
add_executable(engine-tests EXCLUDE_FROM_ALL unit_tests/engine_tests.cpp ${EngineTestsGlob} $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_executable(extractor-tests EXCLUDE_FROM_ALL unit_tests/extractor_tests.cpp ${ExtractorTestsGlob} $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
add_executable(extractor-tests EXCLUDE_FROM_ALL unit_tests/extractor_tests.cpp ${ExtractorTestsGlob} $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
|
||||||
add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob} $<TARGET_OBJECTS:UTIL>)
|
add_executable(util-tests EXCLUDE_FROM_ALL unit_tests/util_tests.cpp ${UtilTestsGlob} $<TARGET_OBJECTS:UTIL>)
|
||||||
|
add_executable(server-tests EXCLUDE_FROM_ALL unit_tests/server_tests.cpp ${ServerTestsGlob} $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:SERVER>)
|
||||||
|
|
||||||
# Benchmarks
|
# Benchmarks
|
||||||
add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL>)
|
add_executable(rtree-bench EXCLUDE_FROM_ALL src/benchmarks/static_rtree.cpp $<TARGET_OBJECTS:UTIL>)
|
||||||
@ -332,6 +334,7 @@ target_link_libraries(osrm_extract ${EXTRACTOR_LIBRARIES})
|
|||||||
target_link_libraries(osrm_store ${STORAGE_LIBRARIES})
|
target_link_libraries(osrm_store ${STORAGE_LIBRARIES})
|
||||||
# Tests
|
# Tests
|
||||||
target_link_libraries(engine-tests ${ENGINE_LIBRARIES})
|
target_link_libraries(engine-tests ${ENGINE_LIBRARIES})
|
||||||
|
target_link_libraries(server-tests osrm ${Boost_LIBRARIES})
|
||||||
target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES})
|
target_link_libraries(extractor-tests ${EXTRACTOR_LIBRARIES})
|
||||||
target_link_libraries(rtree-bench ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES})
|
target_link_libraries(rtree-bench ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TBB_LIBRARIES})
|
||||||
target_link_libraries(util-tests ${UTIL_LIBRARIES})
|
target_link_libraries(util-tests ${UTIL_LIBRARIES})
|
||||||
|
70
include/engine/api/base_api.hpp
Normal file
70
include/engine/api/base_api.hpp
Normal 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 ¶meters_)
|
||||||
|
: 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 ¶meters;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only expose non-templated version
|
||||||
|
using BaseAPI = detail::BaseAPI_<std::true_type>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
51
include/engine/api/base_parameters.hpp
Normal file
51
include/engine/api/base_parameters.hpp
Normal 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
include/engine/api/json_factory.hpp
Normal file
90
include/engine/api/json_factory.hpp
Normal 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
include/engine/api/match_parameters.hpp
Normal file
25
include/engine/api/match_parameters.hpp
Normal 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
include/engine/api/nearest_parameters.hpp
Normal file
23
include/engine/api/nearest_parameters.hpp
Normal 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
include/engine/api/route_api.hpp
Normal file
135
include/engine/api/route_api.hpp
Normal 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 ¶meters_)
|
||||||
|
: 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 ¶meters;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose non-templated version
|
||||||
|
using RouteAPI = detail::RouteAPI_<std::true_type>;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
58
include/engine/api/route_parameters.hpp
Normal file
58
include/engine/api/route_parameters.hpp
Normal 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
include/engine/api/table_parameters.hpp
Normal file
27
include/engine/api/table_parameters.hpp
Normal 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
include/engine/api/trip_parameters.hpp
Normal file
24
include/engine/api/trip_parameters.hpp
Normal 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
|
@ -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_
|
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "extractor/edge_based_node.hpp"
|
#include "extractor/edge_based_node.hpp"
|
||||||
#include "extractor/external_memory_node.hpp"
|
#include "extractor/external_memory_node.hpp"
|
||||||
|
#include "contractor/query_edge.hpp"
|
||||||
#include "engine/phantom_node.hpp"
|
#include "engine/phantom_node.hpp"
|
||||||
#include "extractor/turn_instructions.hpp"
|
#include "extractor/turn_instructions.hpp"
|
||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
@ -29,11 +30,11 @@ namespace datafacade
|
|||||||
|
|
||||||
using EdgeRange = util::range<EdgeID>;
|
using EdgeRange = util::range<EdgeID>;
|
||||||
|
|
||||||
template <class EdgeDataT> class BaseDataFacade
|
class BaseDataFacade
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using EdgeData = contractor::QueryEdge::EdgeData;
|
||||||
using RTreeLeaf = extractor::EdgeBasedNode;
|
using RTreeLeaf = extractor::EdgeBasedNode;
|
||||||
using EdgeData = EdgeDataT;
|
|
||||||
BaseDataFacade() {}
|
BaseDataFacade() {}
|
||||||
virtual ~BaseDataFacade() {}
|
virtual ~BaseDataFacade() {}
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ template <class EdgeDataT> class BaseDataFacade
|
|||||||
|
|
||||||
virtual NodeID GetTarget(const EdgeID e) const = 0;
|
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;
|
virtual EdgeID BeginEdges(const NodeID n) const = 0;
|
||||||
|
|
||||||
@ -94,10 +95,22 @@ template <class EdgeDataT> class BaseDataFacade
|
|||||||
const int bearing = 0,
|
const int bearing = 0,
|
||||||
const int bearing_range = 180) = 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(
|
virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||||
const util::FixedPointCoordinate input_coordinate,
|
const util::FixedPointCoordinate input_coordinate,
|
||||||
const int bearing = 0,
|
const double max_distance,
|
||||||
const int bearing_range = 180) = 0;
|
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;
|
virtual unsigned GetCheckSum() const = 0;
|
||||||
|
|
||||||
|
@ -46,17 +46,17 @@ namespace engine
|
|||||||
namespace datafacade
|
namespace datafacade
|
||||||
{
|
{
|
||||||
|
|
||||||
template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT>
|
class InternalDataFacade final : public BaseDataFacade
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using super = BaseDataFacade<EdgeDataT>;
|
using super = BaseDataFacade;
|
||||||
using QueryGraph = util::StaticGraph<typename super::EdgeData>;
|
using QueryGraph = util::StaticGraph<typename super::EdgeData>;
|
||||||
using InputEdge = typename QueryGraph::InputEdge;
|
using InputEdge = typename QueryGraph::InputEdge;
|
||||||
using RTreeLeaf = typename super::RTreeLeaf;
|
using RTreeLeaf = typename super::RTreeLeaf;
|
||||||
using InternalRTree =
|
using InternalRTree =
|
||||||
util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, false>::vector, false>;
|
util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, false>::vector, false>;
|
||||||
using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade<EdgeDataT>>;
|
using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>;
|
||||||
|
|
||||||
InternalDataFacade() {}
|
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); }
|
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);
|
return m_query_graph->GetEdgeData(e);
|
||||||
}
|
}
|
||||||
@ -386,10 +386,52 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad
|
|||||||
bearing_range);
|
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(
|
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||||
const util::FixedPointCoordinate input_coordinate,
|
const util::FixedPointCoordinate input_coordinate,
|
||||||
const int bearing = 0,
|
const double max_distance,
|
||||||
const int bearing_range = 180) override final
|
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())
|
if (!m_static_rtree.get())
|
||||||
{
|
{
|
||||||
|
@ -36,12 +36,11 @@ namespace engine
|
|||||||
namespace datafacade
|
namespace datafacade
|
||||||
{
|
{
|
||||||
|
|
||||||
template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT>
|
class SharedDataFacade final : public BaseDataFacade
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using EdgeData = EdgeDataT;
|
using super = BaseDataFacade;
|
||||||
using super = BaseDataFacade<EdgeData>;
|
|
||||||
using QueryGraph = util::StaticGraph<EdgeData, true>;
|
using QueryGraph = util::StaticGraph<EdgeData, true>;
|
||||||
using GraphNode = typename QueryGraph::NodeArrayEntry;
|
using GraphNode = typename QueryGraph::NodeArrayEntry;
|
||||||
using GraphEdge = typename QueryGraph::EdgeArrayEntry;
|
using GraphEdge = typename QueryGraph::EdgeArrayEntry;
|
||||||
@ -50,7 +49,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
|
|||||||
using RTreeLeaf = typename super::RTreeLeaf;
|
using RTreeLeaf = typename super::RTreeLeaf;
|
||||||
using SharedRTree =
|
using SharedRTree =
|
||||||
util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, true>::vector, true>;
|
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 TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
|
||||||
using RTreeNode = typename SharedRTree::TreeNode;
|
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); }
|
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);
|
return m_query_graph->GetEdgeData(e);
|
||||||
}
|
}
|
||||||
@ -454,10 +453,52 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<
|
|||||||
bearing_range);
|
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(
|
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||||
const util::FixedPointCoordinate input_coordinate,
|
const util::FixedPointCoordinate input_coordinate,
|
||||||
const int bearing = 0,
|
const double max_distance,
|
||||||
const int bearing_range = 180) override final
|
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)
|
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);
|
input_coordinate, bearing, bearing_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned GetCheckSum() const override final { return m_check_sum; }
|
unsigned GetCheckSum() const override final { return m_check_sum; }
|
||||||
|
|
||||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
|
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef DOUGLAS_PEUCKER_HPP_
|
#ifndef DOUGLAS_PEUCKER_HPP_
|
||||||
#define DOUGLAS_PEUCKER_HPP_
|
#define DOUGLAS_PEUCKER_HPP_
|
||||||
|
|
||||||
#include "engine/segment_information.hpp"
|
#include "util/coordinate.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iterator>
|
#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
|
// Input is vector of pairs. Each pair consists of the point information and a
|
||||||
// bit indicating if the points is present in the generalization.
|
// bit indicating if the points is present in the generalization.
|
||||||
// Note: points may also be pre-selected*/
|
// Note: points may also be pre-selected*/
|
||||||
void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
|
std::vector<util::FixedPointCoordinate>
|
||||||
std::vector<SegmentInformation>::iterator end,
|
douglasPeucker(std::vector<util::FixedPointCoordinate>::const_iterator begin,
|
||||||
const unsigned zoom_level);
|
std::vector<util::FixedPointCoordinate>::const_iterator end,
|
||||||
|
const unsigned zoom_level);
|
||||||
|
|
||||||
// Convenience range-based function
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
#ifndef ENGINE_HPP
|
#ifndef ENGINE_HPP
|
||||||
#define ENGINE_HPP
|
#define ENGINE_HPP
|
||||||
|
|
||||||
#include "contractor/query_edge.hpp"
|
#include "engine/status.hpp"
|
||||||
|
#include "storage/shared_barriers.hpp"
|
||||||
#include "osrm/json_container.hpp"
|
#include "util/json_container.hpp"
|
||||||
#include "osrm/osrm.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -13,11 +12,6 @@
|
|||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace storage
|
|
||||||
{
|
|
||||||
struct SharedBarriers;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
namespace json
|
namespace json
|
||||||
@ -29,41 +23,43 @@ struct Object;
|
|||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
struct EngineConfig;
|
struct EngineConfig;
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
struct RouteParameters;
|
struct RouteParameters;
|
||||||
|
}
|
||||||
namespace plugins
|
namespace plugins
|
||||||
{
|
{
|
||||||
class BasePlugin;
|
class ViaRoutePlugin;
|
||||||
}
|
}
|
||||||
namespace datafacade
|
namespace datafacade
|
||||||
{
|
{
|
||||||
template <class EdgeDataT> class BaseDataFacade;
|
class BaseDataFacade;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Engine final
|
class Engine final
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
using PluginMap = std::unordered_map<std::string, std::unique_ptr<plugins::BasePlugin>>;
|
|
||||||
|
|
||||||
public:
|
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(EngineConfig &config_);
|
||||||
|
|
||||||
Engine(const Engine &) = delete;
|
Engine(const Engine &) = delete;
|
||||||
Engine &operator=(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:
|
private:
|
||||||
void RegisterPlugin(plugins::BasePlugin *plugin);
|
std::unique_ptr<EngineLock> lock;
|
||||||
PluginMap plugin_map;
|
std::unique_ptr<plugins::ViaRoutePlugin> route_plugin;
|
||||||
// will only be initialized if shared memory is used
|
std::unique_ptr<datafacade::BaseDataFacade> query_data_facade;
|
||||||
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();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
// 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.
|
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||||
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||||
const util::FixedPointCoordinate input_coordinate,
|
const util::FixedPointCoordinate input_coordinate, const double max_distance)
|
||||||
const int bearing = 0,
|
|
||||||
const int bearing_range = 180)
|
|
||||||
{
|
{
|
||||||
bool has_small_component = false;
|
bool has_small_component = false;
|
||||||
bool has_big_component = false;
|
bool has_big_component = false;
|
||||||
auto results = rtree.Nearest(
|
auto results = rtree.Nearest(
|
||||||
input_coordinate,
|
input_coordinate,
|
||||||
[this, bearing, bearing_range, &has_big_component, &has_small_component](
|
[&has_big_component, &has_small_component](const EdgeData &data)
|
||||||
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 =
|
auto use_segment =
|
||||||
(!has_small_component || (!has_big_component && !data.component.is_tiny));
|
(!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);
|
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:
|
private:
|
||||||
std::vector<PhantomNodeWithDistance>
|
std::vector<PhantomNodeWithDistance>
|
||||||
MakePhantomNodes(const util::FixedPointCoordinate input_coordinate,
|
MakePhantomNodes(const util::FixedPointCoordinate input_coordinate,
|
||||||
|
78
include/engine/guidance/assemble_geometry.hpp
Normal file
78
include/engine/guidance/assemble_geometry.hpp
Normal file
@ -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
include/engine/guidance/assemble_leg.hpp
Normal file
165
include/engine/guidance/assemble_leg.hpp
Normal 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_
|
22
include/engine/guidance/assemble_overview.hpp
Normal file
22
include/engine/guidance/assemble_overview.hpp
Normal file
@ -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
|
37
include/engine/guidance/assemble_route.hpp
Normal file
37
include/engine/guidance/assemble_route.hpp
Normal file
@ -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
include/engine/guidance/assemble_steps.hpp
Normal file
135
include/engine/guidance/assemble_steps.hpp
Normal 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
include/engine/guidance/leg_geometry.hpp
Normal file
54
include/engine/guidance/leg_geometry.hpp
Normal 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
include/engine/guidance/route.hpp
Normal file
18
include/engine/guidance/route.hpp
Normal 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
include/engine/guidance/route_leg.hpp
Normal file
30
include/engine/guidance/route_leg.hpp
Normal 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
include/engine/guidance/route_step.hpp
Normal file
39
include/engine/guidance/route_step.hpp
Normal 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
|
@ -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
include/engine/guidance/step_maneuver.hpp
Normal file
26
include/engine/guidance/step_maneuver.hpp
Normal 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
include/engine/hint.hpp
Normal file
61
include/engine/hint.hpp
Normal 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
|
@ -17,26 +17,15 @@ namespace engine
|
|||||||
|
|
||||||
struct PathData
|
struct PathData
|
||||||
{
|
{
|
||||||
PathData()
|
// id of via node of the turn
|
||||||
: node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT),
|
NodeID turn_via_node;
|
||||||
turn_instruction(extractor::TurnInstruction::NoTurn),
|
// name of the street that leads to the turn
|
||||||
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;
|
|
||||||
unsigned name_id;
|
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;
|
extractor::TurnInstruction turn_instruction;
|
||||||
|
// travel mode of the street that leads to the turn
|
||||||
extractor::TravelMode travel_mode : 4;
|
extractor::TravelMode travel_mode : 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ struct PhantomNode
|
|||||||
bool operator==(const PhantomNode &other) const { return location == other.location; }
|
bool operator==(const PhantomNode &other) const { return location == other.location; }
|
||||||
|
|
||||||
template <class OtherT>
|
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;
|
forward_node_id = other.forward_edge_based_node_id;
|
||||||
reverse_node_id = other.reverse_edge_based_node_id;
|
reverse_node_id = other.reverse_edge_based_node_id;
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#ifndef BASE_PLUGIN_HPP
|
#ifndef BASE_PLUGIN_HPP
|
||||||
#define 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/phantom_node.hpp"
|
||||||
|
#include "engine/status.hpp"
|
||||||
|
|
||||||
#include "osrm/coordinate.hpp"
|
#include "util/coordinate.hpp"
|
||||||
#include "osrm/json_container.hpp"
|
#include "util/json_container.hpp"
|
||||||
#include "osrm/route_parameters.hpp"
|
#include "util/integer_range.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -20,38 +23,32 @@ namespace plugins
|
|||||||
|
|
||||||
class BasePlugin
|
class BasePlugin
|
||||||
{
|
{
|
||||||
public:
|
protected:
|
||||||
enum class Status : int
|
datafacade::BaseDataFacade &facade;
|
||||||
{
|
BasePlugin(datafacade::BaseDataFacade &facade_) : facade(facade_) {}
|
||||||
Ok = 200,
|
|
||||||
EmptyResult = 207,
|
|
||||||
NoSegment = 208,
|
|
||||||
Error = 400
|
|
||||||
};
|
|
||||||
|
|
||||||
BasePlugin() {}
|
bool CheckAllCoordinates(const std::vector<util::FixedPointCoordinate> &coordinates)
|
||||||
// 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
|
|
||||||
{
|
{
|
||||||
if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
|
return !std::any_of(std::begin(coordinates), std::end(coordinates),
|
||||||
[](const util::FixedPointCoordinate coordinate)
|
[](const util::FixedPointCoordinate &coordinate)
|
||||||
{
|
{
|
||||||
return !coordinate.IsValid();
|
return !coordinate.IsValid();
|
||||||
}))
|
});
|
||||||
{
|
}
|
||||||
return false;
|
|
||||||
}
|
Status Error(const std::string &code,
|
||||||
return true;
|
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.
|
// 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.
|
// Returns true if all phantom nodes are in the same component after snapping.
|
||||||
std::vector<PhantomNode> snapPhantomNodes(
|
std::vector<PhantomNode>
|
||||||
const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
|
SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const
|
||||||
{
|
{
|
||||||
const auto check_component_id_is_tiny =
|
const auto check_component_id_is_tiny =
|
||||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||||
@ -111,6 +108,69 @@ class BasePlugin
|
|||||||
|
|
||||||
return snapped_phantoms;
|
return snapped_phantoms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<PhantomNodePair> GetPhantomNodes(const api::BaseParameters ¶meters)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
#ifndef VIA_ROUTE_HPP
|
#ifndef VIA_ROUTE_HPP
|
||||||
#define VIA_ROUTE_HPP
|
#define VIA_ROUTE_HPP
|
||||||
|
|
||||||
|
#include "engine/datafacade/datafacade_base.hpp"
|
||||||
#include "engine/plugins/plugin_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/object_encoder.hpp"
|
||||||
#include "engine/search_engine.hpp"
|
#include "engine/search_engine_data.hpp"
|
||||||
#include "util/for_each_pair.hpp"
|
#include "engine/routing_algorithms/shortest_path.hpp"
|
||||||
#include "util/integer_range.hpp"
|
#include "engine/routing_algorithms/alternative_path.hpp"
|
||||||
#include "util/make_unique.hpp"
|
#include "engine/routing_algorithms/direct_shortest_path.hpp"
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/json_container.hpp"
|
||||||
#include "util/timing_util.hpp"
|
|
||||||
#include "osrm/json_container.hpp"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
@ -27,146 +26,20 @@ namespace engine
|
|||||||
namespace plugins
|
namespace plugins
|
||||||
{
|
{
|
||||||
|
|
||||||
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
class ViaRoutePlugin final : public BasePlugin
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string descriptor_string;
|
SearchEngineData heaps;
|
||||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path;
|
||||||
DataFacadeT *facade;
|
routing_algorithms::AlternativeRouting<datafacade::BaseDataFacade> alternative_path;
|
||||||
|
routing_algorithms::DirectShortestPathRouting<datafacade::BaseDataFacade> direct_shortest_path;
|
||||||
int max_locations_viaroute;
|
int max_locations_viaroute;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ViaRoutePlugin(DataFacadeT *facade, int max_locations_viaroute)
|
explicit ViaRoutePlugin(datafacade::BaseDataFacade &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);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ViaRoutePlugin() {}
|
Status HandleRequest(const api::RouteParameters &route_parameters,
|
||||||
|
util::json::Object &json_result);
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define POLYLINECOMPRESSOR_H_
|
#define POLYLINECOMPRESSOR_H_
|
||||||
|
|
||||||
#include "osrm/coordinate.hpp"
|
#include "osrm/coordinate.hpp"
|
||||||
#include "engine/segment_information.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -11,13 +10,21 @@ namespace osrm
|
|||||||
{
|
{
|
||||||
namespace engine
|
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.
|
// Encodes geometry into polyline format.
|
||||||
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
// 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
|
// Decodes geometry from polyline format
|
||||||
// See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
|
@ -1,150 +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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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())
|
|
||||||
{
|
|
||||||
if (alternative_segment_1.position > alternative_segment_2.position)
|
|
||||||
{
|
|
||||||
std::swap(alternative_segment_1, alternative_segment_2);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
@ -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 ¶meter);
|
|
||||||
|
|
||||||
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() {}
|
~DirectShortestPathRouting() {}
|
||||||
|
|
||||||
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||||
const std::vector<bool> &uturn_indicators,
|
|
||||||
InternalRouteResult &raw_route_data) const
|
InternalRouteResult &raw_route_data) const
|
||||||
{
|
{
|
||||||
(void)uturn_indicators; // unused
|
|
||||||
|
|
||||||
// Get distance to next pair of target nodes.
|
// Get distance to next pair of target nodes.
|
||||||
BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
|
BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
|
||||||
"Direct Shortest Path Query only accepts a single source and target pair. "
|
"Direct Shortest Path Query only accepts a single source and target pair. "
|
||||||
|
@ -24,13 +24,6 @@ namespace osrm
|
|||||||
namespace engine
|
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
|
namespace routing_algorithms
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -327,13 +320,13 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
BOOST_ASSERT(start_index < end_index);
|
BOOST_ASSERT(start_index < end_index);
|
||||||
for (std::size_t i = start_index; i < end_index; ++i)
|
for (std::size_t i = start_index; i < end_index; ++i)
|
||||||
{
|
{
|
||||||
unpacked_path.emplace_back(id_vector[i], name_index,
|
unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i],
|
||||||
extractor::TurnInstruction::NoTurn, weight_vector[i],
|
extractor::TurnInstruction::NoTurn,
|
||||||
travel_mode);
|
travel_mode});
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
BOOST_ASSERT(unpacked_path.size() > 0);
|
||||||
unpacked_path.back().turn_instruction = turn_instruction;
|
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;
|
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);
|
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
|
||||||
unpacked_path.emplace_back(
|
unpacked_path.emplace_back(
|
||||||
PathData{id_vector[i], phantom_node_pair.target_phantom.name_id,
|
PathData{id_vector[i], phantom_node_pair.target_phantom.name_id,
|
||||||
extractor::TurnInstruction::NoTurn, 0,
|
0, extractor::TurnInstruction::NoTurn,
|
||||||
target_traversed_in_reverse
|
target_traversed_in_reverse
|
||||||
? phantom_node_pair.target_phantom.backward_travel_mode
|
? phantom_node_pair.target_phantom.backward_travel_mode
|
||||||
: phantom_node_pair.target_phantom.forward_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
|
// looks like a trivially true check but tests for underflow
|
||||||
BOOST_ASSERT(last_index > second_to_last_index);
|
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();
|
unpacked_path.pop_back();
|
||||||
}
|
}
|
||||||
@ -755,7 +748,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
|||||||
double distance = 0;
|
double distance = 0;
|
||||||
for (const auto &p : unpacked_path)
|
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,
|
distance += util::coordinate_calculation::haversineDistance(previous_coordinate,
|
||||||
current_coordinate);
|
current_coordinate);
|
||||||
previous_coordinate = current_coordinate;
|
previous_coordinate = current_coordinate;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace osrm
|
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,
|
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
|
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(
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||||
super::facade->GetNumberOfNodes());
|
super::facade->GetNumberOfNodes());
|
||||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||||
@ -266,6 +269,8 @@ class ShortestPathRouting final
|
|||||||
std::vector<NodeID> total_packed_path_to_reverse;
|
std::vector<NodeID> total_packed_path_to_reverse;
|
||||||
std::vector<std::size_t> packed_leg_to_reverse_begin;
|
std::vector<std::size_t> packed_leg_to_reverse_begin;
|
||||||
|
|
||||||
|
const bool use_uturn_indicators = !uturn_indicators.empty();
|
||||||
|
|
||||||
std::size_t current_leg = 0;
|
std::size_t current_leg = 0;
|
||||||
// this implements a dynamic program that finds the shortest route through
|
// this implements a dynamic program that finds the shortest route through
|
||||||
// a list of vias
|
// a list of vias
|
||||||
@ -280,8 +285,8 @@ class ShortestPathRouting final
|
|||||||
const auto &source_phantom = phantom_node_pair.source_phantom;
|
const auto &source_phantom = phantom_node_pair.source_phantom;
|
||||||
const auto &target_phantom = phantom_node_pair.target_phantom;
|
const auto &target_phantom = phantom_node_pair.target_phantom;
|
||||||
|
|
||||||
BOOST_ASSERT(current_leg + 1 < uturn_indicators.size());
|
const bool use_uturn_default = !use_uturn_indicators || !uturn_indicators[current_leg + 1];
|
||||||
const bool allow_u_turn_at_via = 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_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
||||||
bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
||||||
|
@ -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
|
|
@ -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
include/engine/status.hpp
Normal file
18
include/engine/status.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef ENGINE_STATUS_HPP
|
||||||
|
#define ENGINE_STATUS_HPP
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
Ok,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -28,13 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#ifndef OSRM_HPP
|
#ifndef OSRM_HPP
|
||||||
#define OSRM_HPP
|
#define OSRM_HPP
|
||||||
|
|
||||||
|
#include "osrm/status.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
|
|
||||||
struct LibOSRMConfig;
|
|
||||||
|
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
namespace json
|
namespace json
|
||||||
@ -47,11 +46,14 @@ namespace engine
|
|||||||
{
|
{
|
||||||
class Engine;
|
class Engine;
|
||||||
struct EngineConfig;
|
struct EngineConfig;
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
struct RouteParameters;
|
struct RouteParameters;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using engine::EngineConfig;
|
using engine::EngineConfig;
|
||||||
using engine::RouteParameters;
|
using engine::api::RouteParameters;
|
||||||
namespace json = util::json;
|
namespace json = util::json;
|
||||||
|
|
||||||
class OSRM
|
class OSRM
|
||||||
@ -61,8 +63,8 @@ class OSRM
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
OSRM(EngineConfig &lib_config);
|
OSRM(EngineConfig &lib_config);
|
||||||
~OSRM(); // needed because we need to define it with the implementation of OSRM_impl
|
~OSRM(); // needed for unique_ptr + impl abstraction
|
||||||
int RunQuery(const RouteParameters &route_parameters, json::Object &json_result);
|
Status Route(const RouteParameters &route_parameters, json::Object &json_result);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#ifndef GLOBAL_ROUTE_PARAMETERS_HPP
|
#ifndef GLOBAL_ROUTE_PARAMETERS_HPP
|
||||||
#define GLOBAL_ROUTE_PARAMETERS_HPP
|
#define GLOBAL_ROUTE_PARAMETERS_HPP
|
||||||
|
|
||||||
#include "engine/route_parameters.hpp"
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
using engine::RouteParameters;
|
using engine::api::RouteParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
include/osrm/status.hpp
Normal file
11
include/osrm/status.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef OSRM_STATUS_HPP
|
||||||
|
#define OSRM_STATUS_HPP
|
||||||
|
|
||||||
|
#include "engine/status.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
using engine::Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
82
include/server/api/base_parameters_grammar.hpp
Normal file
82
include/server/api/base_parameters_grammar.hpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
|
||||||
|
#define SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
|
||||||
|
|
||||||
|
#include "engine/api/base_parameters.hpp"
|
||||||
|
|
||||||
|
#include "engine/polyline_compressor.hpp"
|
||||||
|
#include "engine/hint.hpp"
|
||||||
|
|
||||||
|
#include <boost/spirit/include/qi_lit.hpp>
|
||||||
|
#include <boost/spirit/include/qi_char_.hpp>
|
||||||
|
#include <boost/spirit/include/qi_int.hpp>
|
||||||
|
#include <boost/spirit/include/qi_real.hpp>
|
||||||
|
#include <boost/spirit/include/qi_grammar.hpp>
|
||||||
|
#include <boost/spirit/include/qi_action.hpp>
|
||||||
|
#include <boost/spirit/include/qi_optional.hpp>
|
||||||
|
#include <boost/spirit/include/qi_attr_cast.hpp>
|
||||||
|
#include <boost/spirit/include/qi_operator.hpp>
|
||||||
|
#include <boost/spirit/include/qi_repeat.hpp>
|
||||||
|
#include <boost/spirit/include/qi_as_string.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace qi = boost::spirit::qi;
|
||||||
|
struct BaseParametersGrammar : boost::spirit::qi::grammar<std::string::iterator>
|
||||||
|
{
|
||||||
|
using Iterator = std::string::iterator;
|
||||||
|
using RadiusesT = std::vector<boost::optional<double>>;
|
||||||
|
|
||||||
|
BaseParametersGrammar(qi::rule<Iterator> &child_rule,
|
||||||
|
engine::api::BaseParameters ¶meters_)
|
||||||
|
: BaseParametersGrammar::base_type(child_rule), base_parameters(parameters_)
|
||||||
|
{
|
||||||
|
const auto add_bearing = [this](const boost::optional<boost::fusion::vector<short, short>> &bearing_range) {
|
||||||
|
boost::optional<engine::api::BaseParameters::Bearing> bearing;
|
||||||
|
if (bearing_range)
|
||||||
|
{
|
||||||
|
bearing = engine::api::BaseParameters::Bearing {boost::fusion::at_c<0>(*bearing_range), boost::fusion::at_c<1>(*bearing_range)};
|
||||||
|
}
|
||||||
|
base_parameters.bearings.push_back(std::move(bearing));
|
||||||
|
};
|
||||||
|
const auto set_radiuses = [this](RadiusesT& radiuses) {
|
||||||
|
base_parameters.radiuses = std::move(radiuses);
|
||||||
|
};
|
||||||
|
const auto add_hint = [this](const std::string& hint_string) {
|
||||||
|
if (hint_string.size() > 0)
|
||||||
|
{
|
||||||
|
base_parameters.hints.push_back(engine::Hint::FromBase64(hint_string));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
alpha_numeral = +qi::char_("a-zA-Z0-9");
|
||||||
|
base64_char = qi::char_("a-zA-Z0-9--_");
|
||||||
|
|
||||||
|
radiuses_rule = qi::lit("radiuses=") >> -qi::double_ % ";";
|
||||||
|
hints_rule = qi::lit("hints=") >> qi::as_string[qi::repeat(engine::ENCODED_HINT_SIZE)[base64_char]][add_hint] % ";";
|
||||||
|
bearings_rule =
|
||||||
|
qi::lit("bearings=") >> -((qi::short_ >> ',' >> qi::short_))[add_bearing] % ";";
|
||||||
|
base_rule = bearings_rule | radiuses_rule[set_radiuses] | hints_rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
qi::rule<Iterator> base_rule;
|
||||||
|
|
||||||
|
private:
|
||||||
|
engine::api::BaseParameters &base_parameters;
|
||||||
|
qi::rule<Iterator> bearings_rule;
|
||||||
|
qi::rule<Iterator> hints_rule;
|
||||||
|
qi::rule<Iterator, RadiusesT()> radiuses_rule;
|
||||||
|
qi::rule<Iterator, unsigned char()> base64_char;
|
||||||
|
qi::rule<Iterator, std::string()> alpha_numeral;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
29
include/server/api/parsed_url.hpp
Normal file
29
include/server/api/parsed_url.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef SERVER_API_PARSED_URL_HPP
|
||||||
|
#define SERVER_API_PARSED_URL_HPP
|
||||||
|
|
||||||
|
#include "util/coordinate.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ParsedURL
|
||||||
|
{
|
||||||
|
std::string service;
|
||||||
|
unsigned version;
|
||||||
|
std::string profile;
|
||||||
|
std::vector<util::FixedPointCoordinate> coordinates;
|
||||||
|
std::string options;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
92
include/server/api/route_parameters_grammar.hpp
Normal file
92
include/server/api/route_parameters_grammar.hpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#ifndef ROUTE_PARAMETERS_GRAMMAR_HPP
|
||||||
|
#define ROUTE_PARAMETERS_GRAMMAR_HPP
|
||||||
|
|
||||||
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
|
||||||
|
#include "server/api/base_parameters_grammar.hpp"
|
||||||
|
|
||||||
|
#include <boost/spirit/include/qi_lit.hpp>
|
||||||
|
#include <boost/spirit/include/qi_bool.hpp>
|
||||||
|
#include <boost/spirit/include/qi_grammar.hpp>
|
||||||
|
#include <boost/spirit/include/qi_action.hpp>
|
||||||
|
#include <boost/spirit/include/qi_optional.hpp>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace qi = boost::spirit::qi;
|
||||||
|
struct RouteParametersGrammar : public BaseParametersGrammar
|
||||||
|
{
|
||||||
|
using Iterator = std::string::iterator;
|
||||||
|
using StepsT = bool;
|
||||||
|
using AlternativeT = bool;
|
||||||
|
using GeometriesT = engine::api::RouteParameters::GeometriesType;
|
||||||
|
using OverviewT = engine::api::RouteParameters::OverviewType;
|
||||||
|
using UturnsT = std::vector<boost::optional<bool>>;
|
||||||
|
|
||||||
|
RouteParametersGrammar()
|
||||||
|
: BaseParametersGrammar(root_rule, route_parameters)
|
||||||
|
{
|
||||||
|
const auto set_geojson_type = [this]()
|
||||||
|
{
|
||||||
|
route_parameters.geometries = engine::api::RouteParameters::GeometriesType::GeoJSON;
|
||||||
|
};
|
||||||
|
const auto set_polyline_type = [this]()
|
||||||
|
{
|
||||||
|
route_parameters.geometries = engine::api::RouteParameters::GeometriesType::Polyline;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto set_simplified_type = [this]()
|
||||||
|
{
|
||||||
|
route_parameters.overview = engine::api::RouteParameters::OverviewType::Simplified;
|
||||||
|
};
|
||||||
|
const auto set_full_type = [this]()
|
||||||
|
{
|
||||||
|
route_parameters.overview = engine::api::RouteParameters::OverviewType::Full;
|
||||||
|
};
|
||||||
|
const auto set_false_type = [this]()
|
||||||
|
{
|
||||||
|
route_parameters.overview = engine::api::RouteParameters::OverviewType::False;
|
||||||
|
};
|
||||||
|
const auto set_steps = [this](const StepsT steps)
|
||||||
|
{
|
||||||
|
route_parameters.steps = steps;
|
||||||
|
};
|
||||||
|
const auto set_alternative = [this](const AlternativeT alternative)
|
||||||
|
{
|
||||||
|
route_parameters.alternative = alternative;
|
||||||
|
};
|
||||||
|
const auto set_uturns = [this](UturnsT &uturns)
|
||||||
|
{
|
||||||
|
route_parameters.uturns = std::move(uturns);
|
||||||
|
};
|
||||||
|
|
||||||
|
alternative_rule = qi::lit("alternative=") >> qi::bool_;
|
||||||
|
steps_rule = qi::lit("steps=") >> qi::bool_;
|
||||||
|
geometries_rule = qi::lit("geometries=geojson")[set_geojson_type] |
|
||||||
|
qi::lit("geometries=polyline")[set_polyline_type];
|
||||||
|
overview_rule = qi::lit("overview=simplified")[set_simplified_type] |
|
||||||
|
qi::lit("overview=full")[set_full_type] |
|
||||||
|
qi::lit("overview=false")[set_false_type];
|
||||||
|
uturns_rule = qi::lit("uturns=") >> -qi::bool_ % ";";
|
||||||
|
route_rule = steps_rule[set_steps] | alternative_rule[set_alternative] | geometries_rule |
|
||||||
|
overview_rule | uturns_rule[set_uturns];
|
||||||
|
root_rule = -((base_rule | route_rule) % '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::api::RouteParameters route_parameters;
|
||||||
|
private:
|
||||||
|
qi::rule<Iterator> root_rule, route_rule, geometries_rule, overview_rule;
|
||||||
|
qi::rule<Iterator, UturnsT()> uturns_rule;
|
||||||
|
qi::rule<Iterator, StepsT()> steps_rule;
|
||||||
|
qi::rule<Iterator, AlternativeT()> alternative_rule;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
28
include/server/api/route_parameters_parser.hpp
Normal file
28
include/server/api/route_parameters_parser.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef SERVER_API_ROUTE_PARAMETERS_PARSER_HPP
|
||||||
|
#define SERVER_API_ROUTE_PARAMETERS_PARSER_HPP
|
||||||
|
|
||||||
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
#include "server/api/route_parameters_parser.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
// Starts parsing and iter and modifies it until iter == end or parsing failed
|
||||||
|
boost::optional<engine::api::RouteParameters> parseRouteParameters(std::string::iterator& iter, std::string::iterator end);
|
||||||
|
|
||||||
|
// copy on purpose because we need mutability
|
||||||
|
inline boost::optional<engine::api::RouteParameters> parseRouteParameters(std::string options_string)
|
||||||
|
{
|
||||||
|
auto iter = options_string.begin();
|
||||||
|
return parseRouteParameters(iter, options_string.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
30
include/server/api/url_parser.hpp
Normal file
30
include/server/api/url_parser.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef SERVER_URL_PARSER_HPP
|
||||||
|
#define SERVER_URL_PARSER_HPP
|
||||||
|
|
||||||
|
#include "server/api/parsed_url.hpp"
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
// Starts parsing and iter and modifies it until iter == end or parsing failed
|
||||||
|
boost::optional<ParsedURL> parseURL(std::string::iterator& iter, std::string::iterator end);
|
||||||
|
// copy on purpose because we need mutability
|
||||||
|
inline boost::optional<ParsedURL> parseURL(std::string url_string)
|
||||||
|
{
|
||||||
|
auto iter = url_string.begin();
|
||||||
|
return parseURL(iter, url_string.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,151 +0,0 @@
|
|||||||
#ifndef API_GRAMMAR_HPP
|
|
||||||
#define API_GRAMMAR_HPP
|
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
|
||||||
#include <boost/spirit/include/qi.hpp>
|
|
||||||
#include <boost/spirit/include/qi_action.hpp>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace server
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace qi = boost::spirit::qi;
|
|
||||||
|
|
||||||
template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Iterator>
|
|
||||||
{
|
|
||||||
explicit APIGrammar(HandlerT *h) : APIGrammar::base_type(api_call), handler(h)
|
|
||||||
{
|
|
||||||
const auto set_x_wrapper = [this](const int x, bool &pass)
|
|
||||||
{
|
|
||||||
pass = handler->SetX(x);
|
|
||||||
};
|
|
||||||
const auto set_y_wrapper = [this](const int y, bool &pass)
|
|
||||||
{
|
|
||||||
pass = handler->SetY(y);
|
|
||||||
};
|
|
||||||
const auto set_z_wrapper = [this](const int z, bool &pass)
|
|
||||||
{
|
|
||||||
pass = handler->SetZ(z);
|
|
||||||
};
|
|
||||||
const auto add_bearing_wrapper = [this](
|
|
||||||
const boost::fusion::vector<int, boost::optional<int>> &received_bearing, bool &pass)
|
|
||||||
{
|
|
||||||
const int bearing = boost::fusion::at_c<0>(received_bearing);
|
|
||||||
const boost::optional<int> range = boost::fusion::at_c<1>(received_bearing);
|
|
||||||
pass = handler->AddBearing(bearing, range);
|
|
||||||
};
|
|
||||||
const auto add_coordinate_wrapper =
|
|
||||||
[this](const boost::fusion::vector<double, double> &received_coordinate)
|
|
||||||
{
|
|
||||||
handler->AddCoordinate(boost::fusion::at_c<0>(received_coordinate),
|
|
||||||
boost::fusion::at_c<1>(received_coordinate));
|
|
||||||
};
|
|
||||||
const auto add_source_wrapper =
|
|
||||||
[this](const boost::fusion::vector<double, double> &received_coordinate)
|
|
||||||
{
|
|
||||||
handler->AddSource(boost::fusion::at_c<0>(received_coordinate),
|
|
||||||
boost::fusion::at_c<1>(received_coordinate));
|
|
||||||
};
|
|
||||||
const auto add_destination_wrapper =
|
|
||||||
[this](const boost::fusion::vector<double, double> &received_coordinate)
|
|
||||||
{
|
|
||||||
handler->AddDestination(boost::fusion::at_c<0>(received_coordinate),
|
|
||||||
boost::fusion::at_c<1>(received_coordinate));
|
|
||||||
};
|
|
||||||
|
|
||||||
api_call =
|
|
||||||
qi::lit('/') >> string[boost::bind(&HandlerT::SetService, handler, ::_1)] >> -query;
|
|
||||||
query = ('?') >> +(zoom | output | jsonp | checksum | uturns | location_with_options |
|
|
||||||
destination_with_options | source_with_options | cmp | language |
|
|
||||||
instruction | geometry | alt_route | old_API | num_results |
|
|
||||||
matching_beta | gps_precision | classify | locs | x | y | z);
|
|
||||||
// all combinations of timestamp, uturn, hint and bearing without duplicates
|
|
||||||
t_u = (u >> -timestamp) | (timestamp >> -u);
|
|
||||||
t_h = (hint >> -timestamp) | (timestamp >> -hint);
|
|
||||||
u_h = (u >> -hint) | (hint >> -u);
|
|
||||||
t_u_h = (hint >> -t_u) | (u >> -t_h) | (timestamp >> -u_h);
|
|
||||||
location_options =
|
|
||||||
(bearing >> -t_u_h) | (t_u_h >> -bearing) | //
|
|
||||||
(u >> bearing >> -t_h) | (timestamp >> bearing >> -u_h) | (hint >> bearing >> t_u) | //
|
|
||||||
(t_h >> bearing >> -u) | (u_h >> bearing >> -timestamp) | (t_u >> bearing >> -hint);
|
|
||||||
location_with_options = location >> -location_options;
|
|
||||||
source_with_options = source >> -location_options;
|
|
||||||
destination_with_options = destination >> -location_options;
|
|
||||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
|
|
||||||
qi::short_[boost::bind(&HandlerT::SetZoomLevel, handler, ::_1)];
|
|
||||||
output = (-qi::lit('&')) >> qi::lit("output=json");
|
|
||||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
|
|
||||||
stringwithPercent[boost::bind(&HandlerT::SetJSONpParameter, handler, ::_1)];
|
|
||||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
|
|
||||||
qi::uint_[boost::bind(&HandlerT::SetChecksum, handler, ::_1)];
|
|
||||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetInstructionFlag, handler, ::_1)];
|
|
||||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetGeometryFlag, handler, ::_1)];
|
|
||||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetCompressionFlag, handler, ::_1)];
|
|
||||||
location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >>
|
|
||||||
(qi::double_ >> qi::lit(',') >>
|
|
||||||
qi::double_)[boost::bind<void>(add_coordinate_wrapper, ::_1)];
|
|
||||||
destination = (-qi::lit('&')) >> qi::lit("dst") >> '=' >>
|
|
||||||
(qi::double_ >> qi::lit(',') >>
|
|
||||||
qi::double_)[boost::bind<void>(add_destination_wrapper, ::_1)];
|
|
||||||
source = (-qi::lit('&')) >> qi::lit("src") >> '=' >>
|
|
||||||
(qi::double_ >> qi::lit(',') >>
|
|
||||||
qi::double_)[boost::bind<void>(add_source_wrapper, ::_1)];
|
|
||||||
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
|
|
||||||
stringwithDot[boost::bind(&HandlerT::AddHint, handler, ::_1)];
|
|
||||||
timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
|
|
||||||
qi::uint_[boost::bind(&HandlerT::AddTimestamp, handler, ::_1)];
|
|
||||||
bearing = (-qi::lit('&')) >> qi::lit("b") >> '=' >>
|
|
||||||
(qi::int_ >> -(qi::lit(',') >> qi::int_ |
|
|
||||||
qi::attr(10)))[boost::bind<void>(add_bearing_wrapper, ::_1, ::_3)];
|
|
||||||
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetUTurn, handler, ::_1)];
|
|
||||||
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetAllUTurns, handler, ::_1)];
|
|
||||||
language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >>
|
|
||||||
string[boost::bind(&HandlerT::SetLanguage, handler, ::_1)];
|
|
||||||
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetAlternateRouteFlag, handler, ::_1)];
|
|
||||||
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >>
|
|
||||||
string[boost::bind(&HandlerT::SetDeprecatedAPIFlag, handler, ::_1)];
|
|
||||||
num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >>
|
|
||||||
qi::short_[boost::bind(&HandlerT::SetNumberOfResults, handler, ::_1)];
|
|
||||||
matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
|
|
||||||
qi::float_[boost::bind(&HandlerT::SetMatchingBeta, handler, ::_1)];
|
|
||||||
gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
|
|
||||||
qi::float_[boost::bind(&HandlerT::SetGPSPrecision, handler, ::_1)];
|
|
||||||
classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
|
|
||||||
qi::bool_[boost::bind(&HandlerT::SetClassify, handler, ::_1)];
|
|
||||||
locs = (-qi::lit('&')) >> qi::lit("locs") >> '=' >>
|
|
||||||
stringforPolyline[boost::bind(&HandlerT::SetCoordinatesFromGeometry, handler, ::_1)];
|
|
||||||
|
|
||||||
x = (-qi::lit('&')) >> qi::lit("tx") >> '=' >>
|
|
||||||
qi::int_[boost::bind<void>(set_x_wrapper, ::_1, ::_3)];
|
|
||||||
y = (-qi::lit('&')) >> qi::lit("ty") >> '=' >>
|
|
||||||
qi::int_[boost::bind<void>(set_y_wrapper, ::_1, ::_3)];
|
|
||||||
z = (-qi::lit('&')) >> qi::lit("tz") >> '=' >>
|
|
||||||
qi::int_[boost::bind<void>(set_z_wrapper, ::_1, ::_3)];
|
|
||||||
|
|
||||||
string = +(qi::char_("a-zA-Z"));
|
|
||||||
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
|
|
||||||
stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
|
|
||||||
(qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
|
|
||||||
stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
|
|
||||||
}
|
|
||||||
|
|
||||||
qi::rule<Iterator> api_call, query, location_options, location_with_options,
|
|
||||||
destination_with_options, source_with_options, t_u, t_h, u_h, t_u_h;
|
|
||||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
|
|
||||||
destination, source, hint, timestamp, bearing, stringwithDot, stringwithPercent, language,
|
|
||||||
geometry, cmp, alt_route, u, uturns, old_API, num_results, matching_beta, gps_precision,
|
|
||||||
classify, locs, instruction, stringforPolyline, x, y, z;
|
|
||||||
|
|
||||||
HandlerT *handler;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* API_GRAMMAR_HPP */
|
|
@ -1,18 +1,14 @@
|
|||||||
#ifndef REQUEST_HANDLER_HPP
|
#ifndef REQUEST_HANDLER_HPP
|
||||||
#define REQUEST_HANDLER_HPP
|
#define REQUEST_HANDLER_HPP
|
||||||
|
|
||||||
|
#include "server/service_handler.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
class OSRM;
|
|
||||||
namespace engine
|
|
||||||
{
|
|
||||||
struct RouteParameters;
|
|
||||||
}
|
|
||||||
namespace server
|
namespace server
|
||||||
{
|
{
|
||||||
template <typename Iterator, class HandlerT> struct APIGrammar;
|
|
||||||
|
|
||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
@ -24,17 +20,16 @@ class RequestHandler
|
|||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using APIGrammarParser = APIGrammar<std::string::iterator, engine::RouteParameters>;
|
|
||||||
|
|
||||||
RequestHandler();
|
RequestHandler();
|
||||||
RequestHandler(const RequestHandler &) = delete;
|
RequestHandler(const RequestHandler &) = delete;
|
||||||
RequestHandler &operator=(const RequestHandler &) = delete;
|
RequestHandler &operator=(const RequestHandler &) = delete;
|
||||||
|
|
||||||
void handle_request(const http::request ¤t_request, http::reply ¤t_reply);
|
void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler);
|
||||||
void RegisterRoutingMachine(OSRM *osrm);
|
|
||||||
|
void HandleRequest(const http::request ¤t_request, http::reply ¤t_reply);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OSRM *routing_machine;
|
std::unique_ptr<ServiceHandler> service_handler;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "server/connection.hpp"
|
#include "server/connection.hpp"
|
||||||
#include "server/request_handler.hpp"
|
#include "server/request_handler.hpp"
|
||||||
|
#include "server/service_handler.hpp"
|
||||||
|
|
||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
@ -76,7 +77,10 @@ class Server
|
|||||||
|
|
||||||
void Stop() { io_service.stop(); }
|
void Stop() { io_service.stop(); }
|
||||||
|
|
||||||
RequestHandler &GetRequestHandlerPtr() { return request_handler; }
|
void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
|
||||||
|
{
|
||||||
|
request_handler.RegisterServiceHandler(std::move(service_handler_));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleAccept(const boost::system::error_code &e)
|
void HandleAccept(const boost::system::error_code &e)
|
||||||
|
36
include/server/service/base_service.hpp
Normal file
36
include/server/service/base_service.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef SERVER_SERVICE_BASE_SERVICE_HPP
|
||||||
|
#define SERVER_SERVICE_BASE_SERVICE_HPP
|
||||||
|
|
||||||
|
#include "engine/status.hpp"
|
||||||
|
#include "util/coordinate.hpp"
|
||||||
|
#include "osrm/osrm.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace service
|
||||||
|
{
|
||||||
|
|
||||||
|
class BaseService
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseService(OSRM &routing_machine) : routing_machine(routing_machine) {}
|
||||||
|
virtual ~BaseService() = default;
|
||||||
|
|
||||||
|
virtual engine::Status RunQuery(std::vector<util::FixedPointCoordinate> coordinates,
|
||||||
|
std::string &options,
|
||||||
|
util::json::Object &json_result) = 0;
|
||||||
|
virtual unsigned GetVersion() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OSRM &routing_machine;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
34
include/server/service/route_service.hpp
Normal file
34
include/server/service/route_service.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef SERVER_SERVICE_ROUTE_SERVICE_HPP
|
||||||
|
#define SERVER_SERVICE_ROUTE_SERVICE_HPP
|
||||||
|
|
||||||
|
#include "server/service/base_service.hpp"
|
||||||
|
|
||||||
|
#include "engine/status.hpp"
|
||||||
|
#include "util/coordinate.hpp"
|
||||||
|
#include "osrm/osrm.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace service
|
||||||
|
{
|
||||||
|
|
||||||
|
class RouteService final : public BaseService
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RouteService(OSRM& routing_machine) : BaseService(routing_machine) {}
|
||||||
|
|
||||||
|
virtual engine::Status RunQuery(std::vector<util::FixedPointCoordinate> coordinates,
|
||||||
|
std::string &options,
|
||||||
|
util::json::Object &json_result) final override;
|
||||||
|
virtual unsigned GetVersion() final override { return 1; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
40
include/server/service_handler.hpp
Normal file
40
include/server/service_handler.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef SERVER_SERVICE_HANLDER_HPP
|
||||||
|
#define SERVER_SERVICE_HANLDER_HPP
|
||||||
|
|
||||||
|
#include "server/service/base_service.hpp"
|
||||||
|
|
||||||
|
#include "osrm/osrm.hpp"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
namespace json
|
||||||
|
{
|
||||||
|
struct Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
struct ParsedURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServiceHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ServiceHandler(osrm::EngineConfig &config);
|
||||||
|
|
||||||
|
engine::Status RunQuery(api::ParsedURL parsed_url, util::json::Object &json_result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<service::BaseService>> service_map;
|
||||||
|
OSRM routing_machine;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
|
|
||||||
constexpr const double COORDINATE_PRECISION = 1000000.0;
|
constexpr const double COORDINATE_PRECISION = 1e6;
|
||||||
|
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
@ -52,6 +52,7 @@ struct FixedPointCoordinate
|
|||||||
FixedPointCoordinate(const T &coordinate)
|
FixedPointCoordinate(const T &coordinate)
|
||||||
: lat(coordinate.lat), lon(coordinate.lon)
|
: lat(coordinate.lat), lon(coordinate.lon)
|
||||||
{
|
{
|
||||||
|
static_assert(!std::is_same<T, FixedPointCoordinate>::value, "This constructor should not be used for FixedPointCoordinates");
|
||||||
static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value,
|
static_assert(std::is_same<decltype(lat), decltype(coordinate.lat)>::value,
|
||||||
"coordinate types incompatible");
|
"coordinate types incompatible");
|
||||||
static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value,
|
static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value,
|
||||||
@ -59,11 +60,13 @@ struct FixedPointCoordinate
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
bool operator==(const FixedPointCoordinate &other) const;
|
friend bool operator==(const FixedPointCoordinate lhs, const FixedPointCoordinate rhs);
|
||||||
friend std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate &coordinate);
|
friend bool operator!=(const FixedPointCoordinate lhs, const FixedPointCoordinate rhs);
|
||||||
|
friend std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate coordinate);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate &coordinate);
|
bool operator==(const FixedPointCoordinate lhs, const FixedPointCoordinate rhs);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate coordinate);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ template <> Array make_array(const std::vector<bool> &vector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Easy acces to object hierachies
|
// Easy acces to object hierachies
|
||||||
Value &get(Value &value) { return value; }
|
inline Value &get(Value &value) { return value; }
|
||||||
|
|
||||||
template <typename... Keys> Value &get(Value &value, const char *key, Keys... keys)
|
template <typename... Keys> Value &get(Value &value, const char *key, Keys... keys)
|
||||||
{
|
{
|
||||||
|
85
include/util/tiles.hpp
Normal file
85
include/util/tiles.hpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef UTIL_TILES_HPP
|
||||||
|
#define UTIL_TILES_HPP
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
// This is a port of the tilebelt algorithm https://github.com/mapbox/tilebelt
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
namespace tiles
|
||||||
|
{
|
||||||
|
struct Tile
|
||||||
|
{
|
||||||
|
unsigned x;
|
||||||
|
unsigned y;
|
||||||
|
unsigned z;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
// optimized for 32bit integers
|
||||||
|
static constexpr unsigned MAX_ZOOM = 32;
|
||||||
|
|
||||||
|
// Returns 1-indexed 1..32 of MSB if value > 0 or 0 if value == 0
|
||||||
|
inline unsigned getMSBPosition(std::uint32_t value)
|
||||||
|
{
|
||||||
|
if (value == 0)
|
||||||
|
return 0;
|
||||||
|
std::uint8_t pos = 1;
|
||||||
|
while (value >>= 1)
|
||||||
|
pos++;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned getBBMaxZoom(const Tile top_left, const Tile bottom_left)
|
||||||
|
{
|
||||||
|
auto x_xor = top_left.x ^ bottom_left.x;
|
||||||
|
auto y_xor = top_left.y ^ bottom_left.y;
|
||||||
|
auto lon_msb = detail::getMSBPosition(x_xor);
|
||||||
|
auto lat_msb = detail::getMSBPosition(y_xor);
|
||||||
|
return MAX_ZOOM - std::max(lon_msb, lat_msb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Tile pointToTile(const double lon, const double lat)
|
||||||
|
{
|
||||||
|
auto sin_lat = std::sin(lat * M_PI / 180.);
|
||||||
|
auto p2z = std::pow(2, detail::MAX_ZOOM);
|
||||||
|
unsigned x = p2z * (lon / 360. + 0.5);
|
||||||
|
unsigned y = p2z * (0.5 - 0.25 * std::log((1 + sin_lat) / (1 - sin_lat)) / M_PI);
|
||||||
|
|
||||||
|
return Tile{x, y, detail::MAX_ZOOM};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Tile getBBMaxZoomTile(const double min_lon,
|
||||||
|
const double min_lat,
|
||||||
|
const double max_lon,
|
||||||
|
const double max_lat)
|
||||||
|
{
|
||||||
|
const auto top_left = pointToTile(min_lon, min_lat);
|
||||||
|
const auto bottom_left = pointToTile(max_lon, max_lat);
|
||||||
|
BOOST_ASSERT(top_left.z == detail::MAX_ZOOM);
|
||||||
|
BOOST_ASSERT(bottom_left.z == detail::MAX_ZOOM);
|
||||||
|
|
||||||
|
const auto max_zoom = detail::getBBMaxZoom(top_left, bottom_left);
|
||||||
|
|
||||||
|
if (max_zoom == 0)
|
||||||
|
{
|
||||||
|
return Tile{0, 0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto x = top_left.x >> (detail::MAX_ZOOM - max_zoom);
|
||||||
|
auto y = top_left.y >> (detail::MAX_ZOOM - max_zoom);
|
||||||
|
|
||||||
|
return Tile{x, y, max_zoom};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
222
src/engine/api/josn_factory.cpp
Normal file
222
src/engine/api/josn_factory.cpp
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#include "engine/api/json_factory.hpp"
|
||||||
|
|
||||||
|
#include "engine/guidance/route_step.hpp"
|
||||||
|
#include "engine/guidance/step_maneuver.hpp"
|
||||||
|
#include "engine/guidance/route_leg.hpp"
|
||||||
|
#include "engine/guidance/route.hpp"
|
||||||
|
#include "engine/guidance/leg_geometry.hpp"
|
||||||
|
#include "engine/polyline_compressor.hpp"
|
||||||
|
#include "engine/hint.hpp"
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/range/irange.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
namespace json
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string instructionToString(extractor::TurnInstruction instruction)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
// FIXME this could be an array.
|
||||||
|
switch (instruction)
|
||||||
|
{
|
||||||
|
case extractor::TurnInstruction::GoStraight:
|
||||||
|
token = "continue";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::TurnSlightRight:
|
||||||
|
token = "bear right";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::TurnRight:
|
||||||
|
token = "right";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::TurnSharpRight:
|
||||||
|
token = "sharp right";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::UTurn:
|
||||||
|
token = "uturn";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::TurnSharpLeft:
|
||||||
|
token = "sharp left";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::TurnLeft:
|
||||||
|
token = "left";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::TurnSlightLeft:
|
||||||
|
token = "bear left";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::HeadOn:
|
||||||
|
token = "head on";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::EnterRoundAbout:
|
||||||
|
token = "enter roundabout";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::LeaveRoundAbout:
|
||||||
|
token = "leave roundabout";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::StayOnRoundAbout:
|
||||||
|
token = "stay on roundabout";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::StartAtEndOfStreet:
|
||||||
|
token = "depart";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::ReachedYourDestination:
|
||||||
|
token = "arrive";
|
||||||
|
break;
|
||||||
|
case extractor::TurnInstruction::NameChanges:
|
||||||
|
token = "name changed";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case extractor::TurnInstruction::NoTurn:
|
||||||
|
case extractor::TurnInstruction::ReachViaLocation:
|
||||||
|
case extractor::TurnInstruction::EnterAgainstAllowedDirection:
|
||||||
|
case extractor::TurnInstruction::LeaveAgainstAllowedDirection:
|
||||||
|
case extractor::TurnInstruction::InverseAccessRestrictionFlag:
|
||||||
|
case extractor::TurnInstruction::AccessRestrictionFlag:
|
||||||
|
case extractor::TurnInstruction::AccessRestrictionPenalty:
|
||||||
|
BOOST_ASSERT_MSG(false, "Invalid turn type used");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Array coordinateToLonLat(const FixedPointCoordinate &coordinate)
|
||||||
|
{
|
||||||
|
util::json::Array array;
|
||||||
|
array.values.push_back(coordinate.lon / COORDINATE_PRECISION);
|
||||||
|
array.values.push_back(coordinate.lat / COORDINATE_PRECISION);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Array coordinateToLatLon(const FixedPointCoordinate &coordinate)
|
||||||
|
{
|
||||||
|
util::json::Array array;
|
||||||
|
array.values.push_back(coordinate.lat / COORDINATE_PRECISION);
|
||||||
|
array.values.push_back(coordinate.lon / COORDINATE_PRECISION);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME this actually needs to be configurable from the profiles
|
||||||
|
std::string modeToString(const extractor::TravelMode mode)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case TRAVEL_MODE_DEFAULT:
|
||||||
|
token = "default";
|
||||||
|
break;
|
||||||
|
case TRAVEL_MODE_INACCESSIBLE:
|
||||||
|
token = "inaccessible";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
token = "other";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
|
||||||
|
{
|
||||||
|
util::json::Object step_maneuver;
|
||||||
|
step_maneuver.values["type"] = detail::instructionToString(maneuver.instruction);
|
||||||
|
step_maneuver.values["location"] = detail::coordinateToLatLon(maneuver.location);
|
||||||
|
step_maneuver.values["heading_before"] = maneuver.heading_before;
|
||||||
|
step_maneuver.values["heading_after"] = maneuver.heading_after;
|
||||||
|
return step_maneuver;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Object makeRouteStep(guidance::RouteStep &&step,
|
||||||
|
boost::optional<util::json::Value> geometry)
|
||||||
|
{
|
||||||
|
util::json::Object route_step;
|
||||||
|
route_step.values["distance"] = step.distance;
|
||||||
|
route_step.values["duration"] = step.duration;
|
||||||
|
route_step.values["way_name"] = std::move(step.way_name);
|
||||||
|
route_step.values["mode"] = detail::modeToString(step.mode);
|
||||||
|
route_step.values["maneuver"] = makeStepManeuver(step.maneuver);
|
||||||
|
if (geometry)
|
||||||
|
{
|
||||||
|
route_step.values["geometry"] = std::move(*geometry);
|
||||||
|
}
|
||||||
|
return route_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Object makeRoute(const guidance::Route &route,
|
||||||
|
util::json::Array &&legs,
|
||||||
|
boost::optional<util::json::Value> geometry)
|
||||||
|
{
|
||||||
|
util::json::Object json_route;
|
||||||
|
json_route.values["distance"] = route.distance;
|
||||||
|
json_route.values["duration"] = route.duration;
|
||||||
|
json_route.values["legs"] = std::move(legs);
|
||||||
|
if (geometry)
|
||||||
|
{
|
||||||
|
json_route.values["geometry"] = std::move(*geometry);
|
||||||
|
}
|
||||||
|
return json_route;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Object
|
||||||
|
makeWaypoint(const FixedPointCoordinate location, std::string &&way_name, const Hint &hint)
|
||||||
|
{
|
||||||
|
util::json::Object waypoint;
|
||||||
|
waypoint.values["location"] = detail::coordinateToLatLon(location);
|
||||||
|
waypoint.values["way_name"] = std::move(way_name);
|
||||||
|
waypoint.values["hint"] = hint.ToBase64();
|
||||||
|
return waypoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Object makeRouteLeg(guidance::RouteLeg &&leg, util::json::Array &&steps)
|
||||||
|
{
|
||||||
|
util::json::Object route_leg;
|
||||||
|
route_leg.values["distance"] = leg.distance;
|
||||||
|
route_leg.values["duration"] = leg.duration;
|
||||||
|
route_leg.values["summary"] = std::move(leg.summary);
|
||||||
|
route_leg.values["steps"] = std::move(steps);
|
||||||
|
return route_leg;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> &&legs,
|
||||||
|
const std::vector<guidance::LegGeometry> &leg_geometries)
|
||||||
|
{
|
||||||
|
util::json::Array json_legs;
|
||||||
|
for (const auto idx : boost::irange(0UL, legs.size()))
|
||||||
|
{
|
||||||
|
auto &&leg = std::move(legs[idx]);
|
||||||
|
const auto &leg_geometry = leg_geometries[idx];
|
||||||
|
util::json::Array json_steps;
|
||||||
|
json_steps.values.reserve(leg.steps.size());
|
||||||
|
const auto begin_iter = leg_geometry.locations.begin();
|
||||||
|
std::transform(
|
||||||
|
std::make_move_iterator(leg.steps.begin()), std::make_move_iterator(leg.steps.end()),
|
||||||
|
std::back_inserter(json_steps.values), [&begin_iter](guidance::RouteStep &&step)
|
||||||
|
{
|
||||||
|
// FIXME we only support polyline here
|
||||||
|
auto geometry = boost::make_optional<util::json::Value>(
|
||||||
|
makePolyline(begin_iter + step.geometry_begin, begin_iter + step.geometry_end));
|
||||||
|
return makeRouteStep(std::move(step), std::move(geometry));
|
||||||
|
});
|
||||||
|
json_legs.values.push_back(makeRouteLeg(std::move(leg), std::move(json_steps)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_legs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace engine
|
||||||
|
} // namespace osrm
|
@ -1,8 +1,9 @@
|
|||||||
#include "engine/douglas_peucker.hpp"
|
#include "engine/douglas_peucker.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/coordinate.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include "osrm/coordinate.hpp"
|
#include <boost/range/irange.hpp>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -17,8 +18,12 @@ namespace engine
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
// FIXME This algorithm is a very naive approximation that leads to
|
||||||
|
// problems like (almost) co-linear points not being simplified.
|
||||||
|
// Switch to real-point-segment distance of projected coordinates
|
||||||
struct CoordinatePairCalculator
|
struct CoordinatePairCalculator
|
||||||
{
|
{
|
||||||
|
CoordinatePairCalculator() = delete;
|
||||||
CoordinatePairCalculator(const util::FixedPointCoordinate coordinate_a,
|
CoordinatePairCalculator(const util::FixedPointCoordinate coordinate_a,
|
||||||
const util::FixedPointCoordinate coordinate_b)
|
const util::FixedPointCoordinate coordinate_b)
|
||||||
{
|
{
|
||||||
@ -56,44 +61,29 @@ struct CoordinatePairCalculator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
|
std::vector<util::FixedPointCoordinate>
|
||||||
std::vector<SegmentInformation>::iterator end,
|
douglasPeucker(std::vector<util::FixedPointCoordinate>::const_iterator begin,
|
||||||
|
std::vector<util::FixedPointCoordinate>::const_iterator end,
|
||||||
const unsigned zoom_level)
|
const unsigned zoom_level)
|
||||||
{
|
{
|
||||||
using Iter = decltype(begin);
|
BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE,
|
||||||
using GeometryRange = std::pair<Iter, Iter>;
|
"unsupported zoom level");
|
||||||
|
|
||||||
std::stack<GeometryRange> recursion_stack;
|
|
||||||
|
|
||||||
const auto size = std::distance(begin, end);
|
const auto size = std::distance(begin, end);
|
||||||
if (size < 2)
|
if (size < 2)
|
||||||
{
|
{
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
begin->necessary = true;
|
std::vector<bool> is_necessary(size, false);
|
||||||
std::prev(end)->necessary = true;
|
BOOST_ASSERT(is_necessary.size() >= 2);
|
||||||
|
is_necessary.front() = true;
|
||||||
|
is_necessary.back() = true;
|
||||||
|
using GeometryRange = std::pair<std::size_t, std::size_t>;
|
||||||
|
|
||||||
{
|
std::stack<GeometryRange> recursion_stack;
|
||||||
BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE,
|
|
||||||
"unsupported zoom level");
|
recursion_stack.emplace(0UL, size-1);
|
||||||
auto left_border = begin;
|
|
||||||
auto right_border = std::next(begin);
|
|
||||||
// Sweep over array and identify those ranges that need to be checked
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// traverse list until new border element found
|
|
||||||
if (right_border->necessary)
|
|
||||||
{
|
|
||||||
// sanity checks
|
|
||||||
BOOST_ASSERT(left_border->necessary);
|
|
||||||
BOOST_ASSERT(right_border->necessary);
|
|
||||||
recursion_stack.emplace(left_border, right_border);
|
|
||||||
left_border = right_border;
|
|
||||||
}
|
|
||||||
++right_border;
|
|
||||||
} while (right_border != end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark locations as 'necessary' by divide-and-conquer
|
// mark locations as 'necessary' by divide-and-conquer
|
||||||
while (!recursion_stack.empty())
|
while (!recursion_stack.empty())
|
||||||
@ -102,25 +92,24 @@ void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
|
|||||||
const GeometryRange pair = recursion_stack.top();
|
const GeometryRange pair = recursion_stack.top();
|
||||||
recursion_stack.pop();
|
recursion_stack.pop();
|
||||||
// sanity checks
|
// sanity checks
|
||||||
BOOST_ASSERT_MSG(pair.first->necessary, "left border must be necessary");
|
BOOST_ASSERT_MSG(is_necessary[pair.first], "left border must be necessary");
|
||||||
BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
|
BOOST_ASSERT_MSG(is_necessary[pair.second], "right border must be necessary");
|
||||||
BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
|
BOOST_ASSERT_MSG(pair.second < size, "right border outside of geometry");
|
||||||
BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0,
|
BOOST_ASSERT_MSG(pair.first <= pair.second, "left border on the wrong side");
|
||||||
"left border on the wrong side");
|
|
||||||
|
|
||||||
int max_int_distance = 0;
|
int max_int_distance = 0;
|
||||||
auto farthest_entry_it = pair.second;
|
auto farthest_entry_index = pair.second;
|
||||||
const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
|
const CoordinatePairCalculator dist_calc(begin[pair.first], begin[pair.second]);
|
||||||
|
|
||||||
// sweep over range to find the maximum
|
// sweep over range to find the maximum
|
||||||
for (auto it = std::next(pair.first); it != pair.second; ++it)
|
for (auto idx = pair.first + 1; idx != pair.second; ++idx)
|
||||||
{
|
{
|
||||||
const int distance = dist_calc(it->location);
|
const int distance = dist_calc(begin[idx]);
|
||||||
// found new feasible maximum?
|
// found new feasible maximum?
|
||||||
if (distance > max_int_distance &&
|
if (distance > max_int_distance &&
|
||||||
distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
||||||
{
|
{
|
||||||
farthest_entry_it = it;
|
farthest_entry_index = idx;
|
||||||
max_int_distance = distance;
|
max_int_distance = distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,17 +118,29 @@ void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
|
|||||||
if (max_int_distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
if (max_int_distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
||||||
{
|
{
|
||||||
// mark idx as necessary
|
// mark idx as necessary
|
||||||
farthest_entry_it->necessary = true;
|
is_necessary[farthest_entry_index] = true;
|
||||||
if (1 < std::distance(pair.first, farthest_entry_it))
|
if (pair.first < farthest_entry_index)
|
||||||
{
|
{
|
||||||
recursion_stack.emplace(pair.first, farthest_entry_it);
|
recursion_stack.emplace(pair.first, farthest_entry_index);
|
||||||
}
|
}
|
||||||
if (1 < std::distance(farthest_entry_it, pair.second))
|
if (farthest_entry_index < pair.second)
|
||||||
{
|
{
|
||||||
recursion_stack.emplace(farthest_entry_it, pair.second);
|
recursion_stack.emplace(farthest_entry_index, pair.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto simplified_size = std::count(is_necessary.begin(), is_necessary.end(), true);
|
||||||
|
std::vector<util::FixedPointCoordinate> simplified_geometry;
|
||||||
|
simplified_geometry.reserve(simplified_size);
|
||||||
|
for (auto idx : boost::irange<std::size_t>(0UL, size))
|
||||||
|
{
|
||||||
|
if (is_necessary[idx])
|
||||||
|
{
|
||||||
|
simplified_geometry.push_back(begin[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return simplified_geometry;
|
||||||
}
|
}
|
||||||
} // ns engine
|
} // ns engine
|
||||||
} // ns osrm
|
} // ns osrm
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
#include "engine/engine.hpp"
|
#include "engine/engine.hpp"
|
||||||
#include "engine/engine_config.hpp"
|
#include "engine/engine_config.hpp"
|
||||||
#include "engine/route_parameters.hpp"
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
#include "engine/status.hpp"
|
||||||
|
|
||||||
#include "engine/plugins/distance_table.hpp"
|
//#include "engine/plugins/distance_table.hpp"
|
||||||
#include "engine/plugins/hello_world.hpp"
|
//#include "engine/plugins/hello_world.hpp"
|
||||||
#include "engine/plugins/nearest.hpp"
|
//#include "engine/plugins/nearest.hpp"
|
||||||
#include "engine/plugins/timestamp.hpp"
|
//#include "engine/plugins/timestamp.hpp"
|
||||||
#include "engine/plugins/trip.hpp"
|
//#include "engine/plugins/trip.hpp"
|
||||||
#include "engine/plugins/viaroute.hpp"
|
#include "engine/plugins/viaroute.hpp"
|
||||||
#include "engine/plugins/match.hpp"
|
//#include "engine/plugins/match.hpp"
|
||||||
#include "engine/plugins/tile.hpp"
|
//#include "engine/plugins/tile.hpp"
|
||||||
|
|
||||||
#include "engine/datafacade/datafacade_base.hpp"
|
#include "engine/datafacade/datafacade_base.hpp"
|
||||||
#include "engine/datafacade/internal_datafacade.hpp"
|
#include "engine/datafacade/internal_datafacade.hpp"
|
||||||
@ -35,120 +36,93 @@ namespace osrm
|
|||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Abstracted away the query locking into a template function
|
||||||
|
// Works the same for every plugin.
|
||||||
|
template<typename ParameterT, typename PluginT>
|
||||||
|
Status RunQuery(const std::unique_ptr<Engine::EngineLock> &lock,
|
||||||
|
datafacade::BaseDataFacade &facade,
|
||||||
|
const ParameterT ¶meters,
|
||||||
|
PluginT &plugin,
|
||||||
|
util::json::Object &json_result)
|
||||||
|
{
|
||||||
|
if (!lock)
|
||||||
|
{
|
||||||
|
return plugin.HandleRequest(parameters, json_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(lock);
|
||||||
|
lock->IncreaseQueryCount();
|
||||||
|
|
||||||
|
auto& shared_facade = static_cast<datafacade::SharedDataFacade &>(facade);
|
||||||
|
shared_facade.CheckAndReloadFacade();
|
||||||
|
// Get a shared data lock so that other threads won't update
|
||||||
|
// things while the query is running
|
||||||
|
boost::shared_lock<boost::shared_mutex> data_lock{shared_facade.data_mutex};
|
||||||
|
|
||||||
|
Status status = plugin.HandleRequest(parameters, json_result);
|
||||||
|
|
||||||
|
lock->DecreaseQueryCount();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Engine::Engine(EngineConfig &config)
|
Engine::Engine(EngineConfig &config)
|
||||||
{
|
{
|
||||||
if (config.use_shared_memory)
|
if (config.use_shared_memory)
|
||||||
{
|
{
|
||||||
barrier = util::make_unique<storage::SharedBarriers>();
|
lock = util::make_unique<EngineLock>();
|
||||||
query_data_facade = new datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData>();
|
query_data_facade = util::make_unique<datafacade::SharedDataFacade>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// populate base path
|
// populate base path
|
||||||
util::populate_base_path(config.server_paths);
|
util::populate_base_path(config.server_paths);
|
||||||
query_data_facade = new datafacade::InternalDataFacade<contractor::QueryEdge::EdgeData>(
|
query_data_facade = util::make_unique<datafacade::InternalDataFacade>(config.server_paths);
|
||||||
config.server_paths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using DataFacade = datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData>;
|
route_plugin = util::make_unique<plugins::ViaRoutePlugin>(*query_data_facade, config.max_locations_viaroute);
|
||||||
|
|
||||||
// The following plugins handle all requests.
|
|
||||||
RegisterPlugin(new plugins::DistanceTablePlugin<DataFacade>(
|
|
||||||
query_data_facade, config.max_locations_distance_table));
|
|
||||||
RegisterPlugin(new plugins::HelloWorldPlugin());
|
|
||||||
RegisterPlugin(new plugins::NearestPlugin<DataFacade>(query_data_facade));
|
|
||||||
RegisterPlugin(new plugins::MapMatchingPlugin<DataFacade>(query_data_facade,
|
|
||||||
config.max_locations_map_matching));
|
|
||||||
RegisterPlugin(new plugins::TimestampPlugin<DataFacade>(query_data_facade));
|
|
||||||
RegisterPlugin(
|
|
||||||
new plugins::ViaRoutePlugin<DataFacade>(query_data_facade, config.max_locations_viaroute));
|
|
||||||
RegisterPlugin(
|
|
||||||
new plugins::RoundTripPlugin<DataFacade>(query_data_facade, config.max_locations_trip));
|
|
||||||
RegisterPlugin(new plugins::TilePlugin<DataFacade>(query_data_facade));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::RegisterPlugin(plugins::BasePlugin *raw_plugin_ptr)
|
Status Engine::Route(const api::RouteParameters &route_parameters,
|
||||||
|
util::json::Object &result)
|
||||||
{
|
{
|
||||||
std::unique_ptr<plugins::BasePlugin> plugin_ptr(raw_plugin_ptr);
|
return RunQuery(lock, *query_data_facade, route_parameters, *route_plugin, result);
|
||||||
util::SimpleLogger().Write() << "loaded plugin: " << plugin_ptr->GetDescriptor();
|
|
||||||
plugin_map[plugin_ptr->GetDescriptor()] = std::move(plugin_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Engine::RunQuery(const RouteParameters &route_parameters, util::json::Object &json_result)
|
|
||||||
{
|
|
||||||
const auto &plugin_iterator = plugin_map.find(route_parameters.service);
|
|
||||||
|
|
||||||
if (plugin_map.end() == plugin_iterator)
|
|
||||||
{
|
|
||||||
json_result.values["status_message"] = "Service not found";
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
osrm::engine::plugins::BasePlugin::Status return_code;
|
|
||||||
increase_concurrent_query_count();
|
|
||||||
if (barrier)
|
|
||||||
{
|
|
||||||
// Get a shared data lock so that other threads won't update
|
|
||||||
// things while the query is running
|
|
||||||
boost::shared_lock<boost::shared_mutex> data_lock{
|
|
||||||
(static_cast<datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData> *>(
|
|
||||||
query_data_facade))->data_mutex};
|
|
||||||
return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
|
|
||||||
}
|
|
||||||
decrease_concurrent_query_count();
|
|
||||||
return static_cast<int>(return_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrease number of concurrent queries
|
// decrease number of concurrent queries
|
||||||
void Engine::decrease_concurrent_query_count()
|
void Engine::EngineLock::DecreaseQueryCount()
|
||||||
{
|
{
|
||||||
if (!barrier)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// lock query
|
// lock query
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
||||||
barrier->query_mutex);
|
barrier.query_mutex);
|
||||||
|
|
||||||
// decrement query count
|
// decrement query count
|
||||||
--(barrier->number_of_queries);
|
--(barrier.number_of_queries);
|
||||||
BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
|
BOOST_ASSERT_MSG(0 <= barrier.number_of_queries, "invalid number of queries");
|
||||||
|
|
||||||
// notify all processes that were waiting for this condition
|
// notify all processes that were waiting for this condition
|
||||||
if (0 == barrier->number_of_queries)
|
if (0 == barrier.number_of_queries)
|
||||||
{
|
{
|
||||||
barrier->no_running_queries_condition.notify_all();
|
barrier.no_running_queries_condition.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// increase number of concurrent queries
|
// increase number of concurrent queries
|
||||||
void Engine::increase_concurrent_query_count()
|
void Engine::EngineLock::IncreaseQueryCount()
|
||||||
{
|
{
|
||||||
if (!barrier)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock update pending
|
// lock update pending
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
|
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
|
||||||
barrier->pending_update_mutex);
|
barrier.pending_update_mutex);
|
||||||
|
|
||||||
// lock query
|
// lock query
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
|
||||||
barrier->query_mutex);
|
barrier.query_mutex);
|
||||||
|
|
||||||
// unlock update pending
|
// unlock update pending
|
||||||
pending_lock.unlock();
|
pending_lock.unlock();
|
||||||
|
|
||||||
// increment query count
|
// increment query count
|
||||||
++(barrier->number_of_queries);
|
++(barrier.number_of_queries);
|
||||||
|
|
||||||
(static_cast<datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData> *>(
|
|
||||||
query_data_facade))->CheckAndReloadFacade();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
99
src/engine/guidance/assemble_overview.cpp
Normal file
99
src/engine/guidance/assemble_overview.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
|
||||||
|
#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
|
||||||
|
|
||||||
|
#include "engine/guidance/leg_geometry.hpp"
|
||||||
|
#include "engine/douglas_peucker.hpp"
|
||||||
|
#include "util/tiles.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometries)
|
||||||
|
{
|
||||||
|
int min_lon = std::numeric_limits<int>::max();
|
||||||
|
int min_lat = std::numeric_limits<int>::max();
|
||||||
|
int max_lon = -std::numeric_limits<int>::max();
|
||||||
|
int max_lat = -std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
for (const auto &leg_geometry : leg_geometries)
|
||||||
|
{
|
||||||
|
for (const auto coord : leg_geometry.locations)
|
||||||
|
{
|
||||||
|
min_lon = std::min(min_lon, coord.lon);
|
||||||
|
max_lon = std::max(max_lon, coord.lon);
|
||||||
|
min_lat = std::min(min_lat, coord.lat);
|
||||||
|
max_lat = std::max(max_lat, coord.lat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util::tiles::getBBMaxZoomTile(min_lon, min_lat, max_lon, max_lat).z;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<util::FixedPointCoordinate> simplifyGeometry(const std::vector<LegGeometry> &leg_geometries, const unsigned zoom_level)
|
||||||
|
{
|
||||||
|
std::vector<util::FixedPointCoordinate> overview_geometry;
|
||||||
|
auto leg_index = 0UL;
|
||||||
|
for (const auto geometry : leg_geometries)
|
||||||
|
{
|
||||||
|
auto simplified_geometry =
|
||||||
|
douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
|
||||||
|
// not the last leg
|
||||||
|
if (leg_index < leg_geometries.size() - 1)
|
||||||
|
{
|
||||||
|
simplified_geometry.pop_back();
|
||||||
|
}
|
||||||
|
overview_geometry.insert(overview_geometry.end(), simplified_geometry.begin(),
|
||||||
|
simplified_geometry.end());
|
||||||
|
}
|
||||||
|
return overview_geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<util::FixedPointCoordinate>
|
||||||
|
assembleOverview(const std::vector<LegGeometry> &leg_geometries, const bool use_simplification)
|
||||||
|
{
|
||||||
|
if (use_simplification)
|
||||||
|
{
|
||||||
|
const auto zoom_level = calculateOverviewZoomLevel(leg_geometries);
|
||||||
|
return simplifyGeometry(leg_geometries, zoom_level);
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(!use_simplification);
|
||||||
|
|
||||||
|
auto overview_size = std::accumulate(leg_geometries.begin(), leg_geometries.end(), 0,
|
||||||
|
[](const std::size_t sum, const LegGeometry &leg_geometry)
|
||||||
|
{
|
||||||
|
return sum + leg_geometry.locations.size();
|
||||||
|
}) -
|
||||||
|
leg_geometries.size() + 1;
|
||||||
|
std::vector<util::FixedPointCoordinate> overview_geometry;
|
||||||
|
overview_geometry.reserve(overview_size);
|
||||||
|
|
||||||
|
auto leg_index = 0UL;
|
||||||
|
for (const auto geometry : leg_geometries)
|
||||||
|
{
|
||||||
|
auto begin = geometry.locations.begin();
|
||||||
|
auto end = geometry.locations.end();
|
||||||
|
if (leg_index < leg_geometries.size() - 1)
|
||||||
|
{
|
||||||
|
end = std::prev(end);
|
||||||
|
}
|
||||||
|
overview_geometry.insert(overview_geometry.end(), begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return overview_geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace engine
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif
|
115
src/engine/plugins/viaroute.cpp
Normal file
115
src/engine/plugins/viaroute.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include "engine/plugins/viaroute.hpp"
|
||||||
|
#include "engine/datafacade/datafacade_base.hpp"
|
||||||
|
#include "engine/api/route_api.hpp"
|
||||||
|
#include "engine/object_encoder.hpp"
|
||||||
|
#include "engine/status.hpp"
|
||||||
|
|
||||||
|
#include "util/for_each_pair.hpp"
|
||||||
|
#include "util/integer_range.hpp"
|
||||||
|
#include "util/json_container.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
namespace plugins
|
||||||
|
{
|
||||||
|
|
||||||
|
ViaRoutePlugin::ViaRoutePlugin(datafacade::BaseDataFacade &facade_, int max_locations_viaroute)
|
||||||
|
: BasePlugin(facade_), shortest_path(&facade_, heaps), alternative_path(&facade_, heaps),
|
||||||
|
direct_shortest_path(&facade_, heaps), max_locations_viaroute(max_locations_viaroute)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Status ViaRoutePlugin::HandleRequest(const api::RouteParameters &route_parameters,
|
||||||
|
util::json::Object &json_result)
|
||||||
|
{
|
||||||
|
if (max_locations_viaroute > 0 &&
|
||||||
|
(static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
|
||||||
|
{
|
||||||
|
return Error("too-big",
|
||||||
|
"Number of entries " + std::to_string(route_parameters.coordinates.size()) +
|
||||||
|
" is higher than current maximum (" +
|
||||||
|
std::to_string(max_locations_viaroute) + ")",
|
||||||
|
json_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CheckAllCoordinates(route_parameters.coordinates))
|
||||||
|
{
|
||||||
|
return Error("invalid-value", "Invalid coordinate value.", json_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto phantom_node_pairs = GetPhantomNodes(route_parameters);
|
||||||
|
if (phantom_node_pairs.size() != route_parameters.coordinates.size())
|
||||||
|
{
|
||||||
|
return Error("no-segment",
|
||||||
|
std::string("Could not find a matching segment for coordinate ") +
|
||||||
|
std::to_string(phantom_node_pairs.size()),
|
||||||
|
json_result);
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
|
||||||
|
|
||||||
|
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
|
||||||
|
|
||||||
|
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.alternative && facade.GetCoreSize() == 0)
|
||||||
|
{
|
||||||
|
alternative_path(raw_route.segment_end_coordinates.front(), raw_route);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
direct_shortest_path(raw_route.segment_end_coordinates, raw_route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
api::RouteAPI route_api{BasePlugin::facade, route_parameters};
|
||||||
|
route_api.MakeResponse(raw_route, json_result);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return Error("no-route", "Impossible route between points", json_result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Error("no-route", "No route found between points", json_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status::Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
#include "engine/polyline_compressor.hpp"
|
#include "engine/polyline_compressor.hpp"
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@ -55,31 +57,30 @@ std::string encode(std::vector<int> &numbers)
|
|||||||
}
|
}
|
||||||
} // anonymous ns
|
} // anonymous ns
|
||||||
|
|
||||||
std::string polylineEncode(const std::vector<SegmentInformation> &polyline)
|
|
||||||
|
std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end)
|
||||||
{
|
{
|
||||||
if (polyline.empty())
|
auto size = std::distance(begin, end);
|
||||||
|
if (size == 0)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> delta_numbers;
|
std::vector<int> delta_numbers;
|
||||||
delta_numbers.reserve((polyline.size() - 1) * 2);
|
BOOST_ASSERT(size > 0);
|
||||||
|
delta_numbers.reserve((size - 1) * 2);
|
||||||
util::FixedPointCoordinate previous_coordinate = {0, 0};
|
util::FixedPointCoordinate previous_coordinate = {0, 0};
|
||||||
for (const auto &segment : polyline)
|
std::for_each(begin, end, [&delta_numbers, &previous_coordinate](const FixedPointCoordinate loc)
|
||||||
{
|
{
|
||||||
if (segment.necessary)
|
const int lat_diff = (loc.lat - previous_coordinate.lat) * detail::COORDINATE_TO_POLYLINE;
|
||||||
{
|
const int lon_diff = (loc.lon - previous_coordinate.lon) * detail::COORDINATE_TO_POLYLINE;
|
||||||
const int lat_diff = segment.location.lat - previous_coordinate.lat;
|
|
||||||
const int lon_diff = segment.location.lon - previous_coordinate.lon;
|
|
||||||
delta_numbers.emplace_back(lat_diff);
|
delta_numbers.emplace_back(lat_diff);
|
||||||
delta_numbers.emplace_back(lon_diff);
|
delta_numbers.emplace_back(lon_diff);
|
||||||
previous_coordinate = segment.location;
|
previous_coordinate = loc;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
return encode(delta_numbers);
|
return encode(delta_numbers);
|
||||||
}
|
}
|
||||||
|
std::vector<util::FixedPointCoordinate> decodePolyline(const std::string &geometry_string)
|
||||||
std::vector<util::FixedPointCoordinate> polylineDecode(const std::string &geometry_string)
|
|
||||||
{
|
{
|
||||||
std::vector<util::FixedPointCoordinate> new_coordinates;
|
std::vector<util::FixedPointCoordinate> new_coordinates;
|
||||||
int index = 0, len = geometry_string.size();
|
int index = 0, len = geometry_string.size();
|
||||||
@ -109,8 +110,8 @@ std::vector<util::FixedPointCoordinate> polylineDecode(const std::string &geomet
|
|||||||
lng += dlng;
|
lng += dlng;
|
||||||
|
|
||||||
util::FixedPointCoordinate p;
|
util::FixedPointCoordinate p;
|
||||||
p.lat = COORDINATE_PRECISION * (((double)lat / 1E6));
|
p.lat = lat * detail::POLYLINE_TO_COORDINATE;
|
||||||
p.lon = COORDINATE_PRECISION * (((double)lng / 1E6));
|
p.lon = lng * detail::POLYLINE_TO_COORDINATE;
|
||||||
new_coordinates.push_back(p);
|
new_coordinates.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
#include "engine/polyline_formatter.hpp"
|
|
||||||
#include "engine/polyline_compressor.hpp"
|
|
||||||
#include "osrm/coordinate.hpp"
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace engine
|
|
||||||
{
|
|
||||||
|
|
||||||
util::json::String polylineEncodeAsJSON(const std::vector<SegmentInformation> &polyline)
|
|
||||||
{
|
|
||||||
return util::json::String(polylineEncode(polyline));
|
|
||||||
}
|
|
||||||
|
|
||||||
util::json::Array polylineUnencodedAsJSON(const std::vector<SegmentInformation> &polyline)
|
|
||||||
{
|
|
||||||
util::json::Array json_geometry_array;
|
|
||||||
for (const auto &segment : polyline)
|
|
||||||
{
|
|
||||||
if (segment.necessary)
|
|
||||||
{
|
|
||||||
util::json::Array json_coordinate;
|
|
||||||
json_coordinate.values.push_back(segment.location.lat / COORDINATE_PRECISION);
|
|
||||||
json_coordinate.values.push_back(segment.location.lon / COORDINATE_PRECISION);
|
|
||||||
json_geometry_array.values.push_back(json_coordinate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return json_geometry_array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
#include "engine/route_parameters.hpp"
|
|
||||||
#include "util/coordinate.hpp"
|
|
||||||
|
|
||||||
#include "engine/polyline_compressor.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace engine
|
|
||||||
{
|
|
||||||
|
|
||||||
RouteParameters::RouteParameters()
|
|
||||||
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
|
|
||||||
compression(true), deprecatedAPI(false), uturn_default(false), classify(false),
|
|
||||||
matching_beta(5), gps_precision(5), check_sum(-1), num_results(1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetZoomLevel(const short level)
|
|
||||||
{
|
|
||||||
if (18 >= level && 0 <= level)
|
|
||||||
{
|
|
||||||
zoom_level = level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetNumberOfResults(const short number)
|
|
||||||
{
|
|
||||||
if (number > 0 && number <= 100)
|
|
||||||
{
|
|
||||||
num_results = number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetAlternateRouteFlag(const bool flag) { alternate_route = flag; }
|
|
||||||
|
|
||||||
void RouteParameters::SetUTurn(const bool flag)
|
|
||||||
{
|
|
||||||
// the API grammar should make sure this never happens
|
|
||||||
BOOST_ASSERT(!uturns.empty());
|
|
||||||
uturns.back() = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetAllUTurns(const bool flag)
|
|
||||||
{
|
|
||||||
// if the flag flips the default, then we erase everything.
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
uturn_default = flag;
|
|
||||||
uturns.clear();
|
|
||||||
uturns.resize(coordinates.size(), uturn_default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetDeprecatedAPIFlag(const std::string & /*unused*/) { deprecatedAPI = true; }
|
|
||||||
|
|
||||||
void RouteParameters::SetChecksum(const unsigned sum) { check_sum = sum; }
|
|
||||||
|
|
||||||
void RouteParameters::SetInstructionFlag(const bool flag) { print_instructions = flag; }
|
|
||||||
|
|
||||||
void RouteParameters::SetService(const std::string &service_string) { service = service_string; }
|
|
||||||
|
|
||||||
void RouteParameters::SetClassify(const bool flag) { classify = flag; }
|
|
||||||
|
|
||||||
void RouteParameters::SetMatchingBeta(const double beta) { matching_beta = beta; }
|
|
||||||
|
|
||||||
void RouteParameters::SetGPSPrecision(const double precision) { gps_precision = precision; }
|
|
||||||
|
|
||||||
void RouteParameters::SetOutputFormat(const std::string &format) { output_format = format; }
|
|
||||||
|
|
||||||
void RouteParameters::SetJSONpParameter(const std::string ¶meter)
|
|
||||||
{
|
|
||||||
jsonp_parameter = parameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::AddHint(const std::string &hint)
|
|
||||||
{
|
|
||||||
hints.resize(coordinates.size());
|
|
||||||
if (!hints.empty())
|
|
||||||
{
|
|
||||||
hints.back() = hint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::AddTimestamp(const unsigned timestamp)
|
|
||||||
{
|
|
||||||
timestamps.resize(coordinates.size());
|
|
||||||
if (!timestamps.empty())
|
|
||||||
{
|
|
||||||
timestamps.back() = timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RouteParameters::AddBearing(int bearing, boost::optional<int> range)
|
|
||||||
{
|
|
||||||
if (bearing < 0 || bearing > 359)
|
|
||||||
return false;
|
|
||||||
if (range && (*range < 0 || *range > 180))
|
|
||||||
return false;
|
|
||||||
bearings.emplace_back(std::make_pair(bearing, range));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetLanguage(const std::string &language_string)
|
|
||||||
{
|
|
||||||
language = language_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetGeometryFlag(const bool flag) { geometry = flag; }
|
|
||||||
|
|
||||||
void RouteParameters::SetCompressionFlag(const bool flag) { compression = flag; }
|
|
||||||
|
|
||||||
void RouteParameters::AddCoordinate(const double latitude, const double longitude)
|
|
||||||
{
|
|
||||||
coordinates.emplace_back(static_cast<int>(COORDINATE_PRECISION * latitude),
|
|
||||||
static_cast<int>(COORDINATE_PRECISION * longitude));
|
|
||||||
is_source.push_back(true);
|
|
||||||
is_destination.push_back(true);
|
|
||||||
uturns.push_back(uturn_default);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::AddDestination(const double latitude, const double longitude)
|
|
||||||
{
|
|
||||||
coordinates.emplace_back(static_cast<int>(COORDINATE_PRECISION * latitude),
|
|
||||||
static_cast<int>(COORDINATE_PRECISION * longitude));
|
|
||||||
is_source.push_back(false);
|
|
||||||
is_destination.push_back(true);
|
|
||||||
uturns.push_back(uturn_default);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::AddSource(const double latitude, const double longitude)
|
|
||||||
{
|
|
||||||
coordinates.emplace_back(static_cast<int>(COORDINATE_PRECISION * latitude),
|
|
||||||
static_cast<int>(COORDINATE_PRECISION * longitude));
|
|
||||||
is_source.push_back(true);
|
|
||||||
is_destination.push_back(false);
|
|
||||||
uturns.push_back(uturn_default);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouteParameters::SetCoordinatesFromGeometry(const std::string &geometry_string)
|
|
||||||
{
|
|
||||||
coordinates = polylineDecode(geometry_string);
|
|
||||||
uturns.clear();
|
|
||||||
uturns.resize(coordinates.size(), uturn_default);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RouteParameters::SetX(const int x_)
|
|
||||||
{
|
|
||||||
x = x_;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool RouteParameters::SetZ(const int z_)
|
|
||||||
{
|
|
||||||
if (z_ < 12)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
z = z_;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool RouteParameters::SetY(const int y_)
|
|
||||||
{
|
|
||||||
y = y_;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,13 @@ namespace osrm
|
|||||||
namespace engine
|
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;
|
||||||
|
|
||||||
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
|
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
|
||||||
{
|
{
|
||||||
if (forward_heap_1.get())
|
if (forward_heap_1.get())
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include "osrm/osrm.hpp"
|
#include "osrm/osrm.hpp"
|
||||||
#include "engine/engine.hpp"
|
#include "engine/engine.hpp"
|
||||||
|
#include "engine/status.hpp"
|
||||||
#include "engine/engine_config.hpp"
|
#include "engine/engine_config.hpp"
|
||||||
#include "engine/plugins/plugin_base.hpp"
|
#include "engine/plugins/viaroute.hpp"
|
||||||
#include "storage/shared_barriers.hpp"
|
#include "storage/shared_barriers.hpp"
|
||||||
#include "util/make_unique.hpp"
|
#include "util/make_unique.hpp"
|
||||||
|
|
||||||
@ -14,9 +15,9 @@ OSRM::OSRM(engine::EngineConfig &config_) : engine_(util::make_unique<engine::En
|
|||||||
// needed because unique_ptr needs the size of OSRM_impl for delete
|
// needed because unique_ptr needs the size of OSRM_impl for delete
|
||||||
OSRM::~OSRM() {}
|
OSRM::~OSRM() {}
|
||||||
|
|
||||||
int OSRM::RunQuery(const RouteParameters &route_parameters, util::json::Object &json_result)
|
engine::Status OSRM::Route(const RouteParameters &route_parameters, util::json::Object &json_result)
|
||||||
{
|
{
|
||||||
return engine_->RunQuery(route_parameters, json_result);
|
return engine_->Route(route_parameters, json_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
28
src/server/api/route_parameters_parser.cpp
Normal file
28
src/server/api/route_parameters_parser.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "server/api/route_parameters_parser.hpp"
|
||||||
|
#include "server/api/route_parameters_grammar.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
boost::optional<engine::api::RouteParameters> parseRouteParameters(std::string::iterator& iter, std::string::iterator end)
|
||||||
|
{
|
||||||
|
RouteParametersGrammar grammar;
|
||||||
|
const auto result = boost::spirit::qi::parse(iter, end, grammar);
|
||||||
|
|
||||||
|
boost::optional<engine::api::RouteParameters> parameters;
|
||||||
|
if (result && iter == end)
|
||||||
|
{
|
||||||
|
parameters = std::move(grammar.route_parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
104
src/server/api/url_parser.cpp
Normal file
104
src/server/api/url_parser.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#include "server/api/url_parser.hpp"
|
||||||
|
|
||||||
|
#include "engine/polyline_compressor.hpp"
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/spirit/include/qi_char_.hpp>
|
||||||
|
#include <boost/spirit/include/qi_grammar.hpp>
|
||||||
|
#include <boost/spirit/include/qi_uint.hpp>
|
||||||
|
#include <boost/spirit/include/qi_real.hpp>
|
||||||
|
#include <boost/spirit/include/qi_lit.hpp>
|
||||||
|
#include <boost/spirit/include/qi_action.hpp>
|
||||||
|
#include <boost/spirit/include/qi_as_string.hpp>
|
||||||
|
#include <boost/spirit/include/qi_operator.hpp>
|
||||||
|
#include <boost/spirit/include/qi_plus.hpp>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace qi = boost::spirit::qi;
|
||||||
|
using Iterator = std::string::iterator;
|
||||||
|
struct URLGrammar : boost::spirit::qi::grammar<Iterator>
|
||||||
|
{
|
||||||
|
URLGrammar() : URLGrammar::base_type(url_rule)
|
||||||
|
{
|
||||||
|
const auto set_service = [this](std::string &service)
|
||||||
|
{
|
||||||
|
parsed_url.service = std::move(service);
|
||||||
|
};
|
||||||
|
const auto set_version = [this](const unsigned version)
|
||||||
|
{
|
||||||
|
parsed_url.version = version;
|
||||||
|
};
|
||||||
|
const auto set_profile = [this](std::string &profile)
|
||||||
|
{
|
||||||
|
parsed_url.profile = std::move(profile);
|
||||||
|
};
|
||||||
|
const auto set_options = [this](std::string &options)
|
||||||
|
{
|
||||||
|
parsed_url.options = std::move(options);
|
||||||
|
};
|
||||||
|
const auto add_coordinate = [this](const boost::fusion::vector<double, double> &lonLat)
|
||||||
|
{
|
||||||
|
parsed_url.coordinates.emplace_back(
|
||||||
|
util::FixedPointCoordinate(boost::fusion::at_c<1>(lonLat) * COORDINATE_PRECISION,
|
||||||
|
boost::fusion::at_c<0>(lonLat) * COORDINATE_PRECISION));
|
||||||
|
};
|
||||||
|
const auto polyline_to_coordinates = [this](const std::string &polyline)
|
||||||
|
{
|
||||||
|
parsed_url.coordinates = engine::decodePolyline(polyline);
|
||||||
|
};
|
||||||
|
|
||||||
|
alpha_numeral = qi::char_("a-zA-Z0-9");
|
||||||
|
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
|
||||||
|
all_chars = polyline_chars | qi::char_("=,;:&");
|
||||||
|
|
||||||
|
polyline_rule = qi::as_string[qi::lit("polyline(") >> +polyline_chars >>
|
||||||
|
qi::lit(")")][polyline_to_coordinates];
|
||||||
|
location_rule = (qi::double_ >> qi::lit(',') >> qi::double_)[add_coordinate];
|
||||||
|
query_rule = (location_rule % ';') | polyline_rule;
|
||||||
|
|
||||||
|
service_rule = +alpha_numeral;
|
||||||
|
version_rule = qi::uint_;
|
||||||
|
profile_rule = +alpha_numeral;
|
||||||
|
options_rule = *all_chars;
|
||||||
|
|
||||||
|
url_rule = qi::lit('/') >> service_rule[set_service] >> qi::lit('/') >> qi::lit('v') >>
|
||||||
|
version_rule[set_version] >> qi::lit('/') >> profile_rule[set_profile] >>
|
||||||
|
qi::lit('/') >> query_rule >> -(qi::lit('?') >> options_rule[set_options]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedURL parsed_url;
|
||||||
|
|
||||||
|
qi::rule<Iterator> url_rule;
|
||||||
|
qi::rule<Iterator, std::string()> options_rule, service_rule, profile_rule;
|
||||||
|
qi::rule<Iterator> query_rule, polyline_rule, location_rule;
|
||||||
|
qi::rule<Iterator, unsigned()> version_rule;
|
||||||
|
qi::rule<Iterator, char()> alpha_numeral, all_chars, polyline_chars;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<ParsedURL> parseURL(std::string::iterator &iter, std::string::iterator end)
|
||||||
|
{
|
||||||
|
boost::optional<ParsedURL> parsed_url;
|
||||||
|
|
||||||
|
URLGrammar grammar;
|
||||||
|
const auto result = boost::spirit::qi::parse(iter, end, grammar);
|
||||||
|
|
||||||
|
if (result && iter == end)
|
||||||
|
{
|
||||||
|
parsed_url = std::move(grammar.parsed_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -50,7 +50,7 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
|
|||||||
if (result == RequestParser::RequestStatus::valid)
|
if (result == RequestParser::RequestStatus::valid)
|
||||||
{
|
{
|
||||||
current_request.endpoint = TCP_socket.remote_endpoint().address();
|
current_request.endpoint = TCP_socket.remote_endpoint().address();
|
||||||
request_handler.handle_request(current_request, current_reply);
|
request_handler.HandleRequest(current_request, current_reply);
|
||||||
|
|
||||||
// compress the result w/ gzip/deflate if requested
|
// compress the result w/ gzip/deflate if requested
|
||||||
switch (compression_type)
|
switch (compression_type)
|
||||||
|
@ -10,9 +10,9 @@ namespace http
|
|||||||
{
|
{
|
||||||
|
|
||||||
const char ok_html[] = "";
|
const char ok_html[] = "";
|
||||||
const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
|
const char bad_request_html[] = "";
|
||||||
const char internal_server_error_html[] =
|
const char internal_server_error_html[] =
|
||||||
"{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
|
"{\"code\": \"internal-error\",\"message\":\"Internal Server Error\"}";
|
||||||
const char seperators[] = {':', ' '};
|
const char seperators[] = {':', ' '};
|
||||||
const char crlf[] = {'\r', '\n'};
|
const char crlf[] = {'\r', '\n'};
|
||||||
const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
|
const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "server/request_handler.hpp"
|
#include "server/request_handler.hpp"
|
||||||
|
#include "server/service_handler.hpp"
|
||||||
|
|
||||||
#include "server/api_grammar.hpp"
|
#include "server/api/url_parser.hpp"
|
||||||
#include "server/http/reply.hpp"
|
#include "server/http/reply.hpp"
|
||||||
#include "server/http/request.hpp"
|
#include "server/http/request.hpp"
|
||||||
|
|
||||||
@ -9,7 +10,7 @@
|
|||||||
#include "util/string_util.hpp"
|
#include "util/string_util.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
#include "engine/route_parameters.hpp"
|
#include "engine/status.hpp"
|
||||||
#include "util/json_container.hpp"
|
#include "util/json_container.hpp"
|
||||||
#include "osrm/osrm.hpp"
|
#include "osrm/osrm.hpp"
|
||||||
|
|
||||||
@ -28,11 +29,22 @@ namespace osrm
|
|||||||
namespace server
|
namespace server
|
||||||
{
|
{
|
||||||
|
|
||||||
RequestHandler::RequestHandler() : routing_machine(nullptr) {}
|
|
||||||
|
|
||||||
void RequestHandler::handle_request(const http::request ¤t_request,
|
void RequestHandler::RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler_)
|
||||||
|
{
|
||||||
|
service_handler = std::move(service_handler_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestHandler::HandleRequest(const http::request ¤t_request,
|
||||||
http::reply ¤t_reply)
|
http::reply ¤t_reply)
|
||||||
{
|
{
|
||||||
|
if (!service_handler)
|
||||||
|
{
|
||||||
|
current_reply = http::reply::stock_reply(http::reply::internal_server_error);
|
||||||
|
util::SimpleLogger().Write(logWARNING) << "No service handler registered." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
util::json::Object json_result;
|
util::json::Object json_result;
|
||||||
|
|
||||||
// parse command
|
// parse command
|
||||||
@ -67,84 +79,49 @@ void RequestHandler::handle_request(const http::request ¤t_request,
|
|||||||
<< current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
|
<< current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
|
||||||
<< request_string;
|
<< request_string;
|
||||||
|
|
||||||
engine::RouteParameters route_parameters;
|
|
||||||
APIGrammarParser api_parser(&route_parameters);
|
|
||||||
|
|
||||||
auto api_iterator = request_string.begin();
|
auto api_iterator = request_string.begin();
|
||||||
const bool result =
|
auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end());;
|
||||||
boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);
|
|
||||||
|
|
||||||
// check if the was an error with the request
|
// check if the was an error with the request
|
||||||
if (result && api_iterator == request_string.end())
|
if (maybe_parsed_url && api_iterator == request_string.end())
|
||||||
{
|
{
|
||||||
// parsing done, lets call the right plugin to handle the request
|
const engine::Status status = service_handler->RunQuery(std::move(*maybe_parsed_url), json_result);
|
||||||
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
|
if (status != engine::Status::Ok)
|
||||||
|
|
||||||
if (!route_parameters.jsonp_parameter.empty())
|
|
||||||
{ // prepend response with jsonp parameter
|
|
||||||
const std::string json_p = (route_parameters.jsonp_parameter + "(");
|
|
||||||
current_reply.content.insert(current_reply.content.end(), json_p.begin(),
|
|
||||||
json_p.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
const int return_code = routing_machine->RunQuery(route_parameters, json_result);
|
|
||||||
json_result.values["status"] = return_code;
|
|
||||||
// 4xx bad request return code
|
|
||||||
if (return_code / 100 == 4)
|
|
||||||
{
|
{
|
||||||
|
// 4xx bad request return code
|
||||||
current_reply.status = http::reply::bad_request;
|
current_reply.status = http::reply::bad_request;
|
||||||
current_reply.content.clear();
|
|
||||||
route_parameters.output_format.clear();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 2xx valid request
|
BOOST_ASSERT(status == engine::Status::Ok);
|
||||||
BOOST_ASSERT(return_code / 100 == 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto position = std::distance(request_string.begin(), api_iterator);
|
const auto position = std::distance(request_string.begin(), api_iterator);
|
||||||
|
const auto context_begin = request_string.begin() + std::max(position - 3UL, 0UL);
|
||||||
|
const auto context_end = request_string.begin() + std::min(position + 3UL, request_string.size());
|
||||||
|
std::string context(context_begin, context_end);
|
||||||
|
|
||||||
current_reply.status = http::reply::bad_request;
|
current_reply.status = http::reply::bad_request;
|
||||||
json_result.values["status"] = http::reply::bad_request;
|
json_result.values["code"] = "invalid-url";
|
||||||
json_result.values["status_message"] =
|
json_result.values["message"] =
|
||||||
"Query string malformed close to position " + std::to_string(position);
|
"URL string malformed close to position " + std::to_string(position) + ": \"" + context + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
|
current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
|
||||||
current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
|
current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
|
||||||
current_reply.headers.emplace_back("Access-Control-Allow-Headers",
|
current_reply.headers.emplace_back("Access-Control-Allow-Headers",
|
||||||
"X-Requested-With, Content-Type");
|
"X-Requested-With, Content-Type");
|
||||||
|
current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
|
||||||
|
current_reply.headers.emplace_back("Content-Disposition",
|
||||||
|
"inline; filename=\"response.json\"");
|
||||||
|
|
||||||
if (route_parameters.service == "tile" && json_result.values.find("pbf") != json_result.values.end())
|
util::json::render(current_reply.content, json_result);
|
||||||
{
|
|
||||||
std::copy(json_result.values["pbf"].get<osrm::util::json::Buffer>().value.cbegin(),
|
|
||||||
json_result.values["pbf"].get<osrm::util::json::Buffer>().value.cend(),
|
|
||||||
std::back_inserter(current_reply.content));
|
|
||||||
|
|
||||||
current_reply.headers.emplace_back("Content-Type", "application/x-protobuf");
|
// set headers
|
||||||
}
|
|
||||||
else if (route_parameters.jsonp_parameter.empty())
|
|
||||||
{ // json file
|
|
||||||
util::json::render(current_reply.content, json_result);
|
|
||||||
current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
|
|
||||||
current_reply.headers.emplace_back("Content-Disposition",
|
|
||||||
"inline; filename=\"response.json\"");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // jsonp
|
|
||||||
util::json::render(current_reply.content, json_result);
|
|
||||||
current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
|
|
||||||
current_reply.headers.emplace_back("Content-Disposition",
|
|
||||||
"inline; filename=\"response.js\"");
|
|
||||||
}
|
|
||||||
current_reply.headers.emplace_back("Content-Length",
|
current_reply.headers.emplace_back("Content-Length",
|
||||||
std::to_string(current_reply.content.size()));
|
std::to_string(current_reply.content.size()));
|
||||||
if (!route_parameters.jsonp_parameter.empty())
|
|
||||||
{ // append brace to jsonp response
|
|
||||||
current_reply.content.push_back(')');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@ -154,6 +131,5 @@ void RequestHandler::handle_request(const http::request ¤t_request,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
83
src/server/service/route_service.cpp
Normal file
83
src/server/service/route_service.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "server/service/route_service.hpp"
|
||||||
|
|
||||||
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
#include "server/api/route_parameters_parser.hpp"
|
||||||
|
|
||||||
|
#include "util/json_container.hpp"
|
||||||
|
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace service
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const constexpr char PARAMETER_SIZE_MISMATCH_MSG[] = "Number of elements in %1% size %2% does not match coordinate size %3%";
|
||||||
|
|
||||||
|
template<typename ParamT>
|
||||||
|
bool constrainParamSize(const char* msg_template, const char* name, const ParamT& param, const std::size_t target_size, std::string& help)
|
||||||
|
{
|
||||||
|
if (param.size() > 0 && param.size() != target_size)
|
||||||
|
{
|
||||||
|
help = (boost::format(msg_template) % name % param.size() % target_size).str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getWrongOptionHelp(const engine::api::RouteParameters& parameters)
|
||||||
|
{
|
||||||
|
std::string help;
|
||||||
|
|
||||||
|
const auto coord_size = parameters.coordinates.size();
|
||||||
|
|
||||||
|
const bool param_size_mismatch = constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "hints", parameters.hints, coord_size, help)
|
||||||
|
|| constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "bearings", parameters.bearings, coord_size, help)
|
||||||
|
|| constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "radiuses", parameters.radiuses, coord_size, help)
|
||||||
|
|| constrainParamSize(PARAMETER_SIZE_MISMATCH_MSG, "uturns", parameters.uturns, coord_size, help);
|
||||||
|
|
||||||
|
if (!param_size_mismatch && parameters.coordinates.size() < 2)
|
||||||
|
{
|
||||||
|
help = "Number of coordinates needs to be at least two.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return help;
|
||||||
|
}
|
||||||
|
} // anon. ns
|
||||||
|
|
||||||
|
engine::Status RouteService::RunQuery(std::vector<util::FixedPointCoordinate> coordinates,
|
||||||
|
std::string &options,
|
||||||
|
util::json::Object &json_result)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto options_iterator = options.begin();
|
||||||
|
auto parameters = api::parseRouteParameters(options_iterator, options.end());
|
||||||
|
if (!parameters || options_iterator != options.end())
|
||||||
|
{
|
||||||
|
const auto position = std::distance(options.begin(), options_iterator);
|
||||||
|
json_result.values["code"] = "invalid-options";
|
||||||
|
json_result.values["message"] =
|
||||||
|
"Options string malformed close to position " + std::to_string(position);
|
||||||
|
return engine::Status::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(parameters);
|
||||||
|
parameters->coordinates = std::move(coordinates);
|
||||||
|
|
||||||
|
if (!parameters->IsValid())
|
||||||
|
{
|
||||||
|
json_result.values["code"] = "invalid-options";
|
||||||
|
json_result.values["message"] = getWrongOptionHelp(*parameters);
|
||||||
|
return engine::Status::Error;
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(parameters->IsValid());
|
||||||
|
|
||||||
|
return BaseService::routing_machine.Route(*parameters, json_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/server/service_handler.cpp
Normal file
39
src/server/service_handler.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "server/service_handler.hpp"
|
||||||
|
|
||||||
|
#include "server/service/route_service.hpp"
|
||||||
|
|
||||||
|
#include "server/api/parsed_url.hpp"
|
||||||
|
#include "util/json_util.hpp"
|
||||||
|
#include "util/make_unique.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
ServiceHandler::ServiceHandler(osrm::EngineConfig &config) : routing_machine(config)
|
||||||
|
{
|
||||||
|
service_map["route"] = util::make_unique<service::RouteService>(routing_machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::Status ServiceHandler::RunQuery(api::ParsedURL parsed_url, util::json::Object &json_result)
|
||||||
|
{
|
||||||
|
const auto& service_iter = service_map.find(parsed_url.service);
|
||||||
|
if (service_iter == service_map.end())
|
||||||
|
{
|
||||||
|
json_result.values["code"] = "invalid-service";
|
||||||
|
json_result.values["message"] = "Service " + parsed_url.service + " not found!";
|
||||||
|
return engine::Status::Error;
|
||||||
|
}
|
||||||
|
auto &service = service_iter->second;
|
||||||
|
|
||||||
|
if (service->GetVersion() != parsed_url.version)
|
||||||
|
{
|
||||||
|
json_result.values["code"] = "invalid-version";
|
||||||
|
json_result.values["message"] = "Service " + parsed_url.service + " not found!";
|
||||||
|
return engine::Status::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return service->RunQuery(std::move(parsed_url.coordinates), parsed_url.options, json_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,7 @@ namespace storage
|
|||||||
{
|
{
|
||||||
|
|
||||||
using RTreeLeaf =
|
using RTreeLeaf =
|
||||||
typename engine::datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData>::RTreeLeaf;
|
typename engine::datafacade::BaseDataFacade::RTreeLeaf;
|
||||||
using RTreeNode = util::StaticRTree<RTreeLeaf,
|
using RTreeNode = util::StaticRTree<RTreeLeaf,
|
||||||
util::ShM<util::FixedPointCoordinate, true>::vector,
|
util::ShM<util::FixedPointCoordinate, true>::vector,
|
||||||
true>::TreeNode;
|
true>::TreeNode;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "server/server.hpp"
|
#include "server/server.hpp"
|
||||||
#include "util/routed_options.hpp"
|
#include "util/routed_options.hpp"
|
||||||
|
#include "util/make_unique.hpp"
|
||||||
#include "util/simple_logger.hpp"
|
#include "util/simple_logger.hpp"
|
||||||
|
|
||||||
#include "osrm/osrm.hpp"
|
#include "osrm/osrm.hpp"
|
||||||
@ -101,10 +102,10 @@ int main(int argc, const char *argv[]) try
|
|||||||
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
|
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OSRM osrm_lib(config);
|
|
||||||
auto routing_server = server::Server::CreateServer(ip_address, ip_port, requested_thread_num);
|
auto routing_server = server::Server::CreateServer(ip_address, ip_port, requested_thread_num);
|
||||||
|
auto service_handler = util::make_unique<server::ServiceHandler>(config);
|
||||||
|
|
||||||
routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
|
routing_server->RegisterServiceHandler(std::move(service_handler));
|
||||||
|
|
||||||
if (trial_run)
|
if (trial_run)
|
||||||
{
|
{
|
||||||
|
@ -45,12 +45,17 @@ bool FixedPointCoordinate::IsValid() const
|
|||||||
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION);
|
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
|
bool operator==(const FixedPointCoordinate lhs, const FixedPointCoordinate rhs)
|
||||||
{
|
{
|
||||||
return lat == other.lat && lon == other.lon;
|
return lhs.lat == rhs.lat && lhs.lon == rhs.lon;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate &coordinate)
|
bool operator!=(const FixedPointCoordinate lhs, const FixedPointCoordinate rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate coordinate)
|
||||||
{
|
{
|
||||||
out << "(" << static_cast<double>(coordinate.lat / COORDINATE_PRECISION) << ","
|
out << "(" << static_cast<double>(coordinate.lat / COORDINATE_PRECISION) << ","
|
||||||
<< static_cast<double>(coordinate.lon / COORDINATE_PRECISION) << ")";
|
<< static_cast<double>(coordinate.lon / COORDINATE_PRECISION) << ")";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "engine/douglas_peucker.hpp"
|
#include "engine/douglas_peucker.hpp"
|
||||||
#include "engine/segment_information.hpp"
|
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <boost/test/test_case_template.hpp>
|
#include <boost/test/test_case_template.hpp>
|
||||||
@ -13,13 +12,7 @@ BOOST_AUTO_TEST_SUITE(douglas_peucker_simplification)
|
|||||||
using namespace osrm;
|
using namespace osrm;
|
||||||
using namespace osrm::engine;
|
using namespace osrm::engine;
|
||||||
|
|
||||||
SegmentInformation getTestInfo(int lat, int lon, bool necessary)
|
BOOST_AUTO_TEST_CASE(removed_middle_test)
|
||||||
{
|
|
||||||
return SegmentInformation(util::FixedPointCoordinate(lat, lon), 0, 0, 0,
|
|
||||||
extractor::TurnInstruction::HeadOn, necessary, false, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(all_necessary_test)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
x
|
x
|
||||||
@ -27,19 +20,23 @@ BOOST_AUTO_TEST_CASE(all_necessary_test)
|
|||||||
x \
|
x \
|
||||||
/ \
|
/ \
|
||||||
x x
|
x x
|
||||||
/
|
|
||||||
*/
|
*/
|
||||||
std::vector<SegmentInformation> info = {getTestInfo(5, 5, true),
|
std::vector<util::FixedPointCoordinate> coordinates = {
|
||||||
getTestInfo(6, 6, true),
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION),
|
||||||
getTestInfo(10, 10, true),
|
util::FixedPointCoordinate(6 * COORDINATE_PRECISION, 6 * COORDINATE_PRECISION),
|
||||||
getTestInfo(5, 15, true)};
|
util::FixedPointCoordinate(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION),
|
||||||
for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION)};
|
||||||
|
|
||||||
|
// FIXME this test fails for everything below z4 because the DP algorithms
|
||||||
|
// only used a naive distance measurement
|
||||||
|
//for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
|
||||||
|
for (unsigned z = 0; z < 2; z++)
|
||||||
{
|
{
|
||||||
douglasPeucker(info, z);
|
auto result = douglasPeucker(coordinates, z);
|
||||||
for (const auto &i : info)
|
BOOST_CHECK_EQUAL(result.size(), 3);
|
||||||
{
|
BOOST_CHECK_EQUAL(result[0], coordinates[0]);
|
||||||
BOOST_CHECK_EQUAL(i.necessary, true);
|
BOOST_CHECK_EQUAL(result[1], coordinates[2]);
|
||||||
}
|
BOOST_CHECK_EQUAL(result[2], coordinates[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,26 +51,27 @@ BOOST_AUTO_TEST_CASE(remove_second_node_test)
|
|||||||
|
|
|
|
||||||
x
|
x
|
||||||
*/
|
*/
|
||||||
std::vector<SegmentInformation> info = {
|
std::vector<util::FixedPointCoordinate> input = {
|
||||||
getTestInfo(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION, true),
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION),
|
||||||
getTestInfo(5 * COORDINATE_PRECISION,
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION,
|
||||||
5 * COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z], false),
|
5 * COORDINATE_PRECISION +
|
||||||
getTestInfo(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION, false),
|
detail::DOUGLAS_PEUCKER_THRESHOLDS[z]),
|
||||||
getTestInfo(10 * COORDINATE_PRECISION,
|
util::FixedPointCoordinate(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION),
|
||||||
10 + COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2,
|
util::FixedPointCoordinate(10 * COORDINATE_PRECISION,
|
||||||
false),
|
10 + COORDINATE_PRECISION +
|
||||||
getTestInfo(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION, false),
|
detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2),
|
||||||
getTestInfo(5 * COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z],
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION),
|
||||||
15 * COORDINATE_PRECISION, true),
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION +
|
||||||
|
detail::DOUGLAS_PEUCKER_THRESHOLDS[z],
|
||||||
|
15 * COORDINATE_PRECISION),
|
||||||
};
|
};
|
||||||
BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]);
|
BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]);
|
||||||
douglasPeucker(info, z);
|
auto result = douglasPeucker(input, z);
|
||||||
BOOST_CHECK_EQUAL(info[0].necessary, true);
|
BOOST_CHECK_EQUAL(result.size(), 4);
|
||||||
BOOST_CHECK_EQUAL(info[1].necessary, false);
|
BOOST_CHECK_EQUAL(input[0], result[0]);
|
||||||
BOOST_CHECK_EQUAL(info[2].necessary, true);
|
BOOST_CHECK_EQUAL(input[2], result[1]);
|
||||||
BOOST_CHECK_EQUAL(info[3].necessary, true);
|
BOOST_CHECK_EQUAL(input[3], result[2]);
|
||||||
BOOST_CHECK_EQUAL(info[4].necessary, false);
|
BOOST_CHECK_EQUAL(input[5], result[3]);
|
||||||
BOOST_CHECK_EQUAL(info[5].necessary, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE(decode)
|
|||||||
{
|
{
|
||||||
// Polyline string for the 5 coordinates
|
// Polyline string for the 5 coordinates
|
||||||
const std::string polyline = "_gjaR_gjaR_pR_ibE_pR_ibE_pR_ibE_pR_ibE";
|
const std::string polyline = "_gjaR_gjaR_pR_ibE_pR_ibE_pR_ibE_pR_ibE";
|
||||||
const auto coords = polylineDecode(polyline);
|
const auto coords = decodePolyline(polyline);
|
||||||
|
|
||||||
// Test coordinates; these would be the coordinates we give the loc parameter,
|
// Test coordinates; these would be the coordinates we give the loc parameter,
|
||||||
// e.g. loc=10.00,10.0&loc=10.01,10.1...
|
// e.g. loc=10.00,10.0&loc=10.01,10.1...
|
||||||
|
168
unit_tests/server/route_parameters_parser.cpp
Normal file
168
unit_tests/server/route_parameters_parser.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "server/api/route_parameters_parser.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
std::ostream &operator<<(std::ostream &out, api::RouteParameters::GeometriesType geometries)
|
||||||
|
{
|
||||||
|
switch (geometries)
|
||||||
|
{
|
||||||
|
case api::RouteParameters::GeometriesType::GeoJSON:
|
||||||
|
out << "GeoJSON";
|
||||||
|
break;
|
||||||
|
case api::RouteParameters::GeometriesType::Polyline:
|
||||||
|
out << "Polyline";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BOOST_ASSERT_MSG(false, "GeometriesType not fully captured");
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
std::ostream &operator<<(std::ostream &out, api::RouteParameters::OverviewType overview)
|
||||||
|
{
|
||||||
|
switch (overview)
|
||||||
|
{
|
||||||
|
case api::RouteParameters::OverviewType::False:
|
||||||
|
out << "False";
|
||||||
|
break;
|
||||||
|
case api::RouteParameters::OverviewType::Full:
|
||||||
|
out << "Full";
|
||||||
|
break;
|
||||||
|
case api::RouteParameters::OverviewType::Simplified:
|
||||||
|
out << "Simplified";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BOOST_ASSERT_MSG(false, "OverviewType not fully captured");
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
std::ostream &operator<<(std::ostream &out, api::RouteParameters::Bearing bearing)
|
||||||
|
{
|
||||||
|
out << bearing.bearing << "," << bearing.range;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/test_tools.hpp>
|
||||||
|
#include <boost/optional/optional_io.hpp>
|
||||||
|
|
||||||
|
#define CHECK_EQUAL_RANGE(R1, R2) \
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(api_route_parameters_parser)
|
||||||
|
|
||||||
|
using namespace osrm;
|
||||||
|
using namespace osrm::server;
|
||||||
|
|
||||||
|
// returns distance to front
|
||||||
|
std::size_t testInvalidOptions(std::string options)
|
||||||
|
{
|
||||||
|
auto iter = options.begin();
|
||||||
|
auto result = api::parseRouteParameters(iter, options.end());
|
||||||
|
BOOST_CHECK(!result);
|
||||||
|
return std::distance(options.begin(), iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(invalid_urls)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&bla=foo"), 14UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&bearings=foo"), 24UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&uturns=foo"), 22UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&radiuses=foo"), 24UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&hints=foo"), 14UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&geometries=foo"), 14UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&overview=foo"), 14UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidOptions("overview=false&alternative=foo"), 14UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(valid_urls)
|
||||||
|
{
|
||||||
|
engine::api::RouteParameters reference_1{};
|
||||||
|
auto result_1 = api::parseRouteParameters("");
|
||||||
|
BOOST_CHECK(result_1);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.steps, result_1->steps);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.alternative, result_1->alternative);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.geometries, result_1->geometries);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.overview, result_1->overview);
|
||||||
|
CHECK_EQUAL_RANGE(reference_1.uturns, result_1->uturns);
|
||||||
|
CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings);
|
||||||
|
CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses);
|
||||||
|
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
||||||
|
|
||||||
|
// bool steps = true;
|
||||||
|
// bool alternative = true;
|
||||||
|
// GeometriesType geometries = GeometriesType::Polyline;
|
||||||
|
// OverviewType overview = OverviewType::False;
|
||||||
|
// std::vector<boost::optional<bool>> uturns;
|
||||||
|
|
||||||
|
engine::api::RouteParameters reference_2{};
|
||||||
|
auto result_2 = api::parseRouteParameters(
|
||||||
|
"steps=true&alternative=true&geometries=polyline&overview=simplified");
|
||||||
|
BOOST_CHECK(result_2);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.steps, result_2->steps);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.alternative, result_2->alternative);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.geometries, result_2->geometries);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.overview, result_2->overview);
|
||||||
|
CHECK_EQUAL_RANGE(reference_2.uturns, result_2->uturns);
|
||||||
|
CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings);
|
||||||
|
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
|
||||||
|
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
||||||
|
|
||||||
|
std::vector<boost::optional<bool>> uturns_3 = {true, false, boost::none};
|
||||||
|
engine::api::RouteParameters reference_3{
|
||||||
|
false, false, engine::api::RouteParameters::GeometriesType::GeoJSON,
|
||||||
|
engine::api::RouteParameters::OverviewType::False, uturns_3};
|
||||||
|
auto result_3 = api::parseRouteParameters(
|
||||||
|
"steps=false&alternative=false&geometries=geojson&overview=false&uturns=true;false;");
|
||||||
|
BOOST_CHECK(result_3);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.steps, result_3->steps);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.alternative, result_3->alternative);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.geometries, result_3->geometries);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.overview, result_3->overview);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.uturns, result_3->uturns);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.bearings, result_3->bearings);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.radiuses, result_3->radiuses);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
|
||||||
|
|
||||||
|
std::vector<boost::optional<engine::Hint>> hints_4 = {
|
||||||
|
engine::Hint::FromBase64(
|
||||||
|
"rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_0vMAAEAAQGLSzmR"),
|
||||||
|
engine::Hint::FromBase64(
|
||||||
|
"_4ghA4JuzAD_IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR"),
|
||||||
|
engine::Hint::FromBase64(
|
||||||
|
"03AhA0vnzAA_SAAA_____3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR")};
|
||||||
|
engine::api::RouteParameters reference_4{false,
|
||||||
|
true,
|
||||||
|
engine::api::RouteParameters::GeometriesType::Polyline,
|
||||||
|
engine::api::RouteParameters::OverviewType::Simplified,
|
||||||
|
std::vector<boost::optional<bool>>{},
|
||||||
|
std::vector<util::FixedPointCoordinate>{},
|
||||||
|
hints_4,
|
||||||
|
std::vector<boost::optional<double>>{},
|
||||||
|
std::vector<boost::optional<engine::api::BaseParameters::Bearing>>{}
|
||||||
|
};
|
||||||
|
auto result_4 = api::parseRouteParameters(
|
||||||
|
"steps=false&hints=rVghAzxMzABMAwAA5h4CAKMIAAAQAAAAGAAAAAYAAAAAAAAAch8BAJ4AAACpWCED_"
|
||||||
|
"0vMAAEAAQGLSzmR;_4ghA4JuzAD_"
|
||||||
|
"IAAAo28BAOYAAAAzAAAAAgAAAEwAAAAAAAAAdIwAAJ4AAAAXiSEDfm7MAAEAAQGLSzmR;03AhA0vnzAA_SAAA_____"
|
||||||
|
"3wEAAAYAAAAQAAAAB4AAABAAAAAoUYBAJ4AAADlcCEDSefMAAMAAQGLSzmR");
|
||||||
|
BOOST_CHECK(result_3);
|
||||||
|
BOOST_CHECK_EQUAL(reference_4.steps, result_4->steps);
|
||||||
|
BOOST_CHECK_EQUAL(reference_4.alternative, result_4->alternative);
|
||||||
|
BOOST_CHECK_EQUAL(reference_4.geometries, result_4->geometries);
|
||||||
|
BOOST_CHECK_EQUAL(reference_4.overview, result_4->overview);
|
||||||
|
CHECK_EQUAL_RANGE(reference_4.uturns, result_4->uturns);
|
||||||
|
CHECK_EQUAL_RANGE(reference_4.bearings, result_4->bearings);
|
||||||
|
CHECK_EQUAL_RANGE(reference_4.radiuses, result_4->radiuses);
|
||||||
|
CHECK_EQUAL_RANGE(reference_4.coordinates, result_4->coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
110
unit_tests/server/url_parser.cpp
Normal file
110
unit_tests/server/url_parser.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "server/api/url_parser.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
// needed for BOOST_CHECK_EQUAL
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace server
|
||||||
|
{
|
||||||
|
namespace api
|
||||||
|
{
|
||||||
|
std::ostream& operator<<(std::ostream& out, const osrm::server::api::ParsedURL& url)
|
||||||
|
{
|
||||||
|
out << url.service << ", " << url.version << ", " << url.profile << ", ";
|
||||||
|
for (auto c : url.coordinates)
|
||||||
|
{
|
||||||
|
out << c << " ";
|
||||||
|
}
|
||||||
|
out << ", " << url.options;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/test_tools.hpp>
|
||||||
|
|
||||||
|
#define CHECK_EQUAL_RANGE(R1, R2) \
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(R1.begin(), R1.end(), R2.begin(), R2.end());
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(api_url_parser)
|
||||||
|
|
||||||
|
using namespace osrm;
|
||||||
|
using namespace osrm::server;
|
||||||
|
|
||||||
|
// returns distance to front
|
||||||
|
std::size_t testInvalidURL(std::string url)
|
||||||
|
{
|
||||||
|
auto iter = url.begin();
|
||||||
|
auto result = api::parseURL(iter, url.end());
|
||||||
|
BOOST_CHECK(!result);
|
||||||
|
return std::distance(url.begin(), iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(invalid_urls)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidURL("/route/"), 0UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidURL("/route/bla"), 0UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidURL("/route/1/1,2;3;4"), 0UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/pro_file/1,2;3,4"), 0UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile"), 0UL);
|
||||||
|
BOOST_CHECK_EQUAL(testInvalidURL("/route/v1/profile/"), 0UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(valid_urls)
|
||||||
|
{
|
||||||
|
std::vector<util::FixedPointCoordinate> coords_1 = {
|
||||||
|
// lat,lon
|
||||||
|
util::FixedPointCoordinate(1 * COORDINATE_PRECISION, 0 * COORDINATE_PRECISION),
|
||||||
|
util::FixedPointCoordinate(3 * COORDINATE_PRECISION, 2 * COORDINATE_PRECISION),
|
||||||
|
util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 4 * COORDINATE_PRECISION),
|
||||||
|
};
|
||||||
|
api::ParsedURL reference_1{"route", 1, "profile", coords_1, "options=value&foo=bar"};
|
||||||
|
auto result_1 = api::parseURL("/route/v1/profile/0,1;2,3;4,5?options=value&foo=bar");
|
||||||
|
BOOST_CHECK(result_1);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.service, result_1->service);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.version, result_1->version);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.profile, result_1->profile);
|
||||||
|
CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates);
|
||||||
|
BOOST_CHECK_EQUAL(reference_1.options, result_1->options);
|
||||||
|
|
||||||
|
// no options
|
||||||
|
api::ParsedURL reference_2{"route", 1, "profile", coords_1, ""};
|
||||||
|
auto result_2 = api::parseURL("/route/v1/profile/0,1;2,3;4,5");
|
||||||
|
BOOST_CHECK(result_2);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.service, result_2->service);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.version, result_2->version);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.profile, result_2->profile);
|
||||||
|
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
|
||||||
|
BOOST_CHECK_EQUAL(reference_2.options, result_2->options);
|
||||||
|
|
||||||
|
// one coordinate
|
||||||
|
std::vector<util::FixedPointCoordinate> coords_3 = {
|
||||||
|
// lat,lon
|
||||||
|
util::FixedPointCoordinate(1 * COORDINATE_PRECISION, 0 * COORDINATE_PRECISION),
|
||||||
|
};
|
||||||
|
api::ParsedURL reference_3{"route", 1, "profile", coords_3, ""};
|
||||||
|
auto result_3 = api::parseURL("/route/v1/profile/0,1");
|
||||||
|
BOOST_CHECK(result_3);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.service, result_3->service);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.version, result_3->version);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.profile, result_3->profile);
|
||||||
|
CHECK_EQUAL_RANGE(reference_3.coordinates, result_3->coordinates);
|
||||||
|
BOOST_CHECK_EQUAL(reference_3.options, result_3->options);
|
||||||
|
|
||||||
|
// polyline
|
||||||
|
api::ParsedURL reference_5{"route", 1, "profile", coords_1, ""};
|
||||||
|
auto result_5 = api::parseURL("/route/v1/profile/polyline(_ibE?_seK_seK_seK_seK)?");
|
||||||
|
BOOST_CHECK(result_5);
|
||||||
|
BOOST_CHECK_EQUAL(reference_5.service, result_5->service);
|
||||||
|
BOOST_CHECK_EQUAL(reference_5.version, result_5->version);
|
||||||
|
BOOST_CHECK_EQUAL(reference_5.profile, result_5->profile);
|
||||||
|
CHECK_EQUAL_RANGE(reference_5.coordinates, result_5->coordinates);
|
||||||
|
BOOST_CHECK_EQUAL(reference_5.options, result_5->options);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
7
unit_tests/server_tests.cpp
Normal file
7
unit_tests/server_tests.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#define BOOST_TEST_MODULE server tests
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file will contain an automatically generated main function.
|
||||||
|
*/
|
74
unit_tests/util/tiles.cpp
Normal file
74
unit_tests/util/tiles.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "util/tiles.hpp"
|
||||||
|
|
||||||
|
using namespace osrm::util;
|
||||||
|
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/test_case_template.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(tiles_test)
|
||||||
|
|
||||||
|
using namespace osrm;
|
||||||
|
using namespace osrm::util;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(point_to_tile_test)
|
||||||
|
{
|
||||||
|
tiles::Tile tile_1_reference{2306375680,1409941503,32};
|
||||||
|
tiles::Tile tile_2_reference{2308259840,1407668224,32};
|
||||||
|
tiles::Tile tile_3_reference{616562688,2805989376,32};
|
||||||
|
tiles::Tile tile_4_reference{1417674752,2084569088,32};
|
||||||
|
tiles::Tile tile_5_reference{616562688,2805989376,32};
|
||||||
|
tiles::Tile tile_6_reference{712654285,2671662374,32};
|
||||||
|
|
||||||
|
auto tile_1 = tiles::pointToTile(13.31817626953125,52.449314140869696);
|
||||||
|
auto tile_2 = tiles::pointToTile(13.476104736328125,52.56529070208021);
|
||||||
|
auto tile_3 = tiles::pointToTile(-128.32031249999997,-48.224672649565186);
|
||||||
|
auto tile_4 = tiles::pointToTile(-61.17187499999999,5.266007882805498);
|
||||||
|
auto tile_5 = tiles::pointToTile(-128.32031249999997,-48.224672649565186);
|
||||||
|
auto tile_6 = tiles::pointToTile(-120.266007882805532,-40.17187499999999);
|
||||||
|
BOOST_CHECK_EQUAL(tile_1.x, tile_1_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_1.y, tile_1_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_1.z, tile_1_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_2.x, tile_2_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_2.y, tile_2_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_2.z, tile_2_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_3.x, tile_3_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_3.y, tile_3_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_3.z, tile_3_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_4.x, tile_4_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_4.y, tile_4_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_4.z, tile_4_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_5.x, tile_5_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_5.y, tile_5_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_5.z, tile_5_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_6.x, tile_6_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_6.y, tile_6_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_6.z, tile_6_reference.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the bearing-bounds checking function behaves as expected
|
||||||
|
BOOST_AUTO_TEST_CASE(bounding_box_to_tile_test)
|
||||||
|
{
|
||||||
|
tiles::Tile tile_1_reference{17, 10, 5};
|
||||||
|
tiles::Tile tile_2_reference{0, 0, 0};
|
||||||
|
tiles::Tile tile_3_reference{0, 2, 2};
|
||||||
|
auto tile_1 = tiles::getBBMaxZoomTile(13.31817626953125, 52.449314140869696,
|
||||||
|
13.476104736328125, 52.56529070208021);
|
||||||
|
auto tile_2 = tiles::getBBMaxZoomTile(-128.32031249999997, -48.224672649565186,
|
||||||
|
-61.17187499999999, 5.266007882805498);
|
||||||
|
auto tile_3 = tiles::getBBMaxZoomTile(-128.32031249999997, -48.224672649565186,
|
||||||
|
-120.2660078828055, -40.17187499999999);
|
||||||
|
BOOST_CHECK_EQUAL(tile_1.x, tile_1_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_1.y, tile_1_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_1.z, tile_1_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_2.x, tile_2_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_2.y, tile_2_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_2.z, tile_2_reference.z);
|
||||||
|
BOOST_CHECK_EQUAL(tile_3.x, tile_3_reference.x);
|
||||||
|
BOOST_CHECK_EQUAL(tile_3.y, tile_3_reference.y);
|
||||||
|
BOOST_CHECK_EQUAL(tile_3.z, tile_3_reference.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user