Distinguish between offramps and sliproads.
This commit is contained in:
parent
089e60fa1e
commit
3d03797e53
@ -1,3 +1,10 @@
|
||||
# 5.2
|
||||
Changes from 5.2.0 RC2
|
||||
|
||||
- Guidance:
|
||||
- improved handling of sliproads (emit turns instead of 'take the ramp')
|
||||
BREAKING: modifies the file format with new internal identifiers
|
||||
|
||||
# 5.2.0 RC1
|
||||
Changes from 5.1.0
|
||||
|
||||
|
117
features/guidance/dedicated-turn-roads.feature
Normal file
117
features/guidance/dedicated-turn-roads.feature
Normal file
@ -0,0 +1,117 @@
|
||||
@routing @guidance
|
||||
Feature: Slipways and Dedicated Turn Lanes
|
||||
|
||||
Background:
|
||||
Given the profile "car"
|
||||
Given a grid size of 5 meters
|
||||
|
||||
Scenario: Turn Instead of Ramp
|
||||
Given the node map
|
||||
| | | | | e | |
|
||||
| a | b | | | c | d |
|
||||
| | | | h | | |
|
||||
| | | | | | |
|
||||
| | | | 1 | | |
|
||||
| | | | | | |
|
||||
| | | | | f | |
|
||||
| | | | | | |
|
||||
| | | | | g | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abcd | trunk | first |
|
||||
| bhf | trunk_link | |
|
||||
| ecfg | primary | second |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,second,second | depart,turn right,arrive |
|
||||
| a,1 | first,, | depart,turn slight right,arrive |
|
||||
|
||||
Scenario: Turn Instead of Ramp
|
||||
Given the node map
|
||||
| | | | | e | |
|
||||
| a | b | | | c | d |
|
||||
| | | | h | | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | f | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | g | |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abcd | motorway | first |
|
||||
| bhf | motorway_link | |
|
||||
| efg | primary | second |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,g | first,,second,second | depart,off ramp slight right,merge slight left,arrive |
|
||||
|
||||
Scenario: Inner city expressway with on road
|
||||
Given the node map
|
||||
| a | b | | | | c |
|
||||
| | | | | f | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | | d |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | | |
|
||||
| | | | | | e |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name |
|
||||
| abc | primary | road |
|
||||
| bfd | trunk_link | |
|
||||
| cde | trunk | trunk |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,e | road,trunk,trunk | depart,turn right,arrive |
|
||||
|
||||
|
||||
Scenario: Slipway Round U-Turn
|
||||
Given the node map
|
||||
| a | | f |
|
||||
| | | |
|
||||
| b | | e |
|
||||
| | | |
|
||||
| | | |
|
||||
| | g | |
|
||||
| | | |
|
||||
| c | | d |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | primary | road | yes |
|
||||
| bge | primary_link | | yes |
|
||||
| def | primary | road | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,f | road,road,road | depart,continue uturn,arrive |
|
||||
|
||||
Scenario: Slipway Steep U-Turn
|
||||
Given the node map
|
||||
| a | | f |
|
||||
| | | |
|
||||
| b | | e |
|
||||
| | g | |
|
||||
| | | |
|
||||
| | | |
|
||||
| c | | d |
|
||||
|
||||
And the ways
|
||||
| nodes | highway | name | oneway |
|
||||
| abc | primary | road | yes |
|
||||
| bge | primary_link | | yes |
|
||||
| def | primary | road | yes |
|
||||
|
||||
When I route I should get
|
||||
| waypoints | route | turns |
|
||||
| a,f | road,road,road | depart,continue uturn,arrive |
|
@ -12,8 +12,8 @@
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/guidance/toolkit.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
@ -68,10 +68,8 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
StepManeuver maneuver{source_node.location, bearings.first,
|
||||
bearings.second, extractor::guidance::TurnInstruction::NO_TURN(),
|
||||
WaypointType::Depart, 0};
|
||||
Intersection intersection{
|
||||
source_node.location,
|
||||
std::vector<short>({bearings.second}),
|
||||
std::vector<bool>({true}), Intersection::NO_INDEX, 0};
|
||||
Intersection intersection{source_node.location, std::vector<short>({bearings.second}),
|
||||
std::vector<bool>({true}), Intersection::NO_INDEX, 0};
|
||||
|
||||
if (leg_data.size() > 0)
|
||||
{
|
||||
@ -96,6 +94,17 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
const auto name = facade.GetNameForID(step_name_id);
|
||||
const auto distance = leg_geometry.segment_distances[segment_index];
|
||||
|
||||
steps.push_back(RouteStep{step_name_id,
|
||||
name,
|
||||
NO_ROTARY_NAME,
|
||||
segment_duration / 10.0,
|
||||
distance,
|
||||
path_point.travel_mode,
|
||||
maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection}});
|
||||
|
||||
if (leg_data_index + 1 < leg_data.size())
|
||||
{
|
||||
step_name_id = leg_data[leg_data_index + 1].name_id;
|
||||
@ -104,26 +113,26 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
{
|
||||
step_name_id = target_node.name_id;
|
||||
}
|
||||
steps.push_back(RouteStep{
|
||||
step_name_id, name, NO_ROTARY_NAME, segment_duration / 10.0, distance,
|
||||
path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1, {intersection}});
|
||||
|
||||
bearings = detail::getIntermediateBearings(leg_geometry, segment_index);
|
||||
const auto entry_class = facade.GetEntryClass(path_point.entry_classid);
|
||||
const auto bearing_class = facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node));
|
||||
intersection.in = bearing_class.findMatchingBearing(util::bearing::reverseBearing(bearings.first));
|
||||
const auto bearing_class =
|
||||
facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node));
|
||||
intersection.in = bearing_class.findMatchingBearing(
|
||||
util::bearing::reverseBearing(bearings.first));
|
||||
intersection.out = bearing_class.findMatchingBearing(bearings.second);
|
||||
intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node);
|
||||
intersection.bearings.clear();
|
||||
std::copy(bearing_class.getAvailableBearings().begin(), bearing_class.getAvailableBearings().end(),
|
||||
std::copy(bearing_class.getAvailableBearings().begin(),
|
||||
bearing_class.getAvailableBearings().end(),
|
||||
std::back_inserter(intersection.bearings));
|
||||
intersection.entry.clear();
|
||||
for (auto idx : util::irange<std::size_t>(0, intersection.bearings.size()))
|
||||
{
|
||||
intersection.entry.push_back(entry_class.allowsEntry(idx));
|
||||
}
|
||||
maneuver = {intersection.location, bearings.first, bearings.second, path_point.turn_instruction, WaypointType::None, 0};
|
||||
maneuver = {intersection.location, bearings.first, bearings.second,
|
||||
path_point.turn_instruction, WaypointType::None, 0};
|
||||
segment_index++;
|
||||
segment_duration = 0;
|
||||
}
|
||||
@ -131,10 +140,16 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
const auto distance = leg_geometry.segment_distances[segment_index];
|
||||
const int duration = segment_duration + target_duration;
|
||||
BOOST_ASSERT(duration >= 0);
|
||||
steps.push_back(RouteStep{
|
||||
step_name_id, facade.GetNameForID(step_name_id), NO_ROTARY_NAME, duration / 10.,
|
||||
distance, target_mode, maneuver, leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1, {intersection}});
|
||||
steps.push_back(RouteStep{step_name_id,
|
||||
facade.GetNameForID(step_name_id),
|
||||
NO_ROTARY_NAME,
|
||||
duration / 10.,
|
||||
distance,
|
||||
target_mode,
|
||||
maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection}});
|
||||
}
|
||||
// In this case the source + target are on the same edge segment
|
||||
else
|
||||
@ -148,30 +163,41 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
|
||||
int duration = target_duration - source_duration;
|
||||
BOOST_ASSERT(duration >= 0);
|
||||
|
||||
steps.push_back(RouteStep{
|
||||
source_node.name_id, facade.GetNameForID(source_node.name_id), NO_ROTARY_NAME,
|
||||
duration / 10., leg_geometry.segment_distances[segment_index], source_mode,
|
||||
std::move(maneuver), leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1, {intersection}});
|
||||
steps.push_back(RouteStep{source_node.name_id,
|
||||
facade.GetNameForID(source_node.name_id),
|
||||
NO_ROTARY_NAME,
|
||||
duration / 10.,
|
||||
leg_geometry.segment_distances[segment_index],
|
||||
source_mode,
|
||||
std::move(maneuver),
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection}});
|
||||
}
|
||||
|
||||
BOOST_ASSERT(segment_index == number_of_segments - 1);
|
||||
bearings = detail::getArriveBearings(leg_geometry);
|
||||
// This step has length zero, the only reason we need it is the target location
|
||||
maneuver = {intersection.location, bearings.first, bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, 0};
|
||||
maneuver = {intersection.location, bearings.first,
|
||||
bearings.second, extractor::guidance::TurnInstruction::NO_TURN(),
|
||||
WaypointType::Arrive, 0};
|
||||
intersection = {
|
||||
target_node.location,
|
||||
std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}),
|
||||
std::vector<bool>({true}), 0, Intersection::NO_INDEX};
|
||||
|
||||
BOOST_ASSERT(!leg_geometry.locations.empty());
|
||||
steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id),
|
||||
NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode,
|
||||
std::move(maneuver), leg_geometry.locations.size() - 1,
|
||||
steps.push_back(RouteStep{target_node.name_id,
|
||||
facade.GetNameForID(target_node.name_id),
|
||||
NO_ROTARY_NAME,
|
||||
ZERO_DURATION,
|
||||
ZERO_DISTANCE,
|
||||
target_mode,
|
||||
std::move(maneuver),
|
||||
leg_geometry.locations.size() - 1,
|
||||
leg_geometry.locations.size(),
|
||||
{intersection}});
|
||||
|
||||
|
||||
BOOST_ASSERT(steps.front().intersections.size() == 1);
|
||||
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);
|
||||
BOOST_ASSERT(steps.front().intersections.front().entry.size() == 1);
|
||||
|
@ -47,6 +47,17 @@ inline bool isRampClass(const FunctionalRoadClass road_class)
|
||||
road_class == FunctionalRoadClass::TRUNK_LINK;
|
||||
}
|
||||
|
||||
// Links are usually smaller than ramps, but are sometimes tagged
|
||||
// as MOTORWAY_LINK if they exit/enter a motorway/trunk road.
|
||||
inline bool isLinkClass(const FunctionalRoadClass road_class)
|
||||
{
|
||||
return road_class == FunctionalRoadClass::MOTORWAY_LINK ||
|
||||
road_class == FunctionalRoadClass::TRUNK_LINK ||
|
||||
road_class == FunctionalRoadClass::PRIMARY_LINK ||
|
||||
road_class == FunctionalRoadClass::SECONDARY_LINK ||
|
||||
road_class == FunctionalRoadClass::TERTIARY_LINK;
|
||||
}
|
||||
|
||||
// TODO augment this with all data required for guidance generation
|
||||
struct RoadClassificationData
|
||||
{
|
||||
|
@ -22,10 +22,12 @@ const double constexpr FUZZY_ANGLE_DIFFERENCE = 20.;
|
||||
const double constexpr DISTINCTION_RATIO = 2;
|
||||
const unsigned constexpr INVALID_NAME_ID = 0;
|
||||
|
||||
const double constexpr MAX_ROUNDABOUT_INTERSECTION_RADIUS = 5;
|
||||
const double constexpr MAX_ROUNDABOUT_INTERSECTION_RADIUS = 5;
|
||||
const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
|
||||
const double constexpr INCREASES_BY_FOURTY_PERCENT = 1.4;
|
||||
|
||||
const unsigned constexpr MAX_SLIPROAD_THRESHOLD = 250;
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/intersection_handler.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
@ -25,7 +26,8 @@ class MotorwayHandler : public IntersectionHandler
|
||||
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator);
|
||||
~MotorwayHandler() override final;
|
||||
|
||||
// check whether the handler can actually handle the intersection
|
||||
@ -39,10 +41,14 @@ class MotorwayHandler : public IntersectionHandler
|
||||
Intersection intersection) const override final;
|
||||
|
||||
private:
|
||||
Intersection handleSliproads(const NodeID intersection_node_id,
|
||||
Intersection intersection) const;
|
||||
Intersection fromMotorway(const EdgeID via_edge, Intersection intersection) const;
|
||||
Intersection fromRamp(const EdgeID via_edge, Intersection intersection) const;
|
||||
|
||||
Intersection fallback(Intersection intersection) const;
|
||||
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
|
@ -59,6 +59,9 @@ class TurnAnalysis
|
||||
// Utility function, setting basic turn types. Prepares for normal turn handling.
|
||||
Intersection
|
||||
setTurnTypes(const NodeID from, const EdgeID via_edge, Intersection intersection) const;
|
||||
|
||||
Intersection handleSliproads(const NodeID intersection_node_id,
|
||||
Intersection intersection) const;
|
||||
}; // class TurnAnalysis
|
||||
|
||||
} // namespace guidance
|
||||
|
@ -20,7 +20,6 @@ namespace detail
|
||||
const constexpr uint8_t num_direction_modifiers = 8;
|
||||
} // detail
|
||||
|
||||
|
||||
// direction modifiers based on angle
|
||||
namespace DirectionModifier
|
||||
{
|
||||
@ -38,31 +37,36 @@ const constexpr Enum SharpLeft = 7;
|
||||
namespace TurnType
|
||||
{
|
||||
typedef std::uint8_t Enum;
|
||||
const constexpr Enum Invalid = 0; // no valid turn instruction
|
||||
const constexpr Enum NewName = 1; // no turn, but name changes
|
||||
const constexpr Enum Continue = 2; // remain on a street
|
||||
const constexpr Enum Turn = 3; // basic turn
|
||||
const constexpr Enum Merge = 4; // merge onto a street
|
||||
const constexpr Enum OnRamp = 5; // special turn (highway ramp on-ramps)
|
||||
const constexpr Enum OffRamp = 6; // special turn, highway exit
|
||||
const constexpr Enum Fork = 7; // fork road splitting up
|
||||
const constexpr Enum EndOfRoad = 8; // T intersection
|
||||
const constexpr Enum Notification = 9; // Travel Mode Changes, Restrictions apply...
|
||||
const constexpr Enum EnterRoundabout = 10; // Entering a small Roundabout
|
||||
const constexpr Enum EnterAndExitRoundabout = 11; // Touching a roundabout
|
||||
const constexpr Enum EnterRotary = 12; // Enter a rotary
|
||||
const constexpr Enum EnterAndExitRotary = 13; // Touching a rotary
|
||||
const constexpr Enum EnterRoundaboutIntersection = 14; // Entering a small Roundabout
|
||||
const constexpr Enum Invalid = 0; // no valid turn instruction
|
||||
const constexpr Enum NewName = 1; // no turn, but name changes
|
||||
const constexpr Enum Continue = 2; // remain on a street
|
||||
const constexpr Enum Turn = 3; // basic turn
|
||||
const constexpr Enum Merge = 4; // merge onto a street
|
||||
const constexpr Enum OnRamp = 5; // special turn (highway ramp on-ramps)
|
||||
const constexpr Enum OffRamp = 6; // special turn, highway exit
|
||||
const constexpr Enum Fork = 7; // fork road splitting up
|
||||
const constexpr Enum EndOfRoad = 8; // T intersection
|
||||
const constexpr Enum Notification = 9; // Travel Mode Changes, Restrictions apply...
|
||||
const constexpr Enum EnterRoundabout = 10; // Entering a small Roundabout
|
||||
const constexpr Enum EnterAndExitRoundabout = 11; // Touching a roundabout
|
||||
const constexpr Enum EnterRotary = 12; // Enter a rotary
|
||||
const constexpr Enum EnterAndExitRotary = 13; // Touching a rotary
|
||||
const constexpr Enum EnterRoundaboutIntersection = 14; // Entering a small Roundabout
|
||||
const constexpr Enum EnterAndExitRoundaboutIntersection = 15; // Touching a roundabout
|
||||
const constexpr Enum NoTurn = 16; // end of segment without turn/middle of a segment
|
||||
const constexpr Enum Suppressed = 17; // location that suppresses a turn
|
||||
const constexpr Enum EnterRoundaboutAtExit = 18; // Entering a small Roundabout at a countable exit
|
||||
const constexpr Enum ExitRoundabout = 19; // Exiting a small Roundabout
|
||||
const constexpr Enum EnterRotaryAtExit = 20; // Enter A Rotary at a countable exit
|
||||
const constexpr Enum ExitRotary = 21; // Exit a rotary
|
||||
const constexpr Enum EnterRoundaboutIntersectionAtExit = 22; // Entering a small Roundabout at a countable exit
|
||||
const constexpr Enum ExitRoundaboutIntersection = 23; // Exiting a small Roundabout
|
||||
const constexpr Enum StayOnRoundabout = 24; // Continue on Either a small or a large Roundabout
|
||||
|
||||
// Values below here are silent instructions
|
||||
const constexpr Enum NoTurn = 16; // end of segment without turn/middle of a segment
|
||||
const constexpr Enum Suppressed = 17; // location that suppresses a turn
|
||||
const constexpr Enum EnterRoundaboutAtExit = 18; // Entering a small Roundabout at a countable exit
|
||||
const constexpr Enum ExitRoundabout = 19; // Exiting a small Roundabout
|
||||
const constexpr Enum EnterRotaryAtExit = 20; // Enter A Rotary at a countable exit
|
||||
const constexpr Enum ExitRotary = 21; // Exit a rotary
|
||||
const constexpr Enum EnterRoundaboutIntersectionAtExit =
|
||||
22; // Entering a small Roundabout at a countable exit
|
||||
const constexpr Enum ExitRoundaboutIntersection = 23; // Exiting a small Roundabout
|
||||
const constexpr Enum StayOnRoundabout = 24; // Continue on Either a small or a large Roundabout
|
||||
const constexpr Enum Sliproad =
|
||||
25; // Something that looks like a ramp, but is actually just a small sliproad
|
||||
}
|
||||
|
||||
// turn angle in 1.40625 degree -> 128 == 180 degree
|
||||
@ -87,7 +91,8 @@ struct TurnInstruction
|
||||
return TurnInstruction(TurnType::NoTurn, DirectionModifier::UTurn);
|
||||
}
|
||||
|
||||
static TurnInstruction REMAIN_ROUNDABOUT(const RoundaboutType, const DirectionModifier::Enum modifier)
|
||||
static TurnInstruction REMAIN_ROUNDABOUT(const RoundaboutType,
|
||||
const DirectionModifier::Enum modifier)
|
||||
{
|
||||
return TurnInstruction(TurnType::StayOnRoundabout, modifier);
|
||||
}
|
||||
@ -104,9 +109,9 @@ struct TurnInstruction
|
||||
static TurnInstruction EXIT_ROUNDABOUT(const RoundaboutType roundabout_type,
|
||||
const DirectionModifier::Enum modifier)
|
||||
{
|
||||
const constexpr TurnType::Enum exit_instruction[] = {TurnType::Invalid, TurnType::ExitRoundabout,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::ExitRoundaboutIntersection};
|
||||
const constexpr TurnType::Enum exit_instruction[] = {
|
||||
TurnType::Invalid, TurnType::ExitRoundabout, TurnType::ExitRotary,
|
||||
TurnType::ExitRoundaboutIntersection};
|
||||
return {exit_instruction[static_cast<int>(roundabout_type)], modifier};
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
// OpenStreetMap node ids are higher than 2^32
|
||||
OSRM_STRONG_TYPEDEF(std::uint64_t, OSMNodeID)
|
||||
@ -56,6 +56,7 @@ using OSMEdgeID_weak = std::uint64_t;
|
||||
|
||||
using NodeID = unsigned int;
|
||||
using EdgeID = unsigned int;
|
||||
using NameID = std::uint32_t;
|
||||
using EdgeWeight = int;
|
||||
|
||||
using BearingClassID = std::uint32_t;
|
||||
@ -80,8 +81,8 @@ struct SegmentID
|
||||
BOOST_ASSERT(!enabled || id != SPECIAL_SEGMENTID);
|
||||
}
|
||||
|
||||
NodeID id : 31;
|
||||
std::uint32_t enabled : 1;
|
||||
NodeID id : 31;
|
||||
std::uint32_t enabled : 1;
|
||||
};
|
||||
|
||||
static_assert(sizeof(SegmentID) == 4, "SegmentID needs to be 4 bytes big");
|
||||
|
@ -42,7 +42,8 @@ const constexpr char *turn_type_names[] = {
|
||||
"on ramp", "off ramp", "fork", "end of road", "notification",
|
||||
"roundabout", "roundabout", "rotary", "rotary", "roundabout turn",
|
||||
"roundabout turn", "invalid", "invalid", "invalid", "invalid",
|
||||
"invalid", "invalid", "invalid", "invalid", "invalid"};
|
||||
"invalid", "invalid", "invalid", "invalid", "invalid",
|
||||
"invalid"};
|
||||
|
||||
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
|
||||
|
||||
@ -150,20 +151,19 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
|
||||
return step_maneuver;
|
||||
}
|
||||
|
||||
util::json::Object
|
||||
makeIntersection(const guidance::Intersection &intersection)
|
||||
util::json::Object makeIntersection(const guidance::Intersection &intersection)
|
||||
{
|
||||
util::json::Object result;
|
||||
util::json::Array bearings;
|
||||
util::json::Array entry;
|
||||
|
||||
bearings.values.reserve(intersection.bearings.size());
|
||||
std::copy(intersection.bearings.begin(), intersection.bearings.end(), std::back_inserter(bearings.values));
|
||||
std::copy(intersection.bearings.begin(), intersection.bearings.end(),
|
||||
std::back_inserter(bearings.values));
|
||||
|
||||
entry.values.reserve(intersection.entry.size());
|
||||
std::transform(intersection.entry.begin(), intersection.entry.end(),
|
||||
std::back_inserter(entry.values), [](const bool has_entry) -> util::json::Value
|
||||
{
|
||||
std::back_inserter(entry.values), [](const bool has_entry) -> util::json::Value {
|
||||
if (has_entry)
|
||||
return util::json::True();
|
||||
else
|
||||
|
@ -41,8 +41,8 @@ void print(const std::vector<RouteStep> &steps)
|
||||
int segment = 0;
|
||||
for (const auto &step : steps)
|
||||
{
|
||||
std::cout << "\t[" << ++segment << "]: " << step.maneuver.instruction.type << " "
|
||||
<< step.maneuver.instruction.direction_modifier << " "
|
||||
std::cout << "\t[" << ++segment << "]: " << static_cast<int>(step.maneuver.instruction.type)
|
||||
<< " " << static_cast<int>(step.maneuver.instruction.direction_modifier) << " "
|
||||
<< static_cast<int>(step.maneuver.waypoint_type) << " Duration: " << step.duration
|
||||
<< " Distance: " << step.distance << " Geometry: " << step.geometry_begin << " "
|
||||
<< step.geometry_end << " exit: " << step.maneuver.exit
|
||||
@ -63,6 +63,37 @@ void print(const std::vector<RouteStep> &steps)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the angle between two bearings on a normal turn circle
|
||||
//
|
||||
// Bearings Angles
|
||||
//
|
||||
// 0 180
|
||||
// 315 45 225 135
|
||||
//
|
||||
// 270 x 90 270 x 90
|
||||
//
|
||||
// 225 135 315 45
|
||||
// 180 0
|
||||
//
|
||||
// A turn from north to north-east offerst bearing 0 and 45 has to be translated
|
||||
// into a turn of 135 degrees. The same holdes for 90 - 135 (east to south
|
||||
// east).
|
||||
// For north, the transformation works by angle = 540 (360 + 180) - exit_bearing
|
||||
// % 360;
|
||||
// All other cases are handled by first rotating both bearings to an
|
||||
// entry_bearing of 0.
|
||||
double turn_angle(const double entry_bearing, const double exit_bearing)
|
||||
{
|
||||
const double offset = 360 - entry_bearing;
|
||||
const double rotated_exit = [](double bearing, const double offset) {
|
||||
bearing += offset;
|
||||
return bearing > 360 ? bearing - 360 : bearing;
|
||||
}(exit_bearing, offset);
|
||||
|
||||
const auto angle = 540 - rotated_exit;
|
||||
return angle > 360 ? angle - 360 : angle;
|
||||
}
|
||||
|
||||
RouteStep forwardInto(RouteStep destination, const RouteStep &source)
|
||||
{
|
||||
// Merge a turn into a silent turn
|
||||
@ -232,39 +263,11 @@ void closeOffRoundabout(const bool on_roundabout,
|
||||
propagation_step.maneuver.instruction.type ==
|
||||
TurnType::EnterRoundaboutIntersectionAtExit)
|
||||
{
|
||||
// Compute the angle between two bearings on a normal turn circle
|
||||
//
|
||||
// Bearings Angles
|
||||
//
|
||||
// 0 180
|
||||
// 315 45 225 135
|
||||
//
|
||||
// 270 x 90 270 x 90
|
||||
//
|
||||
// 225 135 315 45
|
||||
// 180 0
|
||||
//
|
||||
// A turn from north to north-east offerst bearing 0 and 45 has to be translated
|
||||
// into a turn of 135 degrees. The same holdes for 90 - 135 (east to south
|
||||
// east).
|
||||
// For north, the transformation works by angle = 540 (360 + 180) - exit_bearing
|
||||
// % 360;
|
||||
// All other cases are handled by first rotating both bearings to an
|
||||
// entry_bearing of 0.
|
||||
BOOST_ASSERT(!propagation_step.intersections.empty());
|
||||
const double angle =
|
||||
[](const double entry_bearing, const double exit_bearing) {
|
||||
const double offset = 360 - entry_bearing;
|
||||
const double rotated_exit = [](double bearing, const double offset) {
|
||||
bearing += offset;
|
||||
return bearing > 360 ? bearing - 360 : bearing;
|
||||
}(exit_bearing, offset);
|
||||
|
||||
const auto angle = 540 - rotated_exit;
|
||||
return angle > 360 ? angle - 360 : angle;
|
||||
}(util::bearing::reverseBearing(
|
||||
entry_intersection.bearings[entry_intersection.in]),
|
||||
exit_bearing);
|
||||
turn_angle(util::bearing::reverseBearing(
|
||||
entry_intersection.bearings[entry_intersection.in]),
|
||||
exit_bearing);
|
||||
|
||||
propagation_step.maneuver.instruction.direction_modifier =
|
||||
::osrm::util::guidance::getTurnDirection(angle);
|
||||
@ -417,6 +420,7 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
|
||||
}
|
||||
|
||||
steps[one_back_index].name = steps[two_back_index].name;
|
||||
steps[one_back_index].name_id = steps[two_back_index].name_id;
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
DirectionModifier::UTurn;
|
||||
@ -580,6 +584,15 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
instruction.direction_modifier == DirectionModifier::Straight);
|
||||
};
|
||||
|
||||
// Special case handling: if the phantomnode landed on a sliproad, we
|
||||
// change this into a 'turn' instruction. Sliproads are small ramps
|
||||
// between roads, not ramps.
|
||||
if (steps.size() >= 3 &&
|
||||
steps[steps.size() - 2].maneuver.instruction.type == TurnType::Sliproad)
|
||||
{
|
||||
steps[steps.size() - 2].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
|
||||
// first and last instructions are waypoints that cannot be collapsed
|
||||
for (std::size_t step_index = 2; step_index < steps.size(); ++step_index)
|
||||
{
|
||||
@ -595,10 +608,40 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
const auto two_back_index = getPreviousIndex(one_back_index);
|
||||
BOOST_ASSERT(two_back_index < steps.size());
|
||||
|
||||
// Handle sliproads from motorways in urban areas
|
||||
if (one_back_step.maneuver.instruction.type == TurnType::Sliproad)
|
||||
{
|
||||
|
||||
// Handle possible u-turns between highways that look like slip-roads
|
||||
if (steps[two_back_index].name_id == steps[step_index].name_id &&
|
||||
steps[step_index].name_id != INVALID_NAMEID)
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||
steps[one_back_index].name_id = steps[step_index].name_id;
|
||||
steps[one_back_index].name = steps[step_index].name;
|
||||
|
||||
const auto exit_intersection = steps[step_index].intersections.front();
|
||||
const auto exit_bearing = exit_intersection.bearings[exit_intersection.out];
|
||||
|
||||
const auto entry_intersection = steps[one_back_index].intersections.front();
|
||||
const auto entry_bearing = entry_intersection.bearings[entry_intersection.in];
|
||||
|
||||
const double angle =
|
||||
turn_angle(util::bearing::reverseBearing(entry_bearing), exit_bearing);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
::osrm::util::guidance::getTurnDirection(angle);
|
||||
invalidateStep(steps[step_index]);
|
||||
}
|
||||
// Due to empty segments, we can get name-changes from A->A
|
||||
// These have to be handled in post-processing
|
||||
if (isCollapsableInstruction(current_step.maneuver.instruction) &&
|
||||
current_step.name == steps[one_back_index].name)
|
||||
else if (isCollapsableInstruction(current_step.maneuver.instruction) &&
|
||||
current_step.name == steps[one_back_index].name)
|
||||
{
|
||||
steps[one_back_index] = elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||
invalidateStep(steps[step_index]);
|
||||
|
@ -45,8 +45,10 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base
|
||||
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table)
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table),
|
||||
intersection_generator(intersection_generator)
|
||||
{
|
||||
}
|
||||
|
||||
@ -251,18 +253,16 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
||||
else if (road.turn.angle < continue_angle)
|
||||
{
|
||||
road.turn.instruction = {
|
||||
detail::isRampClass(road.turn.eid, node_based_graph)
|
||||
? TurnType::OffRamp
|
||||
: TurnType::Turn,
|
||||
detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp
|
||||
: TurnType::Turn,
|
||||
(road.turn.angle < 145) ? DirectionModifier::Right
|
||||
: DirectionModifier::SlightRight};
|
||||
}
|
||||
else if (road.turn.angle > continue_angle)
|
||||
{
|
||||
road.turn.instruction = {
|
||||
detail::isRampClass(road.turn.eid, node_based_graph)
|
||||
? TurnType::OffRamp
|
||||
: TurnType::Turn,
|
||||
detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp
|
||||
: TurnType::Turn,
|
||||
(road.turn.angle > 215) ? DirectionModifier::Left
|
||||
: DirectionModifier::SlightLeft};
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
using osrm::util::guidance::getTurnDirection;
|
||||
|
||||
@ -42,9 +42,17 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
barrier_nodes,
|
||||
node_info_list,
|
||||
compressed_edge_container),
|
||||
roundabout_handler(node_based_graph, node_info_list, compressed_edge_container, name_table, street_name_suffix_table),
|
||||
motorway_handler(node_based_graph, node_info_list, name_table,street_name_suffix_table),
|
||||
turn_handler(node_based_graph, node_info_list, name_table,street_name_suffix_table)
|
||||
roundabout_handler(node_based_graph,
|
||||
node_info_list,
|
||||
compressed_edge_container,
|
||||
name_table,
|
||||
street_name_suffix_table),
|
||||
motorway_handler(node_based_graph,
|
||||
node_info_list,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
intersection_generator),
|
||||
turn_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table)
|
||||
{
|
||||
}
|
||||
|
||||
@ -73,6 +81,9 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from_nid, const E
|
||||
}
|
||||
}
|
||||
|
||||
// Handle sliproads
|
||||
intersection = handleSliproads(via_eid, std::move(intersection));
|
||||
|
||||
std::vector<TurnOperation> turns;
|
||||
for (auto road : intersection)
|
||||
if (road.entry_allowed)
|
||||
@ -105,6 +116,88 @@ TurnAnalysis::setTurnTypes(const NodeID from_nid, const EdgeID, Intersection int
|
||||
return intersection;
|
||||
}
|
||||
|
||||
// "Sliproads" occur when we've got a link between two roads (MOTORWAY_LINK, etc), but
|
||||
// the two roads are *also* directly connected shortly afterwards.
|
||||
// In these cases, we tag the turn-type as "sliproad", and then in post-processing
|
||||
// we emit a "turn", instead of "take the ramp"+"merge"
|
||||
Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
|
||||
Intersection intersection) const
|
||||
{
|
||||
|
||||
auto intersection_node_id = node_based_graph.GetTarget(source_edge_id);
|
||||
|
||||
const auto linkTest = [this](const ConnectedRoad &road) {
|
||||
return isLinkClass(
|
||||
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class) &&
|
||||
road.entry_allowed &&
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
|
||||
};
|
||||
|
||||
bool hasRamp =
|
||||
std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end();
|
||||
if (!hasRamp)
|
||||
return intersection;
|
||||
|
||||
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
|
||||
|
||||
// Find the continuation of the intersection we're on
|
||||
auto next_road = std::find_if(
|
||||
intersection.begin(), intersection.end(),
|
||||
[this, source_edge_data](const ConnectedRoad &road) {
|
||||
const auto road_edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||
// Test to see if the source edge and the one we're looking at are the same road
|
||||
return road_edge_data.road_classification.road_class ==
|
||||
source_edge_data.road_classification.road_class &&
|
||||
road_edge_data.name_id != INVALID_NAME_ID &&
|
||||
road_edge_data.name_id == source_edge_data.name_id && road.entry_allowed &&
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE;
|
||||
});
|
||||
|
||||
const bool hasNext = next_road != intersection.end();
|
||||
|
||||
if (!hasNext)
|
||||
{
|
||||
return intersection;
|
||||
}
|
||||
|
||||
// Threshold check, if the intersection is too far away, don't bother continuing
|
||||
const auto &next_road_data = node_based_graph.GetEdgeData(next_road->turn.eid);
|
||||
if (next_road_data.distance > MAX_SLIPROAD_THRESHOLD)
|
||||
{
|
||||
return intersection;
|
||||
}
|
||||
|
||||
const auto next_road_next_intersection =
|
||||
intersection_generator(intersection_node_id, next_road->turn.eid);
|
||||
|
||||
std::unordered_set<NameID> target_road_names;
|
||||
|
||||
for (const auto &road : next_road_next_intersection)
|
||||
{
|
||||
const auto &target_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||
target_road_names.insert(target_data.name_id);
|
||||
}
|
||||
|
||||
for (auto &road : intersection)
|
||||
{
|
||||
if (linkTest(road))
|
||||
{
|
||||
auto target_intersection = intersection_generator(intersection_node_id, road.turn.eid);
|
||||
for (const auto &candidate_road : target_intersection)
|
||||
{
|
||||
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid);
|
||||
if (target_road_names.count(candidate_data.name_id) > 0)
|
||||
{
|
||||
road.turn.instruction.type = TurnType::Sliproad;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
Loading…
Reference in New Issue
Block a user