Add viaroute suport for new API
This commit is contained in:
@@ -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
|
||||
|
||||
+56
-82
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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())
|
||||
|
||||
+4
-3
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) << ")";
|
||||
|
||||
Reference in New Issue
Block a user