diff --git a/CHANGELOG.md b/CHANGELOG.md index d89652a34..9f2a82805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 5.4.0 + - Profiles + - includes library guidance.lua that offers preliminary configuration on guidance. + # 5.3.0 Changes from 5.3.0-rc.3 - Guidance diff --git a/docs/profiles.md b/docs/profiles.md index c36267ec3..dc8546ad6 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -32,3 +32,16 @@ Given an OpenStreetMap way, the way_function will either return nothing (meaning All other calculations stem from that, including the returned timings in driving directions, but also, less directly, it feeds into the actual routing decisions the engine will take (a way with a slow traversal speed, may be less favoured than a way with fast traversal speed, but it depends how long it is, and... what it connects to in the rest of the network graph) Using the power of the scripting language you wouldn't typically see something as simple as a `result.forward_speed = 20` line within the way_function. Instead a way_function will examine the tagging (e.g. `way:get_value_by_key("highway")` and many others), process this information in various ways, calling other local functions, referencing the global variables and look-up hashes, before arriving at the result. + +## Guidance + +The guidance parameters in profiles are currently a work in progress. They can and will change. +Please be aware of this when using guidance configuration possibilities. + +### Road Classification + +Guidance uses road classes to decide on when/if to emit specific instructions and to discover which road is obvious when following a route. +Classification uses three flags and a priority-category. +The flags indicate whether a road is a motorway (required for on/off ramps), a link type (the ramps itself, if also a motorway) and whether a road may be omittted in considerations (is considered purely for connectivity). +The priority-category influences the decision which road is considered the obvious choice and which roads can be seen as fork. +Forks can be emitted between roads of similar priority category only. Obvious choices follow a major priority road, if the priority difference is large. diff --git a/features/guidance/anticipate-lanes.feature b/features/guidance/anticipate-lanes.feature index cb778956a..f350883df 100644 --- a/features/guidance/anticipate-lanes.feature +++ b/features/guidance/anticipate-lanes.feature @@ -271,20 +271,20 @@ Feature: Turn Lane Guidance | | | i | | | And the ways - | nodes | turn:lanes:forward | highway | junction | # | + | nodes | turn:lanes:forward | highway | junction | # | | ab | slight_right\|slight_right\|slight_right | primary | | | | bc | slight_left\|slight_right\|slight_right | primary | roundabout | top | - | cd | | primary | roundabout | top | - | de | | primary | roundabout | top | - | eb | | primary | roundabout | top | - | df | | primary | | | - | cg | slight_right\|slight_right | primary | | | - | gh | slight_left\|slight_right | primary | roundabout | bot | - | hi | | primary | roundabout | bot | - | ij | slight_left\|slight_right | primary | roundabout | bot | - | jg | | primary | roundabout | bot | - | hk | | primary | | | - | jl | | primary | | | + | cd | | primary | roundabout | top | + | de | | primary | roundabout | top | + | eb | | primary | roundabout | top | + | df | | primary | | | + | cg | slight_right\|slight_right | primary | | | + | gh | slight_left\|slight_right | primary | roundabout | bot | + | hi | | primary | roundabout | bot | + | ij | slight_left\|slight_right | primary | roundabout | bot | + | jg | | primary | roundabout | bot | + | hk | | primary | | | + | jl | | primary | | | When I route I should get | # | waypoints | route | turns | lanes | @@ -301,13 +301,13 @@ Feature: Turn Lane Guidance | | | c | | | And the ways - | nodes | turn:lanes:forward | highway | junction | - | ab | | primary | | - | bc | | primary | roundabout | + | nodes | turn:lanes:forward | highway | junction | + | ab | | primary | | + | bc | | primary | roundabout | | cd | slight_left\|slight_left\|slight_right | primary | roundabout | - | de | | primary | roundabout | - | eb | | primary | roundabout | - | df | | primary | | + | de | | primary | roundabout | + | eb | | primary | roundabout | + | df | | primary | | When I route I should get | waypoints | route | turns | lanes | diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp index 8ae948a2c..0503acad9 100644 --- a/include/extractor/extraction_way.hpp +++ b/include/extractor/extraction_way.hpp @@ -2,6 +2,7 @@ #define EXTRACTION_WAY_HPP #include "extractor/travel_mode.hpp" +#include "extractor/guidance/road_classification.hpp" #include "util/guidance/turn_lanes.hpp" #include "util/typedefs.hpp" @@ -38,6 +39,7 @@ struct ExtractionWay backward_travel_mode = TRAVEL_MODE_INACCESSIBLE; turn_lanes_forward.clear(); turn_lanes_backward.clear(); + road_classification = guidance::RoadClassification(); } // These accessors exists because it's not possible to take the address of a bitfield, @@ -60,6 +62,7 @@ struct ExtractionWay bool is_startpoint; TravelMode forward_travel_mode : 4; TravelMode backward_travel_mode : 4; + guidance::RoadClassification road_classification; }; } } diff --git a/include/extractor/guidance/classification_data.hpp b/include/extractor/guidance/classification_data.hpp deleted file mode 100644 index 0454041aa..000000000 --- a/include/extractor/guidance/classification_data.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_ -#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_ - -#include - -#include - -// Forward Declaration to allow usage of external osmium::Way -namespace osmium -{ -class Way; -} - -namespace osrm -{ -namespace extractor -{ -namespace guidance -{ - -enum class FunctionalRoadClass : std::uint8_t -{ - UNKNOWN = 0, - 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 -}; - -FunctionalRoadClass functionalRoadClassFromTag(std::string const &tag); - -inline bool isRampClass(const FunctionalRoadClass road_class) -{ - // Primary Roads and down are usually too small to announce their links as ramps - return road_class == FunctionalRoadClass::MOTORWAY_LINK || - 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; -} - -// check wheter a class is a motorway like class -inline bool isMotorwayClass(const FunctionalRoadClass road_class) -{ - return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK; -} - -// TODO augment this with all data required for guidance generation -struct RoadClassificationData -{ - FunctionalRoadClass road_class = FunctionalRoadClass::UNKNOWN; - - void augment(const osmium::Way &way); -}; - -inline bool operator==(const RoadClassificationData lhs, const RoadClassificationData rhs) -{ - return lhs.road_class == rhs.road_class; -} - -} // namespace guidance -} // namespace extractor -} // namespace osrm - -#endif // OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_ diff --git a/include/extractor/guidance/road_classification.hpp b/include/extractor/guidance/road_classification.hpp new file mode 100644 index 000000000..baec6162e --- /dev/null +++ b/include/extractor/guidance/road_classification.hpp @@ -0,0 +1,130 @@ +#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_ +#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_ + +#include +#include +#include +#include + +#include + +namespace osrm +{ +namespace extractor +{ +namespace guidance +{ + +namespace RoadPriorityClass +{ +typedef std::uint8_t Enum; +// Top priority Road +const constexpr Enum MOTORWAY = 0; +// Second highest priority +const constexpr Enum TRUNK = 2; +// Main roads +const constexpr Enum PRIMARY = 4; +const constexpr Enum SECONDARY = 6; +const constexpr Enum TERTIARY = 8; +// Residential Categories +const constexpr Enum MAIN_RESIDENTIAL = 10; +const constexpr Enum SIDE_RESIDENTIAL = 11; +// Link Category +const constexpr Enum LINK_ROAD = 14; +// Bike Accessible +const constexpr Enum BIKE_PATH = 16; +// Walk Accessible +const constexpr Enum FOOT_PATH = 18; +// Link types are usually not considered in forks, unless amongst each other. +// a road simply offered for connectivity. Will be ignored in forks/other decisions. Always +// considered non-obvious to continue on +const constexpr Enum CONNECTIVITY = 31; +} // namespace Road Class + +#pragma pack(push, 1) +class RoadClassification +{ + // a class that behaves like a motorway (separated directions) + std::uint8_t motorway_class : 1; + // all types of link classes + std::uint8_t link_class : 1; + // a low priority class is a pure connectivity way. It can be ignored in multiple decisions + // (e.g. fork on a primary vs service will not happen) + std::uint8_t may_be_ignored : 1; + // the road priority is used as an indicator for forks. If the roads are of similar priority + // (difference <=1), we can see the road as a fork. Else one of the road classes is seen as + // obvious choice + RoadPriorityClass::Enum road_priority_class : 5; + + public: + // default construction + RoadClassification() + : motorway_class(0), link_class(0), may_be_ignored(1), + road_priority_class(RoadPriorityClass::CONNECTIVITY) + { + } + + RoadClassification(bool motorway_class, + bool link_class, + bool may_be_ignored, + RoadPriorityClass::Enum road_priority_class) + : motorway_class(motorway_class), link_class(link_class), may_be_ignored(may_be_ignored), + road_priority_class(road_priority_class) + { + } + + bool IsMotorwayClass() const { return (0 != motorway_class) && (0 == link_class); } + void SetMotorwayFlag(const bool new_value) { motorway_class = new_value; } + + bool IsRampClass() const { return (0 != motorway_class) && (0 != link_class); } + + bool IsLinkClass() const { return (0 != link_class); } + void SetLinkClass(const bool new_value) { link_class = new_value; } + + bool IsLowPriorityRoadClass() const { return (0 != may_be_ignored); } + void SetLowPriorityFlag(const bool new_value) { may_be_ignored = new_value; } + + std::uint32_t GetPriority() const + { + return static_cast(road_priority_class); + } + + RoadPriorityClass::Enum GetClass() const { return road_priority_class; } + void SetClass(const RoadPriorityClass::Enum new_value) + { + road_priority_class = new_value; + } + + bool operator==(const RoadClassification &other) const + { + return motorway_class == other.motorway_class && link_class == other.link_class && + may_be_ignored == other.may_be_ignored && + road_priority_class == other.road_priority_class; + } + + bool operator!=(const RoadClassification &other ) const + { + return !(*this == other); + } + + std::string ToString() const + { + return std::string() + (motorway_class ? "motorway" : "normal") + + (link_class ? "_link" : "") + (may_be_ignored ? " ignorable " : " important ") + + std::to_string(road_priority_class); + } +}; +#pragma pack(pop) + +static_assert(sizeof(RoadClassification) == 1,"Road Classification should fit a byte. Increasing this has a severe impact on memory."); + +inline bool canBeSeenAsFork(const RoadClassification first, const RoadClassification second) +{ + return std::abs(static_cast(first.GetPriority()) - + static_cast(second.GetPriority())) <= 1; +} +} // namespace guidance +} // namespace extractor +} // namespace osrm + +#endif // OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_ diff --git a/include/extractor/guidance/toolkit.hpp b/include/extractor/guidance/toolkit.hpp index c0f3cfdf0..815cda224 100644 --- a/include/extractor/guidance/toolkit.hpp +++ b/include/extractor/guidance/toolkit.hpp @@ -12,7 +12,6 @@ #include "extractor/query_node.hpp" #include "extractor/suffix_table.hpp" -#include "extractor/guidance/classification_data.hpp" #include "extractor/guidance/discrete_angle.hpp" #include "extractor/guidance/intersection.hpp" #include "extractor/guidance/turn_instruction.hpp" @@ -46,12 +45,6 @@ using util::guidance::leavesRoundabout; 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}; -const constexpr std::uint8_t modifier_bounds[detail::num_direction_modifiers] = { - 0, 36, 93, 121, 136, 163, 220, 255}; - -const constexpr double discrete_angle_step_size = 360. / 24; template util::Coordinate @@ -156,163 +149,6 @@ getRepresentativeCoordinate(const NodeID from_node, } } -// shift an instruction around the degree circle in CCW order -inline DirectionModifier::Enum forcedShiftCCW(const DirectionModifier::Enum modifier) -{ - return static_cast((static_cast(modifier) + 1) % - detail::num_direction_modifiers); -} - -inline DirectionModifier::Enum shiftCCW(const DirectionModifier::Enum modifier) -{ - if (detail::shiftable_ccw[static_cast(modifier)]) - return forcedShiftCCW(modifier); - else - return modifier; -} - -// shift an instruction around the degree circle in CW order -inline DirectionModifier::Enum forcedShiftCW(const DirectionModifier::Enum modifier) -{ - return static_cast( - (static_cast(modifier) + detail::num_direction_modifiers - 1) % - detail::num_direction_modifiers); -} - -inline DirectionModifier::Enum shiftCW(const DirectionModifier::Enum modifier) -{ - if (detail::shiftable_cw[static_cast(modifier)]) - return forcedShiftCW(modifier); - else - return modifier; -} - -inline bool isBasic(const TurnType::Enum 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::Enum 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 DiscreteAngle discretizeAngle(const double angle) -{ - BOOST_ASSERT(angle >= 0. && angle <= 360.); - return DiscreteAngle(static_cast( - (angle + 0.5 * detail::discrete_angle_step_size) / detail::discrete_angle_step_size)); -} - -inline double angleFromDiscreteAngle(const DiscreteAngle angle) -{ - return static_cast(angle) * detail::discrete_angle_step_size + - 0.5 * detail::discrete_angle_step_size; -} - -inline double getAngularPenalty(const double angle, DirectionModifier::Enum modifier) -{ - // these are not aligned with getTurnDirection but represent an ideal center - const double center[] = {0, 45, 90, 135, 180, 225, 270, 315}; - return angularDeviation(center[static_cast(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, 30, 20, 30, 50, 45}; - const double difference = getAngularPenalty(angle, instruction.direction_modifier); - const double max_deviation = deviations[static_cast(instruction.direction_modifier)]; - return 1.0 - (difference / max_deviation) * (difference / max_deviation); -} - -inline bool canBeSuppressed(const TurnType::Enum 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; -} - -inline bool isDistinct(const DirectionModifier::Enum first, const DirectionModifier::Enum second) -{ - if ((first + 1) % detail::num_direction_modifiers == second) - return false; - - if ((second + 1) % detail::num_direction_modifiers == first) - return false; - - return true; -} - inline std::pair getPrefixAndSuffix(const std::string &data) { const auto suffix_pos = data.find_last_of(' '); @@ -422,26 +258,6 @@ inline bool requiresNameAnnounced(const std::string &from, return !obvious_change; } -inline int getPriority(const FunctionalRoadClass road_class) -{ - // The road priorities indicate which roads can bee seen as more or less equal. - // They are used in Fork-Discovery. Possibly should be moved to profiles post v5? - // A fork can happen between road types that are at most 1 priority apart from each other - const constexpr int road_priority[] = { - 14, 0, 14, 2, 14, 4, 14, 6, 14, 8, 10, 11, 10, 12, 10, 14}; - return road_priority[static_cast(road_class)]; -} - -inline bool canBeSeenAsFork(const FunctionalRoadClass first, const FunctionalRoadClass second) -{ - // forks require similar road categories - // Based on the priorities assigned above, we can set forks only if the road priorities match - // closely. - // Potentially we could include features like number of lanes here and others? - // Should also be moved to profiles - return std::abs(getPriority(first) - getPriority(second)) <= 1; -} - // To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection // handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand // turn and vice versa. diff --git a/include/extractor/internal_extractor_edge.hpp b/include/extractor/internal_extractor_edge.hpp index 376e587c1..ec95988d9 100644 --- a/include/extractor/internal_extractor_edge.hpp +++ b/include/extractor/internal_extractor_edge.hpp @@ -7,7 +7,7 @@ #include -#include "extractor/guidance/classification_data.hpp" +#include "extractor/guidance/road_classification.hpp" #include "osrm/coordinate.hpp" #include @@ -51,7 +51,7 @@ struct InternalExtractorEdge TRAVEL_MODE_INACCESSIBLE, false, guidance::TurnLaneType::empty, - guidance::RoadClassificationData()) + guidance::RoadClassification()) { } @@ -67,7 +67,7 @@ struct InternalExtractorEdge TravelMode travel_mode, bool is_split, LaneDescriptionID lane_description, - guidance::RoadClassificationData road_classification) + guidance::RoadClassification road_classification) : result(source, target, name_id, @@ -107,7 +107,7 @@ struct InternalExtractorEdge TRAVEL_MODE_INACCESSIBLE, false, INVALID_LANE_DESCRIPTIONID, - guidance::RoadClassificationData()); + guidance::RoadClassification()); } static InternalExtractorEdge max_osm_value() { @@ -123,7 +123,7 @@ struct InternalExtractorEdge TRAVEL_MODE_INACCESSIBLE, false, INVALID_LANE_DESCRIPTIONID, - guidance::RoadClassificationData()); + guidance::RoadClassification()); } static InternalExtractorEdge min_internal_value() diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp index 100977699..07628cd5b 100644 --- a/include/extractor/node_based_edge.hpp +++ b/include/extractor/node_based_edge.hpp @@ -4,7 +4,7 @@ #include "extractor/travel_mode.hpp" #include "util/typedefs.hpp" -#include "extractor/guidance/classification_data.hpp" +#include "extractor/guidance/road_classification.hpp" namespace osrm { @@ -27,7 +27,7 @@ struct NodeBasedEdge TravelMode travel_mode, bool is_split, const LaneDescriptionID lane_description_id, - guidance::RoadClassificationData road_classification); + guidance::RoadClassification road_classification); bool operator<(const NodeBasedEdge &other) const; @@ -43,7 +43,7 @@ struct NodeBasedEdge bool is_split : 1; TravelMode travel_mode : 4; LaneDescriptionID lane_description_id; - guidance::RoadClassificationData road_classification; + guidance::RoadClassification road_classification; }; struct NodeBasedEdgeWithOSM : NodeBasedEdge @@ -60,7 +60,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge TravelMode travel_mode, bool is_split, const LaneDescriptionID lane_description_id, - guidance::RoadClassificationData road_classification); + guidance::RoadClassification road_classification); OSMNodeID osm_source_id; OSMNodeID osm_target_id; @@ -87,7 +87,7 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source, TravelMode travel_mode, bool is_split, const LaneDescriptionID lane_description_id, - guidance::RoadClassificationData road_classification) + guidance::RoadClassification road_classification) : source(source), target(target), name_id(name_id), weight(weight), forward(forward), backward(backward), roundabout(roundabout), access_restricted(access_restricted), startpoint(startpoint), is_split(is_split), travel_mode(travel_mode), @@ -125,7 +125,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM( TravelMode travel_mode, bool is_split, const LaneDescriptionID lane_description_id, - guidance::RoadClassificationData road_classification) + guidance::RoadClassification road_classification) : NodeBasedEdge(SPECIAL_NODEID, SPECIAL_NODEID, name_id, diff --git a/include/util/debug.hpp b/include/util/debug.hpp index 4d6ba1f16..9dab0f3c7 100644 --- a/include/util/debug.hpp +++ b/include/util/debug.hpp @@ -54,6 +54,15 @@ inline void print(const std::vector &steps) } } +inline void print( const extractor::guidance::Intersection & intersection ) +{ + std::cout << " Intersection:\n"; + for (const auto &road : intersection) + std::cout << "\t" << toString(road) << "\n"; + std::cout << std::flush; +} + + inline void print(const extractor::guidance::lanes::LaneDataVector &turn_lane_data) { std::cout << " Tags:\n"; @@ -76,10 +85,7 @@ printTurnAssignmentData(const NodeID at, std::cout << std::setprecision(12) << toFloating(coordinate.lat) << " " << toFloating(coordinate.lon) << "\n"; - std::cout << " Intersection:\n"; - for (const auto &road : intersection) - std::cout << "\t" << toString(road) << "\n"; - + print(intersection); // flushes as well print(turn_lane_data); } diff --git a/include/util/node_based_graph.hpp b/include/util/node_based_graph.hpp index 957b83c7b..fb1a046fb 100644 --- a/include/util/node_based_graph.hpp +++ b/include/util/node_based_graph.hpp @@ -1,7 +1,7 @@ #ifndef NODE_BASED_GRAPH_HPP #define NODE_BASED_GRAPH_HPP -#include "extractor/guidance/classification_data.hpp" +#include "extractor/guidance/road_classification.hpp" #include "extractor/node_based_edge.hpp" #include "util/dynamic_graph.hpp" #include "util/graph_utils.hpp" @@ -49,7 +49,7 @@ struct NodeBasedEdgeData bool startpoint : 1; extractor::TravelMode travel_mode : 4; LaneDescriptionID lane_description_id; - extractor::guidance::RoadClassificationData road_classification; + extractor::guidance::RoadClassification road_classification; bool IsCompatibleTo(const NodeBasedEdgeData &other) const { diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index be97de3d1..a66e7c38f 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -2,6 +2,7 @@ local find_access_tag = require("lib/access").find_access_tag local limit = require("lib/maxspeed").limit +local set_classification = require("lib/guidance").set_classification -- Begin of globals barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["block"] = true } @@ -392,6 +393,9 @@ function way_function (way, result) result.backward_speed = math.min(surface_speeds[surface], result.backward_speed) end + -- set the road classification based on guidance globals configuration + set_classification(highway,result) + -- maxspeed limit( result, maxspeed, maxspeed_forward, maxspeed_backward ) end diff --git a/profiles/car.lua b/profiles/car.lua index c138f866e..c2f66e2e3 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -1,7 +1,8 @@ -- Car profile - local find_access_tag = require("lib/access").find_access_tag local get_destination = require("lib/destination").get_destination +local set_classification = require("lib/guidance").set_classification +local get_turn_lanes = require("lib/guidance").get_turn_lanes -- Begin of globals barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["lift_gate"] = true, ["no"] = true, ["entrance"] = true } @@ -166,62 +167,6 @@ function get_exceptions(vector) end end --- returns forward,backward psv lane count -local function getPSVCounts(way) - local psv = way:get_value_by_key("lanes:psv") - local psv_forward = way:get_value_by_key("lanes:psv:forward"); - local psv_backward = way:get_value_by_key("lanes:psv:backward"); - - local fw = 0; - local bw = 0; - if( psv and psv ~= "" ) then - fw = tonumber(psv) - if( fw == nil ) then - fw = 0 - end - end - if( psv_forward and psv_forward ~= "" ) then - fw = tonumber(psv_forward) - if( fw == nil ) then - fw = 0 - end - end - if( psv_backward and psv_backward ~= "" ) then - bw = tonumber(psv_backward); - if( bw == nil ) then - bw = 0 - end - end - return fw, bw -end - --- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving -local function getTurnLanes(way) - local fw_psv = 0 - local bw_psv = 0 - fw_psv, bw_psv = getPSVCounts(way) - - local turn_lanes = way:get_value_by_key("turn:lanes") - local turn_lanes_fw = way:get_value_by_key("turn:lanes:forward") - local turn_lanes_bw = way:get_value_by_key("turn:lanes:backward") - - if( fw_psv ~= 0 or bw_psv ~= 0 ) then - if turn_lanes and turn_lanes ~= "" then - turn_lanes = trimLaneString(turn_lanes, bw_psv, fw_psv ) - end - if turn_lanes_fw and turn_lanes_fw ~= "" then - turn_lanes_fw = trimLaneString(turn_lanes_fw, bw_psv, fw_psv ) - end - --backwards turn lanes need to treat bw_psv as fw_psv and vice versa - if turn_lanes_bw and turn_lanes_bw ~= "" then - turn_lanes_bw = trimLaneString(turn_lanes_bw, fw_psv, bw_psv ) - end - end - - return turn_lanes, turn_lanes_fw, turn_lanes_bw -end - - local function parse_maxspeed(source) if not source then return 0 @@ -340,7 +285,7 @@ function way_function (way, result) result.backward_speed = bridge_speed end - -- leave early of this way is not accessible + -- leave early if this way is not accessible if "" == highway then return end @@ -402,6 +347,9 @@ function way_function (way, result) result.backward_speed = math.min(smoothness_speeds[smoothness], result.backward_speed) end + -- set the road classification based on guidance globals configuration + set_classification(highway,result) + -- parse the remaining tags local name = way:get_value_by_key("name") local pronunciation = way:get_value_by_key("name:pronunciation") @@ -432,7 +380,7 @@ function way_function (way, result) local turn_lanes_forward = "" local turn_lanes_backward = "" - turn_lanes, turn_lanes_forward, turn_lanes_backward = getTurnLanes(way) + turn_lanes, turn_lanes_forward, turn_lanes_backward = get_turn_lanes(way) if turn_lanes and turn_lanes ~= "" then result.turn_lanes_forward = turn_lanes; result.turn_lanes_backward = turn_lanes; diff --git a/profiles/lib/guidance.lua b/profiles/lib/guidance.lua new file mode 100644 index 000000000..19409ce11 --- /dev/null +++ b/profiles/lib/guidance.lua @@ -0,0 +1,113 @@ +local Guidance = {} + +-- Guidance: Default Mapping from roads to types/priorities +highway_classes = { ["motorway"] = road_priority_class.motorway, + ["motorway_link"] = road_priority_class.link_road, + ["trunk"] = road_priority_class.trunk, + ["trunk_link"] = road_priority_class.link_road, + ["primary"] = road_priority_class.primary, + ["primary_link"] = road_priority_class.link_road, + ["secondary"] = road_priority_class.secondary, + ["secondary_link"] = road_priority_class.link_road, + ["tertiary"] = road_priority_class.tertiary, + ["tertiary_link"] = road_priority_class.link_road, + ["unclassified"] = road_priority_class.side_residential, + ["residential"] = road_priority_class.side_residential, + ["service"] = road_priority_class.connectivity, + ["living_street"] = road_priority_class.main_residential, + ["track"] = road_priority_class.bike_path, + ["path"] = road_priority_class.bike_path, + ["footway"] = road_priority_class.foot_path, + ["pedestrian"] = road_priority_class.foot_path, + ["steps"] = road_priority_class.foot_path} + +default_highway_class = road_priority_class.connectivity; + +motorway_types = { ["motorway"] = true, ["motorway_link"] = true, ["trunk"] = true, ["trunk_link"] = true } + +-- these road types are set with a car in mind. For bicycle/walk we probably need different ones +road_types = { ["motorway"] = true, + ["motorway_link"] = true, + ["trunk"] = true, + ["trunk_link"] = true, + ["primary"] = true, + ["primary_link"] = true, + ["secondary"] = true, + ["secondary_link"] = true, + ["tertiary"] = true, + ["tertiary_link"] = true, + ["unclassified"] = true, + ["residential"] = true, + ["living_street"] = true } + +link_types = { ["motorway_link"] = true, ["trunk_link"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true } + +function Guidance.set_classification (highway, result) + if motorway_types[highway] then + result.road_classification.motorway_class = true; + end + if link_types[highway] then + result.road_classification.link_class = true; + end + if highway_classes[highway] ~= nil then + result.road_classification.road_priority_class = highway_classes[highway] + else + result.road_classification.road_priority_class = default_highway_class + end + if road_types[highway] then + result.road_classification.may_be_ignored = false; + else + result.road_classification.may_be_ignored = true; + end +end + +-- returns forward,backward psv lane count +local function get_psv_counts(way) + local psv = way:get_value_by_key("lanes:psv") + local psv_forward = way:get_value_by_key("lanes:psv:forward"); + local psv_backward = way:get_value_by_key("lanes:psv:backward"); + + local fw = 0; + local bw = 0; + if( psv and psv ~= "" ) then + fw = tonumber(psv) + if( fw == nil ) then + fw = 0 + end + end + if( psv_forward and psv_forward ~= "" ) then + fw = tonumber(psv_forward) + if( fw == nil ) then + fw = 0 + end + end + if( psv_backward and psv_backward ~= "" ) then + bw = tonumber(psv_backward); + if( bw == nil ) then + fw = 0 + end + end + return fw, bw +end + +-- this is broken for left-sided driving. It needs to switch left and right in case of left-sided driving +function Guidance.get_turn_lanes(way) + local fw_psv = 0 + local bw_psv = 0 + fw_psv, bw_psv = get_psv_counts(way) + + local turn_lanes = way:get_value_by_key("turn:lanes") + local turn_lanes_fw = way:get_value_by_key("turn:lanes:forward") + local turn_lanes_bw = way:get_value_by_key("turn:lanes:backward") + + if( fw_psv ~= 0 or bw_psv ~= 0 ) then + turn_lanes = trimLaneString(turn_lanes, bw_psv, fw_psv ) + turn_lanes_fw = trimLaneString(turn_lanes_fw, bw_psv, fw_psv ) + --backwards turn lanes need to treat bw_psv as fw_psv and vice versa + turn_lanes_bw = trimLaneString(turn_lanes_bw, fw_psv, bw_psv ) + end + + return turn_lanes, turn_lanes_fw, turn_lanes_bw +end + +return Guidance diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 1690bbd70..5c0673039 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -425,7 +425,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( const int32_t turn_penalty = scripting_environment.GetTurnPenalty(180. - turn.angle); const auto turn_instruction = turn.instruction; - if (guidance::isUturn(turn_instruction)) + if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn) { distance += profile_properties.u_turn_penalty; } diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 7d98804e8..0aa506c44 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -1,8 +1,9 @@ -#include "extractor/extractor_callbacks.hpp" #include "extractor/external_memory_node.hpp" #include "extractor/extraction_containers.hpp" #include "extractor/extraction_node.hpp" #include "extractor/extraction_way.hpp" +#include "extractor/extractor_callbacks.hpp" +#include "extractor/guidance/road_classification.hpp" #include "extractor/restriction.hpp" #include "util/for_each_pair.hpp" @@ -140,13 +141,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti } // FIXME this need to be moved into the profiles - const char *data = input_way.get_value_by_key("highway"); - guidance::RoadClassificationData road_classification; - if (data) - { - road_classification.road_class = guidance::functionalRoadClassFromTag(data); - } - + const guidance::RoadClassification road_classification = parsed_way.road_classification; const auto laneStringToDescription = [](std::string lane_string) -> TurnLaneDescription { if (lane_string.empty()) return {}; diff --git a/src/extractor/guidance/classification_data.cpp b/src/extractor/guidance/classification_data.cpp deleted file mode 100644 index 78a8684bc..000000000 --- a/src/extractor/guidance/classification_data.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "extractor/guidance/classification_data.hpp" -#include "util/simple_logger.hpp" - -#include - -namespace osrm -{ -namespace extractor -{ -namespace guidance -{ - -FunctionalRoadClass functionalRoadClassFromTag(std::string const &value) -{ - // FIXME at some point this should be part of the profiles - const static auto class_hash = [] { - std::unordered_map 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; - }(); - - if (class_hash.find(value) != class_hash.end()) - { - return class_hash.find(value)->second; - } - else - { - // TODO activate again, when road classes are moved to the profile - // util::SimpleLogger().Write(logDEBUG) << "Unknown road class encountered: " << value; - return FunctionalRoadClass::UNKNOWN; - } -} - -} // ns guidance -} // ns extractor -} // ns osrm diff --git a/src/extractor/guidance/intersection_handler.cpp b/src/extractor/guidance/intersection_handler.cpp index 036c60a7e..1af73e5be 100644 --- a/src/extractor/guidance/intersection_handler.cpp +++ b/src/extractor/guidance/intersection_handler.cpp @@ -48,9 +48,9 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge, const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); - bool on_ramp = isRampClass(in_data.road_classification.road_class); + bool on_ramp = in_data.road_classification.IsRampClass(); - bool onto_ramp = isRampClass(out_data.road_classification.road_class); + bool onto_ramp = out_data.road_classification.IsRampClass(); if (!on_ramp && onto_ramp) return TurnType::OnRamp; @@ -130,10 +130,10 @@ void IntersectionHandler::assignFork(const EdgeID via_edge, ConnectedRoad &right) const { const auto &in_data = node_based_graph.GetEdgeData(via_edge); - const bool low_priority_left = isLowPriorityRoadClass( - node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class); - const bool low_priority_right = isLowPriorityRoadClass( - node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class); + const bool low_priority_left = + node_based_graph.GetEdgeData(left.turn.eid).road_classification.IsLowPriorityRoadClass(); + const bool low_priority_right = + node_based_graph.GetEdgeData(right.turn.eid).road_classification.IsLowPriorityRoadClass(); if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION && angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)) { @@ -339,6 +339,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, double best_continue_deviation = 180; const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge); + const auto in_classification = in_data.road_classification; for (std::size_t i = 1; i < intersection.size(); ++i) { const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE); @@ -349,12 +350,16 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, } const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid); - auto continue_class = node_based_graph.GetEdgeData(intersection[best_continue].turn.eid) - .road_classification.road_class; + auto continue_class = + node_based_graph.GetEdgeData(intersection[best_continue].turn.eid).road_classification; if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id && - (best_continue == 0 || continue_class > out_data.road_classification.road_class || + (best_continue == 0 || + (continue_class.GetPriority() > out_data.road_classification.GetPriority() && + in_classification != continue_class) || (deviation < best_continue_deviation && - out_data.road_classification.road_class == continue_class))) + out_data.road_classification == continue_class) || + (continue_class != in_classification && + out_data.road_classification == continue_class))) { best_continue_deviation = deviation; best_continue = i; @@ -368,10 +373,8 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, return 0; // has no obvious continued road if (best_continue == 0 || best_continue_deviation >= 2 * NARROW_TURN_ANGLE || - (node_based_graph.GetEdgeData(intersection[best_continue].turn.eid) - .road_classification.road_class == - node_based_graph.GetEdgeData(intersection[best].turn.eid) - .road_classification.road_class && + (node_based_graph.GetEdgeData(intersection[best_continue].turn.eid).road_classification == + node_based_graph.GetEdgeData(intersection[best].turn.eid).road_classification && std::abs(best_continue_deviation) > 1 && best_deviation / best_continue_deviation < 0.75)) { // Find left/right deviation @@ -418,9 +421,8 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge, continue; if (angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE) / deviation < 1.1 && - continue_data.road_classification.road_class == - node_based_graph.GetEdgeData(intersection[i].turn.eid) - .road_classification.road_class) + continue_data.road_classification == + node_based_graph.GetEdgeData(intersection[i].turn.eid).road_classification) return 0; } return best_continue; // no obvious turn diff --git a/src/extractor/guidance/motorway_handler.cpp b/src/extractor/guidance/motorway_handler.cpp index 2d9812b7f..8cea47c48 100644 --- a/src/extractor/guidance/motorway_handler.cpp +++ b/src/extractor/guidance/motorway_handler.cpp @@ -1,6 +1,6 @@ -#include "extractor/guidance/motorway_handler.hpp" -#include "extractor/guidance/classification_data.hpp" #include "extractor/guidance/constants.hpp" +#include "extractor/guidance/motorway_handler.hpp" +#include "extractor/guidance/road_classification.hpp" #include "extractor/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp" @@ -20,25 +20,26 @@ namespace extractor { namespace guidance { -namespace detail +namespace { inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph) { - return isMotorwayClass(node_based_graph.GetEdgeData(eid).road_classification.road_class); + return node_based_graph.GetEdgeData(eid).road_classification.IsMotorwayClass(); } -inline FunctionalRoadClass roadClass(const ConnectedRoad &road, - const util::NodeBasedDynamicGraph &graph) +inline RoadClassification roadClass(const ConnectedRoad &road, + const util::NodeBasedDynamicGraph &graph) { - return graph.GetEdgeData(road.turn.eid).road_classification.road_class; + return graph.GetEdgeData(road.turn.eid).road_classification; } inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph) { - return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class); -} + return node_based_graph.GetEdgeData(eid).road_classification.IsRampClass(); } +} // namespace + MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector &node_info_list, const util::NameTable &name_table, @@ -56,36 +57,29 @@ bool MotorwayHandler::canProcess(const NodeID, for (const auto &road : intersection) { - const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); // not merging or forking? if (road.entry_allowed && angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > 60) return false; - else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY || - out_data.road_classification.road_class == FunctionalRoadClass::TRUNK) + else if (isMotorwayClass(road.turn.eid, node_based_graph)) { if (road.entry_allowed) has_motorway = true; } - else if (!isRampClass(out_data.road_classification.road_class)) + else if (!isRampClass(road.turn.eid, node_based_graph)) has_normal_roads = true; } if (has_normal_roads) return false; - const auto &in_data = node_based_graph.GetEdgeData(via_eid); - return has_motorway || - in_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY || - in_data.road_classification.road_class == FunctionalRoadClass::TRUNK; + return has_motorway || isMotorwayClass(via_eid, node_based_graph); } Intersection MotorwayHandler:: operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const { - const auto &in_data = node_based_graph.GetEdgeData(via_eid); - // coming from motorway - if (isMotorwayClass(in_data.road_classification.road_class)) + if (isMotorwayClass(via_eid, node_based_graph)) { intersection = fromMotorway(via_eid, std::move(intersection)); std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) { @@ -104,13 +98,13 @@ operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection intersection) const { const auto &in_data = node_based_graph.GetEdgeData(via_eid); - BOOST_ASSERT(isMotorwayClass(in_data.road_classification.road_class)); + BOOST_ASSERT(isMotorwayClass(via_eid, node_based_graph)); const auto countExitingMotorways = [this](const Intersection &intersection) { unsigned count = 0; for (const auto &road : intersection) { - if (road.entry_allowed && detail::isMotorwayClass(road.turn.eid, node_based_graph)) + if (road.entry_allowed && isMotorwayClass(road.turn.eid, node_based_graph)) ++count; } return count; @@ -122,8 +116,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in { const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); if (road.turn.angle != 0 && in_data.name_id == out_data.name_id && - in_data.name_id != EMPTY_NAMEID && - isMotorwayClass(out_data.road_classification.road_class)) + in_data.name_id != EMPTY_NAMEID && isMotorwayClass(road.turn.eid, node_based_graph)) return road.turn.angle; } return intersection[0].turn.angle; @@ -134,8 +127,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in double best = 180; for (const auto &road : intersection) { - const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); - if (isMotorwayClass(out_data.road_classification.road_class) && + if (isMotorwayClass(road.turn.eid, node_based_graph) && angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best) { best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE); @@ -183,10 +175,10 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in } } else if (intersection.size() == 4 && - detail::roadClass(intersection[1], node_based_graph) == - detail::roadClass(intersection[2], node_based_graph) && - detail::roadClass(intersection[2], node_based_graph) == - detail::roadClass(intersection[3], node_based_graph)) + roadClass(intersection[1], node_based_graph) == + roadClass(intersection[2], node_based_graph) && + roadClass(intersection[2], node_based_graph) == + roadClass(intersection[3], node_based_graph)) { // tripple fork at the end assignFork(via_eid, intersection[3], intersection[2], intersection[1]); @@ -212,7 +204,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in { if (road.entry_allowed) { - BOOST_ASSERT(detail::isRampClass(road.turn.eid, node_based_graph)); + BOOST_ASSERT(isRampClass(road.turn.eid, node_based_graph)); road.turn.instruction = TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle)); } @@ -223,7 +215,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in // normal motorway passing some ramps or mering onto another motorway if (intersection.size() == 2) { - BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph)); + BOOST_ASSERT(!isRampClass(intersection[1].turn.eid, node_based_graph)); intersection[1].turn.instruction = getInstructionForObvious(intersection.size(), @@ -248,16 +240,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, + 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, + isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp + : TurnType::Turn, (road.turn.angle > 215) ? DirectionModifier::Left : DirectionModifier::SlightLeft}; } @@ -285,7 +277,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in for (std::size_t i = 0; i < intersection.size(); ++i) { if (intersection[i].entry_allowed && - detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph)) + isMotorwayClass(intersection[i].turn.eid, node_based_graph)) { if (first_valid < intersection.size()) { @@ -309,7 +301,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in for (std::size_t i = 0; i < intersection.size(); ++i) { if (intersection[i].entry_allowed && - detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph)) + isMotorwayClass(intersection[i].turn.eid, node_based_graph)) { if (second_valid < intersection.size()) { @@ -349,7 +341,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters if (intersection.size() == 2 && num_valid_turns == 1) { BOOST_ASSERT(!intersection[0].entry_allowed); - BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph)); + BOOST_ASSERT(isMotorwayClass(intersection[1].turn.eid, node_based_graph)); intersection[1].turn.instruction = getInstructionForObvious( intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]); @@ -370,7 +362,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters // 0 if (intersection[1].entry_allowed) { - if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) && + if (isMotorwayClass(intersection[1].turn.eid, node_based_graph) && node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id != EMPTY_NAMEID && node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id == @@ -397,7 +389,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters else { BOOST_ASSERT(intersection[2].entry_allowed); - if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) && + if (isMotorwayClass(intersection[2].turn.eid, node_based_graph) && node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id != EMPTY_NAMEID && node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id == @@ -434,8 +426,8 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters // \ / // | // R - if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) && - detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph)) + if (isMotorwayClass(intersection[1].turn.eid, node_based_graph) && + isMotorwayClass(intersection[2].turn.eid, node_based_graph)) { assignFork(via_eid, intersection[2], intersection[1]); } @@ -446,8 +438,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters // M R // | / // R - if (isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid) - .road_classification.road_class)) + if (isMotorwayClass(intersection[1].turn.eid, node_based_graph)) { intersection[1].turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight}; @@ -467,12 +458,11 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters bool passed_highway_entry = false; for (auto &road : intersection) { - const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); - if (!road.entry_allowed && isMotorwayClass(edge_data.road_classification.road_class)) + if (!road.entry_allowed && isMotorwayClass(road.turn.eid, node_based_graph)) { passed_highway_entry = true; } - else if (isMotorwayClass(edge_data.road_classification.road_class)) + else if (isMotorwayClass(road.turn.eid, node_based_graph)) { road.turn.instruction = {TurnType::Merge, passed_highway_entry ? DirectionModifier::SlightRight @@ -480,7 +470,7 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters } else { - BOOST_ASSERT(isRampClass(edge_data.road_classification.road_class)); + BOOST_ASSERT(isRampClass(road.turn.eid, node_based_graph)); road.turn.instruction = {TurnType::OffRamp, getTurnDirection(road.turn.angle)}; } } @@ -503,13 +493,13 @@ Intersection MotorwayHandler::fallback(Intersection intersection) const util::SimpleLogger().Write(logDEBUG) << "road: " << toString(road) << " Name: " << out_data.name_id - << " Road Class: " << (int)out_data.road_classification.road_class; + << " Road Class: " << out_data.road_classification.ToString(); if (!road.entry_allowed) continue; - const auto type = isMotorwayClass(out_data.road_classification.road_class) ? TurnType::Merge - : TurnType::Turn; + const auto type = + isMotorwayClass(road.turn.eid, node_based_graph) ? TurnType::Merge : TurnType::Turn; if (type == TurnType::Turn) { diff --git a/src/extractor/guidance/sliproad_handler.cpp b/src/extractor/guidance/sliproad_handler.cpp index 251351f72..27dc0b14c 100644 --- a/src/extractor/guidance/sliproad_handler.cpp +++ b/src/extractor/guidance/sliproad_handler.cpp @@ -74,8 +74,8 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection) const auto check_valid = [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 && + return road_edge_data.road_classification == + source_edge_data.road_classification && road_edge_data.name_id != EMPTY_NAMEID && road_edge_data.name_id == source_edge_data.name_id && road.entry_allowed; }; diff --git a/src/extractor/guidance/turn_analysis.cpp b/src/extractor/guidance/turn_analysis.cpp index b2d907ce2..e849b5875 100644 --- a/src/extractor/guidance/turn_analysis.cpp +++ b/src/extractor/guidance/turn_analysis.cpp @@ -1,4 +1,4 @@ -#include "extractor/guidance/classification_data.hpp" +#include "extractor/guidance/road_classification.hpp" #include "extractor/guidance/constants.hpp" #include "extractor/guidance/turn_analysis.hpp" @@ -86,7 +86,8 @@ Intersection TurnAnalysis::assignTurnTypes(const NodeID from_nid, intersection = sliproad_handler(from_nid, via_eid, std::move(intersection)); // Turn On Ramps Into Off Ramps, if we come from a motorway-like road - if (isMotorwayClass(node_based_graph.GetEdgeData(via_eid).road_classification.road_class)) + if (node_based_graph.GetEdgeData(via_eid) + .road_classification.IsMotorwayClass()) { std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) { if (road.turn.instruction.type == TurnType::OnRamp) diff --git a/src/extractor/guidance/turn_handler.cpp b/src/extractor/guidance/turn_handler.cpp index 1d8c6c228..fac9f1255 100644 --- a/src/extractor/guidance/turn_handler.cpp +++ b/src/extractor/guidance/turn_handler.cpp @@ -75,25 +75,28 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge, const ConnectedRoad &other) const { const auto &in_data = node_based_graph.GetEdgeData(via_edge); - const auto first_class = - node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class; - const auto second_class = - node_based_graph.GetEdgeData(other.turn.eid).road_classification.road_class; - - const bool is_ramp = isRampClass(first_class); + const auto &first_data = node_based_graph.GetEdgeData(road.turn.eid); + const auto &second_data = node_based_graph.GetEdgeData(other.turn.eid); + const auto &first_classification = first_data.road_classification; + const auto &second_classification = second_data.road_classification; + const bool is_ramp = first_classification.IsRampClass(); const bool is_obvious_by_road_class = - (!is_ramp && (2 * getPriority(first_class) < getPriority(second_class)) && - in_data.road_classification.road_class == first_class) || - (!isLowPriorityRoadClass(first_class) && isLowPriorityRoadClass(second_class)); + (!is_ramp && + (2 * first_classification.GetPriority() < second_classification.GetPriority()) && + in_data.road_classification == first_classification) || + (!first_classification.IsLowPriorityRoadClass() && + second_classification.IsLowPriorityRoadClass()); if (is_obvious_by_road_class) return true; const bool other_is_obvious_by_road_class = - (!isRampClass(second_class) && (2 * getPriority(second_class) < getPriority(first_class)) && - in_data.road_classification.road_class == second_class) || - (!isLowPriorityRoadClass(second_class) && isLowPriorityRoadClass(first_class)); + (!second_classification.IsRampClass() && + (2 * second_classification.GetPriority() < first_classification.GetPriority()) && + in_data.road_classification == second_classification) || + (!second_classification.IsLowPriorityRoadClass() && + first_classification.IsLowPriorityRoadClass()); if (other_is_obvious_by_road_class) return false; @@ -114,7 +117,7 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge, FUZZY_ANGLE_DIFFERENCE; return is_much_narrower_than_other; -}; +} Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const { @@ -256,13 +259,13 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection { auto &left = intersection[fork_range.second]; auto &right = intersection[fork_range.first]; - const auto left_class = - node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class; - const auto right_class = - node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class; - if (canBeSeenAsFork(left_class, right_class)) + const auto left_classification = + node_based_graph.GetEdgeData(left.turn.eid).road_classification; + const auto right_classification = + node_based_graph.GetEdgeData(right.turn.eid).road_classification; + if (canBeSeenAsFork(left_classification, right_classification)) assignFork(via_edge, left, right); - else if (getPriority(left_class) > getPriority(right_class)) + else if (left_classification.GetPriority() > right_classification.GetPriority()) { right.turn.instruction = getInstructionForObvious(intersection.size(), via_edge, false, right); @@ -541,13 +544,12 @@ std::pair TurnHandler::findFork(const EdgeID via_edge, }(); const bool has_compatible_classes = [&]() { - const bool ramp_class = - isLinkClass(node_based_graph.GetEdgeData(intersection[right].turn.eid) - .road_classification.road_class); + const bool ramp_class = node_based_graph.GetEdgeData(intersection[right].turn.eid) + .road_classification.IsLinkClass(); for (std::size_t index = right + 1; index <= left; ++index) if (ramp_class != - isLinkClass(node_based_graph.GetEdgeData(intersection[index].turn.eid) - .road_classification.road_class)) + node_based_graph.GetEdgeData(intersection[index].turn.eid) + .road_classification.IsLinkClass()) return false; return true; }(); @@ -581,13 +583,13 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge, getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft || getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight) { - const auto left_class = - node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class; - const auto right_class = - node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class; - if (canBeSeenAsFork(left_class, right_class)) + const auto left_classification = + node_based_graph.GetEdgeData(left.turn.eid).road_classification; + const auto right_classification = + node_based_graph.GetEdgeData(right.turn.eid).road_classification; + if (canBeSeenAsFork(left_classification, right_classification)) assignFork(via_edge, left, right); - else if (getPriority(left_class) > getPriority(right_class)) + else if (left_classification.GetPriority() > right_classification.GetPriority()) { // FIXME this should possibly know about the actual roads? // here we don't know about the intersection size. To be on the save side, diff --git a/src/extractor/scripting_environment_lua.cpp b/src/extractor/scripting_environment_lua.cpp index eaba199c7..bd35d1691 100644 --- a/src/extractor/scripting_environment_lua.cpp +++ b/src/extractor/scripting_environment_lua.cpp @@ -95,6 +95,24 @@ void LuaScriptingEnvironment::InitContext(LuaScriptingContext &context) luabind::value("river_up", TRAVEL_MODE_RIVER_UP), luabind::value("river_down", TRAVEL_MODE_RIVER_DOWN), luabind::value("route", TRAVEL_MODE_ROUTE)], + + luabind::class_("road_priority_class") + .enum_("enums") + [luabind::value("motorway", extractor::guidance::RoadPriorityClass::MOTORWAY), + luabind::value("trunk", extractor::guidance::RoadPriorityClass::TRUNK), + luabind::value("primary", extractor::guidance::RoadPriorityClass::PRIMARY), + luabind::value("secondary", extractor::guidance::RoadPriorityClass::SECONDARY), + luabind::value("tertiary", extractor::guidance::RoadPriorityClass::TERTIARY), + luabind::value("main_residential", + extractor::guidance::RoadPriorityClass::MAIN_RESIDENTIAL), + luabind::value("side_residential", + extractor::guidance::RoadPriorityClass::SIDE_RESIDENTIAL), + luabind::value("link_road", extractor::guidance::RoadPriorityClass::LINK_ROAD), + luabind::value("bike_path", extractor::guidance::RoadPriorityClass::BIKE_PATH), + luabind::value("foot_path", extractor::guidance::RoadPriorityClass::FOOT_PATH), + luabind::value("connectivity", + extractor::guidance::RoadPriorityClass::CONNECTIVITY)], + luabind::class_("sources") .def(luabind::constructor<>()) .def("load", &SourceContainer::LoadRasterSource) @@ -135,6 +153,21 @@ void LuaScriptingEnvironment::InitContext(LuaScriptingContext &context) .def_readwrite("traffic_lights", &ExtractionNode::traffic_lights) .def_readwrite("barrier", &ExtractionNode::barrier), + // road classification to be set in profile + luabind::class_("RoadClassification") + .property("motorway_class", + &guidance::RoadClassification::IsMotorwayClass, + &guidance::RoadClassification::SetMotorwayFlag) + .property("link_class", + &guidance::RoadClassification::IsLinkClass, + &guidance::RoadClassification::SetLinkClass) + .property("may_be_ignored", + &guidance::RoadClassification::IsLowPriorityRoadClass, + &guidance::RoadClassification::SetLowPriorityFlag) + .property("road_priority_class", + &guidance::RoadClassification::GetClass, + &guidance::RoadClassification::SetClass), + luabind::class_("ResultWay") // .def(luabind::constructor<>()) .def_readwrite("forward_speed", &ExtractionWay::forward_speed) @@ -148,6 +181,7 @@ void LuaScriptingEnvironment::InitContext(LuaScriptingContext &context) .def_readwrite("duration", &ExtractionWay::duration) .def_readwrite("turn_lanes_forward", &ExtractionWay::turn_lanes_forward) .def_readwrite("turn_lanes_backward", &ExtractionWay::turn_lanes_backward) + .def_readwrite("road_classification", &ExtractionWay::road_classification) .property( "forward_mode", &ExtractionWay::get_forward_mode, &ExtractionWay::set_forward_mode) .property("backward_mode",