#include "engine/api/json_factory.hpp" #include "engine/polyline_compressor.hpp" #include "engine/hint.hpp" #include #include #include #include #include #include #include #include using TurnType = osrm::extractor::guidance::TurnType; using DirectionModifier = osrm::extractor::guidance::DirectionModifier; using TurnInstruction = osrm::extractor::guidance::TurnInstruction; namespace osrm { namespace engine { namespace api { namespace json { namespace detail { const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "slight right", "straight", "slight left", "left", "sharp left"}; // translations of TurnTypes. Not all types are exposed to the outside world. // invalid types should never be returned as part of the API const constexpr char *turn_type_names[] = { "invalid", "no turn", "invalid", "new name", "continue", "turn", "turn", "turn", "turn", "merge", "ramp", "ramp", "ramp", "ramp", "fork", "end of road", "roundabout", "invalid", "roundabout", "invalid", "traffic circle", "invalid", "traffic circle", "invalid", "invalid", "restriction", "notification"}; const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"}; // Check whether to include a modifier in the result of the API inline bool isValidModifier(const guidance::StepManeuver maneuver) { if (maneuver.waypoint_type != guidance::WaypointType::None && maneuver.instruction.direction_modifier == DirectionModifier::UTurn) return false; return true; } inline bool isMultiTurn(const TurnType type) { return (type == TurnType::FirstTurn || type == TurnType::SecondTurn || type == TurnType::ThirdTurn); } inline std::string getCount(const TurnType type) { if (type == TurnType::FirstTurn) return "1"; if (type == TurnType::SecondTurn) return "2"; if (type == TurnType::ThirdTurn) return "3"; return "0"; } std::string instructionTypeToString(const TurnType type) { return turn_type_names[static_cast(type)]; } std::string instructionModifierToString(const DirectionModifier modifier) { return modifier_names[static_cast(modifier)]; } std::string waypointTypeToString(const guidance::WaypointType waypoint_type) { return waypoint_type_names[static_cast(waypoint_type)]; } util::json::Array coordinateToLonLat(const util::Coordinate coordinate) { util::json::Array array; array.values.push_back(static_cast(toFloating(coordinate.lon))); array.values.push_back(static_cast(toFloating(coordinate.lat))); 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_INACCESSIBLE: token = "inaccessible"; break; case TRAVEL_MODE_DRIVING: token = "driving"; break; case TRAVEL_MODE_CYCLING: token = "cycling"; break; case TRAVEL_MODE_WALKING: token = "walking"; break; case TRAVEL_MODE_FERRY: token = "ferry"; break; case TRAVEL_MODE_TRAIN: token = "train"; break; case TRAVEL_MODE_PUSHING_BIKE: token = "pushing bike"; break; case TRAVEL_MODE_MOVABLE_BRIDGE: token = "movable bridge"; break; case TRAVEL_MODE_STEPS_UP: token = "steps up"; break; case TRAVEL_MODE_STEPS_DOWN: token = "steps down"; break; case TRAVEL_MODE_RIVER_UP: token = "river upstream"; break; case TRAVEL_MODE_RIVER_DOWN: token = "river downstream"; break; case TRAVEL_MODE_ROUTE: token = "route"; break; default: token = "other"; break; } return token; } } // namespace detail util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) { util::json::Object step_maneuver; if (maneuver.waypoint_type == guidance::WaypointType::None) step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type); else step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type); if (detail::isMultiTurn(maneuver.instruction.type)) step_maneuver.values["count"] = detail::getCount(maneuver.instruction.type); if (detail::isValidModifier(maneuver)) step_maneuver.values["modifier"] = detail::instructionModifierToString(maneuver.instruction.direction_modifier); step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location); step_maneuver.values["bearing_before"] = maneuver.bearing_before; step_maneuver.values["bearing_after"] = maneuver.bearing_after; if (maneuver.exit != 0) step_maneuver.values["exit"] = maneuver.exit; return step_maneuver; } util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geometry) { util::json::Object route_step; route_step.values["distance"] = std::move(step.distance); route_step.values["duration"] = std::move(step.duration); route_step.values["name"] = std::move(step.name); route_step.values["mode"] = detail::modeToString(std::move(step.mode)); route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver)); route_step.values["geometry"] = std::move(geometry); return route_step; } util::json::Object makeRoute(const guidance::Route &route, util::json::Array legs, boost::optional 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 util::Coordinate location, std::string name, const Hint &hint) { util::json::Object waypoint; waypoint.values["location"] = detail::coordinateToLonLat(location); waypoint.values["name"] = std::move(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"] = std::move(leg.distance); route_leg.values["duration"] = std::move(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 legs, std::vector step_geometries) { util::json::Array json_legs; auto step_geometry_iter = step_geometries.begin(); for (const auto idx : boost::irange(0UL, legs.size())) { auto leg = std::move(legs[idx]); util::json::Array json_steps; json_steps.values.reserve(leg.steps.size()); std::transform( std::make_move_iterator(leg.steps.begin()), std::make_move_iterator(leg.steps.end()), std::back_inserter(json_steps.values), [&step_geometry_iter](guidance::RouteStep step) { return makeRouteStep(std::move(step), std::move(*step_geometry_iter++)); }); json_legs.values.push_back(makeRouteLeg(std::move(leg), std::move(json_steps))); } return json_legs; } } // namespace json } // namespace api } // namespace engine } // namespace osrm