basic turn lane handling

This commit is contained in:
Moritz Kobitzsch
2016-05-13 19:18:00 +02:00
parent 2a05b70dfc
commit efa29edf09
68 changed files with 3010 additions and 207 deletions
+22 -5
View File
@@ -7,6 +7,7 @@
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/typedefs.hpp"
#include <boost/assert.hpp>
#include <boost/optional.hpp>
@@ -47,7 +48,7 @@ const constexpr char *turn_type_names[] = {
"invalid", "new name", "continue", "turn", "merge",
"on ramp", "off ramp", "fork", "end of road", "notification",
"roundabout", "roundabout", "rotary", "rotary", "roundabout turn",
"roundabout turn", "invalid", "invalid", "invalid", "invalid",
"roundabout turn", "use lane", "invalid", "invalid", "invalid",
"invalid", "invalid", "invalid", "invalid", "invalid",
"invalid"};
@@ -56,10 +57,13 @@ 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;
return (maneuver.waypoint_type == guidance::WaypointType::None ||
maneuver.instruction.direction_modifier != DirectionModifier::UTurn);
}
inline bool hasValidLanes(const guidance::StepManeuver maneuver)
{
return maneuver.instruction.lane_tupel.lanes_in_turn > 0;
}
std::string instructionTypeToString(const TurnType::Enum type)
@@ -67,6 +71,15 @@ std::string instructionTypeToString(const TurnType::Enum type)
return turn_type_names[static_cast<std::size_t>(type)];
}
util::json::Array laneArrayFromLaneTupe(const util::guidance::LaneTupel lane_tupel)
{
BOOST_ASSERT(lane_tupel.lanes_in_turn >= 1);
util::json::Array result;
for (LaneID i = 0; i < lane_tupel.lanes_in_turn; ++i)
result.values.push_back(lane_tupel.first_lane_from_the_right + i);
return result;
}
std::string instructionModifierToString(const DirectionModifier::Enum modifier)
{
return modifier_names[static_cast<std::size_t>(modifier)];
@@ -148,6 +161,10 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
step_maneuver.values["modifier"] =
detail::instructionModifierToString(maneuver.instruction.direction_modifier);
if (detail::hasValidLanes(maneuver))
step_maneuver.values["lanes"] =
detail::laneArrayFromLaneTupe(maneuver.instruction.lane_tupel);
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before);
step_maneuver.values["bearing_after"] = std::round(maneuver.bearing_after);
+34 -23
View File
@@ -21,6 +21,8 @@ namespace TurnType = osrm::extractor::guidance::TurnType;
namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::angularDeviation;
using osrm::util::guidance::getTurnDirection;
using osrm::util::guidance::isLeftTurn;
using osrm::util::guidance::isRightTurn;
namespace osrm
{
@@ -31,17 +33,19 @@ namespace guidance
namespace
{
const constexpr double MAX_COLLAPSE_DISTANCE = 25;
const constexpr std::size_t MIN_END_OF_ROAD_INTERSECTIONS = std::size_t{2};
const constexpr double MAX_COLLAPSE_DISTANCE = 30;
inline bool choiceless(const RouteStep &step, const RouteStep &previous)
{
// if the next turn is choiceless, we consider longer turn roads collapsable than usually
// accepted. We might need to improve this to find out whether we merge onto a through-street.
return previous.distance < 3 * MAX_COLLAPSE_DISTANCE &&
1 >= std::count(step.intersections.front().entry.begin(),
step.intersections.front().entry.end(),
true);
BOOST_ASSERT(!step.intersections.empty());
const auto is_without_choice = previous.distance < 4 * MAX_COLLAPSE_DISTANCE &&
1 >= std::count(step.intersections.front().entry.begin(),
step.intersections.front().entry.end(),
true);
return is_without_choice;
}
// List of types that can be collapsed, if all other restrictions pass
@@ -62,9 +66,9 @@ bool isCollapsableInstruction(const TurnInstruction instruction)
// a possible u-turn.
bool collapsable(const RouteStep &step)
{
return step.distance < MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(step.maneuver.instruction);
(step.maneuver.instruction.type == TurnType::UseLane ||
isCollapsableInstruction(step.maneuver.instruction));
}
bool compatible(const RouteStep &lhs, const RouteStep &rhs) { return lhs.mode == rhs.mode; }
@@ -137,6 +141,8 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source)
destination.geometry_begin = std::min(destination.geometry_begin, source.geometry_begin);
destination.geometry_end = std::max(destination.geometry_end, source.geometry_end);
destination.maneuver.exit = source.maneuver.exit;
return destination;
}
@@ -171,8 +177,7 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
// instruction though. it is not contained somewhere until now
steps[propagation_index - 1] =
forwardInto(std::move(steps[propagation_index - 1]), propagation_step);
propagation_step.maneuver.instruction =
TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
invalidateStep(propagation_step);
}
}
}
@@ -220,10 +225,8 @@ void closeOffRoundabout(const bool on_roundabout,
const std::size_t step_index)
{
auto &step = steps[step_index];
step.maneuver.exit += 1;
if (!on_roundabout)
{
// We reached a special case that requires the addition of a special route step in the
// beginning. We started in a roundabout, so to announce the exit, we move use the exit
// instruction and move it right to the beginning to make sure to immediately announce the
@@ -255,6 +258,7 @@ void closeOffRoundabout(const bool on_roundabout,
if (steps[1].maneuver.instruction.type == TurnType::EnterRotary)
steps[1].rotary_name = steps[0].name;
}
step.maneuver.exit += 1;
// Normal exit from the roundabout, or exit from a previously fixed roundabout. Propagate the
// index back to the entering location and prepare the current silent set of instructions for
@@ -265,6 +269,8 @@ void closeOffRoundabout(const bool on_roundabout,
// intersections are locations passed along the way
const auto exit_intersection = steps[step_index].intersections.front();
const auto exit_bearing = exit_intersection.bearings[exit_intersection.out];
const auto destination_name = step.name;
const auto destinatino_name_id = step.name_id;
if (step_index > 1)
{
// The very first route-step is head, so we cannot iterate past that one
@@ -299,22 +305,18 @@ void closeOffRoundabout(const bool on_roundabout,
::osrm::util::guidance::getTurnDirection(angle);
}
propagation_step.name = step.name;
propagation_step.name_id = step.name_id;
propagation_step.name = destination_name;
;
propagation_step.name_id = destinatino_name_id;
invalidateStep(steps[propagation_index + 1]);
break;
}
else
{
BOOST_ASSERT(propagation_step.maneuver.instruction.type ==
TurnType::StayOnRoundabout ||
propagation_step.maneuver.instruction.type == TurnType::Suppressed ||
propagation_step.maneuver.instruction.type == TurnType::NoTurn);
propagation_step.maneuver.instruction =
TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
invalidateStep(steps[propagation_index + 1]);
}
}
// remove exit
step.maneuver.instruction = TurnInstruction::NO_TURN();
}
}
@@ -364,9 +366,15 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
const auto &one_back_step = steps[one_back_index];
// This function assumes driving on the right hand side of the streat
const auto bearingsAreReversed = [](const double bearing_in, const double bearing_out) {
// Nearly perfectly reversed angles have a difference close to 180 degrees (straight)
return angularDeviation(bearing_in, bearing_out) > 170;
const double left_turn_angle = [&]() {
if (0 <= bearing_out && bearing_out <= bearing_in)
return bearing_in - bearing_out;
return bearing_in + 360 - bearing_out;
}();
return angularDeviation(left_turn_angle, 180) <= 35;
};
BOOST_ASSERT(!one_back_step.intersections.empty() && !current_step.intersections.empty());
@@ -396,7 +404,6 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
DirectionModifier::Straight &&
one_back_step.intersections.front().bearings.size() > 2)
steps[step_index].maneuver.instruction.type = TurnType::Turn;
steps[two_back_index] = elongate(std::move(steps[two_back_index]), one_back_step);
// If the previous instruction asked to continue, the name change will have to
// be changed into a turn
@@ -407,6 +414,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
else if (one_back_step.distance <= MAX_COLLAPSE_DISTANCE &&
isCollapsableInstruction(current_step.maneuver.instruction))
{
// TODO check for lanes
if (compatible(one_back_step, current_step))
{
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
@@ -467,7 +475,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
// additionall collapse a name-change as well
const bool continues_with_name_change =
(step_index + 1 < steps.size()) &&
isCollapsableInstruction(steps[step_index + 1].maneuver.instruction);
(steps[step_index + 1].maneuver.instruction.type == TurnType::UseLane ||
isCollapsableInstruction(steps[step_index + 1].maneuver.instruction));
const bool u_turn_with_name_change =
continues_with_name_change && steps[step_index + 1].name == steps[two_back_index].name;
@@ -576,6 +585,8 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
has_entered_roundabout = false;
on_roundabout = false;
}
else if (has_entered_roundabout)
steps[step_index + 1].maneuver.exit = step.maneuver.exit;
}
// unterminated roundabout