Add viaroute suport for new API
This commit is contained in:
		
							parent
							
								
									a1b87b5236
								
							
						
					
					
						commit
						66d241a2d8
					
				| @ -45,7 +45,7 @@ add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND} | ||||
|   COMMENT "Configuring revision fingerprint" | ||||
|   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) | ||||
| 
 | ||||
| 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 EngineTestsGlob unit_tests/engine/*.cpp) | ||||
| file(GLOB UtilTestsGlob unit_tests/util/*.cpp) | ||||
| file(GLOB ServerTestsGlob unit_tests/server/*.cpp) | ||||
| file(GLOB IOTestsGlob unit_tests/io/*.cpp) | ||||
| 
 | ||||
| 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(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(server-tests EXCLUDE_FROM_ALL unit_tests/server_tests.cpp ${ServerTestsGlob} $<TARGET_OBJECTS:UTIL> $<TARGET_OBJECTS:SERVER>) | ||||
| 
 | ||||
| # Benchmarks | ||||
| 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}) | ||||
| # Tests | ||||
| 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(rtree-bench ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TBB_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/external_memory_node.hpp" | ||||
| #include "contractor/query_edge.hpp" | ||||
| #include "engine/phantom_node.hpp" | ||||
| #include "extractor/turn_instructions.hpp" | ||||
| #include "util/integer_range.hpp" | ||||
| @ -29,11 +30,11 @@ namespace datafacade | ||||
| 
 | ||||
| using EdgeRange = util::range<EdgeID>; | ||||
| 
 | ||||
| template <class EdgeDataT> class BaseDataFacade | ||||
| class BaseDataFacade | ||||
| { | ||||
|   public: | ||||
|     using EdgeData = contractor::QueryEdge::EdgeData; | ||||
|     using RTreeLeaf = extractor::EdgeBasedNode; | ||||
|     using EdgeData = EdgeDataT; | ||||
|     BaseDataFacade() {} | ||||
|     virtual ~BaseDataFacade() {} | ||||
| 
 | ||||
| @ -46,7 +47,7 @@ template <class EdgeDataT> class BaseDataFacade | ||||
| 
 | ||||
|     virtual NodeID GetTarget(const EdgeID e) const = 0; | ||||
| 
 | ||||
|     virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0; | ||||
|     virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0; | ||||
| 
 | ||||
|     virtual EdgeID BeginEdges(const NodeID n) const = 0; | ||||
| 
 | ||||
| @ -94,10 +95,22 @@ template <class EdgeDataT> class BaseDataFacade | ||||
|                         const int bearing = 0, | ||||
|                         const int bearing_range = 180) = 0; | ||||
| 
 | ||||
|     virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate) = 0; | ||||
| 
 | ||||
|     virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, const double max_distance) = 0; | ||||
| 
 | ||||
|     virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing = 0, | ||||
|         const int bearing_range = 180) = 0; | ||||
|         const double max_distance, | ||||
|         const int bearing, | ||||
|         const int bearing_range) = 0; | ||||
| 
 | ||||
|     virtual std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing, | ||||
|         const int bearing_range) = 0; | ||||
| 
 | ||||
|     virtual unsigned GetCheckSum() const = 0; | ||||
| 
 | ||||
|  | ||||
| @ -46,17 +46,17 @@ namespace engine | ||||
| namespace datafacade | ||||
| { | ||||
| 
 | ||||
| template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT> | ||||
| class InternalDataFacade final : public BaseDataFacade | ||||
| { | ||||
| 
 | ||||
|   private: | ||||
|     using super = BaseDataFacade<EdgeDataT>; | ||||
|     using super = BaseDataFacade; | ||||
|     using QueryGraph = util::StaticGraph<typename super::EdgeData>; | ||||
|     using InputEdge = typename QueryGraph::InputEdge; | ||||
|     using RTreeLeaf = typename super::RTreeLeaf; | ||||
|     using InternalRTree = | ||||
|         util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, false>::vector, false>; | ||||
|     using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade<EdgeDataT>>; | ||||
|     using InternalGeospatialQuery = GeospatialQuery<InternalRTree, BaseDataFacade>; | ||||
| 
 | ||||
|     InternalDataFacade() {} | ||||
| 
 | ||||
| @ -293,7 +293,7 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad | ||||
| 
 | ||||
|     NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); } | ||||
| 
 | ||||
|     EdgeDataT &GetEdgeData(const EdgeID e) const override final | ||||
|     EdgeData &GetEdgeData(const EdgeID e) const override final | ||||
|     { | ||||
|         return m_query_graph->GetEdgeData(e); | ||||
|     } | ||||
| @ -386,10 +386,52 @@ template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacad | ||||
|                                                        bearing_range); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, const double max_distance) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get()) | ||||
|         { | ||||
|             LoadRTree(); | ||||
|             BOOST_ASSERT(m_geospatial_query.get()); | ||||
|         } | ||||
| 
 | ||||
|         return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|             input_coordinate, max_distance); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get()) | ||||
|         { | ||||
|             LoadRTree(); | ||||
|             BOOST_ASSERT(m_geospatial_query.get()); | ||||
|         } | ||||
| 
 | ||||
|         return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|             input_coordinate); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing = 0, | ||||
|         const int bearing_range = 180) override final | ||||
|         const double max_distance, | ||||
|         const int bearing, | ||||
|         const int bearing_range) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get()) | ||||
|         { | ||||
|             LoadRTree(); | ||||
|             BOOST_ASSERT(m_geospatial_query.get()); | ||||
|         } | ||||
| 
 | ||||
|         return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|             input_coordinate, max_distance, bearing, bearing_range); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing, | ||||
|         const int bearing_range) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get()) | ||||
|         { | ||||
|  | ||||
| @ -36,12 +36,11 @@ namespace engine | ||||
| namespace datafacade | ||||
| { | ||||
| 
 | ||||
| template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT> | ||||
| class SharedDataFacade final : public BaseDataFacade | ||||
| { | ||||
| 
 | ||||
|   private: | ||||
|     using EdgeData = EdgeDataT; | ||||
|     using super = BaseDataFacade<EdgeData>; | ||||
|     using super = BaseDataFacade; | ||||
|     using QueryGraph = util::StaticGraph<EdgeData, true>; | ||||
|     using GraphNode = typename QueryGraph::NodeArrayEntry; | ||||
|     using GraphEdge = typename QueryGraph::EdgeArrayEntry; | ||||
| @ -50,7 +49,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade< | ||||
|     using RTreeLeaf = typename super::RTreeLeaf; | ||||
|     using SharedRTree = | ||||
|         util::StaticRTree<RTreeLeaf, util::ShM<util::FixedPointCoordinate, true>::vector, true>; | ||||
|     using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade<EdgeDataT>>; | ||||
|     using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>; | ||||
|     using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>; | ||||
|     using RTreeNode = typename SharedRTree::TreeNode; | ||||
| 
 | ||||
| @ -333,7 +332,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade< | ||||
| 
 | ||||
|     NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); } | ||||
| 
 | ||||
|     EdgeDataT &GetEdgeData(const EdgeID e) const override final | ||||
|     EdgeData &GetEdgeData(const EdgeID e) const override final | ||||
|     { | ||||
|         return m_query_graph->GetEdgeData(e); | ||||
|     } | ||||
| @ -454,10 +453,52 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade< | ||||
|                                                        bearing_range); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) | ||||
|         { | ||||
|             LoadRTree(); | ||||
|             BOOST_ASSERT(m_geospatial_query.get()); | ||||
|         } | ||||
| 
 | ||||
|         return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|             input_coordinate); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, const double max_distance) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) | ||||
|         { | ||||
|             LoadRTree(); | ||||
|             BOOST_ASSERT(m_geospatial_query.get()); | ||||
|         } | ||||
| 
 | ||||
|         return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|             input_coordinate, max_distance); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing = 0, | ||||
|         const int bearing_range = 180) override final | ||||
|         const double max_distance, | ||||
|         const int bearing, | ||||
|         const int bearing_range) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) | ||||
|         { | ||||
|             LoadRTree(); | ||||
|             BOOST_ASSERT(m_geospatial_query.get()); | ||||
|         } | ||||
| 
 | ||||
|         return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|             input_coordinate, max_distance, bearing, bearing_range); | ||||
|     } | ||||
| 
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing, | ||||
|         const int bearing_range) override final | ||||
|     { | ||||
|         if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first) | ||||
|         { | ||||
| @ -469,6 +510,7 @@ template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade< | ||||
|             input_coordinate, bearing, bearing_range); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     unsigned GetCheckSum() const override final { return m_check_sum; } | ||||
| 
 | ||||
|     unsigned GetNameIndexFromEdgeID(const unsigned id) const override final | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #ifndef DOUGLAS_PEUCKER_HPP_ | ||||
| #define DOUGLAS_PEUCKER_HPP_ | ||||
| 
 | ||||
| #include "engine/segment_information.hpp" | ||||
| #include "util/coordinate.hpp" | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <iterator> | ||||
| @ -44,14 +44,16 @@ const constexpr auto DOUGLAS_PEUCKER_THRESHOLDS_SIZE = | ||||
| // Input is vector of pairs. Each pair consists of the point information and a
 | ||||
| // bit indicating if the points is present in the generalization.
 | ||||
| // Note: points may also be pre-selected*/
 | ||||
