advanced guidance on 5.0

This commit is contained in:
Moritz Kobitzsch 2016-02-24 10:29:23 +01:00 committed by Patrick Niklaus
parent 33f083b213
commit ef1e0e14ec
37 changed files with 1638 additions and 412 deletions

View File

@ -55,11 +55,12 @@ configure_file(
${CMAKE_CURRENT_BINARY_DIR}/include/util/version.hpp ${CMAKE_CURRENT_BINARY_DIR}/include/util/version.hpp
) )
file(GLOB UtilGlob src/util/*.cpp) file(GLOB UtilGlob src/util/*.cpp)
file(GLOB ExtractorGlob src/extractor/*.cpp) file(GLOB ExtractorGlob src/extractor/*.cpp src/engine/guidance/classification_data.cpp)
file(GLOB ContractorGlob src/contractor/*.cpp) file(GLOB ContractorGlob src/contractor/*.cpp)
file(GLOB StorageGlob src/storage/*.cpp) file(GLOB StorageGlob src/storage/*.cpp)
file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp) file(GLOB ServerGlob src/server/*.cpp src/server/**/*.cpp)
file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp) file(GLOB EngineGlob src/engine/*.cpp src/engine/**/*.cpp)
file(GLOB GuidanceGlob src/guidance/*.cpp src/guidance/**/*.cpp)
file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp) file(GLOB ExtractorTestsGlob unit_tests/extractor/*.cpp)
file(GLOB EngineTestsGlob unit_tests/engine/*.cpp) file(GLOB EngineTestsGlob unit_tests/engine/*.cpp)
file(GLOB UtilTestsGlob unit_tests/util/*.cpp) file(GLOB UtilTestsGlob unit_tests/util/*.cpp)
@ -71,6 +72,7 @@ add_library(EXTRACTOR OBJECT ${ExtractorGlob})
add_library(CONTRACTOR OBJECT ${ContractorGlob}) add_library(CONTRACTOR OBJECT ${ContractorGlob})
add_library(STORAGE OBJECT ${StorageGlob}) add_library(STORAGE OBJECT ${StorageGlob})
add_library(ENGINE OBJECT ${EngineGlob}) add_library(ENGINE OBJECT ${EngineGlob})
add_library(GUIDANCE OBJECT ${GuidanceGlob})
add_library(SERVER OBJECT ${ServerGlob}) add_library(SERVER OBJECT ${ServerGlob})
add_dependencies(UTIL FingerPrintConfigure) add_dependencies(UTIL FingerPrintConfigure)
@ -80,7 +82,7 @@ add_executable(osrm-extract src/tools/extract.cpp)
add_executable(osrm-contract src/tools/contract.cpp) add_executable(osrm-contract src/tools/contract.cpp)
add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>) add_executable(osrm-routed src/tools/routed.cpp $<TARGET_OBJECTS:SERVER> $<TARGET_OBJECTS:UTIL>)
add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:UTIL>) add_executable(osrm-datastore src/tools/store.cpp $<TARGET_OBJECTS:UTIL>)
add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:UTIL>) add_library(osrm src/osrm/osrm.cpp $<TARGET_OBJECTS:ENGINE> $<TARGET_OBJECTS:GUIDANCE> $<TARGET_OBJECTS:UTIL>)
add_library(osrm_extract $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>) add_library(osrm_extract $<TARGET_OBJECTS:EXTRACTOR> $<TARGET_OBJECTS:UTIL>)
add_library(osrm_contract $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>) add_library(osrm_contract $<TARGET_OBJECTS:CONTRACTOR> $<TARGET_OBJECTS:UTIL>)
add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>) add_library(osrm_store $<TARGET_OBJECTS:STORAGE> $<TARGET_OBJECTS:UTIL>)

View File

@ -1,7 +1,7 @@
#ifndef ENGINE_RESPONSE_OBJECTS_HPP_ #ifndef ENGINE_RESPONSE_OBJECTS_HPP_
#define 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 "extractor/travel_mode.hpp"
#include "engine/polyline_compressor.hpp" #include "engine/polyline_compressor.hpp"
#include "engine/guidance/route_step.hpp" #include "engine/guidance/route_step.hpp"
@ -32,7 +32,8 @@ namespace json
namespace detail 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); util::json::Array coordinateToLonLat(const util::Coordinate coordinate);

View File

@ -12,6 +12,7 @@
#include "engine/guidance/assemble_geometry.hpp" #include "engine/guidance/assemble_geometry.hpp"
#include "engine/guidance/assemble_overview.hpp" #include "engine/guidance/assemble_overview.hpp"
#include "engine/guidance/assemble_steps.hpp" #include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/post_processing.hpp"
#include "engine/internal_route_result.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, 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> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const 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(); auto number_of_legs = segment_end_coordinates.size();
legs.reserve(number_of_legs); legs.reserve(number_of_legs);
leg_geometries.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)) for (auto idx : util::irange(0UL, number_of_legs))
{ {
const auto &phantoms = segment_end_coordinates[idx]; const auto &phantoms = segment_end_coordinates[idx];
const auto &path_data = unpacked_path_segments[idx]; const auto &path_data = unpacked_path_segments[idx];
const bool reversed_source = source_traversed_in_reverse[idx]; const bool reversed_source = source_traversed_in_reverse[idx];
const bool reversed_target = target_traversed_in_reverse[idx]; const bool reversed_target = target_traversed_in_reverse[idx];

View File

@ -7,7 +7,7 @@
#include "extractor/external_memory_node.hpp" #include "extractor/external_memory_node.hpp"
#include "contractor/query_edge.hpp" #include "contractor/query_edge.hpp"
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "extractor/turn_instructions.hpp" #include "engine/guidance/turn_instruction.hpp"
#include "util/integer_range.hpp" #include "util/integer_range.hpp"
#include "util/exception.hpp" #include "util/exception.hpp"
#include "util/string_util.hpp" #include "util/string_util.hpp"
@ -76,7 +76,7 @@ class BaseDataFacade
virtual void GetUncompressedWeights(const EdgeID id, virtual void GetUncompressedWeights(const EdgeID id,
std::vector<EdgeWeight> &result_weights) const = 0; 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; virtual extractor::TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;

View File

@ -68,7 +68,7 @@ class InternalDataFacade final : public BaseDataFacade
std::shared_ptr<util::ShM<util::Coordinate, false>::vector> m_coordinate_list; std::shared_ptr<util::ShM<util::Coordinate, false>::vector> m_coordinate_list;
util::ShM<NodeID, false>::vector m_via_node_list; util::ShM<NodeID, false>::vector m_via_node_list;
util::ShM<unsigned, false>::vector m_name_ID_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<extractor::TravelMode, false>::vector m_travel_mode_list;
util::ShM<char, false>::vector m_names_char_list; util::ShM<char, false>::vector m_names_char_list;
util::ShM<unsigned, false>::vector m_geometry_indices; util::ShM<unsigned, false>::vector m_geometry_indices;
@ -327,7 +327,7 @@ class InternalDataFacade final : public BaseDataFacade
return m_coordinate_list->at(id); 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); return m_turn_instruction_list.at(id);
} }

View File

@ -70,7 +70,7 @@ class SharedDataFacade final : public BaseDataFacade
std::shared_ptr<util::ShM<util::Coordinate, true>::vector> m_coordinate_list; std::shared_ptr<util::ShM<util::Coordinate, true>::vector> m_coordinate_list;
util::ShM<NodeID, true>::vector m_via_node_list; util::ShM<NodeID, true>::vector m_via_node_list;
util::ShM<unsigned, true>::vector m_name_ID_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<extractor::TravelMode, true>::vector m_travel_mode_list;
util::ShM<char, true>::vector m_names_char_list; util::ShM<char, true>::vector m_names_char_list;
util::ShM<unsigned, true>::vector m_name_begin_indices; 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]); travel_mode_list_ptr, data_layout->num_entries[storage::SharedDataLayout::TRAVEL_MODE]);
m_travel_mode_list = std::move(travel_mode_list); 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); 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, turn_instruction_list_ptr,
data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]); data_layout->num_entries[storage::SharedDataLayout::TURN_INSTRUCTION]);
m_turn_instruction_list = std::move(turn_instruction_list); 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); 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); return m_turn_instruction_list.at(id);
} }

View File

@ -7,7 +7,7 @@
#include "engine/guidance/leg_geometry.hpp" #include "engine/guidance/leg_geometry.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp" #include "engine/guidance/turn_instruction.hpp"
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include <vector> #include <vector>
@ -49,7 +49,7 @@ LegGeometry assembleGeometry(const DataFacadeT &facade,
current_distance += current_distance +=
util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate); 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_distances.push_back(current_distance);
geometry.segment_offsets.push_back(geometry.locations.size()); geometry.segment_offsets.push_back(geometry.locations.size());

View File

@ -134,7 +134,7 @@ RouteLeg assembleLeg(const DataFacadeT &facade,
// `forward_weight`: duration of (d,t) // `forward_weight`: duration of (d,t)
// `forward_offset`: duration of (c, d) // `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. // 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 // As such we want to slice of the duration for (a,s) and add the duration for
// (c,d,t) // (c,d,t)

View File

@ -4,11 +4,13 @@
#include "engine/guidance/route_step.hpp" #include "engine/guidance/route_step.hpp"
#include "engine/guidance/step_maneuver.hpp" #include "engine/guidance/step_maneuver.hpp"
#include "engine/guidance/leg_geometry.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/internal_route_result.hpp"
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp" #include "util/bearing.hpp"
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include <vector> #include <vector>
@ -22,9 +24,10 @@ namespace guidance
namespace detail namespace detail
{ {
// FIXME move implementation to cpp // FIXME move implementation to cpp
inline StepManeuver stepManeuverFromGeometry(const extractor::TurnInstruction instruction, inline StepManeuver stepManeuverFromGeometry(const TurnInstruction instruction,
const LegGeometry &leg_geometry, 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); auto turn_index = leg_geometry.BackIndex(segment_index);
BOOST_ASSERT(turn_index > 0); BOOST_ASSERT(turn_index > 0);
@ -40,7 +43,7 @@ inline StepManeuver stepManeuverFromGeometry(const extractor::TurnInstruction in
const double post_turn_bearing = const double post_turn_bearing =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate); 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; auto segment_index = 0;
if (leg_data.size() > 0) if (leg_data.size() > 0)
{ {
StepManeuver maneuver = detail::stepManeuverFromGeometry(extractor::TurnInstruction::StartAtEndOfStreet, StepManeuver maneuver = detail::stepManeuverFromGeometry(
leg_geometry, segment_index); 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, // PathData saves the information we need of the segment _before_ the turn,
// but a RouteStep is with regard to the segment after 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 // 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) 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]; const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{path_point.name_id, std::move(name), steps.push_back(RouteStep{
path_point.duration_until_turn / 10.0, distance, path_point.name_id, name, path_point.duration_until_turn / 10.0, distance,
path_point.travel_mode, maneuver, path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index),
leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1});
leg_geometry.BackIndex(segment_index) + 1}); maneuver = detail::stepManeuverFromGeometry(
maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction, path_point.turn_instruction, leg_geometry, segment_index, path_point.exit);
leg_geometry, segment_index);
segment_index++; segment_index++;
} }
} }
// TODO remove this hack
const auto distance = leg_geometry.segment_distances[segment_index]; 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), steps.push_back(RouteStep{target_node.name_id, facade.get_name_for_id(target_node.name_id),
target_duration, distance, target_mode, maneuver, target_duration, distance, target_mode, maneuver,
@ -110,19 +116,24 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
// |-------------t target_duration // |-------------t target_duration
// x---*---*---*---z compressed edge // x---*---*---*---z compressed edge
// |-------| duration // |-------| duration
StepManeuver maneuver = {source_node.location, 0., 0.,
TurnInstruction{TurnType::Location, DirectionModifier::Straight},
INVALID_EXIT_NR};
steps.push_back(RouteStep{ steps.push_back(RouteStep{
source_node.name_id, facade.get_name_for_id(source_node.name_id), source_node.name_id, facade.get_name_for_id(source_node.name_id),
target_duration - source_duration, leg_geometry.segment_distances[segment_index], target_duration - source_duration, leg_geometry.segment_distances[segment_index],
source_mode, source_mode, std::move(maneuver), leg_geometry.FrontIndex(segment_index),
StepManeuver{source_node.location, 0., 0., extractor::TurnInstruction::StartAtEndOfStreet}, leg_geometry.BackIndex(segment_index) + 1});
leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1});
} }
BOOST_ASSERT(segment_index == number_of_segments - 1); BOOST_ASSERT(segment_index == number_of_segments - 1);
// This step has length zero, the only reason we need it is the target location // This step has length zero, the only reason we need it is the target location
steps.push_back(RouteStep{ steps.push_back(RouteStep{
target_node.name_id, facade.get_name_for_id(target_node.name_id), 0., 0., target_mode, 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()}); leg_geometry.locations.size(), leg_geometry.locations.size()});
return steps; return steps;

View File

@ -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_

View File

@ -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_

View File

@ -1,17 +1,19 @@
#ifndef TURN_INSTRUCTIONS_HPP #ifndef OSRM_GUIDANCE_INSTRUCTION_SYMBOLS_HPP
#define TURN_INSTRUCTIONS_HPP #define OSRM_GUIDANCE_INSTRUCTION_SYMBOLS_HPP
#include <algorithm> #include "guidance/turn_instruction.hpp"
#include <cmath> #include "guidance/guidance_toolkit.hpp"
#include <boost/assert.hpp> #include "util/simple_logger.hpp"
namespace osrm namespace osrm
{ {
namespace extractor namespace engine
{
namespace guidance
{ {
enum class TurnInstruction : unsigned char enum class InstructionSymbol : unsigned char
{ {
NoTurn = 0, NoTurn = 0,
GoStraight, GoStraight,
@ -37,6 +39,60 @@ enum class TurnInstruction : unsigned char
AccessRestrictionPenalty = 129 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 // shiftable turns to left and right
const constexpr bool shiftable_left[] = {false, false, true, true, true, false, false, true, true}; 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}; const constexpr bool shiftable_right[] = {false, false, true, true, false, false, true, true, true};
@ -178,5 +234,10 @@ inline bool isConflict(const TurnInstruction first, const TurnInstruction second
} }
} }
} }
#endif
#endif /* TURN_INSTRUCTIONS_HPP */ } // namespace guidance
} // namespace engine
} // namespace osrm
#endif /* OSRM_GUIDANCE_INSTRUCTION_SYMBOLS_HPP */

