advanced guidance on 5.0
This commit is contained in:
committed by
Patrick Niklaus
parent
6f5c3067f1
commit
4b46dec169
@@ -1,7 +1,7 @@
|
||||
#ifndef ENGINE_RESPONSE_OBJECTS_HPP_
|
||||
#define ENGINE_RESPONSE_OBJECTS_HPP_
|
||||
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "engine/guidance/turn_instruction.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
#include "engine/polyline_compressor.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
@@ -32,7 +32,8 @@ namespace json
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::string instructionToString(extractor::TurnInstruction instruction);
|
||||
std::string instructionTypeToString(guidance::TurnType type);
|
||||
std::string instructionModifierToString(guidance::DirectionModifier modifier);
|
||||
|
||||
util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "engine/guidance/assemble_geometry.hpp"
|
||||
#include "engine/guidance/assemble_overview.hpp"
|
||||
#include "engine/guidance/assemble_steps.hpp"
|
||||
#include "engine/guidance/post_processing.hpp"
|
||||
|
||||
#include "engine/internal_route_result.hpp"
|
||||
|
||||
@@ -67,7 +68,7 @@ class RouteAPI : public BaseAPI
|
||||
}
|
||||
|
||||
util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates,
|
||||
const std::vector<std::vector<PathData>> &unpacked_path_segments,
|
||||
std::vector<std::vector<PathData>> unpacked_path_segments,
|
||||
const std::vector<bool> &source_traversed_in_reverse,
|
||||
const std::vector<bool> &target_traversed_in_reverse) const
|
||||
{
|
||||
@@ -76,10 +77,13 @@ class RouteAPI : public BaseAPI
|
||||
auto number_of_legs = segment_end_coordinates.size();
|
||||
legs.reserve(number_of_legs);
|
||||
leg_geometries.reserve(number_of_legs);
|
||||
|
||||
unpacked_path_segments = guidance::postProcess( std::move(unpacked_path_segments) );
|
||||
for (auto idx : util::irange(0UL, number_of_legs))
|
||||
{
|
||||
const auto &phantoms = segment_end_coordinates[idx];
|
||||
const auto &path_data = unpacked_path_segments[idx];
|
||||
|
||||
const bool reversed_source = source_traversed_in_reverse[idx];
|
||||
const bool reversed_target = target_traversed_in_reverse[idx];
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "extractor/external_memory_node.hpp"
|
||||
#include "contractor/query_edge.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "engine/guidance/turn_instruction.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
@@ -76,7 +76,7 @@ class BaseDataFacade
|
||||
virtual void GetUncompressedWeights(const EdgeID id,
|
||||
std::vector<EdgeWeight> &result_weights) const = 0;
|
||||
|
||||
virtual extractor::TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
|
||||
virtual guidance::TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
std::shared_ptr<util::ShM<util::Coordinate, false>::vector> m_coordinate_list;
|
||||
util::ShM<NodeID, false>::vector m_via_node_list;
|
||||
util::ShM<unsigned, false>::vector m_name_ID_list;
|
||||
util::ShM<extractor::TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
util::ShM<guidance::TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
util::ShM<extractor::TravelMode, false>::vector m_travel_mode_list;
|
||||
util::ShM<char, false>::vector m_names_char_list;
|
||||
util::ShM<unsigned, false>::vector m_geometry_indices;
|
||||
@@ -327,7 +327,7 @@ class InternalDataFacade final : public BaseDataFacade
|
||||
return m_coordinate_list->at(id);
|
||||
}
|
||||
|
||||
extractor::TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
guidance::TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
std::shared_ptr<util::ShM<util::Coordinate, true>::vector> m_coordinate_list;
|
||||
util::ShM<NodeID, true>::vector m_via_node_list;
|
||||
util::ShM<unsigned, true>::vector m_name_ID_list;
|
||||
util::ShM<extractor::TurnInstruction, true>::vector m_turn_instruction_list;
|
||||
util::ShM<guidance::TurnInstruction, true>::vector m_turn_instruction_list;
|
||||
util::ShM<extractor::TravelMode, true>::vector m_travel_mode_list;
|
||||
util::ShM<char, true>::vector m_names_char_list;
|
||||
util::ShM<unsigned, true>::vector m_name_begin_indices;
|
||||
@@ -145,9 +145,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]);
|
||||
m_travel_mode_list = std::move(travel_mode_list);
|
||||
|
||||
auto turn_instruction_list_ptr = data_layout->GetBlockPtr<extractor::TurnInstruction>(
|
||||
auto turn_instruction_list_ptr = data_layout->GetBlockPtr<guidance::TurnInstruction>(
|
||||
shared_memory, storage::SharedDataLayout::TURN_INSTRUCTION);
|
||||
typename util::ShM<extractor::TurnInstruction, true>::vector turn_instruction_list(
|
||||
typename util::ShM<guidance::TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
|
||||
m_turn_instruction_list = std::move(turn_instruction_list);
|
||||
@@ -398,7 +398,7 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
extractor::TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
guidance::TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "engine/guidance/leg_geometry.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "engine/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 != extractor::TurnInstruction::NoTurn)
|
||||
if (path_point.turn_instruction != TurnInstruction::NO_TURN())
|
||||
{
|
||||
geometry.segment_distances.push_back(current_distance);
|
||||
geometry.segment_offsets.push_back(geometry.locations.size());
|
||||
|
||||
@@ -134,7 +134,7 @@ RouteLeg assembleLeg(const DataFacadeT &facade,
|
||||
// `forward_weight`: duration of (d,t)
|
||||
// `forward_offset`: duration of (c, d)
|
||||
//
|
||||
// The PathData will contain entries of b, c and d. But only c will contain
|
||||
// The PathData will contain entries of b, c and d. But only c will contain //TODO discuss, this should not be the case after danpats fixes
|
||||
// a duration value since its the only point associated with a turn.
|
||||
// As such we want to slice of the duration for (a,s) and add the duration for
|
||||
// (c,d,t)
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#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/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
|
||||
#include <vector>
|
||||
@@ -22,9 +24,10 @@ namespace guidance
|
||||
namespace detail
|
||||
{
|
||||
// FIXME move implementation to cpp
|
||||
inline StepManeuver stepManeuverFromGeometry(const extractor::TurnInstruction instruction,
|
||||
inline StepManeuver stepManeuverFromGeometry(const TurnInstruction instruction,
|
||||
const LegGeometry &leg_geometry,
|
||||
std::size_t segment_index)
|
||||
const std::size_t segment_index,
|
||||
const unsigned exit)
|
||||
{
|
||||
auto turn_index = leg_geometry.BackIndex(segment_index);
|
||||
BOOST_ASSERT(turn_index > 0);
|
||||
@@ -40,7 +43,7 @@ inline StepManeuver stepManeuverFromGeometry(const extractor::TurnInstruction in
|
||||
const double post_turn_bearing =
|
||||
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
|
||||
|
||||
return StepManeuver{turn_coordinate, pre_turn_bearing, post_turn_bearing, instruction};
|
||||
return StepManeuver{turn_coordinate, pre_turn_bearing, post_turn_bearing, instruction, exit};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,28 +78,31 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
auto segment_index = 0;
|
||||
if (leg_data.size() > 0)
|
||||
{
|
||||
StepManeuver maneuver = detail::stepManeuverFromGeometry(extractor::TurnInstruction::StartAtEndOfStreet,
|
||||
leg_geometry, segment_index);
|
||||
StepManeuver maneuver = detail::stepManeuverFromGeometry(
|
||||
TurnInstruction{TurnType::Location, DirectionModifier::Straight}, 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 != extractor::TurnInstruction::NoTurn)
|
||||
if (path_point.turn_instruction != TurnInstruction::NO_TURN())
|
||||
{
|
||||
auto name = facade.get_name_for_id(path_point.name_id);
|
||||
const auto name = facade.get_name_for_id(path_point.name_id);
|
||||
const auto distance = leg_geometry.segment_distances[segment_index];
|
||||
steps.push_back(RouteStep{path_point.name_id, std::move(name),
|
||||
path_point.duration_until_turn / 10.0, distance,
|
||||
path_point.travel_mode, maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1});
|
||||
maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction,
|
||||
leg_geometry, segment_index);
|
||||
steps.push_back(RouteStep{
|
||||
path_point.name_id, name, path_point.duration_until_turn / 10.0, distance,
|
||||
path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1});
|
||||
maneuver = detail::stepManeuverFromGeometry(
|
||||
path_point.turn_instruction, leg_geometry, segment_index, path_point.exit);
|
||||
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,
|
||||
@@ -110,19 +116,24 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
// |-------------t target_duration
|
||||
// x---*---*---*---z compressed edge
|
||||
// |-------| duration
|
||||
StepManeuver maneuver = {source_node.location, 0., 0.,
|
||||
TurnInstruction{TurnType::Location, DirectionModifier::Straight},
|
||||
INVALID_EXIT_NR};
|
||||
|
||||
steps.push_back(RouteStep{
|
||||
source_node.name_id, facade.get_name_for_id(source_node.name_id),
|
||||
target_duration - source_duration, leg_geometry.segment_distances[segment_index],
|
||||
source_mode,
|
||||
StepManeuver{source_node.location, 0., 0., extractor::TurnInstruction::StartAtEndOfStreet},
|
||||
leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1});
|
||||
source_mode, std::move(maneuver), leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1});
|
||||
}
|
||||
|
||||
BOOST_ASSERT(segment_index == number_of_segments - 1);
|
||||
// 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., extractor::TurnInstruction::ReachedYourDestination},
|
||||
StepManeuver{target_node.location, 0., 0.,
|
||||
TurnInstruction{TurnType::Location, DirectionModifier::Straight},
|
||||
INVALID_EXIT_NR},
|
||||
leg_geometry.locations.size(), leg_geometry.locations.size()});
|
||||
|
||||
return steps;
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#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;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_GUIDANCE_CLASSIFICATION_DATA_HPP_
|
||||
@@ -0,0 +1,416 @@
|
||||
#ifndef OSRM_GUIDANCE_GUIDANCE_TOOLKIT_HPP_
|
||||
#define OSRM_GUIDANCE_GUIDANCE_TOOLKIT_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);
|
||||
}
|
||||
|
||||
inline bool leavesRoundabout(const TurnInstruction instruction)
|
||||
{
|
||||
return (instruction.type == TurnType::ExitRoundabout ||
|
||||
instruction.type == TurnType::ExitRotary);
|
||||
}
|
||||
|
||||
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 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_
|
||||
@@ -0,0 +1,243 @@
|
||||
#ifndef OSRM_GUIDANCE_INSTRUCTION_SYMBOLS_HPP
|
||||
#define OSRM_GUIDANCE_INSTRUCTION_SYMBOLS_HPP
|
||||
|
||||
#include "guidance/turn_instruction.hpp"
|
||||
#include "guidance/guidance_toolkit.hpp"
|
||||
|
||||
#include "util/simple_logger.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
enum class InstructionSymbol : 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
|
||||
};
|
||||
|
||||
inline InstructionSymbol directTranslation(const DirectionModifier direction_modifier)
|
||||
{
|
||||
const constexpr InstructionSymbol translation[] = {
|
||||
InstructionSymbol::UTurn, InstructionSymbol::TurnSharpRight,
|
||||
InstructionSymbol::TurnRight, InstructionSymbol::TurnSlightRight,
|
||||
InstructionSymbol::GoStraight, InstructionSymbol::TurnSlightLeft,
|
||||
InstructionSymbol::TurnLeft, InstructionSymbol::TurnSharpLeft};
|
||||
return translation[direction_modifier];
|
||||
}
|
||||
|
||||
inline bool canTranslateDirectly(const TurnType type)
|
||||
{
|
||||
return type == TurnType::Continue // remain on a street
|
||||
|| type == TurnType::NewName // no turn, but name changes
|
||||
|| type == TurnType::Turn // basic turn
|
||||
|| type == TurnType::Ramp // special turn (highway ramp exits)
|
||||
|| type == TurnType::Fork // fork road splitting up
|
||||
|| type == TurnType::EndOfRoad || type == TurnType::Restriction ||
|
||||
type == TurnType::Merge || type == TurnType::Notification;
|
||||
}
|
||||
|
||||
inline InstructionSymbol getSymbol(const TurnInstruction instruction)
|
||||
{
|
||||
if (canTranslateDirectly(instruction.type))
|
||||
{
|
||||
return directTranslation(instruction.direction_modifier);
|
||||
}
|
||||
else if (instruction.type == TurnType::EnterRoundabout ||
|
||||
instruction.type == TurnType::EnterRotary)
|
||||
{
|
||||
return InstructionSymbol::EnterRoundAbout;
|
||||
}
|
||||
else
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG)
|
||||
<< "Unreasonable request for symbol: "
|
||||
<< std::to_string(static_cast<int>(instruction.type)) << " "
|
||||
<< std::to_string(static_cast<int>(instruction.direction_modifier));
|
||||
return InstructionSymbol::NoTurn;
|
||||
}
|
||||
}
|
||||
|
||||
inline InstructionSymbol getLocationSymbol(const LocationType type)
|
||||
{
|
||||
if (type == LocationType::Start)
|
||||
return InstructionSymbol::HeadOn;
|
||||
if (type == LocationType::Intermediate)
|
||||
return InstructionSymbol::ReachViaLocation;
|
||||
if (type == LocationType::Destination)
|
||||
return InstructionSymbol::ReachedYourDestination;
|
||||
return InstructionSymbol::NoTurn;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// 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
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_GUIDANCE_INSTRUCTION_SYMBOLS_HPP */
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef ENGINE_GUIDANCE_POST_PROCESSING_HPP
|
||||
#define ENGINE_GUIDANCE_POST_PROCESSING_HPP
|
||||
|
||||
#include "engine/internal_route_result.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
std::vector<std::vector<PathData>> postProcess( std::vector<std::vector<PathData>> path_data );
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif // ENGINE_GUIDANCE_POST_PROCESSING_HPP
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
||||
#define ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
||||
|
||||
#include "engine/segment_inforamtion.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
/*
|
||||
Simplify turn instructions
|
||||
Input :
|
||||
10. Turn left on B 36 for 20 km
|
||||
11. Continue on B 35; B 36 for 2 km
|
||||
12. Continue on B 36 for 13 km
|
||||
|
||||
Output:
|
||||
10. Turn left on B 36 for 35 km
|
||||
*/
|
||||
|
||||
inline void CombineSimilarSegments(std::vector<SegmentInformation> &segments)
|
||||
{
|
||||
// TODO: rework to check only end and start of string.
|
||||
// stl string is way to expensive
|
||||
// unsigned lastTurn = 0;
|
||||
// for(unsigned i = 1; i < path_description.size(); ++i) {
|
||||
// string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
|
||||
// if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
|
||||
// if(std::string::npos != string0.find(string1+";")
|
||||
// || std::string::npos != string0.find(";"+string1)
|
||||
// || std::string::npos != string0.find(string1+" ;")
|
||||
// || std::string::npos != string0.find("; "+string1)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
|
||||
// string1;
|
||||
// for(; lastTurn != i; ++lastTurn)
|
||||
// path_description[lastTurn].name_id = path_description[i].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// } else if(std::string::npos != string1.find(string0+";")
|
||||
// || std::string::npos != string1.find(";"+string0)
|
||||
// || std::string::npos != string1.find(string0+" ;")
|
||||
// || std::string::npos != string1.find("; "+string0)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
|
||||
// string0;
|
||||
// path_description[i].name_id = path_description[i-1].name_id;
|
||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
//
|
||||
}
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
#endif // ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
||||
@@ -2,7 +2,7 @@
|
||||
#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "engine/guidance/turn_instruction.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -16,9 +16,10 @@ struct StepManeuver
|
||||
util::Coordinate location;
|
||||
double bearing_before;
|
||||
double bearing_after;
|
||||
extractor::TurnInstruction instruction;
|
||||
TurnInstruction instruction;
|
||||
unsigned exit;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace guidance
|
||||
} // namespace engine
|
||||
} // namespace osrmn
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#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 = 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_
|
||||
@@ -0,0 +1,154 @@
|
||||
#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
|
||||
ExitRoundabout, // Exiting a small Roundabout
|
||||
EnterRotary, // Enter a rotary
|
||||
EnterRotaryAtExit, // Enter A Rotary at a countable exit
|
||||
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`
|
||||
};
|
||||
|
||||
const constexpr char *turn_type_names[] = {"invalid",
|
||||
"no turn",
|
||||
"waypoint",
|
||||
"passing intersection",
|
||||
"new name",
|
||||
"continue",
|
||||
"turn",
|
||||
"merge",
|
||||
"ramp",
|
||||
"fork",
|
||||
"end of road",
|
||||
"roundabout",
|
||||
"invalid"
|
||||
"invalid",
|
||||
"traffic circle",
|
||||
"invalid",
|
||||
"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::Straight);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
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_
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "guidance/turn_instruction.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
@@ -15,6 +15,8 @@ namespace osrm
|
||||
namespace engine
|
||||
{
|
||||
|
||||
const constexpr unsigned INVALID_EXIT_NR = 0;
|
||||
|
||||
struct PathData
|
||||
{
|
||||
// id of via node of the turn
|
||||
@@ -24,9 +26,11 @@ struct PathData
|
||||
// duration that is traveled on the segment until the turn is reached
|
||||
EdgeWeight duration_until_turn;
|
||||
// instruction to execute at the turn
|
||||
extractor::TurnInstruction turn_instruction;
|
||||
guidance::TurnInstruction turn_instruction;
|
||||
// travel mode of the street that leads to the turn
|
||||
extractor::TravelMode travel_mode : 4;
|
||||
// exit ID of highway exit, roundabout exit, intersection nr
|
||||
unsigned exit;
|
||||
};
|
||||
|
||||
struct InternalRouteResult
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace engine
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
constexpr double POLYLINE_PECISION = 1e5;
|
||||
constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PECISION / COORDINATE_PRECISION;
|
||||
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PECISION;
|
||||
constexpr double POLYLINE_PRECISION = 1e5;
|
||||
constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PRECISION / COORDINATE_PRECISION;
|
||||
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PRECISION;
|
||||
}
|
||||
|
||||
using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
#include "extractor/turn_instructions.hpp"
|
||||
#include "engine/guidance/turn_instruction.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
@@ -283,7 +283,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
|
||||
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
|
||||
const extractor::TurnInstruction turn_instruction =
|
||||
const guidance::TurnInstruction turn_instruction =
|
||||
facade->GetTurnInstructionForEdgeID(ed.id);
|
||||
const extractor::TravelMode travel_mode =
|
||||
(unpacked_path.empty() && start_traversed_in_reverse)
|
||||
@@ -320,9 +320,9 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
BOOST_ASSERT(start_index < end_index);
|
||||
for (std::size_t i = start_index; i < end_index; ++i)
|
||||
{
|
||||
unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i],
|
||||
extractor::TurnInstruction::NoTurn,
|
||||
travel_mode});
|
||||
unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i],
|
||||
guidance::TurnInstruction::NO_TURN(),
|
||||
travel_mode, INVALID_EXIT_NR});
|
||||
}
|
||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
||||
unpacked_path.back().turn_instruction = turn_instruction;
|
||||
@@ -363,12 +363,12 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
BOOST_ASSERT(i < id_vector.size());
|
||||
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
|
||||
unpacked_path.emplace_back(
|
||||
PathData{id_vector[i], phantom_node_pair.target_phantom.name_id, 0,
|
||||
extractor::TurnInstruction::NoTurn,
|
||||
target_traversed_in_reverse
|
||||
? phantom_node_pair.target_phantom.backward_travel_mode
|
||||
: phantom_node_pair.target_phantom.forward_travel_mode});
|
||||
unpacked_path.emplace_back(PathData{
|
||||
id_vector[i], phantom_node_pair.target_phantom.name_id, 0,
|
||||
guidance::TurnInstruction::NO_TURN(),
|
||||
target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode
|
||||
: phantom_node_pair.target_phantom.forward_travel_mode,
|
||||
INVALID_EXIT_NR});
|
||||
}
|
||||
|
||||
// there is no equivalent to a node-based node in an edge-expanded graph.
|
||||
|
||||
Reference in New Issue
Block a user