| void douglasPeucker(std::vector<SegmentInformation>::iterator begin, | ||||
|                     std::vector<SegmentInformation>::iterator end, | ||||
|                     const unsigned zoom_level); | ||||
| std::vector<util::FixedPointCoordinate> | ||||
| douglasPeucker(std::vector<util::FixedPointCoordinate>::const_iterator begin, | ||||
|                std::vector<util::FixedPointCoordinate>::const_iterator end, | ||||
|                const unsigned zoom_level); | ||||
| 
 | ||||
| // Convenience range-based function
 | ||||
| inline void douglasPeucker(std::vector<SegmentInformation> &geometry, const unsigned zoom_level) | ||||
| inline std::vector<util::FixedPointCoordinate> | ||||
| douglasPeucker(const std::vector<util::FixedPointCoordinate> &geometry, const unsigned zoom_level) | ||||
| { | ||||
|     douglasPeucker(begin(geometry), end(geometry), zoom_level); | ||||
|     return douglasPeucker(begin(geometry), end(geometry), zoom_level); | ||||
| } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,9 @@ | ||||
| #ifndef ENGINE_HPP | ||||
| #define ENGINE_HPP | ||||
| 
 | ||||
| #include "contractor/query_edge.hpp" | ||||
| 
 | ||||
| #include "osrm/json_container.hpp" | ||||
| #include "osrm/osrm.hpp" | ||||
| #include "engine/status.hpp" | ||||
| #include "storage/shared_barriers.hpp" | ||||
| #include "util/json_container.hpp" | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <unordered_map> | ||||
| @ -13,11 +12,6 @@ | ||||
| namespace osrm | ||||
| { | ||||
| 
 | ||||
| namespace storage | ||||
| { | ||||
| struct SharedBarriers; | ||||
| } | ||||
| 
 | ||||
| namespace util | ||||
| { | ||||
| namespace json | ||||
| @ -29,41 +23,43 @@ struct Object; | ||||
| namespace engine | ||||
| { | ||||
| struct EngineConfig; | ||||
| namespace api | ||||
| { | ||||
| struct RouteParameters; | ||||
| } | ||||
| namespace plugins | ||||
| { | ||||
| class BasePlugin; | ||||
| class ViaRoutePlugin; | ||||
| } | ||||
| namespace datafacade | ||||
| { | ||||
| template <class EdgeDataT> class BaseDataFacade; | ||||
| class BaseDataFacade; | ||||
| } | ||||
| 
 | ||||
| class Engine final | ||||
| { | ||||
|   private: | ||||
|     using PluginMap = std::unordered_map<std::string, std::unique_ptr<plugins::BasePlugin>>; | ||||
| 
 | ||||
|   public: | ||||
|     struct EngineLock | ||||
|     { | ||||
|         // will only be initialized if shared memory is used
 | ||||
|         storage::SharedBarriers barrier; | ||||
|         // decrease number of concurrent queries
 | ||||
|         void DecreaseQueryCount(); | ||||
|         // increase number of concurrent queries
 | ||||
|         void IncreaseQueryCount(); | ||||
|     }; | ||||
| 
 | ||||
|     Engine(EngineConfig &config_); | ||||
| 
 | ||||
|     Engine(const Engine &) = delete; | ||||
|     Engine &operator=(const Engine &) = delete; | ||||
| 
 | ||||
|     int RunQuery(const RouteParameters &route_parameters, util::json::Object &json_result); | ||||
|     Status Route(const api::RouteParameters &route_parameters, util::json::Object &json_result); | ||||
| 
 | ||||
|   private: | ||||
|     void RegisterPlugin(plugins::BasePlugin *plugin); | ||||
|     PluginMap plugin_map; | ||||
|     // will only be initialized if shared memory is used
 | ||||
|     std::unique_ptr<storage::SharedBarriers> barrier; | ||||
|     // base class pointer to the objects
 | ||||
|     datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData> *query_data_facade; | ||||
| 
 | ||||
|     // decrease number of concurrent queries
 | ||||
|     void decrease_concurrent_query_count(); | ||||
|     // increase number of concurrent queries
 | ||||
|     void increase_concurrent_query_count(); | ||||
|     std::unique_ptr<EngineLock> lock; | ||||
|     std::unique_ptr<plugins::ViaRoutePlugin> route_plugin; | ||||
|     std::unique_ptr<datafacade::BaseDataFacade> query_data_facade; | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -84,16 +84,86 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery | ||||
|     // Returns the nearest phantom node. If this phantom node is not from a big component
 | ||||
|     // a second phantom node is return that is the nearest coordinate in a big component.
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing = 0, | ||||
|         const int bearing_range = 180) | ||||
|         const util::FixedPointCoordinate input_coordinate, const double max_distance) | ||||
|     { | ||||
|         bool has_small_component = false; | ||||
|         bool has_big_component = false; | ||||
|         auto results = rtree.Nearest( | ||||
|             input_coordinate, | ||||
|             [this, bearing, bearing_range, &has_big_component, &has_small_component]( | ||||
|                 const EdgeData &data) | ||||
|             [&has_big_component, &has_small_component](const EdgeData &data) | ||||
|             { | ||||
|                 auto use_segment = | ||||
|                     (!has_small_component || (!has_big_component && !data.component.is_tiny)); | ||||
|                 auto use_directions = std::make_pair(use_segment, use_segment); | ||||
| 
 | ||||
|                 has_big_component = has_big_component || !data.component.is_tiny; | ||||
|                 has_small_component = has_small_component || data.component.is_tiny; | ||||
| 
 | ||||
|                 return use_directions; | ||||
|             }, | ||||
|             [&has_big_component, max_distance](const std::size_t num_results, const double min_dist) | ||||
|             { | ||||
|                 return (num_results > 0 && has_big_component) || min_dist > max_distance; | ||||
|             }); | ||||
| 
 | ||||
|         if (results.size() == 0) | ||||
|         { | ||||
|             return std::make_pair(PhantomNode{}, PhantomNode{}); | ||||
|         } | ||||
| 
 | ||||
|         BOOST_ASSERT(results.size() == 1 || results.size() == 2); | ||||
|         return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, | ||||
|                               MakePhantomNode(input_coordinate, results.back()).phantom_node); | ||||
|     } | ||||
| 
 | ||||
|     // Returns the nearest phantom node. If this phantom node is not from a big component
 | ||||
|     // a second phantom node is return that is the nearest coordinate in a big component.
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate) | ||||
|     { | ||||
|         bool has_small_component = false; | ||||
|         bool has_big_component = false; | ||||
|         auto results = | ||||
|             rtree.Nearest(input_coordinate, | ||||
|                           [&has_big_component, &has_small_component](const EdgeData &data) | ||||
|                           { | ||||
|                               auto use_segment = (!has_small_component || | ||||
|                                                   (!has_big_component && !data.component.is_tiny)); | ||||
|                               auto use_directions = std::make_pair(use_segment, use_segment); | ||||
| 
 | ||||
|                               has_big_component = has_big_component || !data.component.is_tiny; | ||||
|                               has_small_component = has_small_component || data.component.is_tiny; | ||||
| 
 | ||||
|                               return use_directions; | ||||
|                           }, | ||||
|                           [&has_big_component](const std::size_t num_results, const double) | ||||
|                           { | ||||
|                               return num_results > 0 && has_big_component; | ||||
|                           }); | ||||
| 
 | ||||
|         if (results.size() == 0) | ||||
|         { | ||||
|             return std::make_pair(PhantomNode{}, PhantomNode{}); | ||||
|         } | ||||
| 
 | ||||
|         BOOST_ASSERT(results.size() == 1 || results.size() == 2); | ||||
|         return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, | ||||
|                               MakePhantomNode(input_coordinate, results.back()).phantom_node); | ||||
|     } | ||||
| 
 | ||||
|     // Returns the nearest phantom node. If this phantom node is not from a big component
 | ||||