View File

@ -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

View File

@ -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_

View File

@ -2,7 +2,7 @@
#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP #define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include "extractor/turn_instructions.hpp" #include "engine/guidance/turn_instruction.hpp"
namespace osrm namespace osrm
{ {
@ -16,9 +16,10 @@ struct StepManeuver
util::Coordinate location; util::Coordinate location;
double bearing_before; double bearing_before;
double bearing_after; double bearing_after;
extractor::TurnInstruction instruction; TurnInstruction instruction;
unsigned exit;
}; };
} } // namespace guidance
} } // namespace engine
} } // namespace osrmn
#endif #endif

View File

@ -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_

View File

@ -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_

View File

@ -3,7 +3,7 @@
#include "engine/phantom_node.hpp" #include "engine/phantom_node.hpp"
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "extractor/turn_instructions.hpp" #include "guidance/turn_instruction.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "osrm/coordinate.hpp" #include "osrm/coordinate.hpp"
@ -15,6 +15,8 @@ namespace osrm
namespace engine namespace engine
{ {
const constexpr unsigned INVALID_EXIT_NR = 0;
struct PathData struct PathData
{ {
// id of via node of the turn // 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 // duration that is traveled on the segment until the turn is reached
EdgeWeight duration_until_turn; EdgeWeight duration_until_turn;
// instruction to execute at the 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 // travel mode of the street that leads to the turn
extractor::TravelMode travel_mode : 4; extractor::TravelMode travel_mode : 4;
// exit ID of highway exit, roundabout exit, intersection nr
unsigned exit;
}; };
struct InternalRouteResult struct InternalRouteResult

View File

@ -12,9 +12,9 @@ namespace engine
{ {
namespace detail namespace detail
{ {
constexpr double POLYLINE_PECISION = 1e5; constexpr double POLYLINE_PRECISION = 1e5;
constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PECISION / COORDINATE_PRECISION; constexpr double COORDINATE_TO_POLYLINE = POLYLINE_PRECISION / COORDINATE_PRECISION;
constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PECISION; constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_PRECISION;
} }
using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator; using CoordVectorForwardIter = std::vector<util::Coordinate>::const_iterator;

View File

@ -4,7 +4,7 @@
#include "util/coordinate_calculation.hpp" #include "util/coordinate_calculation.hpp"
#include "engine/internal_route_result.hpp" #include "engine/internal_route_result.hpp"
#include "engine/search_engine_data.hpp" #include "engine/search_engine_data.hpp"
#include "extractor/turn_instructions.hpp" #include "engine/guidance/turn_instruction.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <boost/assert.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"); BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id); unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
const extractor::TurnInstruction turn_instruction = const guidance::TurnInstruction turn_instruction =
facade->GetTurnInstructionForEdgeID(ed.id); facade->GetTurnInstructionForEdgeID(ed.id);
const extractor::TravelMode travel_mode = const extractor::TravelMode travel_mode =
(unpacked_path.empty() && start_traversed_in_reverse) (unpacked_path.empty() && start_traversed_in_reverse)
@ -320,9 +320,9 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface
BOOST_ASSERT(start_index < end_index); BOOST_ASSERT(start_index < end_index);
for (std::size_t i = start_index; i < end_index; ++i) for (std::size_t i = start_index; i < end_index; ++i)
{ {
unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i], unpacked_path.push_back(PathData{id_vector[i], name_index, weight_vector[i],
extractor::TurnInstruction::NoTurn, guidance::TurnInstruction::NO_TURN(),
travel_mode}); travel_mode, INVALID_EXIT_NR});
} }
BOOST_ASSERT(unpacked_path.size() > 0); BOOST_ASSERT(unpacked_path.size() > 0);
unpacked_path.back().turn_instruction = turn_instruction; 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(i < id_vector.size());
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0); BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
unpacked_path.emplace_back( unpacked_path.emplace_back(PathData{
PathData{id_vector[i], phantom_node_pair.target_phantom.name_id, 0, id_vector[i], phantom_node_pair.target_phantom.name_id, 0,
extractor::TurnInstruction::NoTurn, guidance::TurnInstruction::NO_TURN(),
target_traversed_in_reverse target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode
? phantom_node_pair.target_phantom.backward_travel_mode : phantom_node_pair.target_phantom.forward_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. // there is no equivalent to a node-based node in an edge-expanded graph.

View File

@ -5,15 +5,17 @@
#include "extractor/edge_based_edge.hpp" #include "extractor/edge_based_edge.hpp"
#include "extractor/speed_profile.hpp" #include "extractor/speed_profile.hpp"
#include "util/typedefs.hpp" #include "extractor/restriction_map.hpp"
#include "extractor/compressed_edge_container.hpp" #include "extractor/compressed_edge_container.hpp"
#include "util/deallocating_vector.hpp"
#include "extractor/edge_based_node.hpp" #include "extractor/edge_based_node.hpp"
#include "extractor/original_edge_data.hpp" #include "extractor/original_edge_data.hpp"
#include "extractor/query_node.hpp" #include "extractor/query_node.hpp"
#include "extractor/turn_instructions.hpp"
#include "engine/guidance/turn_instruction.hpp"
#include "util/node_based_graph.hpp" #include "util/node_based_graph.hpp"
#include "extractor/restriction_map.hpp" #include "util/typedefs.hpp"
#include "util/deallocating_vector.hpp"
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
@ -68,12 +70,12 @@ class EdgeBasedGraphFactory
// with known angle. // with known angle.
// Handles special cases like u-turns and roundabouts // Handles special cases like u-turns and roundabouts
// For basic turns, the turn based on the angle-classification is returned // For basic turns, the turn based on the angle-classification is returned
TurnInstruction AnalyzeTurn(const NodeID u, engine::guidance::TurnInstruction AnalyzeTurn(const NodeID u,
const EdgeID e1, const EdgeID e1,
const NodeID v, const NodeID v,
const EdgeID e2, const EdgeID e2,
const NodeID w, const NodeID w,
const double angle) const; const double angle) const;
std::int32_t GetTurnPenalty(double angle, lua_State *lua_state) const; std::int32_t GetTurnPenalty(double angle, lua_State *lua_state) const;
@ -130,9 +132,9 @@ class EdgeBasedGraphFactory
{ {
EdgeID eid; // the id of the arc EdgeID eid; // the id of the arc
bool valid; // a turn may be relevant to good instructions, even if we cannot take the road bool valid; // a turn may be relevant to good instructions, even if we cannot take the road
double angle; // the approximated angle of the turn double angle; // the approximated angle of the turn
TurnInstruction instruction; // a proposed instruction engine::guidance::TurnInstruction instruction; // a proposed instruction
double confidence; // how close to the border is the turn? double confidence; // how close to the border is the turn?
std::string toString() const std::string toString() const
{ {
@ -143,7 +145,8 @@ class EdgeBasedGraphFactory
result += " angle: "; result += " angle: ";
result += std::to_string(angle); result += std::to_string(angle);
result += " instruction: "; result += " instruction: ";
result += std::to_string(static_cast<std::int32_t>(instruction)); result += std::to_string(static_cast<std::int32_t>(instruction.type)) + " " +
std::to_string(static_cast<std::int32_t>(instruction.direction_modifier));
result += " confidence: "; result += " confidence: ";
result += std::to_string(confidence); result += std::to_string(confidence);
return result; return result;
@ -153,19 +156,23 @@ class EdgeBasedGraphFactory
// Use In Order to generate base turns // Use In Order to generate base turns
// cannot be const due to the counters... // cannot be const due to the counters...
std::vector<TurnCandidate> getTurnCandidates(NodeID from, EdgeID via_edge); std::vector<TurnCandidate> getTurnCandidates(const NodeID from, const EdgeID via_edge);
std::vector<TurnCandidate> optimizeCandidates(NodeID via_edge, std::vector<TurnCandidate> optimizeCandidates(const EdgeID via_edge,
std::vector<TurnCandidate> turn_candidates) const; std::vector<TurnCandidate> turn_candidates) const;
std::vector<TurnCandidate> suppressTurns(EdgeID via_edge,
std::vector<TurnCandidate> optimizeRamps(const EdgeID via_edge,
std::vector<TurnCandidate> turn_candidates) const; std::vector<TurnCandidate> turn_candidates) const;
QueryNode getRepresentativeCoordinate(const NodeID src, engine::guidance::TurnType
const NodeID tgt, checkForkAndEnd(const EdgeID via_edge, const std::vector<TurnCandidate> &turn_candidates) const;
const EdgeID via_eid, std::vector<TurnCandidate> handleForkAndEnd(const engine::guidance::TurnType type,
bool INVERTED) const; std::vector<TurnCandidate> turn_candidates) const;
bool isObviousChoice(EdgeID coming_from_eid, std::vector<TurnCandidate> suppressTurns(const EdgeID via_edge,
std::size_t turn_index, std::vector<TurnCandidate> turn_candidates) const;
bool isObviousChoice(const EdgeID coming_from_eid,
const std::size_t turn_index,
const std::vector<TurnCandidate> &turn_candidates) const; const std::vector<TurnCandidate> &turn_candidates) const;
std::size_t restricted_turns_counter; std::size_t restricted_turns_counter;

View File

@ -3,6 +3,7 @@
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "engine/guidance/classification_data.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
@ -33,6 +34,7 @@ struct ExtractionWay
name.clear(); name.clear();
forward_travel_mode = TRAVEL_MODE_INACCESSIBLE; forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
backward_travel_mode = TRAVEL_MODE_INACCESSIBLE; backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
road_classification_data.invalidate();
} }
// These accessors exists because it's not possible to take the address of a bitfield, // These accessors exists because it's not possible to take the address of a bitfield,
@ -51,6 +53,7 @@ struct ExtractionWay
bool is_startpoint; bool is_startpoint;
TravelMode forward_travel_mode : 4; TravelMode forward_travel_mode : 4;
TravelMode backward_travel_mode : 4; TravelMode backward_travel_mode : 4;
engine::guidance::RoadClassificationData road_classification_data;
}; };
} }
} }

