advanced guidance on 5.0
This commit is contained in:
parent
33f083b213
commit
ef1e0e14ec
@ -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>)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
114
include/engine/guidance/classification_data.hpp
Normal file
114
include/engine/guidance/classification_data.hpp
Normal 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_
|
416
include/engine/guidance/guidance_toolkit.hpp
Normal file
416
include/engine/guidance/guidance_toolkit.hpp
Normal 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_
|
@ -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 */
|
21
include/engine/guidance/post_processing.hpp
Normal file
21
include/engine/guidance/post_processing.hpp
Normal 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
|
@ -1,66 +0,0 @@
|
|||||||
#ifndef ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
|
||||||
#define ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
|
||||||
|
|
||||||
#include "engine/segment_inforamtion.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace engine
|
|
||||||
{
|
|
||||||
namespace guidance
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
|
||||||
Simplify turn instructions
|
|
||||||
Input :
|
|
||||||
10. Turn left on B 36 for 20 km
|
|
||||||
11. Continue on B 35; B 36 for 2 km
|
|
||||||
12. Continue on B 36 for 13 km
|
|
||||||
|
|
||||||
Output:
|
|
||||||
10. Turn left on B 36 for 35 km
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline void CombineSimilarSegments(std::vector<SegmentInformation> &segments)
|
|
||||||
{
|
|
||||||
// TODO: rework to check only end and start of string.
|
|
||||||
// stl string is way to expensive
|
|
||||||
// unsigned lastTurn = 0;
|
|
||||||
// for(unsigned i = 1; i < path_description.size(); ++i) {
|
|
||||||
// string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
|
|
||||||
// if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
|
|
||||||
// if(std::string::npos != string0.find(string1+";")
|
|
||||||
// || std::string::npos != string0.find(";"+string1)
|
|
||||||
// || std::string::npos != string0.find(string1+" ;")
|
|
||||||
// || std::string::npos != string0.find("; "+string1)
|
|
||||||
// ){
|
|
||||||
// SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
|
|
||||||
// string1;
|
|
||||||
// for(; lastTurn != i; ++lastTurn)
|
|
||||||
// path_description[lastTurn].name_id = path_description[i].name_id;
|
|
||||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
|
||||||
// } else if(std::string::npos != string1.find(string0+";")
|
|
||||||
// || std::string::npos != string1.find(";"+string0)
|
|
||||||
// || std::string::npos != string1.find(string0+" ;")
|
|
||||||
// || std::string::npos != string1.find("; "+string0)
|
|
||||||
// ){
|
|
||||||
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
|
|
||||||
// string0;
|
|
||||||
// path_description[i].name_id = path_description[i-1].name_id;
|
|
||||||
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
|
|
||||||
// lastTurn = i;
|
|
||||||
// }
|
|
||||||
// string0 = string1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
|
||||||
} // namespace guidance
|
|
||||||
} // namespace engine
|
|
||||||
} // namespace osrm
|
|
||||||
|
|
||||||
#endif // ENGINE_GUIDANCE_PROCESSING_SEGMENT_COMPRESSION_HPP_
|
|
@ -2,7 +2,7 @@
|
|||||||
#define ENGINE_GUIDANCE_STEP_MANEUVER_HPP
|
#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
|
||||||
|
104
include/engine/guidance/turn_classification.hpp
Normal file
104
include/engine/guidance/turn_classification.hpp
Normal 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_
|
154
include/engine/guidance/turn_instruction.hpp
Normal file
154
include/engine/guidance/turn_instruction.hpp
Normal 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_
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
|
@ -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!");
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/engine/guidance/classification_data.cpp
Normal file
21
src/engine/guidance/classification_data.cpp
Normal 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
|
150
src/engine/guidance/post_processing.cpp
Normal file
150
src/engine/guidance/post_processing.cpp
Normal 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
|
@ -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;
|
||||||
|
@ -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 ¢er,
|
||||||
[](const TurnCandidate &left, const TurnCandidate ¢er, 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
|
||||||
|
@ -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:
|
||||||
|
@ -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));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user