|     // a second phantom node is return that is the nearest coordinate in a big component.
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const int bearing, | ||||
|         const int bearing_range) | ||||
|     { | ||||
|         bool has_small_component = false; | ||||
|         bool has_big_component = false; | ||||
|         auto results = rtree.Nearest( | ||||
|             input_coordinate, | ||||
|             [this, bearing, bearing_range, &has_big_component, | ||||
|              &has_small_component](const EdgeData &data) | ||||
|             { | ||||
|                 auto use_segment = | ||||
|                     (!has_small_component || (!has_big_component && !data.component.is_tiny)); | ||||
| @ -126,6 +196,52 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery | ||||
|                               MakePhantomNode(input_coordinate, results.back()).phantom_node); | ||||
|     } | ||||
| 
 | ||||
|     // Returns the nearest phantom node. If this phantom node is not from a big component
 | ||||
|     // a second phantom node is return that is the nearest coordinate in a big component.
 | ||||
|     std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|         const util::FixedPointCoordinate input_coordinate, | ||||
|         const double max_distance, | ||||
|         const int bearing, | ||||
|         const int bearing_range) | ||||
|     { | ||||
|         bool has_small_component = false; | ||||
|         bool has_big_component = false; | ||||
|         auto results = rtree.Nearest( | ||||
|             input_coordinate, | ||||
|             [this, bearing, bearing_range, &has_big_component, | ||||
|              &has_small_component](const EdgeData &data) | ||||
|             { | ||||
|                 auto use_segment = | ||||
|                     (!has_small_component || (!has_big_component && !data.component.is_tiny)); | ||||
|                 auto use_directions = std::make_pair(use_segment, use_segment); | ||||
| 
 | ||||
|                 if (use_segment) | ||||
|                 { | ||||
|                     use_directions = checkSegmentBearing(data, bearing, bearing_range); | ||||
|                     if (use_directions.first || use_directions.second) | ||||
|                     { | ||||
|                         has_big_component = has_big_component || !data.component.is_tiny; | ||||
|                         has_small_component = has_small_component || data.component.is_tiny; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 return use_directions; | ||||
|             }, | ||||
|             [&has_big_component, max_distance](const std::size_t num_results, const double min_dist) | ||||
|             { | ||||
|                 return (num_results > 0 && has_big_component) || min_dist > max_distance; | ||||
|             }); | ||||
| 
 | ||||
|         if (results.size() == 0) | ||||
|         { | ||||
|             return std::make_pair(PhantomNode{}, PhantomNode{}); | ||||
|         } | ||||
| 
 | ||||
|         BOOST_ASSERT(results.size() > 0); | ||||
|         return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node, | ||||
|                               MakePhantomNode(input_coordinate, results.back()).phantom_node); | ||||
|     } | ||||
| 
 | ||||
|   private: | ||||
|     std::vector<PhantomNodeWithDistance> | ||||
|     MakePhantomNodes(const util::FixedPointCoordinate input_coordinate, | ||||
|  | ||||
							
								
								
									
										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 | ||||
| { | ||||
|     PathData() | ||||
|         : node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT), | ||||
|           turn_instruction(extractor::TurnInstruction::NoTurn), | ||||
|           travel_mode(TRAVEL_MODE_INACCESSIBLE) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     PathData(NodeID node, | ||||
|              unsigned name_id, | ||||
|              extractor::TurnInstruction turn_instruction, | ||||
|              EdgeWeight segment_duration, | ||||
|              extractor::TravelMode travel_mode) | ||||
|         : node(node), name_id(name_id), segment_duration(segment_duration), | ||||
|           turn_instruction(turn_instruction), travel_mode(travel_mode) | ||||
|     { | ||||
|     } | ||||
|     NodeID node; | ||||
|     // id of via node of the turn
 | ||||
|     NodeID turn_via_node; | ||||
|     // name of the street that leads to the turn
 | ||||
|     unsigned name_id; | ||||
|     EdgeWeight segment_duration; | ||||
|     // duration that is traveled on the segment until the turn is reached
 | ||||
|     EdgeWeight duration_until_turn; | ||||
|     // instruction to execute at the turn
 | ||||
|     extractor::TurnInstruction turn_instruction; | ||||
|     // travel mode of the street that leads to the turn
 | ||||
|     extractor::TravelMode travel_mode : 4; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -94,7 +94,7 @@ struct PhantomNode | ||||
|     bool operator==(const PhantomNode &other) const { return location == other.location; } | ||||
| 
 | ||||
|     template <class OtherT> | ||||
|     PhantomNode(const OtherT &other, int forward_weight_, int forward_offset_, int reverse_weight_, int reverse_offset_, const util::FixedPointCoordinate foot_point) | ||||
|     explicit PhantomNode(const OtherT &other, int forward_weight_, int forward_offset_, int reverse_weight_, int reverse_offset_, const util::FixedPointCoordinate foot_point) | ||||
|     { | ||||
|         forward_node_id = other.forward_edge_based_node_id; | ||||
|         reverse_node_id = other.reverse_edge_based_node_id; | ||||
|  | ||||
| @ -1,11 +1,14 @@ | ||||
| #ifndef BASE_PLUGIN_HPP | ||||
| #define BASE_PLUGIN_HPP | ||||
| 
 | ||||
| #include "engine/datafacade/datafacade_base.hpp" | ||||
| #include "engine/api/base_parameters.hpp" | ||||
| #include "engine/phantom_node.hpp" | ||||
| #include "engine/status.hpp" | ||||
| 
 | ||||
| #include "osrm/coordinate.hpp" | ||||
| #include "osrm/json_container.hpp" | ||||
| #include "osrm/route_parameters.hpp" | ||||
| #include "util/coordinate.hpp" | ||||
| #include "util/json_container.hpp" | ||||
| #include "util/integer_range.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <string> | ||||
| @ -20,38 +23,32 @@ namespace plugins | ||||
| 
 | ||||
| class BasePlugin | ||||
| { | ||||
|   public: | ||||
|     enum class Status : int | ||||
|     { | ||||
|         Ok = 200, | ||||
|         EmptyResult = 207, | ||||
|         NoSegment = 208, | ||||
|         Error = 400 | ||||
|     }; | ||||
|   protected: | ||||
|     datafacade::BaseDataFacade &facade; | ||||
|     BasePlugin(datafacade::BaseDataFacade &facade_) : facade(facade_) {} | ||||
| 
 | ||||
|     BasePlugin() {} | ||||
|     // Maybe someone can explain the pure virtual destructor thing to me (dennis)
 | ||||
|     virtual ~BasePlugin() {} | ||||
|     virtual const std::string GetDescriptor() const = 0; | ||||
|     virtual Status HandleRequest(const RouteParameters &, util::json::Object &) = 0; | ||||
|     virtual bool check_all_coordinates(const std::vector<util::FixedPointCoordinate> &coordinates, | ||||
|                                        const unsigned min = 2) const final | ||||
|     bool CheckAllCoordinates(const std::vector<util::FixedPointCoordinate> &coordinates) | ||||
|     { | ||||
|         if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates), | ||||
|                                                     [](const util::FixedPointCoordinate coordinate) | ||||
|                                                     { | ||||
|                                                         return !coordinate.IsValid(); | ||||
|                                                     })) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|         return !std::any_of(std::begin(coordinates), std::end(coordinates), | ||||
|                            [](const util::FixedPointCoordinate &coordinate) | ||||
|                            { | ||||
|                                return !coordinate.IsValid(); | ||||
|                            }); | ||||
|     } | ||||
| 
 | ||||
|     Status Error(const std::string &code, | ||||
|                  const std::string &message, | ||||
|                  util::json::Object &json_result) const | ||||
|     { | ||||
|         json_result.values["code"] = code; | ||||
|         json_result.values["message"] = message; | ||||
|         return Status::Error; | ||||
|     } | ||||
| 
 | ||||
|     // Decides whether to use the phantom node from a big or small component if both are found.
 | ||||
|     // Returns true if all phantom nodes are in the same component after snapping.
 | ||||
|     std::vector<PhantomNode> snapPhantomNodes( | ||||
|         const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const | ||||
|     std::vector<PhantomNode> | ||||
|     SnapPhantomNodes(const std::vector<PhantomNodePair> &phantom_node_pair_list) const | ||||
|     { | ||||
|         const auto check_component_id_is_tiny = | ||||
|             [](const std::pair<PhantomNode, PhantomNode> &phantom_pair) | ||||
| @ -111,6 +108,69 @@ class BasePlugin | ||||
| 
 | ||||
|         return snapped_phantoms; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<PhantomNodePair> GetPhantomNodes(const api::BaseParameters ¶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 | ||||
| #define VIA_ROUTE_HPP | ||||
| 
 | ||||
| #include "engine/datafacade/datafacade_base.hpp" | ||||
| #include "engine/plugins/plugin_base.hpp" | ||||
| #include "engine/api/route_api.hpp" | ||||
| 
 | ||||
| #include "engine/api_response_generator.hpp" | ||||
| #include "engine/object_encoder.hpp" | ||||
| #include "engine/search_engine.hpp" | ||||
| #include "util/for_each_pair.hpp" | ||||
| #include "util/integer_range.hpp" | ||||
| #include "util/make_unique.hpp" | ||||
| #include "util/simple_logger.hpp" | ||||
| #include "util/timing_util.hpp" | ||||
| #include "osrm/json_container.hpp" | ||||
| #include "engine/search_engine_data.hpp" | ||||
| #include "engine/routing_algorithms/shortest_path.hpp" | ||||
| #include "engine/routing_algorithms/alternative_path.hpp" | ||||
| #include "engine/routing_algorithms/direct_shortest_path.hpp" | ||||
| #include "util/json_container.hpp" | ||||
| 
 | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| @ -27,146 +26,20 @@ namespace engine | ||||
| namespace plugins | ||||
| { | ||||
| 
 | ||||
| template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin | ||||
| class ViaRoutePlugin final : public BasePlugin | ||||
| { | ||||
|   private: | ||||
|     std::string descriptor_string; | ||||
|     std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr; | ||||
|     DataFacadeT *facade; | ||||
|     SearchEngineData heaps; | ||||
|     routing_algorithms::ShortestPathRouting<datafacade::BaseDataFacade> shortest_path; | ||||
|     routing_algorithms::AlternativeRouting<datafacade::BaseDataFacade> alternative_path; | ||||
|     routing_algorithms::DirectShortestPathRouting<datafacade::BaseDataFacade> direct_shortest_path; | ||||
|     int max_locations_viaroute; | ||||
| 
 | ||||
|   public: | ||||
|     explicit ViaRoutePlugin(DataFacadeT *facade, int max_locations_viaroute) | ||||
|         : descriptor_string("viaroute"), facade(facade), | ||||
|           max_locations_viaroute(max_locations_viaroute) | ||||
|     { | ||||
|         search_engine_ptr = util::make_unique<SearchEngine<DataFacadeT>>(facade); | ||||
|     } | ||||
|     explicit ViaRoutePlugin(datafacade::BaseDataFacade &facade, int max_locations_viaroute); | ||||
| 
 | ||||
|     virtual ~ViaRoutePlugin() {} | ||||
| 
 | ||||
|     const std::string GetDescriptor() const override final { return descriptor_string; } | ||||
| 
 | ||||
|     Status HandleRequest(const RouteParameters &route_parameters, | ||||
|                          util::json::Object &json_result) override final | ||||
|     { | ||||
|         if (max_locations_viaroute > 0 && | ||||
|             (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute)) | ||||
|         { | ||||
|             json_result.values["status_message"] = | ||||
|                 "Number of entries " + std::to_string(route_parameters.coordinates.size()) + | ||||
|                 " is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")"; | ||||
|             return Status::Error; | ||||
|         } | ||||
| 
 | ||||
|         if (!check_all_coordinates(route_parameters.coordinates)) | ||||
|         { | ||||
|             json_result.values["status_message"] = "Invalid coordinates"; | ||||
|             return Status::Error; | ||||
|         } | ||||
| 
 | ||||
|         const auto &input_bearings = route_parameters.bearings; | ||||
|         if (input_bearings.size() > 0 && | ||||
|             route_parameters.coordinates.size() != input_bearings.size()) | ||||
|         { | ||||
|             json_result.values["status_message"] = | ||||
|                 "Number of bearings does not match number of coordinate"; | ||||
|             return Status::Error; | ||||
|         } | ||||
| 
 | ||||
|         std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size()); | ||||
|         const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); | ||||
| 
 | ||||
|         for (const auto i : util::irange<std::size_t>(0, route_parameters.coordinates.size())) | ||||
|         { | ||||
|             if (checksum_OK && i < route_parameters.hints.size() && | ||||
|                 !route_parameters.hints[i].empty()) | ||||
|             { | ||||
|                 phantom_node_pair_list[i].first = | ||||
|                     decodeBase64<PhantomNode>(route_parameters.hints[i]); | ||||
|                 if (phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes())) | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|             const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; | ||||
|             const int range = input_bearings.size() > 0 | ||||
|                                   ? (input_bearings[i].second ? *input_bearings[i].second : 10) | ||||
|                                   : 180; | ||||
|             phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent( | ||||
|                 route_parameters.coordinates[i], bearing, range); | ||||
|             // we didn't found a fitting node, return error
 | ||||
|             if (!phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes())) | ||||
|             { | ||||
|                 json_result.values["status_message"] = | ||||
|                     std::string("Could not find a matching segment for coordinate ") + | ||||
|                     std::to_string(i); | ||||
|                 return Status::NoSegment; | ||||
|             } | ||||
|             BOOST_ASSERT(phantom_node_pair_list[i].first.IsValid(facade->GetNumberOfNodes())); | ||||
|             BOOST_ASSERT(phantom_node_pair_list[i].second.IsValid(facade->GetNumberOfNodes())); | ||||
|         } | ||||
| 
 | ||||
|         auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list); | ||||
| 
 | ||||
|         InternalRouteResult raw_route; | ||||
|         auto build_phantom_pairs = | ||||
|             [&raw_route](const PhantomNode &first_node, const PhantomNode &second_node) | ||||
|         { | ||||
|             raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node}); | ||||
|         }; | ||||
|         util::for_each_pair(snapped_phantoms, build_phantom_pairs); | ||||
| 
 | ||||
