Restructure Obvious Turn Handling, code transfer from #4426
This commit is contained in:
parent
bdb116afe5
commit
d166fc6a75
1212
features/guidance/obvious-turn-discovery.feature
Normal file
1212
features/guidance/obvious-turn-discovery.feature
Normal file
File diff suppressed because it is too large
Load Diff
@ -614,8 +614,9 @@ Feature: Turn Lane Guidance
|
|||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
b d
|
b d
|
||||||
h c
|
h-----c
|
||||||
' -- g - - f
|
| `-f
|
||||||
|
g
|
||||||
"""
|
"""
|
||||||
|
|
||||||
And the ways
|
And the ways
|
||||||
|
@ -964,15 +964,15 @@ Feature: Simple Turns
|
|||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
g
|
g
|
||||||
|
|
|
||||||
f y
|
_--f-----y
|
||||||
i
|
i-' |
|
||||||
j k a b x
|
j-k-a]|[b---x
|
||||||
e c
|
e 'c
|
||||||
d
|
|'d'
|
||||||
|
|
|
||||||
h
|
h
|
||||||
|
|
|
||||||
q
|
q
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -1373,6 +1373,36 @@ Feature: Simple Turns
|
|||||||
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
|
| a,d | ab,bcd,bcd | depart,fork slight right,arrive |
|
||||||
| a,g | ab,befg,befg | depart,fork slight left,arrive |
|
| a,g | ab,befg,befg | depart,fork slight left,arrive |
|
||||||
|
|
||||||
|
@routing @car
|
||||||
|
Scenario: No turn instruction when turning from unnamed onto unnamed
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
b----------------c
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | name | ref |
|
||||||
|
| ab | trunk_link | | |
|
||||||
|
| db | secondary | | L 460 |
|
||||||
|
| bc | secondary | | |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| from | to | route | ref | turns |
|
||||||
|
| d | c | ,, | L 460,, | depart,turn right,arrive |
|
||||||
|
| c | d | ,, | ,L 460,L 460 | depart,turn left,arrive |
|
||||||
|
|
||||||
# https://www.openstreetmap.org/#map=18/52.25130/10.42545
|
# https://www.openstreetmap.org/#map=18/52.25130/10.42545
|
||||||
Scenario: Turn for roads with no name, ref changes
|
Scenario: Turn for roads with no name, ref changes
|
||||||
Given the node map
|
Given the node map
|
||||||
|
@ -152,7 +152,7 @@ Feature: Turn Function Information
|
|||||||
And stdout should contain "number_of_roads 3"
|
And stdout should contain "number_of_roads 3"
|
||||||
And stdout should contain "source_priority_class 4"
|
And stdout should contain "source_priority_class 4"
|
||||||
And stdout should contain "target_priority_class 0"
|
And stdout should contain "target_priority_class 0"
|
||||||
And stdout should contain "target_priority_class 11"
|
And stdout should contain "target_priority_class 10"
|
||||||
# turning abd, give information about bc
|
# turning abd, give information about bc
|
||||||
And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: false, is_outgoing: true, highway_turn_classification: 4, access_turn_classification: 0/
|
And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: false, is_outgoing: true, highway_turn_classification: 4, access_turn_classification: 0/
|
||||||
# turning abc, give information about bd
|
# turning abc, give information about bd
|
||||||
@ -180,7 +180,3 @@ Feature: Turn Function Information
|
|||||||
And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 3, access_turn_classification: 0/
|
And stdout should contain /roads_on_the_right \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 3, access_turn_classification: 0/
|
||||||
# turning abc, give information about about db
|
# turning abc, give information about about db
|
||||||
And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 0, access_turn_classification: 1/
|
And stdout should contain /roads_on_the_left \[1\] speed: [0-9]+, is_incoming: true, is_outgoing: false, highway_turn_classification: 0, access_turn_classification: 1/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
|
#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
|
||||||
#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
|
#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -22,17 +23,25 @@ namespace RoadPriorityClass
|
|||||||
typedef std::uint8_t Enum;
|
typedef std::uint8_t Enum;
|
||||||
// Top priority Road
|
// Top priority Road
|
||||||
const constexpr Enum MOTORWAY = 0;
|
const constexpr Enum MOTORWAY = 0;
|
||||||
|
const constexpr Enum MOTORWAY_LINK = 1;
|
||||||
// Second highest priority
|
// Second highest priority
|
||||||
const constexpr Enum TRUNK = 2;
|
const constexpr Enum TRUNK = 2;
|
||||||
|
const constexpr Enum TRUNK_LINK = 3;
|
||||||
// Main roads
|
// Main roads
|
||||||
const constexpr Enum PRIMARY = 4;
|
const constexpr Enum PRIMARY = 4;
|
||||||
|
const constexpr Enum PRIMARY_LINK = 5;
|
||||||
const constexpr Enum SECONDARY = 6;
|
const constexpr Enum SECONDARY = 6;
|
||||||
|
const constexpr Enum SECONDARY_LINK = 7;
|
||||||
const constexpr Enum TERTIARY = 8;
|
const constexpr Enum TERTIARY = 8;
|
||||||
|
const constexpr Enum TERTIARY_LINK = 9;
|
||||||
// Residential Categories
|
// Residential Categories
|
||||||
const constexpr Enum MAIN_RESIDENTIAL = 10;
|
const constexpr Enum MAIN_RESIDENTIAL = 10;
|
||||||
const constexpr Enum SIDE_RESIDENTIAL = 11;
|
const constexpr Enum SIDE_RESIDENTIAL = 11;
|
||||||
|
const constexpr Enum ALLEY = 12;
|
||||||
|
const constexpr Enum PARKING = 13;
|
||||||
// Link Category
|
// Link Category
|
||||||
const constexpr Enum LINK_ROAD = 14;
|
const constexpr Enum LINK_ROAD = 14;
|
||||||
|
const constexpr Enum UNCLASSIFIED = 15;
|
||||||
// Bike Accessible
|
// Bike Accessible
|
||||||
const constexpr Enum BIKE_PATH = 16;
|
const constexpr Enum BIKE_PATH = 16;
|
||||||
// Walk Accessible
|
// Walk Accessible
|
||||||
@ -125,6 +134,67 @@ inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassifica
|
|||||||
static_cast<int>(second.GetPriority())) <= 1;
|
static_cast<int>(second.GetPriority())) <= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// priority groups are road classes that can be categoriesed as somewhat similar
|
||||||
|
inline std::uint32_t getRoadGroup(const RoadClassification classification)
|
||||||
|
{
|
||||||
|
// a list of dividers (inclusive) specifying the end of a class
|
||||||
|
const auto constexpr num_dividers = 7;
|
||||||
|
// dividers point one past the entry we want, so motorways will be pre-primary
|
||||||
|
const constexpr RoadPriorityClass::Enum dividers[num_dividers] = {
|
||||||
|
RoadPriorityClass::PRIMARY,
|
||||||
|
RoadPriorityClass::TERTIARY_LINK,
|
||||||
|
RoadPriorityClass::ALLEY,
|
||||||
|
RoadPriorityClass::LINK_ROAD,
|
||||||
|
RoadPriorityClass::UNCLASSIFIED,
|
||||||
|
RoadPriorityClass::BIKE_PATH,
|
||||||
|
RoadPriorityClass::CONNECTIVITY + 1};
|
||||||
|
|
||||||
|
const auto upper =
|
||||||
|
std::upper_bound(dividers, dividers + num_dividers, classification.GetPriority());
|
||||||
|
return upper - dividers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a road classification is strictly less, if it belongs to a lower general category of roads. E.g.
|
||||||
|
// normal city roads are strictly less of a priority than a motorway and alleys are strictly less
|
||||||
|
// than inner-city roads
|
||||||
|
inline bool strictlyLess(const RoadClassification lhs, const RoadClassification rhs)
|
||||||
|
{
|
||||||
|
const auto lhs_class = getRoadGroup(lhs);
|
||||||
|
const auto rhs_class = getRoadGroup(rhs);
|
||||||
|
// different class, not neighbors
|
||||||
|
return lhs_class > rhs_class &&
|
||||||
|
((lhs.GetPriority() - rhs.GetPriority() > 4) || lhs.IsLowPriorityRoadClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether a link class is the fitting link class to a road
|
||||||
|
inline bool isLinkTo(const RoadClassification link, const RoadClassification road)
|
||||||
|
{
|
||||||
|
// needs to be a link/non-link combination
|
||||||
|
if (!link.IsLinkClass() || road.IsLinkClass())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (link.GetPriority())
|
||||||
|
{
|
||||||
|
case RoadPriorityClass::MOTORWAY_LINK:
|
||||||
|
return road.GetPriority() == RoadPriorityClass::MOTORWAY;
|
||||||
|
|
||||||
|
case RoadPriorityClass::TRUNK_LINK:
|
||||||
|
return road.GetPriority() == RoadPriorityClass::TRUNK;
|
||||||
|
|
||||||
|
case RoadPriorityClass::PRIMARY_LINK:
|
||||||
|
return road.GetPriority() == RoadPriorityClass::PRIMARY;
|
||||||
|
|
||||||
|
case RoadPriorityClass::SECONDARY_LINK:
|
||||||
|
return road.GetPriority() == RoadPriorityClass::SECONDARY;
|
||||||
|
|
||||||
|
case RoadPriorityClass::TERTIARY_LINK:
|
||||||
|
return road.GetPriority() == RoadPriorityClass::TERTIARY;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline bool obviousByRoadClass(const RoadClassification in_classification,
|
inline bool obviousByRoadClass(const RoadClassification in_classification,
|
||||||
const RoadClassification obvious_candidate,
|
const RoadClassification obvious_candidate,
|
||||||
const RoadClassification compare_candidate)
|
const RoadClassification compare_candidate)
|
||||||
|
@ -68,6 +68,16 @@ class IntersectionHandler
|
|||||||
|
|
||||||
TurnType::Enum areSameClasses(const EdgeID via_edge, const ConnectedRoad &road) const;
|
TurnType::Enum areSameClasses(const EdgeID via_edge, const ConnectedRoad &road) const;
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
inline bool IsDistinctTurn(const std::size_t index,
|
||||||
|
const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const;
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
inline bool IsDistinctContinue(const std::size_t index,
|
||||||
|
const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const;
|
||||||
|
|
||||||
// Find the most obvious turn to follow. The function returns an index into the intersection
|
// Find the most obvious turn to follow. The function returns an index into the intersection
|
||||||
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
// determining whether there is a road that can be seen as obvious turn in the presence of many
|
||||||
// other possible turns. The function will consider road categories and other inputs like the
|
// other possible turns. The function will consider road categories and other inputs like the
|
||||||
@ -75,6 +85,14 @@ class IntersectionHandler
|
|||||||
template <typename IntersectionType> // works with Intersection and IntersectionView
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
|
std::size_t findObviousTurn(const EdgeID via_edge, const IntersectionType &intersection) const;
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
std::size_t findObviousTurnOld(const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const;
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
std::size_t findObviousTurnNew(const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const;
|
||||||
|
|
||||||
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
|
// Obvious turns can still take multiple forms. This function looks at the turn onto a road
|
||||||
// candidate when coming from a via_edge and determines the best instruction to emit.
|
// candidate when coming from a via_edge and determines the best instruction to emit.
|
||||||
// `through_street` indicates if the street turned onto is a through sreet (think mergees and
|
// `through_street` indicates if the street turned onto is a through sreet (think mergees and
|
||||||
@ -124,10 +142,621 @@ class IntersectionHandler
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Impl.
|
// Impl.
|
||||||
|
using osrm::extractor::getRoadGroup;
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
inline bool IntersectionHandler::IsDistinctTurn(const std::size_t index,
|
||||||
|
const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const
|
||||||
|
{
|
||||||
|
// for comparing road categories
|
||||||
|
const auto &via_edge_data = node_based_graph.GetEdgeData(via_edge);
|
||||||
|
const auto &candidate = intersection[index];
|
||||||
|
const auto &candidate_data = node_based_graph.GetEdgeData(candidate.eid);
|
||||||
|
|
||||||
|
auto const num_lanes = [](auto const &data) {
|
||||||
|
return data.flags.road_classification.GetNumberOfLanes();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const override_class_by_lanes = [&](auto const &compare_data) {
|
||||||
|
// sometimes roads of same size are tagged strangely within a neighborhood, combining
|
||||||
|
// primary roads with residential roads. If the road with can be deducted from lanes, we
|
||||||
|
// can override such a classification
|
||||||
|
if (num_lanes(compare_data) > 0 && num_lanes(via_edge_data) > 0)
|
||||||
|
{
|
||||||
|
// check if via-edge has more than one additional lane, relative to the compare data
|
||||||
|
if (num_lanes(via_edge_data) - num_lanes(compare_data) > 1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if a road is distinct to the obvious turn candidate in its road class. This is the case
|
||||||
|
// only if we pass by a lower road category class or a link to the same category
|
||||||
|
auto const distinct_by_class = [&](auto const &road) {
|
||||||
|
auto const &compare_data = node_based_graph.GetEdgeData(road.eid);
|
||||||
|
|
||||||
|
// passing a road of a stricly lower category (e.g. residential driving past driveway,
|
||||||
|
// primary road passing a residential road) but also exiting a freeway onto a primary in the
|
||||||
|
// presence of an alley
|
||||||
|
if (strictlyLess(compare_data.flags.road_classification,
|
||||||
|
via_edge_data.flags.road_classification) &&
|
||||||
|
strictlyLess(compare_data.flags.road_classification,
|
||||||
|
candidate_data.flags.road_classification) &&
|
||||||
|
override_class_by_lanes(compare_data))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// passing by a link of the same category
|
||||||
|
if (isLinkTo(compare_data.flags.road_classification,
|
||||||
|
via_edge_data.flags.road_classification) &&
|
||||||
|
isLinkTo(compare_data.flags.road_classification,
|
||||||
|
candidate_data.flags.road_classification))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// staying on the same road class, encountering a road that is a severe change in class
|
||||||
|
// (residential-> motorway_link) is considered a fair distinction
|
||||||
|
if (compare_data.flags.road_classification.IsLinkClass() &&
|
||||||
|
(via_edge_data.flags.road_classification.GetPriority() ==
|
||||||
|
candidate_data.flags.road_classification.GetPriority()) &&
|
||||||
|
(std::abs(static_cast<int>(getRoadGroup(via_edge_data.flags.road_classification)) -
|
||||||
|
static_cast<int>(getRoadGroup(compare_data.flags.road_classification))) >
|
||||||
|
4) &&
|
||||||
|
override_class_by_lanes(compare_data))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// in case of narrow turns, we apply different criteria than for actual turns. In case of a
|
||||||
|
// narrow turn, having two choices one of which is forbidden is fine. In case of a end of the
|
||||||
|
// road turn, having two directions and not being allowed to turn onto one of them isn't always
|
||||||
|
// as clear
|
||||||
|
auto const candidate_deviation = util::angularDeviation(candidate.angle, STRAIGHT_ANGLE);
|
||||||
|
|
||||||
|
const auto &via_edge_annotation =
|
||||||
|
node_data_container.GetAnnotation(via_edge_data.annotation_data);
|
||||||
|
const auto &candidate_annotation =
|
||||||
|
node_data_container.GetAnnotation(candidate_data.annotation_data);
|
||||||
|
|
||||||
|
const auto constexpr max_narrow_deviation = GROUP_ANGLE;
|
||||||
|
// on cases where the candidate deviation is in a narrow range, we can consider the deviaiton of
|
||||||
|
// other turns as a distinction criteria
|
||||||
|
//
|
||||||
|
// c
|
||||||
|
// *
|
||||||
|
// *
|
||||||
|
// b - d
|
||||||
|
// |
|
||||||
|
// a
|
||||||
|
// for example can be considered obvious as goig straight, while
|
||||||
|
//
|
||||||
|
// c
|
||||||
|
// d *
|
||||||
|
// * *
|
||||||
|
// b
|
||||||
|
// |
|
||||||
|
// a
|
||||||
|
// should err on the side of caution (when only comparing deviations)
|
||||||
|
|
||||||
|
if (candidate_deviation <= max_narrow_deviation)
|
||||||
|
{
|
||||||
|
// check if the candidate changes it's name
|
||||||
|
auto const candidate_changes_name =
|
||||||
|
util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
|
||||||
|
candidate_annotation.name_id,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
|
|
||||||
|
// check if there are other narrow turns are not considered passing a low category or simply
|
||||||
|
// a link of the same type as the potentially obvious turn
|
||||||
|
auto const is_similar_turn = [&](auto const &road) {
|
||||||
|
// skip over our candidate
|
||||||
|
if (road.eid == candidate.eid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// since we have a narrow turn, we only care for roads allowing entry
|
||||||
|
if (candidate_deviation < NARROW_TURN_ANGLE && !road.entry_allowed)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect link roads in segregated intersections
|
||||||
|
if (!road.entry_allowed && (intersection.size() == 5) &&
|
||||||
|
(std::count_if(intersection.begin(), intersection.end(), [](auto const &road) {
|
||||||
|
return road.entry_allowed;
|
||||||
|
}) <= 2))
|
||||||
|
{
|
||||||
|
// if we are on a link road and all other turns form a 4 way intersection, the
|
||||||
|
// angular differences of all other turns need to be near 90 degrees
|
||||||
|
bool all_close_to_90 = true;
|
||||||
|
for (std::size_t i = 1; i < 3; ++i)
|
||||||
|
{
|
||||||
|
auto const deviation =
|
||||||
|
util::angularDeviation(intersection[i].angle, intersection[i + 1].angle);
|
||||||
|
if (deviation < 75 || deviation > 105)
|
||||||
|
{
|
||||||
|
all_close_to_90 = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_close_to_90)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const compare_deviation = util::angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||||
|
auto const &compare_data = node_based_graph.GetEdgeData(road.eid);
|
||||||
|
auto const &compare_annotation =
|
||||||
|
node_data_container.GetAnnotation(compare_data.annotation_data);
|
||||||
|
|
||||||
|
// in the states, many small side-roads are marked restricted. We could consider them
|
||||||
|
// driveways. Passing by one of these should always be obvious
|
||||||
|
if (candidate_deviation < NARROW_TURN_ANGLE &&
|
||||||
|
(compare_deviation > 1.5 * candidate_deviation) && compare_data.flags.restricted &&
|
||||||
|
!via_edge_data.flags.restricted && !candidate_data.flags.restricted)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we see a roundabout that is a larger turn, we do not consider it similar. This is
|
||||||
|
// related to throughabouts which often are slightly curved on exits:
|
||||||
|
// |
|
||||||
|
// - a d -
|
||||||
|
// \` e f ` /
|
||||||
|
// b - - c
|
||||||
|
if (compare_data.flags.roundabout != via_edge_data.flags.roundabout &&
|
||||||
|
via_edge_data.flags.roundabout == candidate_data.flags.roundabout &&
|
||||||
|
candidate_deviation < compare_deviation)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// to find whether a continuing road is turning, we need to check if it is an actual
|
||||||
|
// turn, a segregated intersection
|
||||||
|
|
||||||
|
auto const opposing_turn =
|
||||||
|
intersection.FindClosestBearing(util::bearing::reverse(road.perceived_bearing));
|
||||||
|
auto const opposing_data = node_based_graph.GetEdgeData(opposing_turn->eid);
|
||||||
|
// Check for a situation like:
|
||||||
|
//
|
||||||
|
// a a
|
||||||
|
// a a
|
||||||
|
// a a + b b + b b
|
||||||
|
// c ac
|
||||||
|
// c a c
|
||||||
|
//
|
||||||
|
// opposed to
|
||||||
|
//
|
||||||
|
// a
|
||||||
|
// a
|
||||||
|
// a a + b b
|
||||||
|
// a
|
||||||
|
// a
|
||||||
|
auto const name_changes_onto_compare =
|
||||||
|
util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
|
||||||
|
compare_annotation.name_id,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
|
auto const opposing_name =
|
||||||
|
node_data_container.GetAnnotation(opposing_data.annotation_data).name_id;
|
||||||
|
auto const name_changes_onto_compare_from_opposing =
|
||||||
|
util::guidance::requiresNameAnnounced(opposing_name,
|
||||||
|
compare_annotation.name_id,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
|
|
||||||
|
// check if the continuing road takes a turn, and we are turning off it. This is
|
||||||
|
// required, sicne we could end up announcing `follow X for 2 miles` and if `X` turns,
|
||||||
|
// we would be inclined to do the turn as well, if it isn't crazy (like a sharp turn)
|
||||||
|
auto const continue_turns = (via_edge_annotation.name_id != EMPTY_NAMEID) &&
|
||||||
|
!name_changes_onto_compare &&
|
||||||
|
(util::angularDeviation(road.angle, opposing_turn->angle) <
|
||||||
|
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
|
||||||
|
name_changes_onto_compare_from_opposing) &&
|
||||||
|
util::angularDeviation(road.angle, 0) > NARROW_TURN_ANGLE;
|
||||||
|
|
||||||
|
auto const continuing_road_takes_a_turn = candidate_changes_name && continue_turns;
|
||||||
|
// at least a relative and a maximum difference, if the road name does not turn.
|
||||||
|
// Since we can announce `stay on X for 2 miles, we need to ensure that we announce
|
||||||
|
// turns off it (even if straight). Otherwise people might follow X further than they
|
||||||
|
// should
|
||||||
|
// For roads splitting with the same name, we ask for a larger difference.
|
||||||
|
auto const minimum_angle_difference = FUZZY_ANGLE_DIFFERENCE;
|
||||||
|
/*
|
||||||
|
(via_edge_annotation.name_id != EMPTY_NAMEID && !candidate_changes_name &&
|
||||||
|
!name_changes_onto_compare)
|
||||||
|
? NARROW_TURN_ANGLE
|
||||||
|
: FUZZY_ANGLE_DIFFERENCE;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// if a turn angle isn't remotely forward, we don't consider a deviation to be distinct
|
||||||
|
// auto const both_turns_go_into_same_direction =
|
||||||
|
// (candidate.angle >= STRAIGHT_ANGLE) ==
|
||||||
|
// (road.angle >= STRAIGHT_ANGLE); // are both turns to the left?
|
||||||
|
auto const roads_deviation_is_distinct =
|
||||||
|
compare_deviation / std::max(0.1, candidate_deviation) > DISTINCTION_RATIO &&
|
||||||
|
std::abs(compare_deviation - candidate_deviation) > minimum_angle_difference;
|
||||||
|
|
||||||
|
auto const continue_is_main_class =
|
||||||
|
via_edge_data.flags.road_classification.GetPriority() <=
|
||||||
|
extractor::RoadPriorityClass::SECONDARY;
|
||||||
|
if ((!continuing_road_takes_a_turn || !continue_is_main_class) &&
|
||||||
|
roads_deviation_is_distinct)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case of slight turns, there can be exits that are also very narrow. If they are on
|
||||||
|
// a new lane though, we accept smaller distinction angles
|
||||||
|
//
|
||||||
|
// a - - - b - - - - c
|
||||||
|
// ` ` ` `d
|
||||||
|
//
|
||||||
|
// A narrow exit lane can be present, but still be distinct from the road
|
||||||
|
if (num_lanes(via_edge_data) > 0 &&
|
||||||
|
num_lanes(candidate_data) == num_lanes(via_edge_data))
|
||||||
|
{
|
||||||
|
if (compare_deviation > candidate_deviation &&
|
||||||
|
candidate_deviation <= FUZZY_ANGLE_DIFFERENCE &&
|
||||||
|
(compare_deviation - candidate_deviation) > 0.5 * FUZZY_ANGLE_DIFFERENCE)
|
||||||
|
{
|
||||||
|
// very slight angle going straight on the exact same number of lanes as coming
|
||||||
|
// in, one turn branching off in a slight angle with additional lanes
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when crossing an intersection of a similar road category, lower deviations can also
|
||||||
|
// make sense
|
||||||
|
// crossing a compare road
|
||||||
|
auto const crossing_compare =
|
||||||
|
!name_changes_onto_compare_from_opposing &&
|
||||||
|
(util::angularDeviation(opposing_turn->angle, road.angle) >
|
||||||
|
STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE) &&
|
||||||
|
name_changes_onto_compare;
|
||||||
|
|
||||||
|
// in case of a continuing road of higher road class, we accept quite a bit loweer
|
||||||
|
// distinction
|
||||||
|
auto const compare_has_lower_class =
|
||||||
|
(candidate_data.flags.road_classification.GetPriority() ==
|
||||||
|
via_edge_data.flags.road_classification.GetPriority()) &&
|
||||||
|
(candidate_data.flags.road_classification.GetPriority() <
|
||||||
|
compare_data.flags.road_classification.GetPriority());
|
||||||
|
|
||||||
|
// for something like a tertiary link, we skip over tertiary, secondary_link, secondary,
|
||||||
|
// primary_link and require at least a primary road
|
||||||
|
auto const compare_has_way_higher_class =
|
||||||
|
(candidate_data.flags.road_classification.GetPriority() ==
|
||||||
|
via_edge_data.flags.road_classification.GetPriority()) &&
|
||||||
|
(std::abs(static_cast<std::int32_t>(
|
||||||
|
candidate_data.flags.road_classification.GetPriority()) -
|
||||||
|
static_cast<std::int32_t>(
|
||||||
|
compare_data.flags.road_classification.GetPriority())) > 4);
|
||||||
|
|
||||||
|
if (!candidate_changes_name && !continuing_road_takes_a_turn &&
|
||||||
|
(compare_has_lower_class || compare_has_way_higher_class || crossing_compare) &&
|
||||||
|
compare_deviation / std::max(0.1, candidate_deviation) > 0.7 * DISTINCTION_RATIO)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// since the angle and allowed match, we compare road categories. Passing a low priority
|
||||||
|
// road allows us to consider it non obvious
|
||||||
|
if (distinct_by_class(road))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switching the general road class within a turn is not a likely maneuver. We consider
|
||||||
|
// a turn distinct enough (given it's straight/narrow continue), if it's road class
|
||||||
|
// differs from other turns (and is of a lesser category)
|
||||||
|
if ((getRoadGroup(via_edge_data.flags.road_classification) !=
|
||||||
|
getRoadGroup(compare_data.flags.road_classification)) &&
|
||||||
|
(via_edge_data.flags.road_classification.GetPriority() ==
|
||||||
|
candidate_data.flags.road_classification.GetPriority()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const itr =
|
||||||
|
std::find_if(intersection.begin() + 1, intersection.end(), is_similar_turn);
|
||||||
|
return itr == intersection.end();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// deviation is larger than NARROW_TURN_ANGLE0 here for the candidate
|
||||||
|
|
||||||
|
// check if there is any turn, that might look just as obvious, even though it might not be
|
||||||
|
// allowed. Entry-allowed isn't considered a valid distinction criterion here
|
||||||
|
auto const is_similar_turn = [&](auto const &road) {
|
||||||
|
// skip over our candidate
|
||||||
|
if (road.eid == candidate.eid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// we do not consider roads of far lesser category to be more obvious
|
||||||
|
const auto &compare_data = node_based_graph.GetEdgeData(road.eid);
|
||||||
|
/*
|
||||||
|
if (strictlyLess(compare_data.flags.road_classification,
|
||||||
|
candidate_data.flags.road_classification))
|
||||||
|
{
|
||||||
|
std::cout << "Road class is strictly less" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// if the class is just not on the same level
|
||||||
|
if (distinct_by_class(road) && !override_class_by_lanes(compare_data))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just as above, switching the general road class within a turn is not a likely
|
||||||
|
// maneuver. We consider
|
||||||
|
// a turn distinct enough (given it's straight/narrow continue), if it's road class
|
||||||
|
// differs from other turns. However, the difference in angles between the two needs to
|
||||||
|
// be reasonable as well. When coming down to tertiary and less, road groups are more or
|
||||||
|
// less random
|
||||||
|
if (util::angularDeviation(road.angle, candidate.angle) < 100 &&
|
||||||
|
via_edge_data.flags.road_classification.GetPriority() <=
|
||||||
|
extractor::RoadPriorityClass::SECONDARY &&
|
||||||
|
((getRoadGroup(via_edge_data.flags.road_classification) !=
|
||||||
|
getRoadGroup(compare_data.flags.road_classification)) &&
|
||||||
|
(via_edge_data.flags.road_classification.GetPriority() ==
|
||||||
|
candidate_data.flags.road_classification.GetPriority())) &&
|
||||||
|
!override_class_by_lanes(compare_data) &&
|
||||||
|
(via_edge_data.flags.road_classification.GetPriority() !=
|
||||||
|
extractor::RoadPriorityClass::UNCLASSIFIED) &&
|
||||||
|
(compare_data.flags.road_classification.GetPriority() !=
|
||||||
|
extractor::RoadPriorityClass::UNCLASSIFIED))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the turn is much stronger, we are also fine (note that we do not have to check
|
||||||
|
// absolutes, since candidate is at least > NARROW_TURN_ANGLE
|
||||||
|
const auto compare_deviation = util::angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||||
|
if (compare_deviation / candidate_deviation > DISTINCTION_RATIO)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::find_if(intersection.begin() + 1, intersection.end(), is_similar_turn) ==
|
||||||
|
intersection.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
inline bool IntersectionHandler::IsDistinctContinue(const std::size_t index,
|
||||||
|
const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const
|
||||||
|
{
|
||||||
|
// if its good enough for a turn, it's good enough for a continue
|
||||||
|
if (IsDistinctTurn(index, via_edge, intersection))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto const in_classification = node_based_graph.GetEdgeData(via_edge).flags.road_classification;
|
||||||
|
auto const continue_classification =
|
||||||
|
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification;
|
||||||
|
|
||||||
|
// nearly straight on the same road type
|
||||||
|
if (in_classification.GetPriority() == continue_classification.GetPriority() &&
|
||||||
|
util::angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <
|
||||||
|
MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Impl.
|
||||||
template <typename IntersectionType> // works with Intersection and IntersectionView
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||||
const IntersectionType &intersection) const
|
const IntersectionType &intersection) const
|
||||||
|
{
|
||||||
|
auto obvious_old = findObviousTurnOld(via_edge, intersection);
|
||||||
|
auto obvious_new = findObviousTurnNew(via_edge, intersection);
|
||||||
|
// if (obvious_new != obvious_old)
|
||||||
|
// {
|
||||||
|
// std::cout << "via_edge==" << via_edge << " old " << obvious_old << " new " <<
|
||||||
|
// obvious_new
|
||||||
|
// << "\n";
|
||||||
|
// BOOST_ASSERT(false);
|
||||||
|
// }
|
||||||
|
(void)obvious_old;
|
||||||
|
return obvious_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
std::size_t IntersectionHandler::findObviousTurnNew(const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const
|
||||||
|
{
|
||||||
|
|
||||||
|
// no obvious road
|
||||||
|
if (intersection.size() == 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// a single non u-turn is obvious
|
||||||
|
if (intersection.size() == 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// the way we are coming from
|
||||||
|
auto const &via_edge_data = node_based_graph.GetEdgeData(via_edge);
|
||||||
|
auto const &via_edge_annotation =
|
||||||
|
node_data_container.GetAnnotation(via_edge_data.annotation_data);
|
||||||
|
|
||||||
|
// implement a filter, taking out all roads of lower class or different names
|
||||||
|
auto const continues_on_name_with_higher_class = [&](auto const &road) {
|
||||||
|
// it needs to be possible to enter the road
|
||||||
|
if (!road.entry_allowed)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// to continue on a name, we need to have one first
|
||||||
|
if (via_edge_annotation.name_id == EMPTY_NAMEID &&
|
||||||
|
!via_edge_data.flags.road_classification.IsLowPriorityRoadClass())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// and we cannot yloose it (roads loosing their name will be handled after this check here)
|
||||||
|
auto const &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||||
|
const auto &road_annotation = node_data_container.GetAnnotation(road_data.annotation_data);
|
||||||
|
if (road_annotation.name_id == EMPTY_NAMEID &&
|
||||||
|
!road_data.flags.road_classification.IsLowPriorityRoadClass())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// if not both of the entries are empty, we do not consider this a continue
|
||||||
|
if ((via_edge_annotation.name_id == EMPTY_NAMEID) ^
|
||||||
|
(road_annotation.name_id == EMPTY_NAMEID))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// the priority can only stay the same or increase. We don't consider a primary->residential
|
||||||
|
// or residential->service as a continuing road
|
||||||
|
if (strictlyLess(road_data.flags.road_classification,
|
||||||
|
via_edge_data.flags.road_classification))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// filter out link classes to our current class, since they should only be connectivity
|
||||||
|
if (isLinkTo(road_data.flags.road_classification, via_edge_data.flags.road_classification))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// most expensive check last (since we filter, we check whether the name changes
|
||||||
|
return util::guidance::requiresNameAnnounced(via_edge_annotation.name_id,
|
||||||
|
road_annotation.name_id,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table);
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if the current road continues at a given index
|
||||||
|
auto const road_continues_itr =
|
||||||
|
intersection.findClosestTurn(STRAIGHT_ANGLE, continues_on_name_with_higher_class);
|
||||||
|
|
||||||
|
// this check is not part of the main conditions, so that if the turn looks obvious from all
|
||||||
|
// other perspectives, a mode change will not result in different classification
|
||||||
|
auto const to_index_if_valid = [&](auto const iterator) -> std::size_t {
|
||||||
|
auto const &from_data = node_based_graph.GetEdgeData(via_edge);
|
||||||
|
auto const &to_data = node_based_graph.GetEdgeData(iterator->eid);
|
||||||
|
|
||||||
|
if (from_data.flags.roundabout != to_data.flags.roundabout)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto const from_mode =
|
||||||
|
node_data_container.GetAnnotation(from_data.annotation_data).travel_mode;
|
||||||
|
auto const to_mode = node_data_container.GetAnnotation(to_data.annotation_data).travel_mode;
|
||||||
|
|
||||||
|
if (from_mode == to_mode)
|
||||||
|
return std::distance(intersection.begin(), iterator);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// in case the continuing road is distinct, we prefer continuing on the current road. Only if
|
||||||
|
// continue does not exist or we are not distinct, we look for other possible candidates
|
||||||
|
if (road_continues_itr != intersection.end() &&
|
||||||
|
IsDistinctContinue(
|
||||||
|
std::distance(intersection.begin(), road_continues_itr), via_edge, intersection))
|
||||||
|
{
|
||||||
|
return to_index_if_valid(road_continues_itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The road doesn't continue in an obvious fashion. At least we see the start of a new road
|
||||||
|
// here, which might be more obvious than (for example) a turning road of the same name. The
|
||||||
|
// next goal is to find a road which is going more or less straight, but is also a matching
|
||||||
|
// category. So if we are on a primary that has an alley right ahead, the alley will not
|
||||||
|
// quality. But if primary goes straight onto secondary / turns left into primary. We would
|
||||||
|
// consider the secondary a candidate.
|
||||||
|
|
||||||
|
// opposed to before, we do not care about name changes, again: this is a filter, so internal
|
||||||
|
// false/true will be negated for selection
|
||||||
|
auto const valid_of_higher_or_same_category = [&](auto const &road) {
|
||||||
|
if (!road.entry_allowed)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto const &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||||
|
if (strictlyLess(road_data.flags.road_classification,
|
||||||
|
via_edge_data.flags.road_classification))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (isLinkTo(road_data.flags.road_classification, via_edge_data.flags.road_classification))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// check for roads that allow entry only
|
||||||
|
auto const straightmost_turn_itr =
|
||||||
|
intersection.findClosestTurn(STRAIGHT_ANGLE, valid_of_higher_or_same_category);
|
||||||
|
|
||||||
|
if (straightmost_turn_itr != intersection.end() &&
|
||||||
|
IsDistinctTurn(
|
||||||
|
std::distance(intersection.begin(), straightmost_turn_itr), via_edge, intersection))
|
||||||
|
{
|
||||||
|
return to_index_if_valid(straightmost_turn_itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const valid_turn = [&](auto const &road) { return !road.entry_allowed; };
|
||||||
|
|
||||||
|
// we cannot find a turn of same or higher priority, so we check if any straightmost turn could
|
||||||
|
// be obvious. We only consider somewhat narrow turns for these cases though
|
||||||
|
auto const straightmost_valid = intersection.findClosestTurn(STRAIGHT_ANGLE, valid_turn);
|
||||||
|
// no valid turns
|
||||||
|
if (straightmost_valid == intersection.end())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto const non_sharp_turns = intersection.Count(
|
||||||
|
[&](auto const &road) { return util::angularDeviation(road.angle, STRAIGHT_ANGLE) <= 90; });
|
||||||
|
auto const straight_is_only_non_sharp =
|
||||||
|
(util::angularDeviation(straightmost_valid->angle, STRAIGHT_ANGLE) <= 90) &&
|
||||||
|
(non_sharp_turns == 1);
|
||||||
|
|
||||||
|
if ((straightmost_valid != straightmost_turn_itr) &&
|
||||||
|
(straightmost_valid != intersection.end()) &&
|
||||||
|
(util::angularDeviation(STRAIGHT_ANGLE, straightmost_valid->angle) <= GROUP_ANGLE ||
|
||||||
|
straight_is_only_non_sharp) &&
|
||||||
|
!node_based_graph.GetEdgeData(straightmost_valid->eid)
|
||||||
|
.flags.road_classification.IsLowPriorityRoadClass() &&
|
||||||
|
IsDistinctTurn(
|
||||||
|
std::distance(intersection.begin(), straightmost_valid), via_edge, intersection))
|
||||||
|
{
|
||||||
|
return to_index_if_valid(straightmost_valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case handling for motorways, for which nearly narrow / only allowed turns are always
|
||||||
|
// obvious
|
||||||
|
if (node_based_graph.GetEdgeData(straightmost_valid->eid)
|
||||||
|
.flags.road_classification.IsMotorwayClass() &&
|
||||||
|
util::angularDeviation(straightmost_valid->angle, STRAIGHT_ANGLE) <= GROUP_ANGLE &&
|
||||||
|
intersection.countEnterable() == 1)
|
||||||
|
{
|
||||||
|
return to_index_if_valid(straightmost_valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case handling for roads splitting up, all the same name (exactly the same)
|
||||||
|
if (intersection.size() == 3 &&
|
||||||
|
std::all_of(intersection.begin(),
|
||||||
|
intersection.end(),
|
||||||
|
[ id = via_edge_annotation.name_id, this ](auto const &road) {
|
||||||
|
auto const data_id = node_based_graph.GetEdgeData(road.eid).annotation_data;
|
||||||
|
auto const name_id = node_data_container.GetAnnotation(data_id).name_id;
|
||||||
|
return (name_id != EMPTY_NAMEID) && (name_id == id);
|
||||||
|
}) &&
|
||||||
|
intersection.countEnterable() == 1 &&
|
||||||
|
// ensure that we do not lookt at a end of the road turn in a segregated intersection
|
||||||
|
(util::angularDeviation(intersection[1].angle, 90) > NARROW_TURN_ANGLE ||
|
||||||
|
util::angularDeviation(intersection[2].angle, 270) > NARROW_TURN_ANGLE))
|
||||||
|
{
|
||||||
|
return to_index_if_valid(straightmost_valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IntersectionType> // works with Intersection and IntersectionView
|
||||||
|
std::size_t IntersectionHandler::findObviousTurnOld(const EdgeID via_edge,
|
||||||
|
const IntersectionType &intersection) const
|
||||||
{
|
{
|
||||||
using Road = typename IntersectionType::value_type;
|
using Road = typename IntersectionType::value_type;
|
||||||
using osrm::util::angularDeviation;
|
using osrm::util::angularDeviation;
|
||||||
|
@ -6,19 +6,19 @@ local Guidance = {}
|
|||||||
-- Guidance: Default Mapping from roads to types/priorities
|
-- Guidance: Default Mapping from roads to types/priorities
|
||||||
highway_classes = {
|
highway_classes = {
|
||||||
motorway = road_priority_class.motorway,
|
motorway = road_priority_class.motorway,
|
||||||
motorway_link = road_priority_class.link_road,
|
motorway_link = road_priority_class.motorway_link,
|
||||||
trunk = road_priority_class.trunk,
|
trunk = road_priority_class.trunk,
|
||||||
trunk_link = road_priority_class.link_road,
|
trunk_link = road_priority_class.trunk_link,
|
||||||
primary = road_priority_class.primary,
|
primary = road_priority_class.primary,
|
||||||
primary_link = road_priority_class.link_road,
|
primary_link = road_priority_class.primary_link,
|
||||||
secondary = road_priority_class.secondary,
|
secondary = road_priority_class.secondary,
|
||||||
secondary_link = road_priority_class.link_road,
|
secondary_link = road_priority_class.secondary_link,
|
||||||
tertiary = road_priority_class.tertiary,
|
tertiary = road_priority_class.tertiary,
|
||||||
tertiary_link = road_priority_class.link_road,
|
tertiary_link = road_priority_class.tertiary_link,
|
||||||
unclassified = road_priority_class.side_residential,
|
unclassified = road_priority_class.unclassified,
|
||||||
residential = road_priority_class.side_residential,
|
residential = road_priority_class.main_residential,
|
||||||
service = road_priority_class.connectivity,
|
service = road_priority_class.alley,
|
||||||
living_street = road_priority_class.main_residential,
|
living_street = road_priority_class.side_residential,
|
||||||
track = road_priority_class.bike_path,
|
track = road_priority_class.bike_path,
|
||||||
path = road_priority_class.bike_path,
|
path = road_priority_class.bike_path,
|
||||||
footway = road_priority_class.foot_path,
|
footway = road_priority_class.foot_path,
|
||||||
@ -60,6 +60,14 @@ link_types = Set {
|
|||||||
'tertiary_link'
|
'tertiary_link'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- roads like parking lots are very unimportant for normal driving
|
||||||
|
parking_class = Set{
|
||||||
|
'parking_aisle',
|
||||||
|
'driveway',
|
||||||
|
'drive-through',
|
||||||
|
'emergency_access'
|
||||||
|
}
|
||||||
|
|
||||||
function Guidance.set_classification (highway, result, input_way)
|
function Guidance.set_classification (highway, result, input_way)
|
||||||
if motorway_types[highway] then
|
if motorway_types[highway] then
|
||||||
result.road_classification.motorway_class = true;
|
result.road_classification.motorway_class = true;
|
||||||
@ -67,11 +75,31 @@ function Guidance.set_classification (highway, result, input_way)
|
|||||||
if link_types[highway] then
|
if link_types[highway] then
|
||||||
result.road_classification.link_class = true;
|
result.road_classification.link_class = true;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- we distinguish between different service types, if specified, we recognise parking and alleys.
|
||||||
|
-- If we see an unrecognised type, we assume a pure connectivity road. All unspecified are recognised as alley
|
||||||
|
if highway ~= nil and highway == 'service' then
|
||||||
|
local service_type = input_way:get_value_by_key('service');
|
||||||
|
if service_type ~= nil and parking_class[service_type] then
|
||||||
|
result.road_classification.road_priority_class = road_priority_class.parking;
|
||||||
|
else
|
||||||
|
if service_type ~= nil and service_type == 'alley' then
|
||||||
|
result.road_classification.road_priority_class = road_priority_class.alley;
|
||||||
|
else
|
||||||
|
if serice_type == nil then
|
||||||
|
result.road_classification.road_priority_class = road_priority_class.alley;
|
||||||
|
else
|
||||||
|
result.road_classification.road_priority_class = highway_classes[highway]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
if highway_classes[highway] ~= nil then
|
if highway_classes[highway] ~= nil then
|
||||||
result.road_classification.road_priority_class = highway_classes[highway]
|
result.road_classification.road_priority_class = highway_classes[highway]
|
||||||
else
|
else
|
||||||
result.road_classification.road_priority_class = default_highway_class
|
result.road_classification.road_priority_class = default_highway_class
|
||||||
end
|
end
|
||||||
|
end
|
||||||
if road_types[highway] then
|
if road_types[highway] then
|
||||||
result.road_classification.may_be_ignored = false;
|
result.road_classification.may_be_ignored = false;
|
||||||
else
|
else
|
||||||
|
@ -140,20 +140,36 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
|||||||
context.state.new_enum("road_priority_class",
|
context.state.new_enum("road_priority_class",
|
||||||
"motorway",
|
"motorway",
|
||||||
extractor::RoadPriorityClass::MOTORWAY,
|
extractor::RoadPriorityClass::MOTORWAY,
|
||||||
|
"motorway_link",
|
||||||
|
extractor::RoadPriorityClass::MOTORWAY_LINK,
|
||||||
"trunk",
|
"trunk",
|
||||||
extractor::RoadPriorityClass::TRUNK,
|
extractor::RoadPriorityClass::TRUNK,
|
||||||
|
"trunk_link",
|
||||||
|
extractor::RoadPriorityClass::TRUNK_LINK,
|
||||||
"primary",
|
"primary",
|
||||||
extractor::RoadPriorityClass::PRIMARY,
|
extractor::RoadPriorityClass::PRIMARY,
|
||||||
|
"primary_link",
|
||||||
|
extractor::RoadPriorityClass::PRIMARY_LINK,
|
||||||
"secondary",
|
"secondary",
|
||||||
extractor::RoadPriorityClass::SECONDARY,
|
extractor::RoadPriorityClass::SECONDARY,
|
||||||
|
"secondary_link",
|
||||||
|
extractor::RoadPriorityClass::SECONDARY_LINK,
|
||||||
"tertiary",
|
"tertiary",
|
||||||
extractor::RoadPriorityClass::TERTIARY,
|
extractor::RoadPriorityClass::TERTIARY,
|
||||||
|
"tertiary_link",
|
||||||
|
extractor::RoadPriorityClass::TERTIARY_LINK,
|
||||||
"main_residential",
|
"main_residential",
|
||||||
extractor::RoadPriorityClass::MAIN_RESIDENTIAL,
|
extractor::RoadPriorityClass::MAIN_RESIDENTIAL,
|
||||||
"side_residential",
|
"side_residential",
|
||||||
extractor::RoadPriorityClass::SIDE_RESIDENTIAL,
|
extractor::RoadPriorityClass::SIDE_RESIDENTIAL,
|
||||||
|
"alley",
|
||||||
|
extractor::RoadPriorityClass::ALLEY,
|
||||||
|
"parking",
|
||||||
|
extractor::RoadPriorityClass::PARKING,
|
||||||
"link_road",
|
"link_road",
|
||||||
extractor::RoadPriorityClass::LINK_ROAD,
|
extractor::RoadPriorityClass::LINK_ROAD,
|
||||||
|
"unclassified",
|
||||||
|
extractor::RoadPriorityClass::UNCLASSIFIED,
|
||||||
"bike_path",
|
"bike_path",
|
||||||
extractor::RoadPriorityClass::BIKE_PATH,
|
extractor::RoadPriorityClass::BIKE_PATH,
|
||||||
"foot_path",
|
"foot_path",
|
||||||
|
@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
|
|||||||
|
|
||||||
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
|
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
|
||||||
|
|
||||||
exports.test_tile = {'at': [17059, 11948, 15], 'size': 168605};
|
exports.test_tile = {'at': [17059, 11948, 15], 'size': 168571};
|
||||||
|
|
||||||
// Test files generated by the routing engine; check test/data
|
// Test files generated by the routing engine; check test/data
|
||||||
if (process.env.OSRM_DATA_PATH !== undefined) {
|
if (process.env.OSRM_DATA_PATH !== undefined) {
|
||||||
|
Loading…
Reference in New Issue
Block a user