View File

@ -9,6 +9,7 @@
#include "osrm/coordinate.hpp" #include "osrm/coordinate.hpp"
#include <utility> #include <utility>
#include "engine/guidance/classification_data.hpp"
namespace osrm namespace osrm
{ {
@ -50,7 +51,8 @@ struct InternalExtractorEdge
false, false,
true, true,
TRAVEL_MODE_INACCESSIBLE, TRAVEL_MODE_INACCESSIBLE,
false) false,
engine::guidance::RoadClassificationData::INVALID())
{ {
} }
@ -64,7 +66,8 @@ struct InternalExtractorEdge
bool access_restricted, bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split) bool is_split,
engine::guidance::RoadClassificationData road_classification)
: result(OSMNodeID(source), : result(OSMNodeID(source),
OSMNodeID(target), OSMNodeID(target),
name_id, name_id,
@ -75,7 +78,8 @@ struct InternalExtractorEdge
access_restricted, access_restricted,
startpoint, startpoint,
travel_mode, travel_mode,
is_split), is_split,
std::move(road_classification)),
weight_data(std::move(weight_data)) weight_data(std::move(weight_data))
{ {
} }
@ -91,12 +95,14 @@ struct InternalExtractorEdge
static InternalExtractorEdge min_osm_value() static InternalExtractorEdge min_osm_value()
{ {
return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false, return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false,
false, false, true, TRAVEL_MODE_INACCESSIBLE, false); false, false, true, TRAVEL_MODE_INACCESSIBLE, false,
engine::guidance::RoadClassificationData::INVALID());
} }
static InternalExtractorEdge max_osm_value() static InternalExtractorEdge max_osm_value()
{ {
return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false, false, return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false, false,
false, false, true, TRAVEL_MODE_INACCESSIBLE, false); false, false, true, TRAVEL_MODE_INACCESSIBLE, false,
engine::guidance::RoadClassificationData::INVALID());
} }
static InternalExtractorEdge min_internal_value() static InternalExtractorEdge min_internal_value()

View File

@ -4,6 +4,8 @@
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include "engine/guidance/classification_data.hpp"
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
@ -23,7 +25,8 @@ struct NodeBasedEdge
bool access_restricted, bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split); bool is_split,
engine::guidance::RoadClassificationData road_classification);
bool operator<(const NodeBasedEdge &other) const; bool operator<(const NodeBasedEdge &other) const;
@ -38,6 +41,7 @@ struct NodeBasedEdge
bool startpoint : 1; bool startpoint : 1;
bool is_split : 1; bool is_split : 1;
TravelMode travel_mode : 4; TravelMode travel_mode : 4;
engine::guidance::RoadClassificationData road_classification;
}; };
struct NodeBasedEdgeWithOSM : NodeBasedEdge struct NodeBasedEdgeWithOSM : NodeBasedEdge
@ -52,7 +56,8 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
bool access_restricted, bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split); bool is_split,
engine::guidance::RoadClassificationData road_classification);
OSMNodeID osm_source_id; OSMNodeID osm_source_id;
OSMNodeID osm_target_id; OSMNodeID osm_target_id;
@ -65,6 +70,7 @@ inline NodeBasedEdge::NodeBasedEdge()
backward(false), roundabout(false), access_restricted(false), startpoint(true), backward(false), roundabout(false), access_restricted(false), startpoint(true),
is_split(false), travel_mode(false) is_split(false), travel_mode(false)
{ {
road_classification.invalidate();
} }
inline NodeBasedEdge::NodeBasedEdge(NodeID source, inline NodeBasedEdge::NodeBasedEdge(NodeID source,
@ -77,10 +83,12 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
bool access_restricted, bool access_restricted,
bool startpoint, bool startpoint,
TravelMode travel_mode, TravelMode travel_mode,
bool is_split) bool is_split,
engine::guidance::RoadClassificationData road_classification)
: source(source), target(target), name_id(name_id), weight(weight), forward(forward), : source(source), target(target), name_id(name_id), weight(weight), forward(forward),
backward(backward), roundabout(roundabout), access_restricted(access_restricted), backward(backward), roundabout(roundabout), access_restricted(access_restricted),
startpoint(startpoint), is_split(is_split), travel_mode(travel_mode) startpoint(startpoint), is_split(is_split), travel_mode(travel_mode),
road_classification(std::move(road_classification))
{ {
} }
@ -101,17 +109,19 @@ inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
return source < other.source; return source < other.source;
} }
inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source, inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(
OSMNodeID target, OSMNodeID source,
NodeID name_id, OSMNodeID target,
EdgeWeight weight, NodeID name_id,
bool forward, EdgeWeight weight,
bool backward, bool forward,
bool roundabout, bool backward,
bool access_restricted, bool roundabout,
bool startpoint, bool access_restricted,
TravelMode travel_mode, bool startpoint,
bool is_split) TravelMode travel_mode,
bool is_split,
engine::guidance::RoadClassificationData road_classification)
: NodeBasedEdge(SPECIAL_NODEID, : NodeBasedEdge(SPECIAL_NODEID,
SPECIAL_NODEID, SPECIAL_NODEID,
name_id, name_id,
@ -122,7 +132,8 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
access_restricted, access_restricted,
startpoint, startpoint,
travel_mode, travel_mode,
is_split), is_split,
std::move(road_classification)),
osm_source_id(std::move(source)), osm_target_id(std::move(target)) osm_source_id(std::move(source)), osm_target_id(std::move(target))
{ {
} }

View File

@ -2,7 +2,7 @@
#define ORIGINAL_EDGE_DATA_HPP #define ORIGINAL_EDGE_DATA_HPP
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "extractor/turn_instructions.hpp" #include "engine/guidance/turn_instruction.hpp"
#include "util/typedefs.hpp" #include "util/typedefs.hpp"
#include <limits> #include <limits>
@ -16,7 +16,7 @@ struct OriginalEdgeData
{ {
explicit OriginalEdgeData(NodeID via_node, explicit OriginalEdgeData(NodeID via_node,
unsigned name_id, unsigned name_id,
TurnInstruction turn_instruction, engine::guidance::TurnInstruction turn_instruction,
TravelMode travel_mode) TravelMode travel_mode)
: via_node(via_node), name_id(name_id), turn_instruction(turn_instruction), : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
travel_mode(travel_mode) travel_mode(travel_mode)
@ -25,14 +25,15 @@ struct OriginalEdgeData
OriginalEdgeData() OriginalEdgeData()
: via_node(std::numeric_limits<unsigned>::max()), : via_node(std::numeric_limits<unsigned>::max()),
name_id(std::numeric_limits<unsigned>::max()), turn_instruction(TurnInstruction::NoTurn), name_id(std::numeric_limits<unsigned>::max()),
turn_instruction(engine::guidance::TurnInstruction::INVALID()),
travel_mode(TRAVEL_MODE_INACCESSIBLE) travel_mode(TRAVEL_MODE_INACCESSIBLE)
{ {
} }
NodeID via_node; NodeID via_node;
unsigned name_id; unsigned name_id;
TurnInstruction turn_instruction; engine::guidance::TurnInstruction turn_instruction;
TravelMode travel_mode; TravelMode travel_mode;
}; };
} }

View File

