Big Restructuring / Cleanup

This commit is contained in:
Patrick Niklaus
2016-03-01 22:30:31 +01:00
parent adb8d0e845
commit b08b360f38
40 changed files with 419 additions and 511 deletions
@@ -7,7 +7,7 @@
#include "engine/guidance/leg_geometry.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp"
#include "engine/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/travel_mode.hpp"
#include <vector>
@@ -49,7 +49,7 @@ LegGeometry assembleGeometry(const DataFacadeT &facade,
current_distance +=
util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate);
if (path_point.turn_instruction != TurnInstruction::NO_TURN())
if (path_point.turn_instruction != extractor::guidance::TurnInstruction::NO_TURN())
{
geometry.segment_distances.push_back(current_distance);
geometry.segment_offsets.push_back(geometry.locations.size());
+24 -17
View File
@@ -4,8 +4,8 @@
#include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/leg_geometry.hpp"
#include "engine/guidance/guidance_toolkit.hpp"
#include "engine/guidance/turn_instruction.hpp"
#include "engine/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "engine/internal_route_result.hpp"
#include "engine/phantom_node.hpp"
#include "util/coordinate_calculation.hpp"
@@ -25,7 +25,7 @@ namespace guidance
namespace detail
{
// FIXME move implementation to cpp
inline StepManeuver stepManeuverFromGeometry(TurnInstruction instruction,
inline StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const LegGeometry &leg_geometry,
const std::size_t segment_index,
const unsigned exit)
@@ -59,7 +59,6 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
boost::optional<util::Coordinate> source_location,
boost::optional<util::Coordinate> target_location)
{
(void) source_location;
const auto source_duration =
(source_traversed_in_reverse ? source_node.GetReverseWeightPlusOffset()
: source_node.GetForwardWeightPlusOffset()) /
@@ -80,22 +79,28 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
steps.reserve(number_of_segments);
std::size_t segment_index = 0;
const auto initial_modifier =
(source_location && leg_geometry.locations.size() >= 2)
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
source_location.get(), *(leg_geometry.locations.begin()),
*(leg_geometry.locations.begin() + 1)))
: extractor::guidance::DirectionModifier::UTurn;
if (leg_data.size() > 0)
{
StepManeuver maneuver = detail::stepManeuverFromGeometry(
TurnInstruction{TurnType::Location, DirectionModifier::UTurn}, leg_geometry,
segment_index, INVALID_EXIT_NR);
maneuver.instruction.direction_modifier = bearingToDirectionModifier(maneuver.bearing_before);
extractor::guidance::TurnInstruction{extractor::guidance::TurnType::Location,
initial_modifier},
leg_geometry, segment_index, INVALID_EXIT_NR);
// TODO fix this: it makes no sense
// PathData saves the information we need of the segment _before_ the turn,
// but a RouteStep is with regard to the segment after the turn.
// We need to skip the first segment because it is already covered by the
// initial start of a route
for (const auto &path_point : leg_data)
{
if (path_point.turn_instruction != TurnInstruction::NO_TURN())
if (path_point.turn_instruction != extractor::guidance::TurnInstruction::NO_TURN())
{
const auto name = facade.get_name_for_id(path_point.name_id);
const auto distance = leg_geometry.segment_distances[segment_index];
@@ -108,7 +113,6 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
segment_index++;
}
}
// TODO remove this hack
const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{target_node.name_id, facade.get_name_for_id(target_node.name_id),
target_duration, distance, target_mode, maneuver,
@@ -123,9 +127,9 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
// x---*---*---*---z compressed edge
// |-------| duration
StepManeuver maneuver = {source_node.location, 0., 0.,
TurnInstruction{TurnType::Location, DirectionModifier::UTurn},
extractor::guidance::TurnInstruction{
extractor::guidance::TurnType::Location, initial_modifier},
INVALID_EXIT_NR};
maneuver.instruction.direction_modifier = bearingToDirectionModifier(maneuver.bearing_before);
steps.push_back(RouteStep{source_node.name_id, facade.get_name_for_id(source_node.name_id),
target_duration - source_duration,
@@ -136,15 +140,18 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
BOOST_ASSERT(segment_index == number_of_segments - 1);
const auto final_modifier =
target_location ? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
*(leg_geometry.locations.end() - 3),
*(leg_geometry.locations.end() - 1), target_location.get()))
: DirectionModifier::UTurn;
(target_location && leg_geometry.locations.size() >= 2)
? angleToDirectionModifier(util::coordinate_calculation::computeAngle(
*(leg_geometry.locations.end() - 2), *(leg_geometry.locations.end() - 1),
target_location.get()))
: extractor::guidance::DirectionModifier::UTurn;
// This step has length zero, the only reason we need it is the target location
steps.push_back(RouteStep{
target_node.name_id, facade.get_name_for_id(target_node.name_id), 0., 0., target_mode,
StepManeuver{target_node.location, 0., 0.,
TurnInstruction{TurnType::Location, final_modifier}, INVALID_EXIT_NR},
extractor::guidance::TurnInstruction{extractor::guidance::TurnType::Location,
final_modifier},
INVALID_EXIT_NR},
leg_geometry.locations.size(), leg_geometry.locations.size()});
return steps;
@@ -1,119 +0,0 @@
#ifndef OSRM_GUIDANCE_CLASSIFICATION_DATA_HPP_
#define OSRM_GUIDANCE_CLASSIFICATION_DATA_HPP_
#include <string>
#include <unordered_map>
#include <iostream> //TODO remove
#include "util/simple_logger.hpp"
// Forward Declaration to allow usage of external osmium::Way
namespace osmium
{
class Way;
}
namespace osrm
{
namespace engine
{
namespace guidance
{
enum FunctionalRoadClass
{
MOTORWAY,
MOTORWAY_LINK,
TRUNK,
TRUNK_LINK,
PRIMARY,
PRIMARY_LINK,
SECONDARY,
SECONDARY_LINK,
TERTIARY,
TERTIARY_LINK,
UNCLASSIFIED,
RESIDENTIAL,
SERVICE,
LIVING_STREET,
LOW_PRIORITY_ROAD, // a road simply included for connectivity. Should be avoided at all cost
UNKNOWN
};
inline FunctionalRoadClass functionalRoadClassFromTag(std::string const &value)
{
const static auto initializeClassHash = []()
{
std::unordered_map<std::string, FunctionalRoadClass> hash;
hash["motorway"] = FunctionalRoadClass::MOTORWAY;
hash["motorway_link"] = FunctionalRoadClass::MOTORWAY_LINK;
hash["trunk"] = FunctionalRoadClass::TRUNK;
hash["trunk_link"] = FunctionalRoadClass::TRUNK_LINK;
hash["primary"] = FunctionalRoadClass::PRIMARY;
hash["primary_link"] = FunctionalRoadClass::PRIMARY_LINK;
hash["secondary"] = FunctionalRoadClass::SECONDARY;
hash["secondary_link"] = FunctionalRoadClass::SECONDARY_LINK;
hash["tertiary"] = FunctionalRoadClass::TERTIARY;
hash["tertiary_link"] = FunctionalRoadClass::TERTIARY_LINK;
hash["unclassified"] = FunctionalRoadClass::UNCLASSIFIED;
hash["residential"] = FunctionalRoadClass::RESIDENTIAL;
hash["service"] = FunctionalRoadClass::SERVICE;
hash["living_street"] = FunctionalRoadClass::LIVING_STREET;
hash["track"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
hash["road"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
hash["path"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
hash["driveway"] = FunctionalRoadClass::LOW_PRIORITY_ROAD;
return hash;
};
static const std::unordered_map<std::string, FunctionalRoadClass> class_hash =
initializeClassHash();
if (class_hash.find(value) != class_hash.end())
{
return class_hash.find(value)->second;
}
else
{
util::SimpleLogger().Write(logDEBUG) << "Unknown road class encountered: " << value;
return FunctionalRoadClass::UNKNOWN;
}
}
inline bool isRampClass(const FunctionalRoadClass road_class)
{
// Primary Roads and down are usually too small to announce their links as ramps
return road_class == MOTORWAY_LINK || road_class == TRUNK_LINK;
//|| road_class == PRIMARY_LINK ||
// road_class == SECONDARY_LINK || road_class == TERTIARY_LINK;
}
// TODO augment this with all data required for guidance generation
struct RoadClassificationData
{
FunctionalRoadClass road_class;
void augment(const osmium::Way &way);
// reset to a defined but invalid state
void invalidate();
static RoadClassificationData INVALID()
{
RoadClassificationData tmp;
tmp.invalidate();
return tmp;
};
};
inline bool operator==( const RoadClassificationData lhs, const RoadClassificationData rhs )
{
return lhs.road_class == rhs.road_class;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // OSRM_GUIDANCE_CLASSIFICATION_DATA_HPP_
@@ -1,426 +0,0 @@
#ifndef OSRM_GUIDANCE_GUIDANCE_TOOLKIT_HPP_
#define OSRM_GUIDANCE_GUIDANCE_TOOLKIT_HPP_
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
#include "engine/guidance/classification_data.hpp"
#include "engine/guidance/turn_instruction.hpp"
#include <map>
#include <cmath>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
const constexpr double DESIRED_SEGMENT_LENGTH = 10.0;
const constexpr bool shiftable_ccw[] = {false, true, true, false, false, true, true, false};
const constexpr bool shiftable_cw[] = {false, false, true, true, false, false, true, true};
// direction modifier bounds in 360./256. degrees
const constexpr uint8_t modifier_bounds[num_direction_modifiers] = {0, 36, 93, 121,
136, 163, 220, 255};
const constexpr double discrete_angle_step_size = 360. / 256.;
} // namespace detail
namespace detail
{
template <typename IteratorType>
util::Coordinate
getCoordinateFromCompressedRange(util::Coordinate current_coordinate,
IteratorType compressed_geometry_begin,
const IteratorType compressed_geometry_end,
const util::Coordinate final_coordinate,
const std::vector<extractor::QueryNode> &query_nodes)
{
const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
{
return {node.lon, node.lat};
};
double distance_to_current_coordinate = 0;
double distance_to_next_coordinate = 0;
// get the length that is missing from the current segment to reach DESIRED_SEGMENT_LENGTH
const auto getFactor = [](const double first_distance, const double second_distance)
{
BOOST_ASSERT(first_distance < detail::DESIRED_SEGMENT_LENGTH);
double segment_length = second_distance - first_distance;
BOOST_ASSERT(segment_length > 0);
BOOST_ASSERT(second_distance >= detail::DESIRED_SEGMENT_LENGTH);
double missing_distance = detail::DESIRED_SEGMENT_LENGTH - first_distance;
return missing_distance / segment_length;
};
for (auto compressed_geometry_itr = compressed_geometry_begin;
compressed_geometry_itr != compressed_geometry_end; ++compressed_geometry_itr)
{
const auto next_coordinate =
extractCoordinateFromNode(query_nodes[compressed_geometry_itr->node_id]);
distance_to_next_coordinate =
distance_to_current_coordinate +
util::coordinate_calculation::haversineDistance(current_coordinate, next_coordinate);
// reached point where coordinates switch between
if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
return util::coordinate_calculation::interpolateLinear(
getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
current_coordinate, next_coordinate);
// prepare for next iteration
current_coordinate = next_coordinate;
distance_to_current_coordinate = distance_to_next_coordinate;
}
distance_to_next_coordinate =
distance_to_current_coordinate +
util::coordinate_calculation::haversineDistance(current_coordinate, final_coordinate);
// reached point where coordinates switch between
if (distance_to_next_coordinate >= detail::DESIRED_SEGMENT_LENGTH)
return util::coordinate_calculation::interpolateLinear(
getFactor(distance_to_current_coordinate, distance_to_next_coordinate),
current_coordinate, final_coordinate);
else
return final_coordinate;
}
} // namespace detail
// Finds a (potentially inteprolated) coordinate that is DESIRED_SEGMENT_LENGTH away
// from the start of an edge
inline util::Coordinate
getRepresentativeCoordinate(const NodeID from_node,
const NodeID to_node,
const EdgeID via_edge_id,
const bool traverse_in_reverse,
const extractor::CompressedEdgeContainer &compressed_geometries,
const std::vector<extractor::QueryNode> &query_nodes)
{
const auto extractCoordinateFromNode = [](const extractor::QueryNode &node) -> util::Coordinate
{
return {node.lon, node.lat};
};
// Uncompressed roads are simple, return the coordinate at the end
if (!compressed_geometries.HasEntryForID(via_edge_id))
{
return extractCoordinateFromNode(traverse_in_reverse ? query_nodes[from_node]
: query_nodes[to_node]);
}
else
{
const auto &geometry = compressed_geometries.GetBucketReference(via_edge_id);
const auto base_node_id = (traverse_in_reverse) ? to_node : from_node;
const auto base_coordinate = extractCoordinateFromNode(query_nodes[base_node_id]);
const auto final_node = (traverse_in_reverse) ? from_node : to_node;
const auto final_coordinate = extractCoordinateFromNode(query_nodes[final_node]);
if (traverse_in_reverse)
return detail::getCoordinateFromCompressedRange(
base_coordinate, geometry.rbegin(), geometry.rend(), final_coordinate, query_nodes);
else
return detail::getCoordinateFromCompressedRange(
base_coordinate, geometry.begin(), geometry.end(), final_coordinate, query_nodes);
}
}
// shift an instruction around the degree circle in CCW order
inline DirectionModifier forcedShiftCCW(const DirectionModifier modifier)
{
return static_cast<DirectionModifier>((static_cast<uint32_t>(modifier) + 1) %
detail::num_direction_modifiers);
}
inline DirectionModifier shiftCCW(const DirectionModifier modifier)
{
if (detail::shiftable_ccw[static_cast<int>(modifier)])
return forcedShiftCCW(modifier);
else
return modifier;
}
// shift an instruction around the degree circle in CW order
inline DirectionModifier forcedShiftCW(const DirectionModifier modifier)
{
return static_cast<DirectionModifier>(
(static_cast<uint32_t>(modifier) + detail::num_direction_modifiers - 1) %
detail::num_direction_modifiers);
}
inline DirectionModifier shiftCW(const DirectionModifier modifier)
{
if (detail::shiftable_cw[static_cast<int>(modifier)])
return forcedShiftCW(modifier);
else
return modifier;
}
inline bool entersRoundabout(const TurnInstruction instruction)
{
return (instruction.type == TurnType::EnterRoundabout ||
instruction.type == TurnType::EnterRotary ||
instruction.type == TurnType::EnterRoundaboutAtExit ||
instruction.type == TurnType::EnterRotaryAtExit ||
instruction.type == TurnType::EnterAndExitRoundabout ||
instruction.type == TurnType::EnterAndExitRotary);
}
inline bool leavesRoundabout(const TurnInstruction instruction)
{
return (instruction.type == TurnType::ExitRoundabout ||
instruction.type == TurnType::ExitRotary ||
instruction.type == TurnType::EnterAndExitRoundabout ||
instruction.type == TurnType::EnterAndExitRotary);
}
inline bool staysOnRoundabout(const TurnInstruction instruction)
{
return instruction.type == TurnType::StayOnRoundabout;
}
inline bool isOnRoundabout(const TurnInstruction instruction)
{
return staysOnRoundabout(instruction) || leavesRoundabout(instruction);
}
inline bool isTurnNecessary(const TurnInstruction instruction)
{
return instruction.type != TurnType::NoTurn && instruction.type != TurnType::Suppressed;
}
inline bool isLeftRight(const DirectionModifier modifier)
{
return DirectionModifier::Right == modifier || DirectionModifier::Left == modifier;
}
inline bool isSlightLeftRight(const DirectionModifier modifier)
{
return DirectionModifier::SlightRight == modifier || DirectionModifier::SlightLeft == modifier;
}
inline bool isBasic(const TurnType type)
{
return type == TurnType::Turn || type == TurnType::EndOfRoad;
}
inline bool isUturn(const TurnInstruction instruction)
{
return isBasic(instruction.type) && instruction.direction_modifier == DirectionModifier::UTurn;
}
inline bool resolve(TurnInstruction &to_resolve, const TurnInstruction neighbor, bool resolve_cw)
{
const auto shifted_turn = resolve_cw ? shiftCW(to_resolve.direction_modifier)
: shiftCCW(to_resolve.direction_modifier);
if (shifted_turn == neighbor.direction_modifier ||
shifted_turn == to_resolve.direction_modifier)
return false;
to_resolve.direction_modifier = shifted_turn;
return true;
}
inline bool resolveTransitive(TurnInstruction &first,
TurnInstruction &second,
const TurnInstruction third,
bool resolve_cw)
{
if (resolve(second, third, resolve_cw))
{
first.direction_modifier =
resolve_cw ? shiftCW(first.direction_modifier) : shiftCCW(first.direction_modifier);
return true;
}
return false;
}
inline bool isSlightTurn(const TurnInstruction turn)
{
return (isBasic(turn.type) || turn.type == TurnType::NoTurn) &&
(turn.direction_modifier == DirectionModifier::Straight ||
turn.direction_modifier == DirectionModifier::SlightRight ||
turn.direction_modifier == DirectionModifier::SlightLeft);
}
inline bool isSlightModifier(const DirectionModifier direction_modifier)
{
return (direction_modifier == DirectionModifier::Straight ||
direction_modifier == DirectionModifier::SlightRight ||
direction_modifier == DirectionModifier::SlightLeft);
}
inline bool isSharpTurn(const TurnInstruction turn)
{
return isBasic(turn.type) && (turn.direction_modifier == DirectionModifier::SharpLeft ||
turn.direction_modifier == DirectionModifier::SharpRight);
}
inline bool isStraight(const TurnInstruction turn)
{
return (isBasic(turn.type) || turn.type == TurnType::NoTurn) &&
turn.direction_modifier == DirectionModifier::Straight;
}
inline bool isConflict(const TurnInstruction first, const TurnInstruction second)
{
return (first.type == second.type && first.direction_modifier == second.direction_modifier) ||
(isStraight(first) && isStraight(second));
}
inline DirectionModifier discreteAngleToDircetionModifier(const DiscreteAngle angle)
{
auto modifier = DirectionModifier::UTurn;
DiscreteAngle bound(detail::modifier_bounds[modifier]);
do
{
if (angle <= bound)
return modifier;
modifier = forcedShiftCW(modifier);
bound = static_cast<DiscreteAngle>(detail::modifier_bounds[modifier]);
} while (modifier != DirectionModifier::UTurn);
return modifier;
}
inline DiscreteAngle discretizeAngle(const double angle)
{
BOOST_ASSERT(angle >= 0. && angle <= 360.);
return DiscreteAngle(static_cast<uint8_t>(angle / detail::discrete_angle_step_size));
}
inline double angleFromDiscreteAngle(const DiscreteAngle angle)
{
return static_cast<double>(angle) * detail::discrete_angle_step_size;
}
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)
{
const double center[] = {0, 45, 90, 135, 180, 225, 270, 315};
return angularDeviation(center[static_cast<int>(instruction.direction_modifier)], angle);
}
inline double getTurnConfidence(const double angle, TurnInstruction instruction)
{
// special handling of U-Turns and Roundabout
if (!isBasic(instruction.type) || instruction.direction_modifier == DirectionModifier::UTurn)
return 1.0;
const double deviations[] = {0, 45, 50, 35, 10, 35, 50, 45};
const double difference = getAngularPenalty(angle, instruction);
const double max_deviation = deviations[static_cast<int>(instruction.direction_modifier)];
return 1.0 - (difference / max_deviation) * (difference / max_deviation);
}
// Translates between angles and their human-friendly directional representation
inline DirectionModifier 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 DirectionModifier::SharpRight;
if (angle >= 60 && angle < 140)
return DirectionModifier::Right;
if (angle >= 140 && angle < 170)
return DirectionModifier::SlightRight;
if (angle >= 170 && angle <= 190)
return DirectionModifier::Straight;
if (angle > 190 && angle <= 220)
return DirectionModifier::SlightLeft;
if (angle > 220 && angle <= 300)
return DirectionModifier::Left;
if (angle > 300 && angle < 360)
return DirectionModifier::SharpLeft;
return DirectionModifier::UTurn;
}
inline DirectionModifier angleToDirectionModifier(const double bearing)
{
if (bearing < 135)
{
return DirectionModifier::Right;
}
if (bearing <= 225)
{
return DirectionModifier::Straight;
}
return DirectionModifier::Left;
}
inline DirectionModifier bearingToDirectionModifier(const std::string &bearing)
{
const static auto buildHash = []()
{
std::map<std::string, DirectionModifier> hash;
hash["N"] = DirectionModifier::Straight;
hash["NE"] = DirectionModifier::SlightRight;
hash["E"] = DirectionModifier::Right;
hash["SE"] = DirectionModifier::SharpRight;
hash["S"] = DirectionModifier::UTurn;
hash["SW"] = DirectionModifier::SharpLeft;
hash["W"] = DirectionModifier::Left;
hash["NW"] = DirectionModifier::SlightLeft;
return hash;
};
const static std::map<std::string, DirectionModifier> hash = buildHash();
return hash.find(bearing)->second;
}
inline DirectionModifier bearingToDirectionModifier(const double angle)
{
return bearingToDirectionModifier(util::bearing::get(angle));
}
inline bool isHighway(FunctionalRoadClass road_class)
{
return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK;
}
// swaps left <-> right modifier types
inline DirectionModifier mirrorDirectionModifier(const DirectionModifier modifier)
{
const constexpr DirectionModifier results[] = {
DirectionModifier::UTurn, DirectionModifier::SharpLeft, DirectionModifier::Left,
DirectionModifier::SlightLeft, DirectionModifier::Straight, DirectionModifier::SlightRight,
DirectionModifier::Right, DirectionModifier::SharpRight};
return results[modifier];
}
inline bool canBeSuppressed(const TurnType type)
{
if (type == TurnType::Turn)
return true;
return false;
}
inline bool isLowPriorityRoadClass(const FunctionalRoadClass road_class)
{
return road_class == FunctionalRoadClass::LOW_PRIORITY_ROAD ||
road_class == FunctionalRoadClass::SERVICE;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // OSRM_GUIDANCE_GUIDANCE_TOOLKIT_HPP_
+1 -1
View File
@@ -12,7 +12,7 @@ namespace engine
namespace guidance
{
std::vector<std::vector<PathData>> postProcess( std::vector<std::vector<PathData>> path_data );
std::vector<std::vector<PathData>> postProcess(std::vector<std::vector<PathData>> path_data);
} // namespace guidance
} // namespace engine
+2 -2
View File
@@ -2,7 +2,7 @@
#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
#include "util/coordinate.hpp"
#include "engine/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_instruction.hpp"
namespace osrm
{
@@ -16,7 +16,7 @@ struct StepManeuver
util::Coordinate location;
double bearing_before;
double bearing_after;
TurnInstruction instruction;
extractor::guidance::TurnInstruction instruction;
unsigned exit;
};
} // namespace guidance
+62
View File
@@ -0,0 +1,62 @@
#ifndef OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
#define OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_
#include "extractor/guidance/turn_instruction.hpp"
#include "util/bearing.hpp"
namespace osrm
{
namespace engine
{
namespace guidance
{
// Silent Turn Instructions are not to be mentioned to the outside world but
inline bool isSilent(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::NoTurn || instruction.type == extractor::guidance::TurnType::Suppressed ||
instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
inline bool entersRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::EnterRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterRotary ||
instruction.type == extractor::guidance::TurnType::EnterRoundaboutAtExit ||
instruction.type == extractor::guidance::TurnType::EnterRotaryAtExit ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
}
inline bool leavesRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return (instruction.type == extractor::guidance::TurnType::ExitRoundabout ||
instruction.type == extractor::guidance::TurnType::ExitRotary ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRoundabout ||
instruction.type == extractor::guidance::TurnType::EnterAndExitRotary);
}
inline bool staysOnRoundabout(const extractor::guidance::TurnInstruction instruction)
{
return instruction.type == extractor::guidance::TurnType::StayOnRoundabout;
}
inline extractor::guidance::DirectionModifier angleToDirectionModifier(const double bearing)
{
if (bearing < 135)
{
return extractor::guidance::DirectionModifier::Right;
}
if (bearing <= 225)
{
return extractor::guidance::DirectionModifier::Straight;
}
return extractor::guidance::DirectionModifier::Left;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif /* OSRM_UTIL_GUIDANCE_TOOLKIT_HPP_ */
@@ -1,104 +0,0 @@
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#include "engine/guidance/turn_instruction.hpp"
#include "engine/guidance/guidance_toolkit.hpp"
#include "util/typedefs.hpp"
#include "util/coordinate.hpp"
#include "util/node_based_graph.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
#include <algorithm>
#include <cstddef>
#include <vector>
namespace osrm
{
namespace engine
{
namespace guidance
{
struct TurnPossibility
{
TurnPossibility(DiscreteAngle angle, EdgeID edge_id)
: angle(std::move(angle)), edge_id(std::move(edge_id))
{
}
TurnPossibility() : angle(0), edge_id(SPECIAL_EDGEID) {}
DiscreteAngle angle;
EdgeID edge_id;
};
inline std::vector<TurnPossibility>
classifyIntersection(NodeID nid,
const util::NodeBasedDynamicGraph &graph,
const extractor::CompressedEdgeContainer &compressed_geometries,
const std::vector<extractor::QueryNode> &query_nodes)
{
std::vector<TurnPossibility> turns;
if (graph.BeginEdges(nid) == graph.EndEdges(nid))
return std::vector<TurnPossibility>();
const EdgeID base_id = graph.BeginEdges(nid);
const auto base_coordinate = getRepresentativeCoordinate(nid, graph.GetTarget(base_id), base_id,
graph.GetEdgeData(base_id).reversed,
compressed_geometries, query_nodes);
const auto node_coordinate = util::Coordinate(query_nodes[nid].lon, query_nodes[nid].lat);
// generate a list of all turn angles between a base edge, the node and a current edge
for (const EdgeID eid : graph.GetAdjacentEdgeRange(nid))
{
const auto edge_coordinate = getRepresentativeCoordinate(
nid, graph.GetTarget(eid), eid, false, compressed_geometries, query_nodes);
double angle = util::coordinate_calculation::computeAngle(base_coordinate, node_coordinate,
edge_coordinate);
turns.emplace_back(discretizeAngle(angle), eid);
}
std::sort(turns.begin(), turns.end(),
[](const TurnPossibility left, const TurnPossibility right)
{
return left.angle < right.angle;
});
turns.push_back(turns.front()); // sentinel
for (std::size_t turn_nr = 0; turn_nr + 1 < turns.size(); ++turn_nr)
{
turns[turn_nr].angle = (256 + static_cast<uint32_t>(turns[turn_nr + 1].angle) -
static_cast<uint32_t>(turns[turn_nr].angle)) %
256; // calculate the difference to the right
}
turns.pop_back(); // remove sentinel again
// find largest:
std::size_t best_id = 0;
DiscreteAngle largest_turn_angle = turns.front().angle;
for (std::size_t current_turn_id = 1; current_turn_id < turns.size(); ++current_turn_id)
{
if (turns[current_turn_id].angle > largest_turn_angle)
{
largest_turn_angle = turns[current_turn_id].angle;
best_id = current_turn_id;
}
}
// rotate all angles so the largest angle comes first
std::rotate(turns.begin(), turns.begin() + best_id, turns.end());
return turns;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
@@ -1,173 +0,0 @@
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
#include <cstdint>
#include <boost/assert.hpp>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
// inclusive bounds for turn modifiers
const constexpr uint8_t num_direction_modifiers = 8;
} // detail
// direction modifiers based on angle
// Would be nice to have
// enum class DirectionModifier : unsigned char
enum DirectionModifier
{
UTurn,
SharpRight,
Right,
SlightRight,
Straight,
SlightLeft,
Left,
SharpLeft
};
const constexpr char *modifier_names[detail::num_direction_modifiers] = {
"uturn", "sharp right", "right", "slight right",
"straight", "slight left", "left", "sharp left"};
enum LocationType
{
Start,
Intermediate,
Destination
};
// enum class TurnType : unsigned char
enum TurnType // at the moment we can support 32 turn types, without increasing memory consumption
{
Invalid, // no valid turn instruction
NoTurn, // end of segment without turn
Location, // start,end,via
Suppressed, // location that suppresses a turn
NewName, // no turn, but name changes
Continue, // remain on a street
Turn, // basic turn
Merge, // merge onto a street
Ramp, // special turn (highway ramp exits)
Fork, // fork road splitting up
EndOfRoad, // T intersection
EnterRoundabout, // Entering a small Roundabout
EnterRoundaboutAtExit, // Entering a small Roundabout at a countable exit
EnterAndExitRoundabout, // Touching a roundabout
ExitRoundabout, // Exiting a small Roundabout
EnterRotary, // Enter a rotary
EnterRotaryAtExit, // Enter A Rotary at a countable exit
EnterAndExitRotary, // Touching a rotary
ExitRotary, // Exit a rotary
StayOnRoundabout, // Continue on Either a small or a large Roundabout
Restriction, // Cross a Barrier, requires barrier penalties instead of full block
Notification // Travel Mode Changes`
};
inline bool isValidModifier( const TurnType type, const DirectionModifier modifier )
{
if( type == TurnType::Location &&
modifier != DirectionModifier::Left
&& modifier != DirectionModifier::Straight
&& modifier != DirectionModifier::Right )
return false;
return true;
}
const constexpr char *turn_type_names[] = {"invalid",
"no turn",
"waypoint",
"invalid",
"new name",
"continue",
"turn",
"merge",
"ramp",
"fork",
"end of road",
"roundabout",
"invalid",
"roundabout",
"invalid",
"traffic circle",
"invalid",
"traffic circle",
"invalid",
"invalid",
"restriction",
"notification"};
// turn angle in 1.40625 degree -> 128 == 180 degree
typedef uint8_t DiscreteAngle;
struct TurnInstruction
{
TurnInstruction(const TurnType type = TurnType::Invalid,
const DirectionModifier direction_modifier = DirectionModifier::Straight)
: type(type), direction_modifier(direction_modifier)
{
}
TurnType type : 5;
DirectionModifier direction_modifier : 3;
static TurnInstruction INVALID()
{
return TurnInstruction(TurnType::Invalid, DirectionModifier::UTurn);
}
static TurnInstruction NO_TURN()
{
return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
}
static TurnInstruction REMAIN_ROUNDABOUT(const DirectionModifier modifier)
{
return TurnInstruction(TurnType::StayOnRoundabout, modifier);
}
static TurnInstruction ENTER_ROUNDABOUT(const DirectionModifier modifier)
{
return TurnInstruction(TurnType::EnterRoundabout, modifier);
}
static TurnInstruction EXIT_ROUNDABOUT(const DirectionModifier modifier)
{
return TurnInstruction(TurnType::ExitRoundabout, modifier);
}
static TurnInstruction SUPPRESSED(const DirectionModifier modifier)
{
return TurnInstruction{TurnType::Suppressed,modifier};
}
};
inline bool operator!=(const TurnInstruction lhs, const TurnInstruction rhs)
{
return lhs.type != rhs.type || lhs.direction_modifier != rhs.direction_modifier;
}
inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
{
return lhs.type == rhs.type && lhs.direction_modifier == rhs.direction_modifier;
}
// Silent Turn Instructions are not to be mentioned to the outside world
inline bool isSilent(const TurnInstruction instruction)
{
return instruction.type == TurnType::NoTurn || instruction.type == TurnType::Suppressed ||
instruction.type == TurnType::StayOnRoundabout;
}
} // namespace guidance
} // namespace engine
} // namespace osrm
#endif // OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_