#ifndef TURN_INSTRUCTIONS_HPP #define TURN_INSTRUCTIONS_HPP #include #include #include 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(turn) < 9, "Shift turn only supports basic turn instructions"); if (turn > TurnInstruction::TurnSlightLeft) return turn; else return shiftable_left[static_cast(turn)] ? (static_cast(static_cast(turn) - 1)) : turn; } inline TurnInstruction shiftTurnToRight(TurnInstruction turn) { BOOST_ASSERT_MSG(static_cast(turn) < 9, "Shift turn only supports basic turn instructions"); if (turn > TurnInstruction::TurnSlightLeft) return turn; else return shiftable_right[static_cast(turn)] ? (static_cast(static_cast(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(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(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(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(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 */