@ -3,9 +3,11 @@
#include "util/coordinate.hpp" #include "util/coordinate.hpp"
#include <string> #include <iostream>
#include <utility> #include <utility>
#include <boost/assert.hpp>
namespace osrm namespace osrm
{ {
namespace util namespace util
@ -59,6 +61,8 @@ double bearing(const Coordinate first_coordinate, const Coordinate second_coordi
// Get angle of line segment (A,C)->(C,B) // Get angle of line segment (A,C)->(C,B)
double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third); double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third);
Coordinate interpolateLinear( double factor, const Coordinate from, const Coordinate to );
namespace mercator namespace mercator
{ {
FloatLatitude yToLat(const double value); FloatLatitude yToLat(const double value);

View File

@ -4,6 +4,7 @@
#include "util/dynamic_graph.hpp" #include "util/dynamic_graph.hpp"
#include "extractor/node_based_edge.hpp" #include "extractor/node_based_edge.hpp"
#include "util/graph_utils.hpp" #include "util/graph_utils.hpp"
#include "engine/guidance/classification_data.hpp"
#include <tbb/parallel_sort.h> #include <tbb/parallel_sort.h>
@ -45,6 +46,7 @@ struct NodeBasedEdgeData
bool roundabout : 1; bool roundabout : 1;
bool startpoint : 1; bool startpoint : 1;
extractor::TravelMode travel_mode : 4; extractor::TravelMode travel_mode : 4;
engine::guidance::RoadClassificationData road_classification;
bool IsCompatibleTo(const NodeBasedEdgeData &other) const bool IsCompatibleTo(const NodeBasedEdgeData &other) const
{ {
@ -74,6 +76,7 @@ NodeBasedDynamicGraphFromEdges(std::size_t number_of_nodes,
output_edge.data.access_restricted = input_edge.access_restricted; output_edge.data.access_restricted = input_edge.access_restricted;
output_edge.data.travel_mode = input_edge.travel_mode; output_edge.data.travel_mode = input_edge.travel_mode;
output_edge.data.startpoint = input_edge.startpoint; output_edge.data.startpoint = input_edge.startpoint;
output_edge.data.road_classification = input_edge.road_classification;
}); });
tbb::parallel_sort(edges_list.begin(), edges_list.end()); tbb::parallel_sort(edges_list.begin(), edges_list.end());

View File

@ -52,7 +52,7 @@ int Contractor::Run()
#ifdef WIN32 #ifdef WIN32
#pragma message("Memory consumption on Windows can be higher due to different bit packing") #pragma message("Memory consumption on Windows can be higher due to different bit packing")
#else #else
static_assert(sizeof(extractor::NodeBasedEdge) == 20, static_assert(sizeof(extractor::NodeBasedEdge) == 24,
"changing extractor::NodeBasedEdge type has influence on memory consumption!"); "changing extractor::NodeBasedEdge type has influence on memory consumption!");
static_assert(sizeof(extractor::EdgeBasedEdge) == 16, static_assert(sizeof(extractor::EdgeBasedEdge) == 16,
"changing EdgeBasedEdge type has influence on memory consumption!"); "changing EdgeBasedEdge type has influence on memory consumption!");

View File

@ -24,74 +24,14 @@ namespace json
namespace detail namespace detail
{ {
std::string instructionToString(extractor::TurnInstruction instruction) std::string instructionTypeToString(guidance::TurnType type)
{ {
std::string token; return guidance::turn_type_names[static_cast<std::size_t>(type)];
// FIXME this could be an array. }
switch (instruction)
{
case extractor::TurnInstruction::GoStraight:
token = "continue";
break;
case extractor::TurnInstruction::TurnSlightRight:
token = "bear right";
break;
case extractor::TurnInstruction::TurnRight:
token = "right";
break;
case extractor::TurnInstruction::TurnSharpRight:
token = "sharp right";
break;
case extractor::TurnInstruction::UTurn:
token = "uturn";
break;
case extractor::TurnInstruction::TurnSharpLeft:
token = "sharp left";
break;
case extractor::TurnInstruction::TurnLeft:
token = "left";
break;
case extractor::TurnInstruction::TurnSlightLeft:
token = "bear left";
break;
case extractor::TurnInstruction::HeadOn:
token = "head on";
break;
case extractor::TurnInstruction::EnterRoundAbout:
token = "enter roundabout";
break;
case extractor::TurnInstruction::LeaveRoundAbout:
token = "leave roundabout";
break;
case extractor::TurnInstruction::StayOnRoundAbout:
token = "stay on roundabout";
break;
case extractor::TurnInstruction::StartAtEndOfStreet:
token = "depart";
break;
case extractor::TurnInstruction::ReachedYourDestination:
token = "arrive";
break;
case extractor::TurnInstruction::NameChanges:
token = "name changed";
break;
case extractor::TurnInstruction::NoTurn: std::string instructionModifierToString(guidance::DirectionModifier modifier)
case extractor::TurnInstruction::ReachViaLocation: {
case extractor::TurnInstruction::EnterAgainstAllowedDirection: return guidance::modifier_names[static_cast<std::size_t>(modifier)];
case extractor::TurnInstruction::LeaveAgainstAllowedDirection:
case extractor::TurnInstruction::InverseAccessRestrictionFlag:
case extractor::TurnInstruction::AccessRestrictionFlag:
case extractor::TurnInstruction::AccessRestrictionPenalty:
BOOST_ASSERT_MSG(false, "Invalid turn type used");
break;
default:
BOOST_ASSERT_MSG(false, "unknown TurnInstruction");
break;
}
return token;
} }
util::json::Array coordinateToLonLat(const util::Coordinate coordinate) util::json::Array coordinateToLonLat(const util::Coordinate coordinate)
@ -159,10 +99,14 @@ std::string modeToString(const extractor::TravelMode mode)
util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
{ {
util::json::Object step_maneuver; util::json::Object step_maneuver;
step_maneuver.values["type"] = detail::instructionToString(maneuver.instruction); step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type);
step_maneuver.values["modifier"] =
detail::instructionModifierToString(maneuver.instruction.direction_modifier);
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location); step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
step_maneuver.values["bearing_before"] = maneuver.bearing_before; step_maneuver.values["bearing_before"] = maneuver.bearing_before;
step_maneuver.values["bearing_after"] = maneuver.bearing_after; step_maneuver.values["bearing_after"] = maneuver.bearing_after;
if( maneuver.exit != 0 )
step_maneuver.values["exit"] = maneuver.exit;
return step_maneuver; return step_maneuver;
} }

View File

@ -0,0 +1,21 @@
#include "engine/guidance/classification_data.hpp"
#include <osmium/osm.hpp>
namespace osrm
{
namespace engine
{
namespace guidance
{
void RoadClassificationData::invalidate() { road_class = FunctionalRoadClass::UNKNOWN; }
void RoadClassificationData::augment(const osmium::Way &way)
{
const char *data = way.get_value_by_key("highway");
if (data)
road_class = functionalRoadClassFromTag(data);
}
} // namespace guidance
} // namespace engine
} // namespace osrm

View File

@ -0,0 +1,150 @@
#include "engine/guidance/post_processing.hpp"
#include "engine/guidance/turn_instruction.hpp"
#include "engine/guidance/guidance_toolkit.hpp"
#include <boost/assert.hpp>
#include <iostream>
namespace osrm
{
namespace engine
{
namespace guidance
{
namespace detail
{
bool canMergeTrivially(const PathData &destination, const PathData &source)
{
return destination.exit == 0 && destination.name_id == source.name_id &&
destination.travel_mode == source.travel_mode && isSilent(destination.turn_instruction);
}
PathData forwardInto(PathData destination, const PathData &source)
{
// Merge a turn into a silent turn
// Overwrites turn instruction and increases exit NR
destination.duration_until_turn += source.duration_until_turn;
destination.exit = source.exit;
return destination;
}
PathData accumulateInto(PathData destination, const PathData &source)
{
// Merge a turn into a silent turn
// Overwrites turn instruction and increases exit NR
BOOST_ASSERT(canMergeTrivially(destination, source));
destination.duration_until_turn += source.duration_until_turn;
destination.exit = source.exit + 1;
return destination;
}
PathData mergeInto(PathData destination, const PathData &source)
{
if (source.turn_instruction == TurnInstruction::NO_TURN())
{
BOOST_ASSERT(canMergeTrivially(destination, source));
return detail::forwardInto(destination, source);
}
if (source.turn_instruction == TurnType::Suppressed &&
detail::canMergeTrivially(destination, source))
{
return detail::accumulateInto(destination, source);
}
if (source.turn_instruction.type == TurnType::StayOnRoundabout)
{
return detail::accumulateInto(destination, source);
}
return destination;
}
} // namespace detail
void print( const std::vector<std::vector<PathData>> & leg_data )
{
std::cout << "Path\n";
int legnr = 0;
for( const auto & leg : leg_data )
{
std::cout << "\tLeg: " << ++legnr << "\n";
int segment = 0;
for( const auto &data : leg ){
std::cout << "\t\t[" << ++segment << "]: " << (int) data.turn_instruction.type << " " << (int)data.turn_instruction.direction_modifier << " exit: " << data.exit << "\n";
}
}
std::cout << std::endl;
}
std::vector<std::vector<PathData>> postProcess(std::vector<std::vector<PathData>> leg_data)
{
std::cout << "[POSTPROCESSING ITERATION]" << std::endl;
unsigned carry_exit = 0;
// Count Street Exits forward
print( leg_data );
for (auto &path_data : leg_data)
{
path_data[0].exit = carry_exit;
for (std::size_t data_index = 0; data_index + 1 < path_data.size(); ++data_index)
{
if (path_data[data_index].turn_instruction.type == TurnType::EnterRoundaboutAtExit)
{
path_data[data_index].exit += 1; // Count the exit
path_data[data_index].turn_instruction.type = TurnType::EnterRoundabout;
}
else if (path_data[data_index].turn_instruction.type == TurnType::EnterRotaryAtExit)
{
path_data[data_index].exit += 1;
path_data[data_index].turn_instruction.type = TurnType::EnterRotary;
}
if (isSilent(path_data[data_index].turn_instruction))
{
path_data[data_index + 1] =
detail::mergeInto(path_data[data_index + 1], path_data[data_index]);
}
carry_exit = path_data[data_index].exit;
}
}
print( leg_data );
// Move Roundabout exit numbers to front
for (auto rev_itr = leg_data.rbegin(); rev_itr != leg_data.rend(); ++rev_itr)
{
auto &path_data = *rev_itr;
for (std::size_t data_index = path_data.size(); data_index > 1; --data_index)
{
if (leavesRoundabout(path_data[data_index - 1].turn_instruction) ||
staysOnRoundabout(path_data[data_index - 1].turn_instruction))
{
path_data[data_index - 2].exit = path_data[data_index - 1].exit;
}
}
auto prev_leg = std::next(rev_itr);
if (!path_data.empty() && prev_leg != leg_data.rend())
{
if (staysOnRoundabout(path_data[0].turn_instruction) ||
leavesRoundabout(path_data[0].turn_instruction))
{
prev_leg->back().exit = path_data[0].exit;
}
}
}
print( leg_data );
// silence turns for good
for (auto &path_data : leg_data)
{
for (auto &data : path_data)
{
if (isSilent(data.turn_instruction) || leavesRoundabout(data.turn_instruction))
data.turn_instruction = TurnInstruction::NO_TURN();
}
}
print( leg_data );
return std::move(leg_data);
}
} // namespace guidance
} // namespace engine
} // namespace osrm

View File

@ -81,6 +81,7 @@ std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter
}); });
return encode(delta_numbers); return encode(delta_numbers);
} }
std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string) std::vector<util::Coordinate> decodePolyline(const std::string &geometry_string)
{ {
std::vector<util::Coordinate> new_coordinates; std::vector<util::Coordinate> new_coordinates;

View File

@ -9,6 +9,9 @@
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "util/exception.hpp" #include "util/exception.hpp"
#include "engine/guidance/turn_classification.hpp"
#include "engine/guidance/guidance_toolkit.hpp"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/numeric/conversion/cast.hpp> #include <boost/numeric/conversion/cast.hpp>
@ -35,14 +38,31 @@ const double constexpr STRAIGHT_ANGLE = 180.;
// if a turn deviates this much from going straight, it will be kept straight // if a turn deviates this much from going straight, it will be kept straight
const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 2.; const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 2.;
// angle that lies between two nearly indistinguishable roads // angle that lies between two nearly indistinguishable roads
const double constexpr NARROW_TURN_ANGLE = 25.; const double constexpr NARROW_TURN_ANGLE = 35.;
// angle difference that can be classified as straight, if its the only narrow turn // angle difference that can be classified as straight, if its the only narrow turn
const double constexpr FUZZY_STRAIGHT_ANGLE = 15.; const double constexpr FUZZY_STRAIGHT_ANGLE = 15.;
const double constexpr DISTINCTION_RATIO = 2; const double constexpr DISTINCTION_RATIO = 2;
using engine::guidance::TurnPossibility;
using engine::guidance::TurnInstruction;
using engine::guidance::DirectionModifier;
using engine::guidance::TurnType;
using engine::guidance::FunctionalRoadClass;
using engine::guidance::classifyIntersection;
using engine::guidance::isLowPriorityRoadClass;
using engine::guidance::angularDeviation;
using engine::guidance::getTurnDirection;
using engine::guidance::getRepresentativeCoordinate;
using engine::guidance::isBasic;
using engine::guidance::isRampClass;
using engine::guidance::isUturn;
using engine::guidance::isConflict;
using engine::guidance::isSlightTurn;
using engine::guidance::isSlightModifier;
using engine::guidance::mirrorDirectionModifier;
// Configuration to find representative candidate for turn angle calculations // Configuration to find representative candidate for turn angle calculations
const double constexpr MINIMAL_SEGMENT_LENGTH = 1.;
const double constexpr DESIRED_SEGMENT_LENGTH = 10.;
EdgeBasedGraphFactory::EdgeBasedGraphFactory( EdgeBasedGraphFactory::EdgeBasedGraphFactory(
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph, std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
@ -140,9 +160,10 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeI
// traverse arrays from start and end respectively // traverse arrays from start and end respectively
for (const auto i : util::irange(std::size_t{ 0 }, geometry_size)) for (const auto i : util::irange(std::size_t{ 0 }, geometry_size))
{ {
BOOST_ASSERT(current_edge_source_coordinate_id == BOOST_ASSERT(
m_compressed_edge_container.GetBucketReference( current_edge_source_coordinate_id ==
edge_id_2)[geometry_size - 1 - i].node_id); m_compressed_edge_container.GetBucketReference(edge_id_2)[geometry_size - 1 - i]
.node_id);
const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id; const NodeID current_edge_target_coordinate_id = forward_geometry[i].node_id;
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id); BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
@ -321,8 +342,55 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// linear number of turns only. // linear number of turns only.
util::Percent progress(m_node_based_graph->GetNumberOfNodes()); util::Percent progress(m_node_based_graph->GetNumberOfNodes());
struct CompareTurnPossibilities
{
bool operator()(const std::vector<TurnPossibility> &left,
const std::vector<TurnPossibility> &right) const
{
if (left.size() < right.size())
return true;
if (left.size() > right.size())
return false;
for (std::size_t i = 0; i < left.size(); ++i)
{
if ((((int)left[i].angle + 16) % 256) / 32 <
(((int)right[i].angle + 16) % 256) / 32)
return true;
if ((((int)left[i].angle + 16) % 256) / 32 >
(((int)right[i].angle + 16) % 256) / 32)
return false;
}
return false;
}
};
// temporary switch to allow display of turn types
#define SHOW_TURN_TYPES 0
#if SHOW_TURN_TYPES
std::map<std::vector<TurnPossibility>, std::vector<util::FixedPointCoordinate>,
CompareTurnPossibilities> turn_types;
#endif
for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes())) for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{ {
#if SHOW_TURN_TYPES
auto turn_possibilities = classifyIntersection(
node_u, *m_node_based_graph, m_compressed_edge_container, m_node_info_list);
if (turn_possibilities.empty())
continue;
auto set = turn_types.find(turn_possibilities);
if (set != turn_types.end())
{
if (set->second.size() < 5)
set->second.emplace_back(m_node_info_list[node_u].lat,
m_node_info_list[node_u].lon);
}
else
{
turn_types[turn_possibilities] = std::vector<util::FixedPointCoordinate>(
1, {m_node_info_list[node_u].lat, m_node_info_list[node_u].lon});
}
#endif
// progress.printStatus(node_u); // progress.printStatus(node_u);
for (const EdgeID edge_form_u : m_node_based_graph->GetAdjacentEdgeRange(node_u)) for (const EdgeID edge_form_u : m_node_based_graph->GetAdjacentEdgeRange(node_u))
{ {
@ -333,8 +401,33 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
++node_based_edge_counter; ++node_based_edge_counter;
auto turn_candidates = getTurnCandidates(node_u, edge_form_u); auto turn_candidates = getTurnCandidates(node_u, edge_form_u);
#define PRINT_DEBUG_CANDIDATES 0
#if PRINT_DEBUG_CANDIDATES
std::cout << "Initial Candidates:\n";
for (auto tc : turn_candidates)
std::cout << "\t" << tc.toString() << " "
<< (int)m_node_based_graph->GetEdgeData(tc.eid)
.road_classification.road_class
<< std::endl;
#endif
turn_candidates = optimizeCandidates(edge_form_u, turn_candidates); turn_candidates = optimizeCandidates(edge_form_u, turn_candidates);
#if PRINT_DEBUG_CANDIDATES
std::cout << "Optimized Candidates:\n";
for (auto tc : turn_candidates)
std::cout << "\t" << tc.toString() << " "
<< (int)m_node_based_graph->GetEdgeData(tc.eid)
.road_classification.road_class
<< std::endl;
#endif
turn_candidates = suppressTurns(edge_form_u, turn_candidates); turn_candidates = suppressTurns(edge_form_u, turn_candidates);
#if PRINT_DEBUG_CANDIDATES
std::cout << "Suppressed Candidates:\n";
for (auto tc : turn_candidates)
std::cout << "\t" << tc.toString() << " "
<< (int)m_node_based_graph->GetEdgeData(tc.eid)
.road_classification.road_class
<< std::endl;
#endif
const NodeID node_v = m_node_based_graph->GetTarget(edge_form_u); const NodeID node_v = m_node_based_graph->GetTarget(edge_form_u);
@ -361,9 +454,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
} }
const int turn_penalty = GetTurnPenalty(turn_angle, lua_state); const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
const TurnInstruction turn_instruction = turn.instruction; const auto turn_instruction = turn.instruction;
if (turn_instruction == TurnInstruction::UTurn) if (isUturn(turn_instruction))
{ {
distance += speed_profile.u_turn_penalty; distance += speed_profile.u_turn_penalty;
} }
@ -438,6 +531,21 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
} }
} }
} }
#if SHOW_TURN_TYPES
std::cout << "[info] found " << turn_types.size() << " turn types." << std::endl;
for (const auto &tt : turn_types)
{
std::cout << tt.second.size();
for (auto coord : tt.second)
std::cout << " " << coord.lat << " " << coord.lon;
std::cout << " " << tt.first.size();
for (auto tte : tt.first)
std::cout << " " << (int)tte.angle;
std::cout << std::endl;
}
#endif
FlushVectorToStream(edge_data_file, original_edge_data_vector); FlushVectorToStream(edge_data_file, original_edge_data_vector);
@ -463,9 +571,107 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
<< " turns over barriers"; << " turns over barriers";
} }
std::vector<EdgeBasedGraphFactory::TurnCandidate>
EdgeBasedGraphFactory::optimizeRamps(const EdgeID via_edge,
std::vector<TurnCandidate> turn_candidates) const
{
EdgeID continue_eid = SPECIAL_EDGEID;
double continue_angle = 0;
const auto &in_edge_data = m_node_based_graph->GetEdgeData(via_edge);
for (auto &candidate : turn_candidates)
{
if (candidate.instruction.direction_modifier == DirectionModifier::UTurn)
continue;
const auto &out_edge_data = m_node_based_graph->GetEdgeData(candidate.eid);
if (out_edge_data.name_id == in_edge_data.name_id)
{
continue_eid = candidate.eid;
continue_angle = candidate.angle;
if (angularDeviation(candidate.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
isRampClass(in_edge_data.road_classification.road_class))
candidate.instruction = TurnType::Suppressed;
break;
}
}
if (continue_eid != SPECIAL_EDGEID)
{
bool to_the_right = true;
for (auto &candidate : turn_candidates)
{
if (candidate.eid == continue_eid)
{
to_the_right = false;
continue;
}
if (candidate.instruction.type != TurnType::Ramp)
continue;
if (isSlightModifier(candidate.instruction.direction_modifier))
candidate.instruction.direction_modifier =
(to_the_right) ? DirectionModifier::SlightRight : DirectionModifier::SlightLeft;
}
}
return turn_candidates;
}
TurnType
EdgeBasedGraphFactory::checkForkAndEnd(const EdgeID via_eid,
const std::vector<TurnCandidate> &turn_candidates) const
{
if (turn_candidates.size() != 3 ||
turn_candidates.front().instruction.direction_modifier != DirectionModifier::UTurn)
return TurnType::Invalid;
if (isOnRoundabout(turn_candidates[1].instruction))
{
BOOST_ASSERT(isOnRoundabout(turn_candidates[2].instruction));
return TurnType::Invalid;
}
BOOST_ASSERT(!isOnRoundabout(turn_candidates[2].instruction));
FunctionalRoadClass road_classes[3] = {
m_node_based_graph->GetEdgeData(via_eid).road_classification.road_class,
m_node_based_graph->GetEdgeData(turn_candidates[1].eid).road_classification.road_class,
m_node_based_graph->GetEdgeData(turn_candidates[2].eid).road_classification.road_class};
if (angularDeviation(turn_candidates[1].angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
angularDeviation(turn_candidates[2].angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
{
if (road_classes[0] != road_classes[1] || road_classes[1] != road_classes[2])
return TurnType::Invalid;
if (turn_candidates[1].valid && turn_candidates[2].valid)
return TurnType::Fork;
}
else if (angularDeviation(turn_candidates[1].angle, 90) < NARROW_TURN_ANGLE &&
angularDeviation(turn_candidates[2].angle, 270) < NARROW_TURN_ANGLE)
{
return TurnType::EndOfRoad;
}
return TurnType::Invalid;
}
std::vector<EdgeBasedGraphFactory::TurnCandidate>
EdgeBasedGraphFactory::handleForkAndEnd(const TurnType type,
std::vector<TurnCandidate> turn_candidates) const
{
turn_candidates[1].instruction.type = type;
turn_candidates[1].instruction.direction_modifier =
(type == TurnType::Fork) ? DirectionModifier::SlightRight : DirectionModifier::Right;
turn_candidates[2].instruction.type = type;
turn_candidates[2].instruction.direction_modifier =
(type == TurnType::Fork) ? DirectionModifier::SlightLeft : DirectionModifier::Left;
return turn_candidates;
}
// requires sorted candidates // requires sorted candidates
std::vector<EdgeBasedGraphFactory::TurnCandidate> std::vector<EdgeBasedGraphFactory::TurnCandidate>
EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid, EdgeBasedGraphFactory::optimizeCandidates(const EdgeID via_eid,
std::vector<TurnCandidate> turn_candidates) const std::vector<TurnCandidate> turn_candidates) const
{ {
BOOST_ASSERT_MSG(std::is_sorted(turn_candidates.begin(), turn_candidates.end(), BOOST_ASSERT_MSG(std::is_sorted(turn_candidates.begin(), turn_candidates.end(),
@ -477,6 +683,12 @@ EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
if (turn_candidates.size() <= 1) if (turn_candidates.size() <= 1)
return turn_candidates; return turn_candidates;
TurnType type = checkForkAndEnd(via_eid, turn_candidates);
if (type != TurnType::Invalid)
return handleForkAndEnd(type, std::move(turn_candidates));
turn_candidates = optimizeRamps(via_eid, std::move(turn_candidates));
const auto getLeft = [&turn_candidates](std::size_t index) const auto getLeft = [&turn_candidates](std::size_t index)
{ {
return (index + 1) % turn_candidates.size(); return (index + 1) % turn_candidates.size();
@ -487,12 +699,14 @@ EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
}; };
// handle availability of multiple u-turns (e.g. street with separated small parking roads) // handle availability of multiple u-turns (e.g. street with separated small parking roads)
if (turn_candidates[0].instruction == TurnInstruction::UTurn && turn_candidates[0].angle == 0) if (isUturn(turn_candidates[0].instruction) && turn_candidates[0].angle == 0)
{ {
if (turn_candidates[getLeft(0)].instruction == TurnInstruction::UTurn) if (isUturn(turn_candidates[getLeft(0)].instruction))
turn_candidates[getLeft(0)].instruction = TurnInstruction::TurnSharpLeft; turn_candidates[getLeft(0)].instruction.direction_modifier =
if (turn_candidates[getRight(0)].instruction == TurnInstruction::UTurn) DirectionModifier::SharpLeft;
turn_candidates[getRight(0)].instruction = TurnInstruction::TurnSharpRight; if (isUturn(turn_candidates[getRight(0)].instruction))
turn_candidates[getRight(0)].instruction.direction_modifier =
DirectionModifier::SharpRight;
} }
const auto keepStraight = [](double angle) const auto keepStraight = [](double angle)
@ -503,8 +717,8 @@ EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index) for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index)
{ {
auto &turn = turn_candidates[turn_index]; auto &turn = turn_candidates[turn_index];
if (turn.instruction > TurnInstruction::TurnSlightLeft || if (!isBasic(turn.instruction.type) || isUturn(turn.instruction) ||
turn.instruction == TurnInstruction::UTurn) isOnRoundabout(turn.instruction))
continue; continue;
auto &left = turn_candidates[getLeft(turn_index)]; auto &left = turn_candidates[getLeft(turn_index)];
if (turn.angle == left.angle) if (turn.angle == left.angle)
@ -542,10 +756,12 @@ EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
auto &candidate_at_begin = turn_candidates[conflict_begin]; auto &candidate_at_begin = turn_candidates[conflict_begin];
if (conflict_size == 2) if (conflict_size == 2)
{ {
if (turn.instruction == TurnInstruction::GoStraight) if (turn.instruction.direction_modifier == DirectionModifier::Straight)
{ {
if (instruction_left_of_end != TurnInstruction::TurnSlightLeft && if (instruction_left_of_end.direction_modifier !=
instruction_right_of_begin != TurnInstruction::TurnSlightRight) DirectionModifier::SlightLeft &&
instruction_right_of_begin.direction_modifier !=
DirectionModifier::SlightRight)
{ {
std::int32_t resolved_count = 0; std::int32_t resolved_count = 0;
// uses side-effects in resolve // uses side-effects in resolve
@ -592,8 +808,8 @@ EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
if (isSlightTurn(turn.instruction) || isSharpTurn(turn.instruction)) if (isSlightTurn(turn.instruction) || isSharpTurn(turn.instruction))
{ {
auto resolve_direction = auto resolve_direction =
(turn.instruction == TurnInstruction::TurnSlightRight || (turn.instruction.direction_modifier == DirectionModifier::SlightRight ||
turn.instruction == TurnInstruction::TurnSharpLeft) turn.instruction.direction_modifier == DirectionModifier::SharpLeft)
? RESOLVE_TO_RIGHT ? RESOLVE_TO_RIGHT
: RESOLVE_TO_LEFT; : RESOLVE_TO_LEFT;
if (resolve_direction == RESOLVE_TO_RIGHT && if (resolve_direction == RESOLVE_TO_RIGHT &&
@ -658,8 +874,8 @@ EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
return turn_candidates; return turn_candidates;
} }
bool EdgeBasedGraphFactory::isObviousChoice(EdgeID via_eid, bool EdgeBasedGraphFactory::isObviousChoice(const EdgeID via_eid,
std::size_t turn_index, const std::size_t turn_index,
const std::vector<TurnCandidate> &turn_candidates) const const std::vector<TurnCandidate> &turn_candidates) const
{ {
const auto getLeft = [&turn_candidates](std::size_t index) const auto getLeft = [&turn_candidates](std::size_t index)
@ -677,8 +893,8 @@ bool EdgeBasedGraphFactory::isObviousChoice(EdgeID via_eid,
const auto &candidate_to_the_right = turn_candidates[getRight(turn_index)]; const auto &candidate_to_the_right = turn_candidates[getRight(turn_index)];
const auto hasValidRatio = const auto hasValidRatio = [this](const TurnCandidate &left, const TurnCandidate &center,
[](const TurnCandidate &left, const TurnCandidate &center, const TurnCandidate &right) const TurnCandidate &right)
{ {
auto angle_left = (left.angle > 180) ? angularDeviation(left.angle, STRAIGHT_ANGLE) : 180; auto angle_left = (left.angle > 180) ? angularDeviation(left.angle, STRAIGHT_ANGLE) : 180;
auto angle_right = auto angle_right =
@ -690,11 +906,31 @@ bool EdgeBasedGraphFactory::isObviousChoice(EdgeID via_eid,
: (angle_left > self_angle && angle_right / self_angle > DISTINCTION_RATIO)); : (angle_left > self_angle && angle_right / self_angle > DISTINCTION_RATIO));
}; };
// only valid turn // only valid turn
if (!isLowPriorityRoadClass(
m_node_based_graph->GetEdgeData(candidate.eid).road_classification.road_class))
{
bool is_only_normal_road = true;
BOOST_ASSERT(turn_candidates[0].instruction.type == TurnType::Turn &&
turn_candidates[0].instruction.direction_modifier == DirectionModifier::UTurn);
for (size_t i = 0; i < turn_candidates.size(); ++i)
{
if (i == turn_index || turn_candidates[i].angle == 0) // skip self and u-turn
continue;
if (!isLowPriorityRoadClass(m_node_based_graph->GetEdgeData(turn_candidates[i].eid)
.road_classification.road_class))
{
is_only_normal_road = false;
break;
}
}
if (is_only_normal_road == true)
return true;
}
return turn_candidates.size() == 1 || return turn_candidates.size() == 1 ||
// only non u-turn // only non u-turn
(turn_candidates.size() == 2 && (turn_candidates.size() == 2 &&
candidate_to_the_left.instruction == TurnInstruction::UTurn) || // nearly straight turn isUturn(candidate_to_the_left.instruction)) || // nearly straight turn
angularDeviation(candidate.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION || angularDeviation(candidate.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION ||
hasValidRatio(candidate_to_the_left, candidate, candidate_to_the_right) || hasValidRatio(candidate_to_the_left, candidate, candidate_to_the_right) ||
(in_data.name_id != 0 && in_data.name_id == out_data.name_id && (in_data.name_id != 0 && in_data.name_id == out_data.name_id &&
@ -702,22 +938,58 @@ bool EdgeBasedGraphFactory::isObviousChoice(EdgeID via_eid,
} }
std::vector<EdgeBasedGraphFactory::TurnCandidate> std::vector<EdgeBasedGraphFactory::TurnCandidate>
EdgeBasedGraphFactory::suppressTurns(EdgeID via_eid, EdgeBasedGraphFactory::suppressTurns(const EdgeID via_eid,
std::vector<TurnCandidate> turn_candidates) const std::vector<TurnCandidate> turn_candidates) const
{ {
// remove invalid candidates if (turn_candidates.size() == 3)
{
BOOST_ASSERT(turn_candidates[0].instruction.direction_modifier == DirectionModifier::UTurn);
if (isLowPriorityRoadClass(m_node_based_graph->GetEdgeData(turn_candidates[1].eid)
.road_classification.road_class) &&
!isLowPriorityRoadClass(m_node_based_graph->GetEdgeData(turn_candidates[2].eid)
.road_classification.road_class))
{
if (angularDeviation(turn_candidates[2].angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
{
if (m_node_based_graph->GetEdgeData(turn_candidates[2].eid).name_id ==
m_node_based_graph->GetEdgeData(via_eid).name_id)
{
turn_candidates[2].instruction = TurnInstruction::NO_TURN();
}
else
{
turn_candidates[2].instruction.type = TurnType::NewName;
}
return turn_candidates;
}
}
else if (isLowPriorityRoadClass(m_node_based_graph->GetEdgeData(turn_candidates[2].eid)
.road_classification.road_class) &&
!isLowPriorityRoadClass(m_node_based_graph->GetEdgeData(turn_candidates[1].eid)
.road_classification.road_class))
{
if (angularDeviation(turn_candidates[1].angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
{
if (m_node_based_graph->GetEdgeData(turn_candidates[1].eid).name_id ==
m_node_based_graph->GetEdgeData(via_eid).name_id)
{
turn_candidates[1].instruction = TurnInstruction::NO_TURN();
}
else
{
turn_candidates[1].instruction.type = TurnType::NewName;
}
return turn_candidates;
}
}
}
BOOST_ASSERT_MSG(std::is_sorted(turn_candidates.begin(), turn_candidates.end(), BOOST_ASSERT_MSG(std::is_sorted(turn_candidates.begin(), turn_candidates.end(),
[](const TurnCandidate &left, const TurnCandidate &right) [](const TurnCandidate &left, const TurnCandidate &right)
{ {
return left.angle < right.angle; return left.angle < right.angle;
}), }),
"Turn Candidates not sorted by angle."); "Turn Candidates not sorted by angle.");
const auto end_valid = std::remove_if(turn_candidates.begin(), turn_candidates.end(),
[](const TurnCandidate &candidate)
{
return !candidate.valid;
});
turn_candidates.erase(end_valid, turn_candidates.end());
const auto getLeft = [&turn_candidates](std::size_t index) const auto getLeft = [&turn_candidates](std::size_t index)
{ {
@ -747,56 +1019,73 @@ EdgeBasedGraphFactory::suppressTurns(EdgeID via_eid,
for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index) for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index)
{ {
auto &candidate = turn_candidates[turn_index]; auto &candidate = turn_candidates[turn_index];
if (!isBasic(candidate.instruction.type))
continue;
const EdgeData &out_data = m_node_based_graph->GetEdgeData(candidate.eid); const EdgeData &out_data = m_node_based_graph->GetEdgeData(candidate.eid);
if (candidate.valid && candidate.instruction != TurnInstruction::UTurn) if (out_data.name_id == in_data.name_id && in_data.name_id != 0 &&
candidate.instruction.direction_modifier != DirectionModifier::UTurn &&
!has_obvious_with_same_name)
{
candidate.instruction.type = TurnType::Continue;
}
if (candidate.valid && !isUturn(candidate.instruction))
{ {
// TODO road category would be useful to indicate obviousness of turn // TODO road category would be useful to indicate obviousness of turn
// check if turn can be omitted or at least changed // check if turn can be omitted or at least changed
const auto &left = turn_candidates[getLeft(turn_index)]; const auto &left = turn_candidates[getLeft(turn_index)];
const auto &right = turn_candidates[getRight(turn_index)]; const auto &right = turn_candidates[getRight(turn_index)];
// make very slight instructions straight, if they are the only valid choice going with // make very slight instructions straight, if they are the only valid choice going
// with
// at most a slight turn // at most a slight turn
if (candidate.instruction < TurnInstruction::ReachViaLocation && if ((!isSlightModifier(getTurnDirection(left.angle)) || !left.valid) &&
(!isSlightTurn(getTurnDirection(left.angle)) || !left.valid) && (!isSlightModifier(getTurnDirection(right.angle)) || !right.valid) &&
(!isSlightTurn(getTurnDirection(right.angle)) || !right.valid) &&
angularDeviation(candidate.angle, STRAIGHT_ANGLE) < FUZZY_STRAIGHT_ANGLE) angularDeviation(candidate.angle, STRAIGHT_ANGLE) < FUZZY_STRAIGHT_ANGLE)
candidate.instruction = TurnInstruction::GoStraight; candidate.instruction.direction_modifier = DirectionModifier::Straight;
// TODO this smaller comparison for turns is DANGEROUS, has to be revised if turn // TODO this smaller comparison for turns is DANGEROUS, has to be revised if turn
// instructions change // instructions change
if (candidate.instruction < TurnInstruction::ReachViaLocation) if (in_data.travel_mode ==
out_data.travel_mode) // make sure to always announce mode changes
{ {
if (in_data.travel_mode == if (isObviousChoice(via_eid, turn_index, turn_candidates))
out_data.travel_mode) // make sure to always announce mode changes
{ {
if (isObviousChoice(via_eid, turn_index, turn_candidates))
{
if (in_data.name_id == out_data.name_id) // same road if (in_data.name_id == out_data.name_id) // same road
{
candidate.instruction = TurnInstruction::NoTurn;
}
else if (!has_obvious_with_same_name)
{
// TODO discuss, we might want to keep the current name of the turn. But
// this would mean emitting a turn when you just keep on a road
candidate.instruction = TurnInstruction::NameChanges;
}
else if (candidate.angle < obvious_with_same_name_angle)
candidate.instruction = TurnInstruction::TurnSlightRight;
else
candidate.instruction = TurnInstruction::TurnSlightLeft;
}
else if (candidate.instruction == TurnInstruction::GoStraight &&
has_obvious_with_same_name)
{ {
if (candidate.angle < obvious_with_same_name_angle) candidate.instruction.type = TurnType::Suppressed;
candidate.instruction = TurnInstruction::TurnSlightRight;
else
candidate.instruction = TurnInstruction::TurnSlightLeft;
} }
else if (!has_obvious_with_same_name)
{
// TODO discuss, we might want to keep the current name of the turn. But
// this would mean emitting a turn when you just keep on a road
if (isRampClass(in_data.road_classification.road_class) &&
!isRampClass(out_data.road_classification.road_class))
{
candidate.instruction.type = TurnType::Merge;
candidate.instruction.direction_modifier =
mirrorDirectionModifier(candidate.instruction.direction_modifier);
}
else
{
if (engine::guidance::canBeSuppressed(candidate.instruction.type))
candidate.instruction.type = TurnType::NewName;
}
}
else if (candidate.angle < obvious_with_same_name_angle)
candidate.instruction.direction_modifier = DirectionModifier::SlightRight;
else
candidate.instruction.direction_modifier = DirectionModifier::SlightLeft;
}
else if (candidate.instruction.direction_modifier == DirectionModifier::Straight &&
has_obvious_with_same_name)
{
if (candidate.angle < obvious_with_same_name_angle)
candidate.instruction.direction_modifier = DirectionModifier::SlightRight;
else
candidate.instruction.direction_modifier = DirectionModifier::SlightLeft;
} }
} }
} }
@ -805,7 +1094,7 @@ EdgeBasedGraphFactory::suppressTurns(EdgeID via_eid,
} }
std::vector<EdgeBasedGraphFactory::TurnCandidate> std::vector<EdgeBasedGraphFactory::TurnCandidate>
EdgeBasedGraphFactory::getTurnCandidates(NodeID from_node, EdgeID via_eid) EdgeBasedGraphFactory::getTurnCandidates(const NodeID from_node, const EdgeID via_eid)
{ {
std::vector<TurnCandidate> turn_candidates; std::vector<TurnCandidate> turn_candidates;
const NodeID turn_node = m_node_based_graph->GetTarget(via_eid); const NodeID turn_node = m_node_based_graph->GetTarget(via_eid);
@ -813,6 +1102,7 @@ EdgeBasedGraphFactory::getTurnCandidates(NodeID from_node, EdgeID via_eid)
m_restriction_map->CheckForEmanatingIsOnlyTurn(from_node, turn_node); m_restriction_map->CheckForEmanatingIsOnlyTurn(from_node, turn_node);
const bool is_barrier_node = m_barrier_nodes.find(turn_node) != m_barrier_nodes.end(); const bool is_barrier_node = m_barrier_nodes.find(turn_node) != m_barrier_nodes.end();
bool has_non_roundabout = false, has_roundabout_entry;
for (const EdgeID onto_edge : m_node_based_graph->GetAdjacentEdgeRange(turn_node)) for (const EdgeID onto_edge : m_node_based_graph->GetAdjacentEdgeRange(turn_node))
{ {
bool turn_is_valid = true; bool turn_is_valid = true;
@ -875,16 +1165,21 @@ EdgeBasedGraphFactory::getTurnCandidates(NodeID from_node, EdgeID via_eid)
// unpack first node of second segment if packed // unpack first node of second segment if packed
const auto first_coordinate = const auto first_coordinate = getRepresentativeCoordinate(
getRepresentativeCoordinate(from_node, turn_node, via_eid, INVERT); from_node, turn_node, via_eid, INVERT, m_compressed_edge_container, m_node_info_list);
const auto third_coordinate = const auto third_coordinate = getRepresentativeCoordinate(
getRepresentativeCoordinate(turn_node, to_node, onto_edge, !INVERT); turn_node, to_node, onto_edge, !INVERT, m_compressed_edge_container, m_node_info_list);
const auto angle = util::coordinate_calculation::computeAngle( const auto angle = util::coordinate_calculation::computeAngle(
first_coordinate, m_node_info_list[turn_node], third_coordinate); first_coordinate, m_node_info_list[turn_node], third_coordinate);
const auto turn = AnalyzeTurn(from_node, via_eid, turn_node, onto_edge, to_node, angle); const auto turn = AnalyzeTurn(from_node, via_eid, turn_node, onto_edge, to_node, angle);
if (turn_is_valid && !entersRoundabout(turn))
has_non_roundabout = true;
else if (turn_is_valid)
has_roundabout_entry = true;
auto confidence = getTurnConfidence(angle, turn); auto confidence = getTurnConfidence(angle, turn);
if (!turn_is_valid) if (!turn_is_valid)
confidence *= 0.8; // makes invalid turns more likely to be resolved in conflicts confidence *= 0.8; // makes invalid turns more likely to be resolved in conflicts
@ -892,6 +1187,20 @@ EdgeBasedGraphFactory::getTurnCandidates(NodeID from_node, EdgeID via_eid)
turn_candidates.push_back({onto_edge, turn_is_valid, angle, turn, confidence}); turn_candidates.push_back({onto_edge, turn_is_valid, angle, turn, confidence});
} }
if (has_non_roundabout && has_roundabout_entry)
{
for (auto &candidate : turn_candidates)
{
if (entersRoundabout(candidate.instruction))
{
if (candidate.instruction.type == TurnType::EnterRotary)
candidate.instruction.type = TurnType::EnterRotaryAtExit;
if (candidate.instruction.type == TurnType::EnterRoundabout)
candidate.instruction.type = TurnType::EnterRoundaboutAtExit;
}
}
}
const auto ByAngle = [](const TurnCandidate &first, const TurnCandidate second) const auto ByAngle = [](const TurnCandidate &first, const TurnCandidate second)
{ {
return first.angle < second.angle; return first.angle < second.angle;
@ -960,9 +1269,11 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1); const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2); const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
bool from_ramp = isRampClass(data1.road_classification.road_class);
bool to_ramp = isRampClass(data2.road_classification.road_class);
if (node_u == node_w) if (node_u == node_w)
{ {
return TurnInstruction::UTurn; return {TurnType::Turn, DirectionModifier::UTurn};
} }
// roundabouts need to be handled explicitely // roundabouts need to be handled explicitely
@ -972,9 +1283,9 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
if (1 == m_node_based_graph->GetDirectedOutDegree(node_v)) if (1 == m_node_based_graph->GetDirectedOutDegree(node_v))
{ {
// No turn possible. // No turn possible.
return TurnInstruction::NoTurn; return TurnInstruction::NO_TURN();
} }
return TurnInstruction::StayOnRoundAbout; return TurnInstruction::REMAIN_ROUNDABOUT(getTurnDirection(angle));
} }
// Does turn start or end on roundabout? // Does turn start or end on roundabout?
if (data1.roundabout || data2.roundabout) if (data1.roundabout || data2.roundabout)
@ -982,97 +1293,23 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
// We are entering the roundabout // We are entering the roundabout
if ((!data1.roundabout) && data2.roundabout) if ((!data1.roundabout) && data2.roundabout)
{ {
return TurnInstruction::EnterRoundAbout; return TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(angle));
} }
// We are leaving the roundabout // We are leaving the roundabout
if (data1.roundabout && (!data2.roundabout)) if (data1.roundabout && (!data2.roundabout))
{ {
return TurnInstruction::LeaveRoundAbout; return TurnInstruction::EXIT_ROUNDABOUT(getTurnDirection(angle));
} }
} }
if (!from_ramp && to_ramp)
{
return {TurnType::Ramp, getTurnDirection(angle)};
}
// assign a designated turn angle instruction purely based on the angle // assign a designated turn angle instruction purely based on the angle
return getTurnDirection(angle); return {TurnType::Turn, getTurnDirection(angle)};
} }
QueryNode EdgeBasedGraphFactory::getRepresentativeCoordinate(const NodeID src,
const NodeID tgt,
const EdgeID via_eid,
bool INVERTED) const
{
if (m_compressed_edge_container.HasEntryForID(via_eid))
{
util::Coordinate prev = util::Coordinate(m_node_info_list[INVERTED ? tgt : src].lon,
m_node_info_list[INVERTED ? tgt : src].lat),
cur;
// walk along the edge for the first 5 meters
const auto &geometry = m_compressed_edge_container.GetBucketReference(via_eid);
double dist = 0;
double this_dist = 0;
NodeID prev_id = INVERTED ? tgt : src;
const auto selectBestCandidate =
[this](const NodeID current, const double current_distance, const NodeID previous,
const double previous_distance)
{
if (current_distance < DESIRED_SEGMENT_LENGTH ||
current_distance - DESIRED_SEGMENT_LENGTH <
DESIRED_SEGMENT_LENGTH - previous_distance ||
previous_distance < MINIMAL_SEGMENT_LENGTH)
{
return m_node_info_list[current];
}
else
{
return m_node_info_list[previous];
}
};
if (INVERTED)
{
for (auto itr = geometry.rbegin(), end = geometry.rend(); itr != end; ++itr)
{
const auto compressed_node = *itr;
cur = util::Coordinate(m_node_info_list[compressed_node.node_id].lon,
m_node_info_list[compressed_node.node_id].lat);
this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
if (dist + this_dist > DESIRED_SEGMENT_LENGTH)
{
return selectBestCandidate(compressed_node.node_id, dist + this_dist, prev_id,
dist);
}
dist += this_dist;
prev = cur;
prev_id = compressed_node.node_id;
}
cur = util::Coordinate(m_node_info_list[src].lon, m_node_info_list[src].lat);
this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
return selectBestCandidate(src, dist + this_dist, prev_id, dist);
}
else
{
for (auto itr = geometry.begin(), end = geometry.end(); itr != end; ++itr)
{
const auto compressed_node = *itr;
cur = util::Coordinate(m_node_info_list[compressed_node.node_id].lon,
m_node_info_list[compressed_node.node_id].lat);
this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
if (dist + this_dist > DESIRED_SEGMENT_LENGTH)
{
return selectBestCandidate(compressed_node.node_id, dist + this_dist, prev_id,
dist);
}
dist += this_dist;
prev = cur;
prev_id = compressed_node.node_id;
}
cur = util::Coordinate(m_node_info_list[tgt].lon, m_node_info_list[tgt].lat);
this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
return selectBestCandidate(tgt, dist + this_dist, prev_id, dist);
}
}
// default: If the edge is very short, or we do not have a compressed geometry
return m_node_info_list[INVERTED ? src : tgt];
}
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm

View File

@ -188,6 +188,7 @@ int Extractor::run()
local_state, "way_function", local_state, "way_function",
boost::cref(static_cast<const osmium::Way &>(*entity)), boost::cref(static_cast<const osmium::Way &>(*entity)),
boost::ref(result_way)); boost::ref(result_way));
result_way.road_classification_data.augment(static_cast<const osmium::Way &>(*entity));
resulting_ways.push_back(std::make_pair(x, result_way)); resulting_ways.push_back(std::make_pair(x, result_way));
break; break;
case osmium::item_type::relation: case osmium::item_type::relation:

View File

@ -173,7 +173,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
name_id, backward_weight_data, true, false, name_id, backward_weight_data, true, false,
parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.roundabout, parsed_way.is_access_restricted,
parsed_way.is_startpoint, parsed_way.backward_travel_mode, parsed_way.is_startpoint, parsed_way.backward_travel_mode,
false)); false,parsed_way.road_classification_data));
}); });
external_memory.way_start_end_id_list.push_back( external_memory.way_start_end_id_list.push_back(
@ -193,7 +193,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
name_id, forward_weight_data, true, !forward_only, name_id, forward_weight_data, true, !forward_only,
parsed_way.roundabout, parsed_way.is_access_restricted, parsed_way.roundabout, parsed_way.is_access_restricted,
parsed_way.is_startpoint, parsed_way.forward_travel_mode, parsed_way.is_startpoint, parsed_way.forward_travel_mode,
split_edge)); split_edge,parsed_way.road_classification_data));
}); });
if (split_edge) if (split_edge)
{ {
@ -206,7 +206,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id, OSMNodeID(first_node.ref()), OSMNodeID(last_node.ref()), name_id,
backward_weight_data, false, true, parsed_way.roundabout, backward_weight_data, false, true, parsed_way.roundabout,
parsed_way.is_access_restricted, parsed_way.is_startpoint, parsed_way.is_access_restricted, parsed_way.is_startpoint,
parsed_way.backward_travel_mode, true)); parsed_way.backward_travel_mode, true,parsed_way.road_classification_data));
}); });
} }

View File

@ -8,7 +8,7 @@
#include "util/static_rtree.hpp" #include "util/static_rtree.hpp"
#include "engine/datafacade/datafacade_base.hpp" #include "engine/datafacade/datafacade_base.hpp"
#include "extractor/travel_mode.hpp" #include "extractor/travel_mode.hpp"
#include "extractor/turn_instructions.hpp" #include "engine/guidance/turn_instruction.hpp"
#include "storage/storage.hpp" #include "storage/storage.hpp"
#include "storage/shared_datatype.hpp" #include "storage/shared_datatype.hpp"
#include "storage/shared_barriers.hpp" #include "storage/shared_barriers.hpp"
@ -225,8 +225,8 @@ int Storage::Run()
number_of_original_edges); number_of_original_edges);
shared_layout_ptr->SetBlockSize<extractor::TravelMode>(SharedDataLayout::TRAVEL_MODE, shared_layout_ptr->SetBlockSize<extractor::TravelMode>(SharedDataLayout::TRAVEL_MODE,
number_of_original_edges); number_of_original_edges);
shared_layout_ptr->SetBlockSize<extractor::TurnInstruction>(SharedDataLayout::TURN_INSTRUCTION, shared_layout_ptr->SetBlockSize<engine::guidance::TurnInstruction>(
number_of_original_edges); SharedDataLayout::TURN_INSTRUCTION, number_of_original_edges);
boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary); boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary);
@ -390,8 +390,8 @@ int Storage::Run()
shared_layout_ptr->GetBlockPtr<extractor::TravelMode, true>(shared_memory_ptr, shared_layout_ptr->GetBlockPtr<extractor::TravelMode, true>(shared_memory_ptr,
SharedDataLayout::TRAVEL_MODE); SharedDataLayout::TRAVEL_MODE);
extractor::TurnInstruction *turn_instructions_ptr = engine::guidance::TurnInstruction *turn_instructions_ptr =
shared_layout_ptr->GetBlockPtr<extractor::TurnInstruction, true>( shared_layout_ptr->GetBlockPtr<engine::guidance::TurnInstruction, true>(
shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION); shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
extractor::OriginalEdgeData current_edge_data; extractor::OriginalEdgeData current_edge_data;

View File

@ -257,6 +257,15 @@ double computeAngle(const Coordinate first, const Coordinate second, const Coord
return angle; return angle;
} }
Coordinate interpolateLinear(double factor, const Coordinate from, const Coordinate to)
{
BOOST_ASSERT(0 <= factor && factor <= 1.0);
return {from.lon + toFixed(FloatLongitude(
factor * static_cast<double>(toFloating(to.lon - from.lon)))),
from.lat + toFixed(FloatLatitude(
factor * static_cast<double>(toFloating(to.lat - from.lat))))};
}
namespace mercator namespace mercator
{ {
FloatLatitude yToLat(const double value) FloatLatitude yToLat(const double value)
@ -276,6 +285,7 @@ double latToY(const FloatLatitude latitude)
std::log(std::tan((pi<double>() / 4.) + std::log(std::tan((pi<double>() / 4.) +
static_cast<double>(latitude) * (pi<double>() / 180.) / 2.)); static_cast<double>(latitude) * (pi<double>() / 180.) / 2.));
} }
} // ns mercato // ns mercatorr } // ns mercato // ns mercatorr
} // ns coordinate_calculation } // ns coordinate_calculation
} // ns util } // ns util