|         if (1 == raw_route.segment_end_coordinates.size()) | ||||
|         { | ||||
|             if (route_parameters.alternate_route && facade->GetCoreSize() == 0) | ||||
|             { | ||||
|                 search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(), | ||||
|                                                     raw_route); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates, | ||||
|                                                         route_parameters.uturns, raw_route); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, | ||||
|                                              route_parameters.uturns, raw_route); | ||||
|         } | ||||
| 
 | ||||
|         // we can only know this after the fact, different SCC ids still
 | ||||
|         // allow for connection in one direction.
 | ||||
|         if (raw_route.is_valid()) | ||||
|         { | ||||
|             auto generator = MakeApiResponseGenerator(facade); | ||||
|             generator.DescribeRoute(route_parameters, raw_route, json_result); | ||||
|             json_result.values["status_message"] = "Found route between points"; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             auto first_component_id = snapped_phantoms.front().component.id; | ||||
|             auto not_in_same_component = | ||||
|                 std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(), | ||||
|                             [first_component_id](const PhantomNode &node) | ||||
|                             { | ||||
|                                 return node.component.id != first_component_id; | ||||
|                             }); | ||||
| 
 | ||||
|             if (not_in_same_component) | ||||
|             { | ||||
|                 json_result.values["status_message"] = "Impossible route between points"; | ||||
|                 return Status::EmptyResult; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 json_result.values["status_message"] = "No route found between points"; | ||||
|                 return Status::Error; | ||||
|             } | ||||
|         } | ||||
|         return Status::Ok; | ||||
|     } | ||||
|     Status HandleRequest(const api::RouteParameters &route_parameters, | ||||
|                          util::json::Object &json_result); | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,6 @@ | ||||
| #define POLYLINECOMPRESSOR_H_ | ||||
| 
 | ||||
| #include "osrm/coordinate.hpp" | ||||
| #include "engine/segment_information.hpp" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| @ -11,13 +10,21 @@ namespace osrm | ||||
| { | ||||
| namespace engine | ||||
| { | ||||
| namespace detail | ||||
| { | ||||
|     constexpr double POLYLINE_PECISION = 1e5; | ||||
|     constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PECISION / COORDINATE_PRECISION; | ||||
|     constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PECISION; | ||||
| } | ||||
| 
 | ||||
| using CoordVectorForwardIter = std::vector<FixedPointCoordinate>::const_iterator; | ||||
| // Encodes geometry into polyline format.
 | ||||
| // See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
 | ||||
| std::string polylineEncode(const std::vector<SegmentInformation> &geometry); | ||||
| std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter end); | ||||
| 
 | ||||
| // Decodes geometry from polyline format
 | ||||
| // See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
 | ||||
| std::vector<util::FixedPointCoordinate> polylineDecode(const std::string &polyline); | ||||
| std::vector<util::FixedPointCoordinate> decodePolyline(const std::string &polyline); | ||||
| } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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,149 +0,0 @@ | ||||
| #ifndef EXTRACT_ROUTE_NAMES_H | ||||
| #define EXTRACT_ROUTE_NAMES_H | ||||
| 
 | ||||
