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())
|
||||
|
||||
Reference in New Issue
Block a user