183 lines
5.9 KiB
C++
183 lines
5.9 KiB
C++
#ifndef TURN_INSTRUCTIONS_HPP
|
|
#define TURN_INSTRUCTIONS_HPP
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
namespace osrm
|
|
{
|
|
namespace extractor
|
|
{
|
|
|
|
enum class TurnInstruction : unsigned char
|
|
{
|
|
NoTurn = 0,
|
|
GoStraight,
|
|
TurnSlightRight,
|
|
TurnRight,
|
|
TurnSharpRight,
|
|
UTurn,
|
|
TurnSharpLeft,
|
|
TurnLeft,
|
|
TurnSlightLeft,
|
|
ReachViaLocation,
|
|
HeadOn,
|
|
EnterRoundAbout,
|
|
LeaveRoundAbout,
|
|
StayOnRoundAbout,
|
|
StartAtEndOfStreet,
|
|
ReachedYourDestination,
|
|
NameChanges,
|
|
EnterAgainstAllowedDirection,
|
|
LeaveAgainstAllowedDirection,
|
|
InverseAccessRestrictionFlag = 127,
|
|
AccessRestrictionFlag = 128,
|
|
AccessRestrictionPenalty = 129
|
|
};
|
|
|
|
// shiftable turns to left and right
|
|
const constexpr bool shiftable_left[] = {false, false, true, true, true, false, false, true, true};
|
|
const constexpr bool shiftable_right[] = {false, false, true, true, false, false, true, true, true};
|
|
|
|
inline TurnInstruction shiftTurnToLeft(TurnInstruction turn)
|
|
{
|
|
BOOST_ASSERT_MSG(static_cast<int>(turn) < 9,
|
|
"Shift turn only supports basic turn instructions");
|
|
if (turn > TurnInstruction::TurnSlightLeft)
|
|
return turn;
|
|
else
|
|
return shiftable_left[static_cast<int>(turn)]
|
|
? (static_cast<TurnInstruction>(static_cast<int>(turn) - 1))
|
|
: turn;
|
|
}
|
|
|
|
inline TurnInstruction shiftTurnToRight(TurnInstruction turn)
|
|
{
|
|
BOOST_ASSERT_MSG(static_cast<int>(turn) < 9,
|
|
"Shift turn only supports basic turn instructions");
|
|
if (turn > TurnInstruction::TurnSlightLeft)
|
|
return turn;
|
|
else
|
|
return shiftable_right[static_cast<int>(turn)]
|
|
? (static_cast<TurnInstruction>(static_cast<int>(turn) + 1))
|
|
: turn;
|
|
}
|
|
|
|
inline double angularDeviation(const double angle, const double from)
|
|
{
|
|
const double deviation = std::abs(angle - from);
|
|
return std::min(360 - deviation, deviation);
|
|
}
|
|
|
|
inline double getAngularPenalty(const double angle, TurnInstruction instruction)
|
|
{
|
|
BOOST_ASSERT_MSG(static_cast<int>(instruction) < 9,
|
|
"Angular penalty only supports basic turn instructions");
|
|
const double center[] = {180, 180, 135, 90, 45,
|
|
0, 315, 270, 225}; // centers of turns from getTurnDirection
|
|
return angularDeviation(center[static_cast<int>(instruction)], angle);
|
|
}
|
|
|
|
inline double getTurnConfidence(const double angle, TurnInstruction instruction)
|
|
{
|
|
|
|
// special handling of U-Turns and Roundabout
|
|
if (instruction >= TurnInstruction::HeadOn || instruction == TurnInstruction::UTurn ||
|
|
instruction == TurnInstruction::NoTurn || instruction == TurnInstruction::EnterRoundAbout ||
|
|
instruction == TurnInstruction::StayOnRoundAbout || instruction == TurnInstruction::LeaveRoundAbout )
|
|
return 1.0;
|
|
|
|
BOOST_ASSERT_MSG(static_cast<int>(instruction) < 9,
|
|
"Turn confidence only supports basic turn instructions");
|
|
const double deviations[] = {10, 10, 35, 50, 45, 0, 45, 50, 35};
|
|
const double difference = getAngularPenalty(angle, instruction);
|
|
const double max_deviation = deviations[static_cast<int>(instruction)];
|
|
return 1.0 - (difference / max_deviation) * (difference / max_deviation);
|
|
}
|
|
|
|
// Translates between angles and their human-friendly directional representation
|
|
inline TurnInstruction getTurnDirection(const double angle)
|
|
{
|
|
// An angle of zero is a u-turn
|
|
// 180 goes perfectly straight
|
|
// 0-180 are right turns
|
|
// 180-360 are left turns
|
|
if (angle > 0 && angle < 60)
|
|
return TurnInstruction::TurnSharpRight;
|
|
if (angle >= 60 && angle < 140)
|
|
return TurnInstruction::TurnRight;
|
|
if (angle >= 140 && angle < 170)
|
|
return TurnInstruction::TurnSlightRight;
|
|
if (angle >= 170 && angle <= 190)
|
|
return TurnInstruction::GoStraight;
|
|
if (angle > 190 && angle <= 220)
|
|
return TurnInstruction::TurnSlightLeft;
|
|
if (angle > 220 && angle <= 300)
|
|
return TurnInstruction::TurnLeft;
|
|
if (angle > 300 && angle < 360)
|
|
return TurnInstruction::TurnSharpLeft;
|
|
return TurnInstruction::UTurn;
|
|
}
|
|
|
|
// Decides if a turn is needed to be done for the current instruction
|
|
inline bool isTurnNecessary(const TurnInstruction turn_instruction)
|
|
{
|
|
if (TurnInstruction::NoTurn == turn_instruction ||
|
|
TurnInstruction::StayOnRoundAbout == turn_instruction)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
inline bool resolve(TurnInstruction &to_resolve, const TurnInstruction neighbor, bool resolve_right)
|
|
{
|
|
const auto shifted_turn =
|
|
resolve_right ? shiftTurnToRight(to_resolve) : shiftTurnToLeft(to_resolve);
|
|
if (shifted_turn == neighbor || shifted_turn == to_resolve)
|
|
return false;
|
|
|
|
to_resolve = shifted_turn;
|
|
return true;
|
|
}
|
|
|
|
inline bool resolveTransitive(TurnInstruction &first,
|
|
TurnInstruction &second,
|
|
const TurnInstruction third,
|
|
bool resolve_right)
|
|
{
|
|
if (resolve(second, third, resolve_right))
|
|
{
|
|
first = resolve_right ? shiftTurnToRight(first) : shiftTurnToLeft(first);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline bool isSlightTurn(const TurnInstruction turn)
|
|
{
|
|
return turn == TurnInstruction::GoStraight || turn == TurnInstruction::TurnSlightRight ||
|
|
turn == TurnInstruction::TurnSlightLeft || turn == TurnInstruction::NoTurn;
|
|
}
|
|
|
|
inline bool isSharpTurn(const TurnInstruction turn)
|
|
{
|
|
return turn == TurnInstruction::TurnSharpLeft || turn == TurnInstruction::TurnSharpRight;
|
|
}
|
|
|
|
inline bool isStraight(const TurnInstruction turn)
|
|
{
|
|
return turn == TurnInstruction::GoStraight || turn == TurnInstruction::NoTurn;
|
|
}
|
|
|
|
inline bool isConflict(const TurnInstruction first, const TurnInstruction second)
|
|
{
|
|
return first == second || (isStraight(first) && isStraight(second));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* TURN_INSTRUCTIONS_HPP */
|