| #include <boost/assert.hpp> | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <string> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace osrm | ||||
| { | ||||
| namespace engine | ||||
| { | ||||
| 
 | ||||
| struct RouteNames | ||||
| { | ||||
|     std::string shortest_path_name_1; | ||||
|     std::string shortest_path_name_2; | ||||
|     std::string alternative_path_name_1; | ||||
|     std::string alternative_path_name_2; | ||||
| }; | ||||
| 
 | ||||
| namespace detail | ||||
| { | ||||
| 
 | ||||
| template <class SegmentT> | ||||
| SegmentT pickNextLongestSegment(const std::vector<SegmentT> &segment_list, | ||||
|                                 const unsigned blocked_name_id) | ||||
| { | ||||
|     SegmentT result_segment; | ||||
|     result_segment.name_id = blocked_name_id; // make sure we get a valid name
 | ||||
|     result_segment.length = 0; | ||||
| 
 | ||||
|     for (const SegmentT &segment : segment_list) | ||||
|     { | ||||
|         if (segment.name_id != blocked_name_id && segment.length > result_segment.length && | ||||
|             segment.name_id != 0) | ||||
|         { | ||||
|             result_segment = segment; | ||||
|         } | ||||
|     } | ||||
|     return result_segment; | ||||
| } | ||||
| 
 | ||||
| } // ns detail
 | ||||
| 
 | ||||
| template <class DataFacadeT, class SegmentT> | ||||
| RouteNames extractRouteNames(std::vector<SegmentT> &shortest_path_segments, | ||||
|                              std::vector<SegmentT> &alternative_path_segments, | ||||
|                              const DataFacadeT *facade) | ||||
| { | ||||
|     RouteNames route_names; | ||||
| 
 | ||||
|     if (shortest_path_segments.empty()) | ||||
|     { | ||||
|         return route_names; | ||||
|     } | ||||
| 
 | ||||
|     SegmentT shortest_segment_1, shortest_segment_2; | ||||
|     SegmentT alternative_segment_1, alternative_segment_2; | ||||
| 
 | ||||
|     const auto length_comperator = [](const SegmentT &a, const SegmentT &b) | ||||
|     { | ||||
|         return a.length > b.length; | ||||
|     }; | ||||
|     const auto name_id_comperator = [](const SegmentT &a, const SegmentT &b) | ||||
|     { | ||||
|         return a.name_id < b.name_id; | ||||
|     }; | ||||
| 
 | ||||
|     // pick the longest segment for the shortest path.
 | ||||
|     std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator); | ||||
|     shortest_segment_1 = shortest_path_segments[0]; | ||||
| 
 | ||||
|     if (!alternative_path_segments.empty()) | ||||
|     { | ||||
|         std::sort(alternative_path_segments.begin(), alternative_path_segments.end(), | ||||
|                   length_comperator); | ||||
| 
 | ||||
|         // also pick the longest segment for the alternative path
 | ||||
|         alternative_segment_1 = alternative_path_segments[0]; | ||||
|     } | ||||
| 
 | ||||
|     // compute the set difference (for shortest path) depending on names between shortest and
 | ||||
|     // alternative
 | ||||
|     std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size()); | ||||
|     std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator); | ||||
|     std::sort(alternative_path_segments.begin(), alternative_path_segments.end(), | ||||
|               name_id_comperator); | ||||
|     std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(), | ||||
|                         alternative_path_segments.begin(), alternative_path_segments.end(), | ||||
|                         shortest_path_set_difference.begin(), name_id_comperator); | ||||
| 
 | ||||
|     std::sort(shortest_path_set_difference.begin(), shortest_path_set_difference.end(), | ||||
|               length_comperator); | ||||
|     shortest_segment_2 = | ||||
|         pickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id); | ||||
| 
 | ||||
|     // compute the set difference (for alternative path) depending on names between shortest and
 | ||||
|     // alternative
 | ||||
|     // vectors are still sorted, no need to do again
 | ||||
|     BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(), shortest_path_segments.end(), | ||||
|                                 name_id_comperator)); | ||||
|     BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(), alternative_path_segments.end(), | ||||
|                                 name_id_comperator)); | ||||
| 
 | ||||
|     std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size()); | ||||
|     std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(), | ||||
|                         shortest_path_segments.begin(), shortest_path_segments.end(), | ||||
|                         alternative_path_set_difference.begin(), name_id_comperator); | ||||
| 
 | ||||
|     std::sort(alternative_path_set_difference.begin(), alternative_path_set_difference.end(), | ||||
|               length_comperator); | ||||
| 
 | ||||
|     if (!alternative_path_segments.empty()) | ||||
|     { | ||||
|         alternative_segment_2 = | ||||
|             pickNextLongestSegment(alternative_path_set_difference, alternative_segment_1.name_id); | ||||
|     } | ||||
| 
 | ||||
|     // move the segments into the order in which they occur.
 | ||||
|     if (shortest_segment_1.position > shortest_segment_2.position) | ||||
|     { | ||||
|         std::swap(shortest_segment_1, shortest_segment_2); | ||||
|     } | ||||
|     if (alternative_segment_1.position > alternative_segment_2.position) | ||||
|     { | ||||
|         std::swap(alternative_segment_1, alternative_segment_2); | ||||
|     } | ||||
| 
 | ||||
|     // fetching names for the selected segments
 | ||||
|     route_names.shortest_path_name_1 = facade->get_name_for_id(shortest_segment_1.name_id); | ||||
|     route_names.shortest_path_name_2 = facade->get_name_for_id(shortest_segment_2.name_id); | ||||
| 
 | ||||
|     if (!alternative_path_segments.empty()) | ||||
|     { | ||||
|         route_names.alternative_path_name_1 = | ||||
|             facade->get_name_for_id(alternative_segment_1.name_id); | ||||
|         route_names.alternative_path_name_2 = | ||||
|             facade->get_name_for_id(alternative_segment_2.name_id); | ||||
|     } | ||||
| 
 | ||||
|     return route_names; | ||||
| } | ||||
| } | ||||
| } | ||||
| 
 | ||||
| #endif // EXTRACT_ROUTE_NAMES_H
 | ||||
| @ -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() {} | ||||
| 
 | ||||
|     void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector, | ||||
|                     const std::vector<bool> &uturn_indicators, | ||||
|                     InternalRouteResult &raw_route_data) const | ||||
|     { | ||||
|         (void)uturn_indicators; // unused
 | ||||
| 
 | ||||
|         // Get distance to next pair of target nodes.
 | ||||
|         BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(), | ||||
|                          "Direct Shortest Path Query only accepts a single source and target pair. " | ||||
|  | ||||
| @ -24,13 +24,6 @@ namespace osrm | ||||
| namespace engine | ||||
| { | ||||
| 
 | ||||
| SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1; | ||||
| SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1; | ||||
| SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2; | ||||
| SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2; | ||||
| SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3; | ||||
| SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3; | ||||
| 
 | ||||
| namespace routing_algorithms | ||||
| { | ||||
| 
 | ||||
| @ -327,13 +320,13 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | ||||
|                 BOOST_ASSERT(start_index < end_index); | ||||
|                 for (std::size_t i = start_index; i < end_index; ++i) | ||||
|                 { | ||||
|                     unpacked_path.emplace_back(id_vector[i], name_index, | ||||
|                                                extractor::TurnInstruction::NoTurn, weight_vector[i], | ||||
|                                                travel_mode); | ||||
|                     unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i], | ||||
|                                                      extractor::TurnInstruction::NoTurn, | ||||
|                                                      travel_mode}); | ||||
|                 } | ||||
|                 BOOST_ASSERT(unpacked_path.size() > 0); | ||||
|                 unpacked_path.back().turn_instruction = turn_instruction; | ||||
|                 unpacked_path.back().segment_duration += (ed.distance - total_weight); | ||||
|                 unpacked_path.back().duration_until_turn += (ed.distance - total_weight); | ||||
|             } | ||||
|         } | ||||
|         std::vector<unsigned> id_vector; | ||||
| @ -373,7 +366,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | ||||
|             BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0); | ||||
|             unpacked_path.emplace_back( | ||||
|                 PathData{id_vector[i], phantom_node_pair.target_phantom.name_id, | ||||
|                          extractor::TurnInstruction::NoTurn, 0, | ||||
|                          0, extractor::TurnInstruction::NoTurn, | ||||
|                          target_traversed_in_reverse | ||||
|                              ? phantom_node_pair.target_phantom.backward_travel_mode | ||||
|                              : phantom_node_pair.target_phantom.forward_travel_mode}); | ||||
| @ -392,7 +385,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | ||||
|             // looks like a trivially true check but tests for underflow
 | ||||
|             BOOST_ASSERT(last_index > second_to_last_index); | ||||
| 
 | ||||
