Add viaroute suport for new API

This commit is contained in:
Patrick Niklaus
2016-01-28 16:28:44 +01:00
parent 54ee76bcef
commit f3e72623e9
87 changed files with 3352 additions and 2099 deletions
+222
View File
@@ -0,0 +1,222 @@
#include "engine/api/json_factory.hpp"
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/route_leg.hpp"
#include "engine/guidance/route.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/polyline_compressor.hpp"
#include "engine/hint.hpp"
#include <boost/assert.hpp>
#include <boost/range/irange.hpp>
#include <string>
#include <utility>
#include <algorithm>
#include <vector>
namespace osrm
{
namespace engine
{
namespace api
{
namespace json
{
namespace detail
{
std::string instructionToString(extractor::TurnInstruction instruction)
{
std::string token;
// FIXME this could be an array.
switch (instruction)
{
case extractor::TurnInstruction::GoStraight:
token = "continue";
break;
case extractor::TurnInstruction::TurnSlightRight:
token = "bear right";
break;
case extractor::TurnInstruction::TurnRight:
token = "right";
break;
case extractor::TurnInstruction::TurnSharpRight:
token = "sharp right";
break;
case extractor::TurnInstruction::UTurn:
token = "uturn";
break;
case extractor::TurnInstruction::TurnSharpLeft:
token = "sharp left";
break;
case extractor::TurnInstruction::TurnLeft:
token = "left";
break;
case extractor::TurnInstruction::TurnSlightLeft:
token = "bear left";
break;
case extractor::TurnInstruction::HeadOn:
token = "head on";
break;
case extractor::TurnInstruction::EnterRoundAbout:
token = "enter roundabout";
break;
case extractor::TurnInstruction::LeaveRoundAbout:
token = "leave roundabout";
break;
case extractor::TurnInstruction::StayOnRoundAbout:
token = "stay on roundabout";
break;
case extractor::TurnInstruction::StartAtEndOfStreet:
token = "depart";
break;
case extractor::TurnInstruction::ReachedYourDestination:
token = "arrive";
break;
case extractor::TurnInstruction::NameChanges:
token = "name changed";
break;
case extractor::TurnInstruction::NoTurn:
case extractor::TurnInstruction::ReachViaLocation:
case extractor::TurnInstruction::EnterAgainstAllowedDirection:
case extractor::TurnInstruction::LeaveAgainstAllowedDirection:
case extractor::TurnInstruction::InverseAccessRestrictionFlag:
case extractor::TurnInstruction::AccessRestrictionFlag:
case extractor::TurnInstruction::AccessRestrictionPenalty:
BOOST_ASSERT_MSG(false, "Invalid turn type used");
break;
}
return token;
}
util::json::Array coordinateToLonLat(const FixedPointCoordinate &coordinate)
{
util::json::Array array;
array.values.push_back(coordinate.lon / COORDINATE_PRECISION);
array.values.push_back(coordinate.lat / COORDINATE_PRECISION);
return array;
}
util::json::Array coordinateToLatLon(const FixedPointCoordinate &coordinate)
{
util::json::Array array;
array.values.push_back(coordinate.lat / COORDINATE_PRECISION);
array.values.push_back(coordinate.lon / COORDINATE_PRECISION);
return array;
}
// FIXME this actually needs to be configurable from the profiles
std::string modeToString(const extractor::TravelMode mode)
{
std::string token;
switch (mode)
{
case TRAVEL_MODE_DEFAULT:
token = "default";
break;
case TRAVEL_MODE_INACCESSIBLE:
token = "inaccessible";
break;
default:
token = "other";
break;
}
return token;
}
} // namespace detail
util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
{
util::json::Object step_maneuver;
step_maneuver.values["type"] = detail::instructionToString(maneuver.instruction);
step_maneuver.values["location"] = detail::coordinateToLatLon(maneuver.location);
step_maneuver.values["heading_before"] = maneuver.heading_before;
step_maneuver.values["heading_after"] = maneuver.heading_after;
return step_maneuver;
}
util::json::Object makeRouteStep(guidance::RouteStep &&step,
boost::optional<util::json::Value> geometry)
{
util::json::Object route_step;
route_step.values["distance"] = step.distance;
route_step.values["duration"] = step.duration;
route_step.values["way_name"] = std::move(step.way_name);
route_step.values["mode"] = detail::modeToString(step.mode);
route_step.values["maneuver"] = makeStepManeuver(step.maneuver);
if (geometry)
{
route_step.values["geometry"] = std::move(*geometry);
}
return route_step;
}
util::json::Object makeRoute(const guidance::Route &route,
util::json::Array &&legs,
boost::optional<util::json::Value> geometry)
{
util::json::Object json_route;
json_route.values["distance"] = route.distance;
json_route.values["duration"] = route.duration;
json_route.values["legs"] = std::move(legs);
if (geometry)
{
json_route.values["geometry"] = std::move(*geometry);
}
return json_route;
}
util::json::Object
makeWaypoint(const FixedPointCoordinate location, std::string &&way_name, const Hint &hint)
{
util::json::Object waypoint;
waypoint.values["location"] = detail::coordinateToLatLon(location);
waypoint.values["way_name"] = std::move(way_name);
waypoint.values["hint"] = hint.ToBase64();
return waypoint;
}
util::json::Object makeRouteLeg(guidance::RouteLeg &&leg, util::json::Array &&steps)
{
util::json::Object route_leg;
route_leg.values["distance"] = leg.distance;
route_leg.values["duration"] = leg.duration;
route_leg.values["summary"] = std::move(leg.summary);
route_leg.values["steps"] = std::move(steps);
return route_leg;
}
util::json::Array makeRouteLegs(std::vector<guidance::RouteLeg> &&legs,
const std::vector<guidance::LegGeometry> &leg_geometries)
{
util::json::Array json_legs;
for (const auto idx : boost::irange(0UL, legs.size()))
{
auto &&leg = std::move(legs[idx]);
const auto &leg_geometry = leg_geometries[idx];
util::json::Array json_steps;
json_steps.values.reserve(leg.steps.size());
const auto begin_iter = leg_geometry.locations.begin();
std::transform(
std::make_move_iterator(leg.steps.begin()), std::make_move_iterator(leg.steps.end()),
std::back_inserter(json_steps.values), [&begin_iter](guidance::RouteStep &&step)
{
// FIXME we only support polyline here
auto geometry = boost::make_optional<util::json::Value>(
makePolyline(begin_iter + step.geometry_begin, begin_iter + step.geometry_end));
return makeRouteStep(std::move(step), std::move(geometry));
});
json_legs.values.push_back(makeRouteLeg(std::move(leg), std::move(json_steps)));
}
return json_legs;
}
}
}
} // namespace engine
} // namespace osrm
+46 -45
View File
@@ -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
View File
@@ -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 &parameters,
PluginT &plugin,
util::json::Object &json_result)
{
if (!lock)
{
return plugin.HandleRequest(parameters, json_result);
}
BOOST_ASSERT(lock);
lock->IncreaseQueryCount();
auto& shared_facade = static_cast<datafacade::SharedDataFacade &>(facade);
shared_facade.CheckAndReloadFacade();
// Get a shared data lock so that other threads won't update
// things while the query is running
boost::shared_lock<boost::shared_mutex> data_lock{shared_facade.data_mutex};
Status status = plugin.HandleRequest(parameters, json_result);
lock->DecreaseQueryCount();
return status;
}
Engine::Engine(EngineConfig &config)
{
if (config.use_shared_memory)
{
barrier = util::make_unique<storage::SharedBarriers>();
query_data_facade = new datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData>();
lock = util::make_unique<EngineLock>();
query_data_facade = util::make_unique<datafacade::SharedDataFacade>();
}
else
{
// populate base path
util::populate_base_path(config.server_paths);
query_data_facade = new datafacade::InternalDataFacade<contractor::QueryEdge::EdgeData>(
config.server_paths);
query_data_facade = util::make_unique<datafacade::InternalDataFacade>(config.server_paths);
}
using DataFacade = datafacade::BaseDataFacade<contractor::QueryEdge::EdgeData>;
// The following plugins handle all requests.
RegisterPlugin(new plugins::DistanceTablePlugin<DataFacade>(
query_data_facade, config.max_locations_distance_table));
RegisterPlugin(new plugins::HelloWorldPlugin());
RegisterPlugin(new plugins::NearestPlugin<DataFacade>(query_data_facade));
RegisterPlugin(new plugins::MapMatchingPlugin<DataFacade>(query_data_facade,
config.max_locations_map_matching));
RegisterPlugin(new plugins::TimestampPlugin<DataFacade>(query_data_facade));
RegisterPlugin(
new plugins::ViaRoutePlugin<DataFacade>(query_data_facade, config.max_locations_viaroute));
RegisterPlugin(
new plugins::RoundTripPlugin<DataFacade>(query_data_facade, config.max_locations_trip));
RegisterPlugin(new plugins::TilePlugin<DataFacade>(query_data_facade));
route_plugin = util::make_unique<plugins::ViaRoutePlugin>(*query_data_facade, config.max_locations_viaroute);
}
void Engine::RegisterPlugin(plugins::BasePlugin *raw_plugin_ptr)
Status Engine::Route(const api::RouteParameters &route_parameters,
util::json::Object &result)
{
std::unique_ptr<plugins::BasePlugin> plugin_ptr(raw_plugin_ptr);
util::SimpleLogger().Write() << "loaded plugin: " << plugin_ptr->GetDescriptor();
plugin_map[plugin_ptr->GetDescriptor()] = std::move(plugin_ptr);
}
int Engine::RunQuery(const RouteParameters &route_parameters, util::json::Object &json_result)
{
const auto &plugin_iterator = plugin_map.find(route_parameters.service);
if (plugin_map.end() == plugin_iterator)
{
json_result.values["status_message"] = "Service not found";
return 400;
}
osrm::engine::plugins::BasePlugin::Status return_code;
increase_concurrent_query_count();
if (barrier)
{
// Get a shared data lock so that other threads won't update
// things while the query is running
boost::shared_lock<boost::shared_mutex> data_lock{
(static_cast<datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData> *>(
query_data_facade))->data_mutex};
return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
}
else
{
return_code = plugin_iterator->second->HandleRequest(route_parameters, json_result);
}
decrease_concurrent_query_count();
return static_cast<int>(return_code);
return RunQuery(lock, *query_data_facade, route_parameters, *route_plugin, result);
}
// decrease number of concurrent queries
void Engine::decrease_concurrent_query_count()
void Engine::EngineLock::DecreaseQueryCount()
{
if (!barrier)
{
return;
}
// lock query
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
barrier->query_mutex);
barrier.query_mutex);
// decrement query count
--(barrier->number_of_queries);
BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
--(barrier.number_of_queries);
BOOST_ASSERT_MSG(0 <= barrier.number_of_queries, "invalid number of queries");
// notify all processes that were waiting for this condition
if (0 == barrier->number_of_queries)
if (0 == barrier.number_of_queries)
{
barrier->no_running_queries_condition.notify_all();
barrier.no_running_queries_condition.notify_all();
}
}
// increase number of concurrent queries
void Engine::increase_concurrent_query_count()
void Engine::EngineLock::IncreaseQueryCount()
{
if (!barrier)
{
return;
}
// lock update pending
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
barrier->pending_update_mutex);
barrier.pending_update_mutex);
// lock query
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
barrier->query_mutex);
barrier.query_mutex);
// unlock update pending
pending_lock.unlock();
// increment query count
++(barrier->number_of_queries);
(static_cast<datafacade::SharedDataFacade<contractor::QueryEdge::EdgeData> *>(
query_data_facade))->CheckAndReloadFacade();
++(barrier.number_of_queries);
}
}
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
#define ENGINE_GUIDANCE_ASSEMBLE_OVERVIEW_HPP
#include "engine/guidance/leg_geometry.hpp"
#include "engine/douglas_peucker.hpp"
#include "util/tiles.hpp"
#include <vector>
#include <tuple>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace
{
unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometries)
{
int min_lon = std::numeric_limits<int>::max();
int min_lat = std::numeric_limits<int>::max();
int max_lon = -std::numeric_limits<int>::max();
int max_lat = -std::numeric_limits<int>::max();
for (const auto &leg_geometry : leg_geometries)
{
for (const auto coord : leg_geometry.locations)
{
min_lon = std::min(min_lon, coord.lon);
max_lon = std::max(max_lon, coord.lon);
min_lat = std::min(min_lat, coord.lat);
max_lat = std::max(max_lat, coord.lat);
}
}
return util::tiles::getBBMaxZoomTile(min_lon, min_lat, max_lon, max_lat).z;
}
std::vector<util::FixedPointCoordinate> simplifyGeometry(const std::vector<LegGeometry> &leg_geometries, const unsigned zoom_level)
{
std::vector<util::FixedPointCoordinate> overview_geometry;
auto leg_index = 0UL;
for (const auto geometry : leg_geometries)
{
auto simplified_geometry =
douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
// not the last leg
if (leg_index < leg_geometries.size() - 1)
{
simplified_geometry.pop_back();
}
overview_geometry.insert(overview_geometry.end(), simplified_geometry.begin(),
simplified_geometry.end());
}
return overview_geometry;
}
}
std::vector<util::FixedPointCoordinate>
assembleOverview(const std::vector<LegGeometry> &leg_geometries, const bool use_simplification)
{
if (use_simplification)
{
const auto zoom_level = calculateOverviewZoomLevel(leg_geometries);
return simplifyGeometry(leg_geometries, zoom_level);
}
BOOST_ASSERT(!use_simplification);
auto overview_size = std::accumulate(leg_geometries.begin(), leg_geometries.end(), 0,
[](const std::size_t sum, const LegGeometry &leg_geometry)
{
return sum + leg_geometry.locations.size();
}) -
leg_geometries.size() + 1;
std::vector<util::FixedPointCoordinate> overview_geometry;
overview_geometry.reserve(overview_size);
auto leg_index = 0UL;
for (const auto geometry : leg_geometries)
{
auto begin = geometry.locations.begin();
auto end = geometry.locations.end();
if (leg_index < leg_geometries.size() - 1)
{
end = std::prev(end);
}
overview_geometry.insert(overview_geometry.end(), begin, end);
}
return overview_geometry;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif
+115
View File
@@ -0,0 +1,115 @@
#include "engine/plugins/viaroute.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/api/route_api.hpp"
#include "engine/object_encoder.hpp"
#include "engine/status.hpp"
#include "util/for_each_pair.hpp"
#include "util/integer_range.hpp"
#include "util/json_container.hpp"
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
namespace osrm
{
namespace engine
{
namespace plugins
{
ViaRoutePlugin::ViaRoutePlugin(datafacade::BaseDataFacade &facade_, int max_locations_viaroute)
: BasePlugin(facade_), shortest_path(&facade_, heaps), alternative_path(&facade_, heaps),
direct_shortest_path(&facade_, heaps), max_locations_viaroute(max_locations_viaroute)
{
}
Status ViaRoutePlugin::HandleRequest(const api::RouteParameters &route_parameters,
util::json::Object &json_result)
{
if (max_locations_viaroute > 0 &&
(static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
{
return Error("too-big",
"Number of entries " + std::to_string(route_parameters.coordinates.size()) +
" is higher than current maximum (" +
std::to_string(max_locations_viaroute) + ")",
json_result);
}
if (!CheckAllCoordinates(route_parameters.coordinates))
{
return Error("invalid-value", "Invalid coordinate value.", json_result);
}
auto phantom_node_pairs = GetPhantomNodes(route_parameters);
if (phantom_node_pairs.size() != route_parameters.coordinates.size())
{
return Error("no-segment",
std::string("Could not find a matching segment for coordinate ") +
std::to_string(phantom_node_pairs.size()),
json_result);
}
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
InternalRouteResult raw_route;
auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
const PhantomNode &second_node)
{
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
};
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
if (1 == raw_route.segment_end_coordinates.size())
{
if (route_parameters.alternative && facade.GetCoreSize() == 0)
{
alternative_path(raw_route.segment_end_coordinates.front(), raw_route);
}
else
{
direct_shortest_path(raw_route.segment_end_coordinates, raw_route);
}
}
else
{
shortest_path(raw_route.segment_end_coordinates, route_parameters.uturns, raw_route);
}
// we can only know this after the fact, different SCC ids still
// allow for connection in one direction.
if (raw_route.is_valid())
{
api::RouteAPI route_api{BasePlugin::facade, route_parameters};
route_api.MakeResponse(raw_route, json_result);
}
else
{
auto first_component_id = snapped_phantoms.front().component.id;
auto not_in_same_component = std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
[first_component_id](const PhantomNode &node)
{
return node.component.id != first_component_id;
});
if (not_in_same_component)
{
return Error("no-route", "Impossible route between points", json_result);
}
else
{
return Error("no-route", "No route found between points", json_result);
}
}
return Status::Ok;
}
}
}
}
+16 -15
View File
@@ -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);
}
-31
View File
@@ -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;
}
}
}
-170
View File
@@ -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 &parameter)
{
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
View File
@@ -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())