move hardcoded road priorities into profiles, change road classification

This commit is contained in:
Moritz Kobitzsch
2016-06-24 16:06:45 +02:00
committed by Patrick Niklaus
parent fd6bb5ec1f
commit 1fc63e1e72
23 changed files with 451 additions and 527 deletions
+3
View File
@@ -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;
};
}
}
@@ -1,84 +0,0 @@
#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
#include <cstdint>
#include <string>
// 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_
@@ -0,0 +1,130 @@
#ifndef OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
#define OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
#include <cmath>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <osmium/osm.hpp>
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<std::uint32_t>(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<int>(first.GetPriority()) -
static_cast<int>(second.GetPriority())) <= 1;
}
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_CLASSIFICATION_DATA_HPP_
-184
View File
@@ -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 <typename IteratorType>
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<DirectionModifier::Enum>((static_cast<std::uint32_t>(modifier) + 1) %
detail::num_direction_modifiers);
}
inline DirectionModifier::Enum shiftCCW(const DirectionModifier::Enum modifier)
{
if (detail::shiftable_ccw[static_cast<int>(modifier)])
return forcedShiftCCW(modifier);
else
return modifier;
}
// shift an instruction around the degree circle in CW order
inline DirectionModifier::Enum forcedShiftCW(const DirectionModifier::Enum modifier)
{
return static_cast<DirectionModifier::Enum>(
(static_cast<std::uint32_t>(modifier) + detail::num_direction_modifiers - 1) %
detail::num_direction_modifiers);
}
inline DirectionModifier::Enum shiftCW(const DirectionModifier::Enum modifier)
{
if (detail::shiftable_cw[static_cast<int>(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<std::uint8_t>(
(angle + 0.5 * detail::discrete_angle_step_size) / detail::discrete_angle_step_size));
}
inline double angleFromDiscreteAngle(const DiscreteAngle angle)
{
return static_cast<double>(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<int>(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<int>(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<std::string, std::string> 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<int>(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.
@@ -7,7 +7,7 @@
#include <boost/assert.hpp>
#include "extractor/guidance/classification_data.hpp"
#include "extractor/guidance/road_classification.hpp"
#include "osrm/coordinate.hpp"
#include <utility>
@@ -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()
+6 -6
View File
@@ -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,