|             if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node) | ||||
|             if (unpacked_path[last_index].turn_via_node == unpacked_path[second_to_last_index].turn_via_node) | ||||
|             { | ||||
|                 unpacked_path.pop_back(); | ||||
|             } | ||||
| @ -755,7 +748,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | ||||
|         double distance = 0; | ||||
|         for (const auto &p : unpacked_path) | ||||
|         { | ||||
|             current_coordinate = facade->GetCoordinateOfNode(p.node); | ||||
|             current_coordinate = facade->GetCoordinateOfNode(p.turn_via_node); | ||||
|             distance += util::coordinate_calculation::haversineDistance(previous_coordinate, | ||||
|                                                                         current_coordinate); | ||||
|             previous_coordinate = current_coordinate; | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include "util/integer_range.hpp" | ||||
| 
 | ||||
| #include <boost/assert.hpp> | ||||
| #include <boost/optional.hpp> | ||||
| 
 | ||||
| namespace osrm | ||||
| { | ||||
| @ -236,11 +237,13 @@ class ShortestPathRouting final | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static const constexpr bool UTURN_DEFAULT = false; | ||||
| 
 | ||||
|     void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector, | ||||
|                     const std::vector<bool> &uturn_indicators, | ||||
|                     const std::vector<boost::optional<bool>> &uturn_indicators, | ||||
|                     InternalRouteResult &raw_route_data) const | ||||
|     { | ||||
|         BOOST_ASSERT(uturn_indicators.size() == phantom_nodes_vector.size() + 1); | ||||
|         BOOST_ASSERT(uturn_indicators.empty() || uturn_indicators.size() == phantom_nodes_vector.size() + 1); | ||||
|         engine_working_data.InitializeOrClearFirstThreadLocalStorage( | ||||
|             super::facade->GetNumberOfNodes()); | ||||
|         engine_working_data.InitializeOrClearSecondThreadLocalStorage( | ||||
| @ -266,6 +269,8 @@ class ShortestPathRouting final | ||||
|         std::vector<NodeID> total_packed_path_to_reverse; | ||||
|         std::vector<std::size_t> packed_leg_to_reverse_begin; | ||||
| 
 | ||||
|         const bool use_uturn_indicators = !uturn_indicators.empty(); | ||||
| 
 | ||||
|         std::size_t current_leg = 0; | ||||
|         // this implements a dynamic program that finds the shortest route through
 | ||||
|         // a list of vias
 | ||||
| @ -280,8 +285,8 @@ class ShortestPathRouting final | ||||
|             const auto &source_phantom = phantom_node_pair.source_phantom; | ||||
|             const auto &target_phantom = phantom_node_pair.target_phantom; | ||||
| 
 | ||||
|             BOOST_ASSERT(current_leg + 1 < uturn_indicators.size()); | ||||
|             const bool allow_u_turn_at_via = uturn_indicators[current_leg + 1]; | ||||
|             const bool use_uturn_default = !use_uturn_indicators || !uturn_indicators[current_leg + 1]; | ||||
|             const bool allow_u_turn_at_via = (use_uturn_default && UTURN_DEFAULT) || (!use_uturn_default && *uturn_indicators[current_leg + 1]); | ||||
| 
 | ||||
|             bool search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID; | ||||
|             bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID; | ||||
|  | ||||
| @ -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 | ||||
| #define OSRM_HPP | ||||
| 
 | ||||
| #include "osrm/status.hpp" | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace osrm | ||||
| { | ||||
| 
 | ||||
| struct LibOSRMConfig; | ||||
| 
 | ||||
| namespace util | ||||
| { | ||||
| namespace json | ||||
| @ -47,11 +46,14 @@ namespace engine | ||||
| { | ||||
| class Engine; | ||||
| struct EngineConfig; | ||||
| namespace api | ||||
| { | ||||
| struct RouteParameters; | ||||
| } | ||||
| } | ||||
| 
 | ||||
| using engine::EngineConfig; | ||||
| using engine::RouteParameters; | ||||
| using engine::api::RouteParameters; | ||||
| namespace json = util::json; | ||||
| 
 | ||||
| class OSRM | ||||
| @ -61,8 +63,8 @@ class OSRM | ||||
| 
 | ||||
|   public: | ||||
|     OSRM(EngineConfig &lib_config); | ||||
|     ~OSRM(); // needed because we need to define it with the implementation of OSRM_impl
 | ||||
|     int RunQuery(const RouteParameters &route_parameters, json::Object &json_result); | ||||
|     ~OSRM(); // needed for unique_ptr + impl abstraction
 | ||||
|     Status Route(const RouteParameters &route_parameters, json::Object &json_result); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,11 +1,11 @@ | ||||
| #ifndef GLOBAL_ROUTE_PARAMETERS_HPP | ||||
| #define GLOBAL_ROUTE_PARAMETERS_HPP | ||||
| 
 | ||||
| #include "engine/route_parameters.hpp" | ||||
| #include "engine/api/route_parameters.hpp" | ||||
| 
 | ||||
| namespace osrm | ||||
| { | ||||
|     using engine::RouteParameters; | ||||
|     using engine::api::RouteParameters; | ||||
| } | ||||
| 
 | ||||
| #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 | ||||
| #define REQUEST_HANDLER_HPP | ||||
| 
 | ||||
| #include "server/service_handler.hpp" | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace osrm | ||||
| { | ||||
| class OSRM; | ||||
| namespace engine | ||||
| { | ||||
| struct RouteParameters; | ||||
| } | ||||
| namespace server | ||||
| { | ||||
| template <typename Iterator, class HandlerT> struct APIGrammar; | ||||
| 
 | ||||
| namespace http | ||||
| { | ||||
| @ -24,17 +20,16 @@ class RequestHandler | ||||
| { | ||||
| 
 | ||||
|   public: | ||||
|     using APIGrammarParser = APIGrammar<std::string::iterator, engine::RouteParameters>; | ||||
| 
 | ||||
|     RequestHandler(); | ||||
|     RequestHandler(const RequestHandler &) = delete; | ||||
|     RequestHandler &operator=(const RequestHandler &) = delete; | ||||
| 
 | ||||
|     void handle_request(const http::request ¤t_request, http::reply ¤t_reply); | ||||
|     void RegisterRoutingMachine(OSRM *osrm); | ||||
|     void RegisterServiceHandler(std::unique_ptr<ServiceHandler> service_handler); | ||||
| 
 | ||||
|     void HandleRequest(const http::request ¤t_request, http::reply ¤t_reply); | ||||
| 
 | ||||
|   private: | ||||
|     OSRM *routing_machine; | ||||
|     std::unique_ptr<ServiceHandler> service_handler; | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| 
 | ||||
| #include "server/connection.hpp" | ||||
| #include "server/request_handler.hpp" | ||||
| #include "server/service_handler.hpp" | ||||
| 
 | ||||
| #include "util/integer_range.hpp" | ||||
| #include "util/simple_logger.hpp" | ||||
| @ -76,7 +77,10 @@ class Server | ||||
| 
 | ||||
|     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: | ||||
|     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 | ||||
| { | ||||
| 
 | ||||
| constexpr const double COORDINATE_PRECISION = 1000000.0; | ||||
| constexpr const double COORDINATE_PRECISION = 1e6; | ||||
| 
 | ||||
| namespace util | ||||
| { | ||||
| @ -52,6 +52,7 @@ struct FixedPointCoordinate | ||||
|     FixedPointCoordinate(const T &coordinate) | ||||
|         : 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, | ||||
|                       "coordinate types incompatible"); | ||||
|         static_assert(std::is_same<decltype(lon), decltype(coordinate.lon)>::value, | ||||
| @ -59,11 +60,13 @@ struct FixedPointCoordinate | ||||
|     } | ||||
| 
 | ||||
|     bool IsValid() const; | ||||
|     bool operator==(const FixedPointCoordinate &other) const; | ||||
|     friend std::ostream &operator<<(std::ostream &out, const FixedPointCoordinate &coordinate); | ||||
|     friend bool operator==(const FixedPointCoordinate lhs, const FixedPointCoordinate rhs); | ||||
|     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
 | ||||
| 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) | ||||
| { | ||||
|  | ||||
							
								
								
									
										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 "util/coordinate_calculation.hpp" | ||||
| #include "util/coordinate.hpp" | ||||
| 
 | ||||
| #include <boost/assert.hpp> | ||||
| #include "osrm/coordinate.hpp" | ||||
| #include <boost/range/irange.hpp> | ||||
| 
 | ||||
| #include <cmath> | ||||
| #include <algorithm> | ||||
| @ -17,8 +18,12 @@ namespace engine | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
|     CoordinatePairCalculator() = delete; | ||||
|     CoordinatePairCalculator(const util::FixedPointCoordinate coordinate_a, | ||||
|                              const util::FixedPointCoordinate coordinate_b) | ||||
|     { | ||||
| @ -56,44 +61,29 @@ struct CoordinatePairCalculator | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| void douglasPeucker(std::vector<SegmentInformation>::iterator begin, | ||||
|                     std::vector<SegmentInformation>::iterator end, | ||||
| std::vector<util::FixedPointCoordinate> | ||||
| douglasPeucker(std::vector<util::FixedPointCoordinate>::const_iterator begin, | ||||
|                std::vector<util::FixedPointCoordinate>::const_iterator end, | ||||
|                     const unsigned zoom_level) | ||||
| { | ||||
|     using Iter = decltype(begin); | ||||
|     using GeometryRange = std::pair<Iter, Iter>; | ||||
| 
 | ||||
|     std::stack<GeometryRange> recursion_stack; | ||||
|     BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE, | ||||
|             "unsupported zoom level"); | ||||
| 
 | ||||
|     const auto size = std::distance(begin, end); | ||||
|     if (size < 2) | ||||
|     { | ||||
|         return; | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     begin->necessary = true; | ||||
|     std::prev(end)->necessary = true; | ||||
|     std::vector<bool> is_necessary(size, false); | ||||
|     BOOST_ASSERT(is_necessary.size() >= 2); | ||||
|     is_necessary.front() = true; | ||||
|     is_necessary.back() = true; | ||||
|     using GeometryRange = std::pair<std::size_t, std::size_t>; | ||||
| 
 | ||||
|     { | ||||
|         BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE, | ||||
|                          "unsupported zoom level"); | ||||
|         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); | ||||
|     } | ||||
|     std::stack<GeometryRange> recursion_stack; | ||||
| 
 | ||||
|     recursion_stack.emplace(0UL, size-1); | ||||
| 
 | ||||
|     // mark locations as 'necessary' by divide-and-conquer
 | ||||
|     while (!recursion_stack.empty()) | ||||
| @ -102,25 +92,24 @@ void douglasPeucker(std::vector<SegmentInformation>::iterator begin, | ||||
|         const GeometryRange pair = recursion_stack.top(); | ||||
|         recursion_stack.pop(); | ||||
|         // sanity checks
 | ||||
|         BOOST_ASSERT_MSG(pair.first->necessary, "left border must be necessary"); | ||||
|         BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary"); | ||||
|         BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry"); | ||||
|         BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0, | ||||
|                          "left border on the wrong side"); | ||||
|         BOOST_ASSERT_MSG(is_necessary[pair.first], "left border must be necessary"); | ||||
|         BOOST_ASSERT_MSG(is_necessary[pair.second], "right border must be necessary"); | ||||
|         BOOST_ASSERT_MSG(pair.second < size, "right border outside of geometry"); | ||||
|         BOOST_ASSERT_MSG(pair.first <= pair.second, "left border on the wrong side"); | ||||
| 
 | ||||
|         int max_int_distance = 0; | ||||
|         auto farthest_entry_it = pair.second; | ||||
|         const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location); | ||||
|         auto farthest_entry_index = pair.second; | ||||
|         const CoordinatePairCalculator dist_calc(begin[pair.first], begin[pair.second]); | ||||
| 
 | ||||
|         // 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?
 | ||||
|             if (distance > max_int_distance && | ||||
|                 distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level]) | ||||
|             { | ||||
|                 farthest_entry_it = it; | ||||
|                 farthest_entry_index = idx; | ||||
|                 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]) | ||||
|         { | ||||
|             //  mark idx as necessary
 | ||||
|             farthest_entry_it->necessary = true; | ||||
|             if (1 < std::distance(pair.first, farthest_entry_it)) | ||||
|             is_necessary[farthest_entry_index] = true; | ||||
|             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 osrm
 | ||||
|  | ||||
| @ -1,15 +1,16 @@ | ||||
| #include "engine/engine.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/hello_world.hpp" | ||||
| #include "engine/plugins/nearest.hpp" | ||||
| #include "engine/plugins/timestamp.hpp" | ||||
| #include "engine/plugins/trip.hpp" | ||||
| //#include "engine/plugins/distance_table.hpp"
 | ||||
| //#include "engine/plugins/hello_world.hpp"
 | ||||
| //#include "engine/plugins/nearest.hpp"
 | ||||
| //#include "engine/plugins/timestamp.hpp"
 | ||||
| //#include "engine/plugins/trip.hpp"
 | ||||
| #include "engine/plugins/viaroute.hpp" | ||||
| #include "engine/plugins/match.hpp" | ||||
| #include "engine/plugins/tile.hpp" | ||||
| //#include "engine/plugins/match.hpp"
 | ||||
| //#include "engine/plugins/tile.hpp"
 | ||||
| 
 | ||||
| #include "engine/datafacade/datafacade_base.hpp" | ||||
| #include "engine/datafacade/internal_datafacade.hpp" | ||||
| @ -35,120 +36,93 @@ namespace osrm | ||||
| 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) | ||||
| { | ||||
|     if (config.use_shared_memory) | ||||
|     { | ||||
|         barrier = util::make_unique<storage::SharedBarriers>(); | ||||
|         query_data_facade = new datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData>(); | ||||
|         lock = util::make_unique<EngineLock>(); | ||||
|         query_data_facade = util::make_unique<datafacade::SharedDataFacade>(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // populate base path
 | ||||
|         util::populate_base_path(config.server_paths); | ||||
|         query_data_facade = new datafacade::InternalDataFacade<contractor::QueryEdge::EdgeData>( | ||||
|             config.server_paths); | ||||
|         query_data_facade = util::make_unique<datafacade::InternalDataFacade>(config.server_paths); | ||||
|     } | ||||
| 
 | ||||
|     using DataFacade = datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData>; | ||||
| 
 | ||||
|     // 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)); | ||||
|     route_plugin = util::make_unique<plugins::ViaRoutePlugin>(*query_data_facade, config.max_locations_viaroute); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     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); | ||||
|     return RunQuery(lock, *query_data_facade, route_parameters, *route_plugin, result); | ||||
| } | ||||
| 
 | ||||
| // decrease number of concurrent queries
 | ||||
| void Engine::decrease_concurrent_query_count() | ||||
| void Engine::EngineLock::DecreaseQueryCount() | ||||
| { | ||||
|     if (!barrier) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|     // lock query
 | ||||
|     boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock( | ||||
|         barrier->query_mutex); | ||||
|         barrier.query_mutex); | ||||
| 
 | ||||
|     // decrement query count
 | ||||
|     --(barrier->number_of_queries); | ||||
|     BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries"); | ||||
|     --(barrier.number_of_queries); | ||||
|     BOOST_ASSERT_MSG(0 <= barrier.number_of_queries, "invalid number of queries"); | ||||
| 
 | ||||
|     // 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
 | ||||
| void Engine::increase_concurrent_query_count() | ||||
| void Engine::EngineLock::IncreaseQueryCount() | ||||
| { | ||||
|     if (!barrier) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // lock update pending
 | ||||
|     boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock( | ||||
|         barrier->pending_update_mutex); | ||||
|         barrier.pending_update_mutex); | ||||
| 
 | ||||
|     // lock query
 | ||||
|     boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock( | ||||
|         barrier->query_mutex); | ||||
|         barrier.query_mutex); | ||||
| 
 | ||||
|     // unlock update pending
 | ||||
|     pending_lock.unlock(); | ||||
| 
 | ||||
|     // increment query count
 | ||||
|     ++(barrier->number_of_queries); | ||||
| 
 | ||||
|     (static_cast<datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData> *>( | ||||
|          query_data_facade))->CheckAndReloadFacade(); | ||||
|     ++(barrier.number_of_queries); | ||||
| } | ||||
| } | ||||
| } | ||||
|  | ||||
							
								
								
									
										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 <boost/assert.hpp> | ||||
| #include <cstddef> | ||||
| #include <cstdlib> | ||||
| #include <cmath> | ||||
| #include <algorithm> | ||||
| 
 | ||||
| namespace osrm | ||||
| { | ||||
| @ -55,31 +57,30 @@ std::string encode(std::vector<int> &numbers) | ||||
| } | ||||
| } // 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 {}; | ||||
|     } | ||||
| 
 | ||||
|     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}; | ||||
|     for (const auto &segment : polyline) | ||||
|     std::for_each(begin, end, [&delta_numbers, &previous_coordinate](const FixedPointCoordinate loc) | ||||
|     { | ||||
|         if (segment.necessary) | ||||
|         { | ||||
|             const int lat_diff = segment.location.lat - previous_coordinate.lat; | ||||
|             const int lon_diff = segment.location.lon - previous_coordinate.lon; | ||||
|             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; | ||||
|             delta_numbers.emplace_back(lat_diff); | ||||
|             delta_numbers.emplace_back(lon_diff); | ||||
|             previous_coordinate = segment.location; | ||||
|         } | ||||
|     } | ||||
|             previous_coordinate = loc; | ||||
|     }); | ||||
|     return encode(delta_numbers); | ||||
| } | ||||
| 
 | ||||
