osrm-backend/include/engine/api/route_api.hpp

261 lines
12 KiB
C++
Raw Normal View History

2016-01-28 10:28:44 -05:00
#ifndef ENGINE_API_ROUTE_HPP
#define ENGINE_API_ROUTE_HPP
#include "engine/api/base_api.hpp"
#include "engine/api/json_factory.hpp"
2016-04-06 03:47:17 -04:00
#include "engine/api/route_parameters.hpp"
2016-01-28 10:28:44 -05:00
#include "engine/datafacade/datafacade_base.hpp"
#include "engine/guidance/assemble_geometry.hpp"
2016-04-06 03:47:17 -04:00
#include "engine/guidance/assemble_leg.hpp"
2016-01-28 10:28:44 -05:00
#include "engine/guidance/assemble_overview.hpp"
2016-04-06 03:47:17 -04:00
#include "engine/guidance/assemble_route.hpp"
2016-01-28 10:28:44 -05:00
#include "engine/guidance/assemble_steps.hpp"
2016-06-15 08:38:24 -04:00
#include "engine/guidance/lane_processing.hpp"
2016-02-24 04:29:23 -05:00
#include "engine/guidance/post_processing.hpp"
2016-01-28 10:28:44 -05:00
#include "engine/internal_route_result.hpp"
2016-02-25 04:01:16 -05:00
#include "util/coordinate.hpp"
2016-01-28 10:28:44 -05:00
#include "util/integer_range.hpp"
2016-04-12 09:00:08 -04:00
#include <iterator>
2016-02-25 04:01:16 -05:00
#include <vector>
2016-01-28 10:28:44 -05:00
namespace osrm
{
namespace engine
{
namespace api
{
class RouteAPI : public BaseAPI
2016-01-28 10:28:44 -05:00
{
public:
RouteAPI(const datafacade::BaseDataFacade &facade_, const RouteParameters &parameters_)
: BaseAPI(facade_, parameters_), parameters(parameters_)
2016-01-28 10:28:44 -05:00
{
}
void MakeResponse(const InternalRouteResult &raw_route, util::json::Object &response) const
2016-01-28 10:28:44 -05:00
{
auto number_of_routes = raw_route.has_alternative() ? 2UL : 1UL;
util::json::Array routes;
routes.values.resize(number_of_routes);
2016-05-27 15:05:04 -04:00
routes.values[0] = MakeRoute(raw_route.segment_end_coordinates,
raw_route.unpacked_path_segments,
raw_route.source_traversed_in_reverse,
raw_route.target_traversed_in_reverse);
2016-01-28 10:28:44 -05:00
if (raw_route.has_alternative())
{
std::vector<std::vector<PathData>> wrapped_leg(1);
wrapped_leg.front() = std::move(raw_route.unpacked_alternative);
2016-05-27 15:05:04 -04:00
routes.values[1] = MakeRoute(raw_route.segment_end_coordinates,
wrapped_leg,
2016-01-28 10:28:44 -05:00
raw_route.alt_source_traversed_in_reverse,
raw_route.alt_target_traversed_in_reverse);
2016-01-28 10:28:44 -05:00
}
response.values["waypoints"] = BaseAPI::MakeWaypoints(raw_route.segment_end_coordinates);
2016-01-28 10:28:44 -05:00
response.values["routes"] = std::move(routes);
2016-04-04 08:05:38 -04:00
response.values["code"] = "Ok";
2016-01-28 10:28:44 -05:00
}
// FIXME gcc 4.8 doesn't support for lambdas to call protected member functions
// protected:
2016-01-28 10:28:44 -05:00
template <typename ForwardIter>
util::json::Value MakeGeometry(ForwardIter begin, ForwardIter end) const
{
if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
{
return json::makePolyline(begin, end);
}
BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
return json::makeGeoJSONGeometry(begin, end);
2016-01-28 10:28:44 -05:00
}
util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates,
const std::vector<std::vector<PathData>> &unpacked_path_segments,
const std::vector<bool> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const
2016-01-28 10:28:44 -05:00
{
std::vector<guidance::RouteLeg> legs;
std::vector<guidance::LegGeometry> leg_geometries;
auto number_of_legs = segment_end_coordinates.size();
legs.reserve(number_of_legs);
leg_geometries.reserve(number_of_legs);
2016-02-24 04:29:23 -05:00
for (auto idx : util::irange<std::size_t>(0UL, number_of_legs))
2016-01-28 10:28:44 -05:00
{
const auto &phantoms = segment_end_coordinates[idx];
const auto &path_data = unpacked_path_segments[idx];
2016-02-24 04:29:23 -05:00
2016-01-28 10:28:44 -05:00
const bool reversed_source = source_traversed_in_reverse[idx];
const bool reversed_target = target_traversed_in_reverse[idx];
auto leg_geometry = guidance::assembleGeometry(BaseAPI::facade,
path_data,
phantoms.source_phantom,
phantoms.target_phantom,
reversed_source,
reversed_target);
2016-05-27 15:05:04 -04:00
auto leg = guidance::assembleLeg(facade,
path_data,
leg_geometry,
phantoms.source_phantom,
phantoms.target_phantom,
reversed_target,
parameters.steps);
2016-01-28 10:28:44 -05:00
if (parameters.steps)
{
2016-05-27 15:05:04 -04:00
auto steps = guidance::assembleSteps(BaseAPI::facade,
path_data,
leg_geometry,
phantoms.source_phantom,
phantoms.target_phantom,
reversed_source,
reversed_target);
/* Perform step-based post-processing.
*
* Using post-processing on basis of route-steps for a single leg at a time
* comes at the cost that we cannot count the correct exit for roundabouts.
* We can only emit the exit nr/intersections up to/starting at a part of the leg.
2016-03-29 07:45:48 -04:00
* If a roundabout is not terminated in a leg, we will end up with a
*enter-roundabout
* and exit-roundabout-nr where the exit nr is out of sync with the previous enter.
*
* | S |
* * *
* ----* * ----
* T
* ----* * ----
* V * *
* | |
* | |
*
2016-03-29 07:45:48 -04:00
* Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say to
*take
* the second exit, even though counting from S it would be the third.
2016-03-29 07:45:48 -04:00
* For S, we only emit `roundabout` without an exit number, showing that we enter a
*roundabout
* to find a via point.
* The same exit will be emitted, though, if we should start routing at S, making
* the overall response consistent.
*/
guidance::trimShortSegments(steps, leg_geometry);
2016-03-29 07:45:48 -04:00
leg.steps = guidance::postProcess(std::move(steps));
leg.steps = guidance::collapseTurns(std::move(leg.steps));
2016-05-30 11:42:28 -04:00
leg.steps = guidance::buildIntersections(std::move(leg.steps));
2016-05-27 15:05:04 -04:00
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps),
leg_geometry,
2016-03-29 07:45:48 -04:00
phantoms.source_phantom,
phantoms.target_phantom);
Remove lanes from roundabouts, closes #2626 After half a day of looking at the tagging and the data came to the following conclusion: We can't keep the user to the innermost / outermost lanes depending on the exit the route takes: we found situations where both heuristics were wrong. Even on popular roundabouts the tagging is often wrong or in the best case not present at all. There are at least two different ways to interpret roundabout indications: 1/ where e.g. a right arrow on the lane indicates turn restrictions for the roundabout and the need to take this lane to exit the roundabout to the right (possibly skipping multiple exits) and 2/ where a right arrow just means this is a lane in a immediate right turn. Example: Australia marks lanes with arrows that seem to indicate "angles you can exit the roundabout from", for example, these two ways: - http://www.openstreetmap.org/way/320941710 - http://www.openstreetmap.org/way/42918021 Whereas Germany marks lanes with "directions you can travel in these lanes immediately after entering the roundabout": - http://www.openstreetmap.org/way/52578338 These two different interpretations of how to draw the arrows on the roads mean we have conflicting solutions to "which lanes can you use to take exit B from entry A" based on locality. Continuing to tag ways based on lane markings is no problem, but unfortunately, we can't reliably resolve good advice for navigation system users (like "use the inside lane to take the second exit at the roundabout"), there are too many situations that would generate bad instructions (instructions that tell users to go into a lane they shouldn't use).
2016-07-22 12:59:08 -04:00
leg.steps = guidance::removeLanesFromRoundabouts(std::move(leg.steps));
2016-06-06 07:52:41 -04:00
leg.steps = guidance::anticipateLaneChange(std::move(leg.steps));
leg.steps = guidance::collapseUseLane(std::move(leg.steps));
2016-03-29 07:45:48 -04:00
leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps);
2016-01-28 10:28:44 -05:00
}
leg_geometries.push_back(std::move(leg_geometry));
legs.push_back(std::move(leg));
}
2016-01-28 10:28:44 -05:00
auto route = guidance::assembleRoute(legs);
boost::optional<util::json::Value> json_overview;
if (parameters.overview != RouteParameters::OverviewType::False)
{
const auto use_simplification =
parameters.overview == RouteParameters::OverviewType::Simplified;
BOOST_ASSERT(use_simplification ||
parameters.overview == RouteParameters::OverviewType::Full);
auto overview = guidance::assembleOverview(leg_geometries, use_simplification);
json_overview = MakeGeometry(overview.begin(), overview.end());
}
2016-02-25 11:55:52 -05:00
std::vector<util::json::Value> step_geometries;
for (const auto idx : util::irange<std::size_t>(0UL, legs.size()))
2016-02-25 11:55:52 -05:00
{
auto &leg_geometry = leg_geometries[idx];
step_geometries.reserve(step_geometries.size() + legs[idx].steps.size());
2016-02-25 11:55:52 -05:00
std::transform(
2016-05-27 15:05:04 -04:00
legs[idx].steps.begin(),
legs[idx].steps.end(),
std::back_inserter(step_geometries),
2016-04-06 03:47:17 -04:00
[this, &leg_geometry](const guidance::RouteStep &step) {
2016-02-25 11:55:52 -05:00
if (parameters.geometries == RouteParameters::GeometriesType::Polyline)
{
return static_cast<util::json::Value>(
json::makePolyline(leg_geometry.locations.begin() + step.geometry_begin,
leg_geometry.locations.begin() + step.geometry_end));
}
BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON);
return static_cast<util::json::Value>(json::makeGeoJSONGeometry(
2016-02-25 11:55:52 -05:00
leg_geometry.locations.begin() + step.geometry_begin,
leg_geometry.locations.begin() + step.geometry_end));
});
}
2016-03-01 16:30:31 -05:00
std::vector<util::json::Object> annotations;
2016-05-26 15:29:15 -04:00
if (parameters.annotations)
{
for (const auto idx : util::irange<std::size_t>(0UL, leg_geometries.size()))
{
util::json::Array durations;
util::json::Array distances;
2016-05-18 16:09:14 -04:00
util::json::Array nodes;
util::json::Array datasources;
auto &leg_geometry = leg_geometries[idx];
durations.values.reserve(leg_geometry.annotations.size());
distances.values.reserve(leg_geometry.annotations.size());
nodes.values.reserve(leg_geometry.osm_node_ids.size());
datasources.values.reserve(leg_geometry.annotations.size());
2016-07-29 01:13:17 -04:00
std::for_each(leg_geometry.annotations.begin(),
leg_geometry.annotations.end(),
[this, &durations, &distances, &datasources](
const guidance::LegGeometry::Annotation &step) {
durations.values.push_back(step.duration);
distances.values.push_back(step.distance);
datasources.values.push_back(step.datasource);
});
2016-06-02 08:43:27 -04:00
std::for_each(leg_geometry.osm_node_ids.begin(),
leg_geometry.osm_node_ids.end(),
[this, &nodes](const OSMNodeID &node_id) {
nodes.values.push_back(static_cast<std::uint64_t>(node_id));
});
util::json::Object annotation;
annotation.values["distance"] = std::move(distances);
annotation.values["duration"] = std::move(durations);
2016-05-18 16:09:14 -04:00
annotation.values["nodes"] = std::move(nodes);
annotation.values["datasources"] = std::move(datasources);
annotations.push_back(std::move(annotation));
}
}
auto result = json::makeRoute(route,
2016-05-27 15:05:04 -04:00
json::makeRouteLegs(std::move(legs),
std::move(step_geometries),
std::move(annotations)),
std::move(json_overview));
return result;
2016-01-28 10:28:44 -05:00
}
const RouteParameters &parameters;
};
} // ns api
} // ns engine
} // ns osrm
2016-01-28 10:28:44 -05:00
#endif