| std::vector<util::FixedPointCoordinate> polylineDecode(const std::string &geometry_string) | ||||
| std::vector<util::FixedPointCoordinate> decodePolyline(const std::string &geometry_string) | ||||
| { | ||||
|     std::vector<util::FixedPointCoordinate> new_coordinates; | ||||
|     int index = 0, len = geometry_string.size(); | ||||
| @ -109,8 +110,8 @@ std::vector<util::FixedPointCoordinate> polylineDecode(const std::string &geomet | ||||
|         lng += dlng; | ||||
| 
 | ||||
|         util::FixedPointCoordinate p; | ||||
|         p.lat = COORDINATE_PRECISION * (((double)lat / 1E6)); | ||||
|         p.lon = COORDINATE_PRECISION * (((double)lng / 1E6)); | ||||
|         p.lat = lat * detail::POLYLINE_TO_COORDINATE; | ||||
|         p.lon = lng * detail::POLYLINE_TO_COORDINATE; | ||||
|         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 | ||||
| { | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     if (forward_heap_1.get()) | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| #include "osrm/osrm.hpp" | ||||
| #include "engine/engine.hpp" | ||||
| #include "engine/status.hpp" | ||||
| #include "engine/engine_config.hpp" | ||||
| #include "engine/plugins/plugin_base.hpp" | ||||
| #include "engine/plugins/viaroute.hpp" | ||||
| #include "storage/shared_barriers.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
 | ||||
| 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) | ||||
|     { | ||||
|         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
 | ||||
|         switch (compression_type) | ||||
|  | ||||
| @ -10,9 +10,9 @@ namespace http | ||||
| { | ||||
| 
 | ||||
| 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[] = | ||||
|     "{\"status\": 500,\"status_message\":\"Internal Server Error\"}"; | ||||
|     "{\"code\": \"internal-error\",\"message\":\"Internal Server Error\"}"; | ||||
| const char seperators[] = {':', ' '}; | ||||
| const char crlf[] = {'\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/service_handler.hpp" | ||||
| 
 | ||||
| #include "server/api_grammar.hpp" | ||||
| #include "server/api/url_parser.hpp" | ||||
| #include "server/http/reply.hpp" | ||||
| #include "server/http/request.hpp" | ||||
| 
 | ||||
| @ -9,7 +10,7 @@ | ||||
| #include "util/string_util.hpp" | ||||
| #include "util/typedefs.hpp" | ||||
| 
 | ||||
| #include "engine/route_parameters.hpp" | ||||
| #include "engine/status.hpp" | ||||
| #include "util/json_container.hpp" | ||||
| #include "osrm/osrm.hpp" | ||||
| 
 | ||||
| @ -28,11 +29,22 @@ namespace osrm | ||||
| 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) | ||||
| { | ||||
|     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; | ||||
| 
 | ||||
|     // parse command
 | ||||
| @ -67,84 +79,49 @@ void RequestHandler::handle_request(const http::request ¤t_request, | ||||
|             << current_request.agent << (0 == current_request.agent.length() ? "- " : " ") | ||||
|             << request_string; | ||||
| 
 | ||||
|         engine::RouteParameters route_parameters; | ||||
|         APIGrammarParser api_parser(&route_parameters); | ||||
| 
 | ||||
|         auto api_iterator = request_string.begin(); | ||||
|         const bool result = | ||||
|             boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser); | ||||
|         auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end());; | ||||
| 
 | ||||
|         // 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
 | ||||
|             BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed"); | ||||
| 
 | ||||
|             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) | ||||
|             const engine::Status status = service_handler->RunQuery(std::move(*maybe_parsed_url), json_result); | ||||
|             if (status != engine::Status::Ok) | ||||
|             { | ||||
|                 // 4xx bad request return code
 | ||||
|                 current_reply.status = http::reply::bad_request; | ||||
|                 current_reply.content.clear(); | ||||
|                 route_parameters.output_format.clear(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // 2xx valid request
 | ||||
|                 BOOST_ASSERT(return_code / 100 == 2); | ||||
|                 BOOST_ASSERT(status == engine::Status::Ok); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             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; | ||||
|             json_result.values["status"] = http::reply::bad_request; | ||||
|             json_result.values["status_message"] = | ||||
|                 "Query string malformed close to position " + std::to_string(position); | ||||
|             json_result.values["code"] = "invalid-url"; | ||||
|             json_result.values["message"] = | ||||
|                 "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-Methods", "GET"); | ||||
|         current_reply.headers.emplace_back("Access-Control-Allow-Headers", | ||||
|                                            "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()) | ||||
|         { | ||||
|             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)); | ||||
|         util::json::render(current_reply.content, json_result); | ||||
| 
 | ||||
|             current_reply.headers.emplace_back("Content-Type", "application/x-protobuf"); | ||||
|         } | ||||
|         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\""); | ||||
|         } | ||||
|         // set headers
 | ||||
|         current_reply.headers.emplace_back("Content-Length", | ||||
|                                            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) | ||||
|     { | ||||
| @ -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 = | ||||
|     typename engine::datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData>::RTreeLeaf; | ||||
|     typename engine::datafacade::BaseDataFacade::RTreeLeaf; | ||||
| using RTreeNode = util::StaticRTree<RTreeLeaf, | ||||
|                                     util::ShM<util::FixedPointCoordinate, true>::vector, | ||||
|                                     true>::TreeNode; | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "server/server.hpp" | ||||
| #include "util/routed_options.hpp" | ||||
| #include "util/make_unique.hpp" | ||||
| #include "util/simple_logger.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); | ||||
| #endif | ||||
| 
 | ||||
|     OSRM osrm_lib(config); | ||||
|     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) | ||||
|     { | ||||
|  | ||||
| @ -45,12 +45,17 @@ bool FixedPointCoordinate::IsValid() const | ||||
|              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) << "," | ||||
|         << static_cast<double>(coordinate.lon / COORDINATE_PRECISION) << ")"; | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| #include "engine/douglas_peucker.hpp" | ||||
| #include "engine/segment_information.hpp" | ||||
| 
 | ||||
| #include <boost/test/unit_test.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::engine; | ||||
| 
 | ||||
| SegmentInformation getTestInfo(int lat, int lon, bool necessary) | ||||
| { | ||||
|     return SegmentInformation(util::FixedPointCoordinate(lat, lon), 0, 0, 0, | ||||
|                               extractor::TurnInstruction::HeadOn, necessary, false, 0); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(all_necessary_test) | ||||
| BOOST_AUTO_TEST_CASE(removed_middle_test) | ||||
| { | ||||
|     /*
 | ||||
|             x | ||||
| @ -27,19 +20,23 @@ BOOST_AUTO_TEST_CASE(all_necessary_test) | ||||
|           x   \ | ||||
|          /     \ | ||||
|         x       x | ||||
|        / | ||||
|     */ | ||||
|     std::vector<SegmentInformation> info = {getTestInfo(5, 5, true), | ||||
|                                             getTestInfo(6, 6, true), | ||||
|                                             getTestInfo(10, 10, true), | ||||
|                                             getTestInfo(5, 15, true)}; | ||||
|     for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++) | ||||
|     std::vector<util::FixedPointCoordinate> coordinates = { | ||||
|         util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION), | ||||
|         util::FixedPointCoordinate(6 * COORDINATE_PRECISION, 6 * COORDINATE_PRECISION), | ||||
|         util::FixedPointCoordinate(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION), | ||||
|         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); | ||||
|         for (const auto &i : info) | ||||
|         { | ||||
|             BOOST_CHECK_EQUAL(i.necessary, true); | ||||
|         } | ||||
|         auto result = douglasPeucker(coordinates, z); | ||||
|         BOOST_CHECK_EQUAL(result.size(), 3); | ||||
|         BOOST_CHECK_EQUAL(result[0], coordinates[0]); | ||||
|         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 | ||||
|         */ | ||||
|         std::vector<SegmentInformation> info = { | ||||
|             getTestInfo(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION, true), | ||||
|             getTestInfo(5 * COORDINATE_PRECISION, | ||||
|                         5 * COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z], false), | ||||
|             getTestInfo(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION, false), | ||||
|             getTestInfo(10 * COORDINATE_PRECISION, | ||||
|                         10 + COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2, | ||||
|                         false), | ||||
|             getTestInfo(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION, false), | ||||
|             getTestInfo(5 * COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z], | ||||
|                         15 * COORDINATE_PRECISION, true), | ||||
|         std::vector<util::FixedPointCoordinate> input = { | ||||
|             util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION), | ||||
|             util::FixedPointCoordinate(5 * COORDINATE_PRECISION, | ||||
|                                        5 * COORDINATE_PRECISION + | ||||
|                                            detail::DOUGLAS_PEUCKER_THRESHOLDS[z]), | ||||
|             util::FixedPointCoordinate(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION), | ||||
|             util::FixedPointCoordinate(10 * COORDINATE_PRECISION, | ||||
|                                        10 + COORDINATE_PRECISION + | ||||
|                                            detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2), | ||||
|             util::FixedPointCoordinate(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION), | ||||
|             util::FixedPointCoordinate(5 * COORDINATE_PRECISION + | ||||
|                                            detail::DOUGLAS_PEUCKER_THRESHOLDS[z], | ||||
|                                        15 * COORDINATE_PRECISION), | ||||
|         }; | ||||
|         BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]); | ||||
|         douglasPeucker(info, z); | ||||
|         BOOST_CHECK_EQUAL(info[0].necessary, true); | ||||
|         BOOST_CHECK_EQUAL(info[1].necessary, false); | ||||
|         BOOST_CHECK_EQUAL(info[2].necessary, true); | ||||
|         BOOST_CHECK_EQUAL(info[3].necessary, true); | ||||
|         BOOST_CHECK_EQUAL(info[4].necessary, false); | ||||
|         BOOST_CHECK_EQUAL(info[5].necessary, true); | ||||
|         auto result = douglasPeucker(input, z); | ||||
|         BOOST_CHECK_EQUAL(result.size(), 4); | ||||
|         BOOST_CHECK_EQUAL(input[0], result[0]); | ||||
|         BOOST_CHECK_EQUAL(input[2], result[1]); | ||||
|         BOOST_CHECK_EQUAL(input[3], result[2]); | ||||
|         BOOST_CHECK_EQUAL(input[5], result[3]); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -18,7 +18,7 @@ BOOST_AUTO_TEST_CASE(decode) | ||||
| { | ||||
|     // Polyline string for the 5 coordinates
 | ||||
|     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,
 | ||||
|     // 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