Allow users to specify a class for each way

This adds the ability to mark ways with a user-defined
class in the profile. This class information will be included
in the response as property of the RouteStep object.
This commit is contained in:
Patrick Niklaus 2017-06-27 22:01:05 +00:00 committed by Patrick Niklaus
parent d52d530cbe
commit 44739f2dc3
39 changed files with 614 additions and 57 deletions

View File

@ -5,8 +5,11 @@
- Plugins supported: `table`
- API:
- Support for exits numbers and names. New member `exits` in `RouteStep`, based on `junction:ref` on ways
- `RouteStep` now has new parameter `classes` that can be set in the profile on each way.
- Profiles:
- `result.exits` allows you to set a way's exit numbers and names, see [`junction:ref`](http://wiki.openstreetmap.org/wiki/Proposed_features/junction_details)
- `ExtractionWay` now as new property `forward_classes` and `backward_classes` that can set in the `way_function`.
The maximum number of classes is 8.
# 5.8.0
- Changes from 5.7

View File

@ -583,6 +583,7 @@ step.
- `destinations`: The destinations of the way. Will be `undefined` if there are no destinations.
- `exits`: The exit numbers or names of the way. Will be `undefined` if there are no exit numbers or names.
- `mode`: A string signifying the mode of transportation.
- `classes`: An array of strings signifying the classes of the road as specified in the profile.
- `maneuver`: A `StepManeuver` object representing the maneuver.
- `intersections`: A list of `Intersection` objects that are passed along the segment, the very first belonging to the StepManeuver
- `rotary_name`: The name for the rotary. Optionally included, if the step is a rotary and a rotary name is available.
@ -596,6 +597,7 @@ step.
"mode" : "driving",
"duration" : 15.6,
"weight" : 15.6,
"classes": ["toll", "restricted"],
"intersections" : [
{ "bearings" : [ 10, 92, 184, 270 ],
"lanes" : [
@ -660,7 +662,7 @@ step.
| `roundabout` | traverse roundabout, has additional property `exit` with NR if the roundabout is left. The modifier specifies the direction of entering the roundabout. |
| `rotary` | a traffic circle. While very similar to a larger version of a roundabout, it does not necessarily follow roundabout rules for right of way. It can offer `rotary_name` and/or `rotary_pronunciation` parameters (located in the RouteStep object) in addition to the `exit` parameter (located on the StepManeuver object). |
| `roundabout turn`| Describes a turn at a small roundabout that should be treated as normal turn. The `modifier` indicates the turn direciton. Example instruction: `At the roundabout turn left`. |
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode. If the road takes a turn itself, the `modifier` describes the direction |
| `notification` | not an actual turn but a change in the driving conditions. For example the travel mode or classes. If the road takes a turn itself, the `modifier` describes the direction |
Please note that even though there are `new name` and `notification` instructions, the `mode` and `name` can change
between all instructions. They only offer a fallback in case nothing else is to report.

View File

@ -56,6 +56,8 @@ forward_rate | Float | Routing weight, expressed a
backward_rate | Float | " "
forward_mode | Enum | Mode of travel (e.g. `car`, `ferry`). Mandatory. Defined in `include/extractor/travel_mode.hpp`.
backward_mode | Enum | " "
forward_classes | Table | Mark this way as being of a specific class, e.g. `result.classes["toll"] = true`. This will be exposed in the API as `classes` on each `RouteStep`.
backward_classes | Table | " "
duration | Float | Alternative setter for duration of the whole way in both directions
weight | Float | Alternative setter for weight of the whole way in both directions
turn_lanes_forward | String | Directions for individual lanes (normalised OSM `turn:lanes` value)

View File

@ -0,0 +1,101 @@
@routing @car @mode
Feature: Car - Mode flag
Background:
Given the profile "car"
Scenario: Car - We tag ferries with a class
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway | route |
| ab | primary | |
| bc | | ferry |
| cd | primary | |
When I route I should get
| from | to | route | turns | classes |
| a | d | ab,bc,cd,cd | depart,notification right,notification left,arrive | ,ferry,, |
| d | a | cd,bc,ab,ab | depart,notification right,notification left,arrive | ,ferry,, |
| c | a | bc,ab,ab | depart,notification left,arrive | ferry,, |
| d | b | cd,bc,bc | depart,notification right,arrive | ,ferry,ferry |
| a | c | ab,bc,bc | depart,notification right,arrive | ,ferry,ferry |
| b | d | bc,cd,cd | depart,notification left,arrive | ferry,, |
Scenario: Car - We tag motorways with a class
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway |
| ab | primary |
| bc | motorway|
| cd | primary |
When I route I should get
| from | to | route | turns | classes | # |
| a | d | ab,bc,cd | depart,notification right,arrive | ,motorway, | |
| a | c | ab,bc,bc | depart,notification right,arrive | ,motorway,motorway | |
| b | d | bc,cd | depart,arrive | motorway, | we don't announce when we leave the highway |
Scenario: Car - We tag motorway_link with a class
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway |
| ab | primary |
| bc | motorway_link |
| cd | primary |
When I route I should get
| from | to | route | turns | classes | # |
| a | d | ab,bc,cd | depart,on ramp right,arrive | ,motorway, | notification replaced by on-ramp |
| a | c | ab,bc,bc | depart,on ramp right,arrive | ,motorway,motorway | " " |
| b | d | bc,cd | depart,arrive | motorway, | no announcement |
Scenario: Car - We tag restricted with a class
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway | access |
| ab | primary | private |
| bc | motorway| private |
| cd | primary | |
When I route I should get
| from | to | route | turns | classes |
| a | d | ab,bc,cd | depart,notification right,arrive| restricted,motorway;restricted, |
Scenario: Car - We toll restricted with a class
Given the node map
"""
a b
c d
"""
And the ways
| nodes | highway | toll |
| ab | primary | yes |
| bc | motorway| yes |
| cd | primary | |
When I route I should get
| from | to | route | turns | classes |
| a | d | ab,bc,cd | depart,notification right,arrive | toll,motorway;toll, |

View File

@ -23,11 +23,11 @@ Feature: Car - Destination only, no passing through
When I route I should get
| from | to | route |
| a | b | ab,ab |
| a | c | ab,bcd |
| a | c | ab,bcd,bcd |
| a | d | ab,bcd,bcd |
| a | e | axye,axye |
| e | d | de,de |
| e | c | de,bcd |
| e | c | de,bcd,bcd |
| e | b | de,bcd,bcd |
| e | a | axye,axye |
@ -51,12 +51,12 @@ Feature: Car - Destination only, no passing through
When I route I should get
| from | to | route |
| a | b | ab,ab |
| a | c | ab,bc |
| a | d | ab,cd |
| a | c | ab,bc,bc |
| a | d | ab,bc,cd |
| a | e | axye,axye |
| e | d | de,de |
| e | c | de,cd |
| e | b | de,bc |
| e | c | de,cd,cd |
| e | b | de,cd,bc |
| e | a | axye,axye |
Scenario: Car - Routing inside a destination only area

View File

@ -260,6 +260,10 @@ module.exports = function () {
return this.extractInstructionList(instructions, s => s.mode);
};
this.classesList = (instructions) => {
return this.extractInstructionList(instructions, s => s.classes ? s.classes.join(';') : '');
};
this.timeList = (instructions) => {
return this.extractInstructionList(instructions, s => s.duration + 's');
};

View File

@ -34,7 +34,7 @@ module.exports = function () {
var afterRequest = (err, res, body) => {
if (err) return cb(err);
if (body && body.length) {
let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times,
let destinations, exits, pronunciations, instructions, refs, bearings, turns, modes, times, classes,
distances, summary, intersections, lanes, locations, annotation, weight_name, weights, approaches;
let json = JSON.parse(body);
@ -53,6 +53,7 @@ module.exports = function () {
turns = this.turnList(json.routes[0]);
intersections = this.intersectionList(json.routes[0]);
modes = this.modeList(json.routes[0]);
classes = this.classesList(json.routes[0]);
times = this.timeList(json.routes[0]);
distances = this.distanceList(json.routes[0]);
lanes = this.lanesList(json.routes[0]);
@ -174,6 +175,7 @@ module.exports = function () {
putValue('bearing', bearings);
putValue('turns', turns);
putValue('modes', modes);
putValue('classes', classes);
putValue('times', times);
putValue('distances', distances);
putValue('pronunciations', pronunciations);

View File

@ -318,7 +318,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
void InitializeEdgeBasedNodeDataInformationPointers(storage::DataLayout &layout,
char *memory_ptr)
{
auto via_geometry_list_ptr =
const auto via_geometry_list_ptr =
layout.GetBlockPtr<GeometryID>(memory_ptr, storage::DataLayout::GEOMETRY_ID_LIST);
util::vector_view<GeometryID> geometry_ids(
via_geometry_list_ptr, layout.num_entries[storage::DataLayout::GEOMETRY_ID_LIST]);
@ -338,10 +338,16 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
util::vector_view<extractor::TravelMode> travel_modes(
travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]);
const auto classes_list_ptr =
layout.GetBlockPtr<extractor::ClassData>(memory_ptr, storage::DataLayout::CLASSES_LIST);
util::vector_view<extractor::ClassData> classes(
classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]);
edge_based_node_data = extractor::EdgeBasedNodeDataView(std::move(geometry_ids),
std::move(name_ids),
std::move(component_ids),
std::move(travel_modes));
std::move(travel_modes),
std::move(classes));
}
void InitializeEdgeInformationPointers(storage::DataLayout &layout, char *memory_ptr)
@ -783,6 +789,22 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
return edge_based_node_data.GetTravelMode(id);
}
extractor::ClassData GetClassData(const NodeID id) const override final
{
return edge_based_node_data.GetClassData(id);
}
std::vector<std::string> GetClasses(const extractor::ClassData class_data) const override final
{
auto indexes = extractor::getClassIndexes(class_data);
std::vector<std::string> classes(indexes.size());
std::transform(indexes.begin(), indexes.end(), classes.begin(), [this](const auto index) {
return m_profile_properties->GetClassName(index);
});
return classes;
}
NameID GetNameIndex(const NodeID id) const override final
{
return edge_based_node_data.GetNameID(id);

View File

@ -3,14 +3,19 @@
// Exposes all data access interfaces to the algorithms via base class ptr
#include "engine/approach.hpp"
#include "engine/phantom_node.hpp"
#include "contractor/query_edge.hpp"
#include "extractor/class_data.hpp"
#include "extractor/edge_based_node_segment.hpp"
#include "extractor/external_memory_node.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
#include "extractor/original_edge_data.hpp"
#include "engine/approach.hpp"
#include "engine/phantom_node.hpp"
#include "extractor/travel_mode.hpp"
#include "util/exception.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
@ -87,6 +92,10 @@ class BaseDataFacade
virtual extractor::TravelMode GetTravelMode(const NodeID id) const = 0;
virtual extractor::ClassData GetClassData(const NodeID id) const = 0;
virtual std::vector<std::string> GetClasses(const extractor::ClassData class_data) const = 0;
virtual std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
const util::Coordinate north_east) const = 0;

View File

@ -53,6 +53,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
: source_node.forward_segment_id.id;
const auto source_name_id = facade.GetNameIndex(source_node_id);
const auto source_mode = facade.GetTravelMode(source_node_id);
auto source_classes = facade.GetClasses(facade.GetClassData(source_node_id));
const EdgeWeight target_duration =
target_traversed_in_reverse ? target_node.reverse_duration : target_node.forward_duration;
@ -62,6 +63,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
: target_node.forward_segment_id.id;
const auto target_name_id = facade.GetNameIndex(target_node_id);
const auto target_mode = facade.GetTravelMode(target_node_id);
auto target_classes = facade.GetClasses(facade.GetClassData(target_node_id));
const auto number_of_segments = leg_geometry.GetNumberOfSegments();
@ -116,6 +118,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
const auto destinations = facade.GetDestinationsForID(step_name_id);
const auto exits = facade.GetExitsForID(step_name_id);
const auto distance = leg_geometry.segment_distances[segment_index];
auto classes = facade.GetClasses(path_point.classes);
steps.push_back(RouteStep{step_name_id,
name.to_string(),
@ -132,7 +135,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1,
{intersection}});
{intersection},
std::move(classes)});
if (leg_data_index + 1 < leg_data.size())
{
@ -208,7 +212,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1,
{intersection}});
{intersection},
std::move(target_classes)});
}
// In this case the source + target are on the same edge segment
else
@ -250,7 +255,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
std::move(maneuver),
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1,
{intersection}});
{intersection},
std::move(source_classes)});
}
BOOST_ASSERT(segment_index == number_of_segments - 1);
@ -289,7 +295,8 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
std::move(maneuver),
leg_geometry.locations.size() - 1,
leg_geometry.locations.size(),
{intersection}});
{intersection},
std::move(target_classes)});
BOOST_ASSERT(steps.front().intersections.size() == 1);
BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1);

View File

@ -74,6 +74,7 @@ struct RouteStep
std::size_t geometry_begin;
std::size_t geometry_end;
std::vector<IntermediateIntersection> intersections;
std::vector<std::string> classes;
// remove all information from the route step, marking it as invalid (used to indicate empty
// steps to be removed).
@ -127,6 +128,7 @@ inline void RouteStep::Invalidate()
geometry_end = 0;
intersections.clear();
intersections.push_back(getInvalidIntersection());
classes.clear();
}
// Elongate by another step in front

View File

@ -33,6 +33,8 @@ struct PathData
util::guidance::LaneTupleIdPair lane_data;
// travel mode of the street that leads to the turn
extractor::TravelMode travel_mode : 4;
// user defined classed of the street that leads to the turn
extractor::ClassData classes;
// entry class of the turn, indicating possibility of turns
util::guidance::EntryClass entry_class;

View File

@ -140,6 +140,7 @@ void annotatePath(const FacadeT &facade,
const auto name_index = facade.GetNameIndex(node_id);
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id);
const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id);
const auto classes = facade.GetClassData(node_id);
const auto geometry_index = facade.GetGeometryIndex(node_id);
std::vector<NodeID> id_vector;
@ -186,6 +187,7 @@ void annotatePath(const FacadeT &facade,
extractor::guidance::TurnInstruction::NO_TURN(),
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
travel_mode,
classes,
EMPTY_ENTRY_CLASS,
datasource_vector[segment_idx],
util::guidance::TurnBearing(0),
@ -261,6 +263,7 @@ void annotatePath(const FacadeT &facade,
extractor::guidance::TurnInstruction::NO_TURN(),
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
facade.GetTravelMode(target_node_id),
facade.GetClassData(target_node_id),
EMPTY_ENTRY_CLASS,
datasource_vector[segment_idx],
util::guidance::TurnBearing(0),

View File

@ -0,0 +1,22 @@
#ifndef OSRM_EXTRACTOR_CLASSES_DATA_HPP
#define OSRM_EXTRACTOR_CLASSES_DATA_HPP
#include "util/bit_range.hpp"
#include <cstdint>
namespace osrm
{
namespace extractor
{
using ClassData = std::uint8_t;
static const std::uint8_t MAX_CLASS_INDEX = 8 - 1;
inline bool isSubset(const ClassData lhs, const ClassData rhs) { return (lhs & rhs) == lhs; }
inline auto getClassIndexes(const ClassData data) { return util::makeBitRange<ClassData>(data); }
}
}
#endif

View File

@ -85,6 +85,10 @@ struct ExtractionWay
}
const char *GetTurnLanesBackward() const { return turn_lanes_backward.c_str(); }
// markers for determining user-defined classes for each way
std::unordered_map<std::string, bool> forward_classes;
std::unordered_map<std::string, bool> backward_classes;
// speed in km/h
double forward_speed;
double backward_speed;

View File

@ -1,6 +1,7 @@
#ifndef EXTRACTOR_CALLBACKS_HPP
#define EXTRACTOR_CALLBACKS_HPP
#include "extractor/class_data.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
#include "util/typedefs.hpp"
@ -61,13 +62,18 @@ class ExtractorCallbacks
using MapKey = std::tuple<std::string, std::string, std::string, std::string, std::string>;
using MapVal = unsigned;
std::unordered_map<MapKey, MapVal> string_map;
guidance::LaneDescriptionMap lane_description_map;
ExtractionContainers &external_memory;
std::unordered_map<std::string, ClassData> &classes_map;
guidance::LaneDescriptionMap &lane_description_map;
bool fallback_to_duration;
bool force_split_edges;
public:
using ClassesMap = std::unordered_map<std::string, ClassData>;
explicit ExtractorCallbacks(ExtractionContainers &extraction_containers,
std::unordered_map<std::string, ClassData> &classes_map,
guidance::LaneDescriptionMap &lane_description_map,
const ProfileProperties &properties);
ExtractorCallbacks(const ExtractorCallbacks &) = delete;
@ -81,9 +87,6 @@ class ExtractorCallbacks
// warning: caller needs to take care of synchronization!
void ProcessWay(const osmium::Way &current_way, const ExtractionWay &result_way);
// destroys the internal laneDescriptionMap
guidance::LaneDescriptionMap &&moveOutLaneDescriptionMap();
};
}
}

View File

@ -72,6 +72,7 @@ struct InternalExtractorEdge
false, // local access only
false, // split edge
TRAVEL_MODE_INACCESSIBLE,
0,
guidance::TurnLaneType::empty,
guidance::RoadClassification()),
weight_data(), duration_data()
@ -91,6 +92,7 @@ struct InternalExtractorEdge
bool restricted,
bool is_split,
TravelMode travel_mode,
ClassData classes,
LaneDescriptionID lane_description,
guidance::RoadClassification road_classification,
util::Coordinate source_coordinate)
@ -107,6 +109,7 @@ struct InternalExtractorEdge
restricted,
is_split,
travel_mode,
classes,
lane_description,
std::move(road_classification)),
weight_data(std::move(weight_data)), duration_data(std::move(duration_data)),
@ -139,6 +142,7 @@ struct InternalExtractorEdge
false, // local access only
false, // split edge
TRAVEL_MODE_INACCESSIBLE,
0,
INVALID_LANE_DESCRIPTIONID,
guidance::RoadClassification(),
util::Coordinate());
@ -158,6 +162,7 @@ struct InternalExtractorEdge
false, // local access only
false, // split edge
TRAVEL_MODE_INACCESSIBLE,
0,
INVALID_LANE_DESCRIPTIONID,
guidance::RoadClassification(),
util::Coordinate());

View File

@ -1,6 +1,7 @@
#ifndef NODE_BASED_EDGE_HPP
#define NODE_BASED_EDGE_HPP
#include "extractor/class_data.hpp"
#include "extractor/travel_mode.hpp"
#include "util/typedefs.hpp"
@ -28,6 +29,7 @@ struct NodeBasedEdge
bool restricted,
bool is_split,
TravelMode travel_mode,
ClassData classes,
const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification);
@ -46,6 +48,7 @@ struct NodeBasedEdge
std::uint8_t restricted : 1; // 1
std::uint8_t is_split : 1; // 1
TravelMode travel_mode : 4; // 4
ClassData classes; // 8 1
LaneDescriptionID lane_description_id; // 16 2
guidance::RoadClassification road_classification; // 16 2
};
@ -65,6 +68,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
bool restricted,
bool is_split,
TravelMode travel_mode,
ClassData classes,
const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification);
@ -95,12 +99,14 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
bool restricted,
bool is_split,
TravelMode travel_mode,
ClassData classes,
const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification)
: source(source), target(target), name_id(name_id), weight(weight), duration(duration),
forward(forward), backward(backward), roundabout(roundabout), circular(circular),
startpoint(startpoint), restricted(restricted), is_split(is_split), travel_mode(travel_mode),
lane_description_id(lane_description_id), road_classification(std::move(road_classification))
classes(classes), lane_description_id(lane_description_id),
road_classification(std::move(road_classification))
{
}
@ -134,6 +140,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
bool restricted,
bool is_split,
TravelMode travel_mode,
ClassData classes,
const LaneDescriptionID lane_description_id,
guidance::RoadClassification road_classification)
: NodeBasedEdge(SPECIAL_NODEID,
@ -149,6 +156,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
restricted,
is_split,
travel_mode,
classes,
lane_description_id,
std::move(road_classification)),
osm_source_id(std::move(source)), osm_target_id(std::move(target))

View File

@ -1,6 +1,7 @@
#ifndef OSRM_EXTRACTOR_NODE_DATA_CONTAINER_HPP
#define OSRM_EXTRACTOR_NODE_DATA_CONTAINER_HPP
#include "extractor/class_data.hpp"
#include "extractor/travel_mode.hpp"
#include "storage/io_fwd.hpp"
@ -41,16 +42,18 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
EdgeBasedNodeDataContainerImpl() = default;
EdgeBasedNodeDataContainerImpl(std::size_t size)
: geometry_ids(size), name_ids(size), component_ids(size), travel_modes(size)
: geometry_ids(size), name_ids(size), component_ids(size), travel_modes(size), classes(size)
{
}
EdgeBasedNodeDataContainerImpl(Vector<GeometryID> geometry_ids,
Vector<NameID> name_ids,
Vector<ComponentID> component_ids,
Vector<TravelMode> travel_modes)
Vector<TravelMode> travel_modes,
Vector<ClassData> classes)
: geometry_ids(std::move(geometry_ids)), name_ids(std::move(name_ids)),
component_ids(std::move(component_ids)), travel_modes(std::move(travel_modes))
component_ids(std::move(component_ids)), travel_modes(std::move(travel_modes)),
classes(std::move(classes))
{
}
@ -62,13 +65,20 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
ComponentID GetComponentID(const NodeID node_id) const { return component_ids[node_id]; }
ClassData GetClassData(const NodeID node_id) const { return classes[node_id]; }
// Used by EdgeBasedGraphFactory to fill data structure
template <typename = std::enable_if<Ownership == storage::Ownership::Container>>
void SetData(NodeID node_id, GeometryID geometry_id, NameID name_id, TravelMode travel_mode)
void SetData(NodeID node_id,
GeometryID geometry_id,
NameID name_id,
TravelMode travel_mode,
ClassData class_data)
{
geometry_ids[node_id] = geometry_id;
name_ids[node_id] = name_id;
travel_modes[node_id] = travel_mode;
classes[node_id] = class_data;
}
// Used by EdgeBasedGraphFactory to fill data structure
@ -91,6 +101,7 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
util::inplacePermutation(name_ids.begin(), name_ids.end(), permutation);
util::inplacePermutation(component_ids.begin(), component_ids.end(), permutation);
util::inplacePermutation(travel_modes.begin(), travel_modes.end(), permutation);
util::inplacePermutation(classes.begin(), classes.end(), permutation);
}
private:
@ -98,6 +109,7 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
Vector<NameID> name_ids;
Vector<ComponentID> component_ids;
Vector<TravelMode> travel_modes;
Vector<ClassData> classes;
};
}

View File

@ -1,6 +1,8 @@
#ifndef PROFILE_PROPERTIES_HPP
#define PROFILE_PROPERTIES_HPP
#include "extractor/class_data.hpp"
#include "util/typedefs.hpp"
#include <algorithm>
@ -17,6 +19,7 @@ const constexpr auto DEFAULT_MAX_SPEED = 180 / 3.6; // 180kmph -> m/s
struct ProfileProperties
{
static constexpr int MAX_WEIGHT_NAME_LENGTH = 255;
static constexpr int MAX_CLASS_NAME_LENGTH = 255;
ProfileProperties()
: traffic_signal_penalty(0), u_turn_penalty(0),
@ -66,6 +69,22 @@ struct ProfileProperties
return std::string(weight_name);
}
void SetClassName(std::size_t index, const std::string &name)
{
char *name_ptr = class_names[index];
auto count = std::min<std::size_t>(name.length(), MAX_CLASS_NAME_LENGTH) + 1;
std::copy_n(name.c_str(), count, name_ptr);
// Make sure this is always zero terminated
BOOST_ASSERT(class_names[index][count - 1] == '\0');
BOOST_ASSERT(class_names[index][MAX_CLASS_NAME_LENGTH] == '\0');
}
std::string GetClassName(std::size_t index) const
{
BOOST_ASSERT(index <= MAX_CLASS_INDEX);
return std::string(class_names[index]);
}
double GetWeightMultiplier() const { return std::pow(10., weight_precision); }
double GetMaxTurnWeight() const
@ -86,6 +105,8 @@ struct ProfileProperties
bool fallback_to_duration;
//! stores the name of the weight (e.g. 'duration', 'distance', 'safety')
char weight_name[MAX_WEIGHT_NAME_LENGTH + 1];
//! stores the names of each class
std::array<char[MAX_CLASS_NAME_LENGTH + 1], MAX_CLASS_INDEX + 1> class_names;
unsigned weight_precision = 1;
bool force_split_edges = false;

View File

@ -121,6 +121,7 @@ inline void read(storage::io::FileReader &reader,
storage::serialization::read(reader, node_data_container.name_ids);
storage::serialization::read(reader, node_data_container.component_ids);
storage::serialization::read(reader, node_data_container.travel_modes);
storage::serialization::read(reader, node_data_container.classes);
}
template <storage::Ownership Ownership>
@ -131,6 +132,7 @@ inline void write(storage::io::FileWriter &writer,
storage::serialization::write(writer, node_data_container.name_ids);
storage::serialization::write(writer, node_data_container.component_ids);
storage::serialization::write(writer, node_data_container.travel_modes);
storage::serialization::write(writer, node_data_container.classes);
}
// read/write for conditional turn restrictions file

View File

@ -23,6 +23,7 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
"NAME_ID_LIST",
"COMPONENT_ID_LIST",
"TRAVEL_MODE_LIST",
"CLASSES_LIST",
"CH_GRAPH_NODE_LIST",
"CH_GRAPH_EDGE_LIST",
"COORDINATE_LIST",
@ -79,6 +80,7 @@ struct DataLayout
NAME_ID_LIST,
COMPONENT_ID_LIST,
TRAVEL_MODE_LIST,
CLASSES_LIST,
CH_GRAPH_NODE_LIST,
CH_GRAPH_EDGE_LIST,
COORDINATE_LIST,

View File

@ -0,0 +1,99 @@
#ifndef OSRM_UTIL_BIT_RANGE_HPP
#define OSRM_UTIL_BIT_RANGE_HPP
#include "util/msb.hpp"
#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/iterator_range.hpp>
namespace osrm
{
namespace util
{
namespace detail
{
template <typename T> std::size_t countOnes(T value)
{
static_assert(std::is_unsigned<T>::value, "Only unsigned types allowed");
std::size_t number_of_ones = 0;
while (value > 0)
{
auto index = msb(value);
value = value & ~(T{1} << index);
number_of_ones++;
}
return number_of_ones;
}
#if (defined(__clang__) || defined(__GNUC__) || defined(__GNUG__))
inline std::size_t countOnes(std::uint8_t value)
{
return __builtin_popcount(std::uint32_t{value});
}
inline std::size_t countOnes(std::uint16_t value)
{
return __builtin_popcount(std::uint32_t{value});
}
inline std::size_t countOnes(unsigned int value) { return __builtin_popcount(value); }
inline std::size_t countOnes(unsigned long value) { return __builtin_popcountl(value); }
inline std::size_t countOnes(unsigned long long value) { return __builtin_popcountll(value); }
#endif
}
// Investigate if we can replace this with
// http://www.boost.org/doc/libs/1_64_0/libs/dynamic_bitset/dynamic_bitset.html
template <typename DataT>
class BitIterator : public boost::iterator_facade<BitIterator<DataT>,
const std::size_t,
boost::forward_traversal_tag,
const std::size_t>
{
typedef boost::iterator_facade<BitIterator<DataT>,
const std::size_t,
boost::forward_traversal_tag,
const std::size_t>
base_t;
public:
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::reference reference;
typedef std::random_access_iterator_tag iterator_category;
explicit BitIterator() : m_value(0) {}
explicit BitIterator(const DataT x) : m_value(std::move(x)) {}
private:
void increment()
{
auto index = msb(m_value);
m_value = m_value & ~(DataT{1} << index);
}
difference_type distance_to(const BitIterator &other) const
{
return detail::countOnes(m_value) - detail::countOnes(other.m_value);
}
bool equal(const BitIterator &other) const { return m_value == other.m_value; }
reference dereference() const
{
BOOST_ASSERT(m_value > 0);
return msb(m_value);
}
friend class ::boost::iterator_core_access;
DataT m_value;
};
// Returns range over all 1 bits of value
template <typename T> auto makeBitRange(const T value)
{
return boost::make_iterator_range(BitIterator<T>{value}, BitIterator<T>{});
}
}
}
#endif

View File

@ -3,6 +3,7 @@
#include <boost/assert.hpp>
#include <climits>
#include <cstdint>
#include <utility>
@ -26,16 +27,24 @@ template <typename T> std::size_t msb(T value)
return msb - 1;
}
#if (defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)) && __x86_64__
inline std::size_t msb(std::uint64_t v)
#if (defined(__clang__) || defined(__GNUC__) || defined(__GNUG__))
inline std::size_t msb(unsigned long long v)
{
BOOST_ASSERT(v > 0);
return 63UL - __builtin_clzl(v);
constexpr auto MSB_INDEX = CHAR_BIT * sizeof(unsigned long long) - 1;
return MSB_INDEX - __builtin_clzll(v);
}
inline std::size_t msb(std::uint32_t v)
inline std::size_t msb(unsigned long v)
{
BOOST_ASSERT(v > 0);
return 31UL - __builtin_clz(v);
constexpr auto MSB_INDEX = CHAR_BIT * sizeof(unsigned long) - 1;
return MSB_INDEX - __builtin_clzl(v);
}
inline std::size_t msb(unsigned int v)
{
BOOST_ASSERT(v > 0);
constexpr auto MSB_INDEX = CHAR_BIT * sizeof(unsigned int) - 1;
return MSB_INDEX - __builtin_clz(v);
}
#endif
}

View File

@ -1,6 +1,7 @@
#ifndef NODE_BASED_GRAPH_HPP
#define NODE_BASED_GRAPH_HPP
#include "extractor/class_data.hpp"
#include "extractor/guidance/road_classification.hpp"
#include "extractor/node_based_edge.hpp"
#include "util/dynamic_graph.hpp"
@ -35,10 +36,12 @@ struct NodeBasedEdgeData
bool startpoint,
bool restricted,
extractor::TravelMode travel_mode,
extractor::ClassData classes,
const LaneDescriptionID lane_description_id)
: weight(weight), duration(duration), edge_id(edge_id), name_id(name_id),
reversed(reversed), roundabout(roundabout), circular(circular), startpoint(startpoint),
restricted(restricted), travel_mode(travel_mode), lane_description_id(lane_description_id)
restricted(restricted), travel_mode(travel_mode), classes(classes),
lane_description_id(lane_description_id)
{
}
@ -52,6 +55,7 @@ struct NodeBasedEdgeData
bool startpoint : 1;
bool restricted : 1;
extractor::TravelMode travel_mode : 4;
extractor::ClassData classes;
LaneDescriptionID lane_description_id;
extractor::guidance::RoadClassification road_classification;
@ -59,7 +63,7 @@ struct NodeBasedEdgeData
{
return (reversed == other.reversed) && (roundabout == other.roundabout) &&
(circular == other.circular) && (startpoint == other.startpoint) &&
(travel_mode == other.travel_mode) &&
(travel_mode == other.travel_mode) && (classes == other.classes) &&
(road_classification == other.road_classification) &&
(restricted == other.restricted);
}
@ -89,6 +93,7 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
output_edge.data.circular = input_edge.circular;
output_edge.data.name_id = input_edge.name_id;
output_edge.data.travel_mode = input_edge.travel_mode;
output_edge.data.classes = input_edge.classes;
output_edge.data.startpoint = input_edge.startpoint;
output_edge.data.restricted = input_edge.restricted;
output_edge.data.road_classification = input_edge.road_classification;

View File

@ -366,6 +366,9 @@ function way_function(way, result)
'handle_maxspeed',
'handle_penalties',
-- compute class labels
'handle_classes',
-- handle turn lanes and road classification, used for guidance
'handle_turn_lanes',
'handle_classification',

View File

@ -277,6 +277,38 @@ function Handlers.handle_speed(way,result,data,profile)
end
end
-- add class information
function Handlers.handle_classes(way,result,data,profile)
local forward_toll, backward_toll = Tags.get_forward_backward_by_key(way, data, "toll")
local forward_route, backward_route = Tags.get_forward_backward_by_key(way, data, "route")
if forward_toll == "yes" then
result.forward_classes["toll"] = true
end
if backward_toll == "yes" then
result.backward_classes["toll"] = true
end
if forward_route == "ferry" then
result.forward_classes["ferry"] = true
end
if backward_route == "ferry" then
result.backward_classes["ferry"] = true
end
if result.forward_restricted then
result.forward_classes["restricted"] = true
end
if result.backward_restricted then
result.backward_classes["restricted"] = true
end
if data.highway == "motorway" or data.highway == "motorway_link" then
result.forward_classes["motorway"] = true
result.backward_classes["motorway"] = true
end
end
-- reduce speed on bad surfaces
function Handlers.handle_surface(way,result,data,profile)
local surface = way:get_value_by_key("surface")

View File

@ -265,6 +265,18 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
route_step.values["geometry"] = std::move(geometry);
if (!step.classes.empty())
{
util::json::Array classes;
classes.values.reserve(step.classes.size());
std::transform(
step.classes.begin(),
step.classes.end(),
std::back_inserter(classes.values),
[](const std::string &class_name) { return util::json::String{class_name}; });
route_step.values["classes"] = std::move(classes);
}
util::json::Array intersections;
intersections.values.reserve(step.intersections.size());
std::transform(step.intersections.begin(),

View File

@ -486,6 +486,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
auto &new_next_to_last = *(steps.end() - 2);
next_to_last_step.AdaptStepSignage(new_next_to_last);
next_to_last_step.mode = new_next_to_last.mode;
next_to_last_step.classes = new_next_to_last.classes;
// the geometry indices of the last step are already correct;
}
else if (util::coordinate_calculation::haversineDistance(

View File

@ -148,13 +148,15 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
m_edge_based_node_container.SetData(forward_data.edge_id,
GeometryID{packed_geometry_id, true},
forward_data.name_id,
forward_data.travel_mode);
forward_data.travel_mode,
forward_data.classes);
if (reverse_data.edge_id != SPECIAL_EDGEID)
{
m_edge_based_node_container.SetData(reverse_data.edge_id,
GeometryID{packed_geometry_id, false},
reverse_data.name_id,
reverse_data.travel_mode);
reverse_data.travel_mode,
reverse_data.classes);
}
// Add segments of edge-based nodes

View File

@ -63,6 +63,21 @@ namespace osrm
namespace extractor
{
namespace
{
// Converts the class name map into a fixed mapping of index to name
void SetClassNames(const ExtractorCallbacks::ClassesMap &classes_map,
ProfileProperties &profile_properties)
{
for (const auto &pair : classes_map)
{
auto range = getClassIndexes(pair.second);
BOOST_ASSERT(range.size() == 1);
profile_properties.SetClassName(range.front(), pair.first);
}
}
}
/**
* TODO: Refactor this function into smaller functions for better readability.
*
@ -201,8 +216,13 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
TIMER_START(parsing);
ExtractionContainers extraction_containers;
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(
extraction_containers, scripting_environment.GetProfileProperties());
ExtractorCallbacks::ClassesMap classes_map;
guidance::LaneDescriptionMap turn_lane_map;
auto extractor_callbacks =
std::make_unique<ExtractorCallbacks>(extraction_containers,
classes_map,
turn_lane_map,
scripting_environment.GetProfileProperties());
// setup raster sources
scripting_environment.SetupSources();
@ -304,10 +324,6 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
util::Log() << "Raw input contains " << number_of_nodes << " nodes, " << number_of_ways
<< " ways, and " << number_of_relations << " relations";
// take control over the turn lane map
guidance::LaneDescriptionMap turn_lane_map;
turn_lane_map.data = extractor_callbacks->moveOutLaneDescriptionMap().data;
extractor_callbacks.reset();
if (extraction_containers.all_edges_list.empty())
@ -321,8 +337,9 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
config.restriction_file_name,
config.names_file_name);
files::writeProfileProperties(config.profile_properties_output_path,
scripting_environment.GetProfileProperties());
auto profile_properties = scripting_environment.GetProfileProperties();
SetClassNames(classes_map, profile_properties);
files::writeProfileProperties(config.profile_properties_output_path, profile_properties);
TIMER_STOP(extracting);
util::Log() << "extraction finished after " << TIMER_SEC(extracting) << "s";

View File

@ -34,8 +34,11 @@ using TurnLaneDescription = guidance::TurnLaneDescription;
namespace TurnLaneType = guidance::TurnLaneType;
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers_,
std::unordered_map<std::string, ClassData> &classes_map,
guidance::LaneDescriptionMap &lane_description_map,
const ProfileProperties &properties)
: external_memory(extraction_containers_),
: external_memory(extraction_containers_), classes_map(classes_map),
lane_description_map(lane_description_map),
fallback_to_duration(properties.fallback_to_duration),
force_split_edges(properties.force_split_edges)
{
@ -175,6 +178,38 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
}
}
const auto classStringToMask = [this](const std::string &class_name) {
auto iter = classes_map.find(class_name);
if (iter == classes_map.end())
{
if (classes_map.size() > MAX_CLASS_INDEX)
{
throw util::exception("Maximum number of classes if " +
std::to_string(MAX_CLASS_INDEX + 1));
}
ClassData class_mask = 1u << classes_map.size();
classes_map[class_name] = class_mask;
return class_mask;
}
else
{
return iter->second;
}
};
const auto classesToMask = [&](const auto &classes) {
ClassData mask = 0;
for (const auto &name_and_flag : classes)
{
if (name_and_flag.second)
{
mask |= classStringToMask(name_and_flag.first);
}
}
return mask;
};
const ClassData forward_classes = classesToMask(parsed_way.forward_classes);
const ClassData backward_classes = classesToMask(parsed_way.backward_classes);
const auto laneStringToDescription = [](const std::string &lane_string) -> TurnLaneDescription {
if (lane_string.empty())
return {};
@ -330,7 +365,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
(force_split_edges || (parsed_way.forward_rate != parsed_way.backward_rate) ||
(parsed_way.forward_speed != parsed_way.backward_speed) ||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode) ||
(turn_lane_id_forward != turn_lane_id_backward));
(turn_lane_id_forward != turn_lane_id_backward) || (forward_classes != backward_classes));
if (in_forward_direction)
{ // add (forward) segments or (forward,backward) for non-split edges in backward direction
@ -352,6 +387,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
parsed_way.forward_restricted,
split_edge,
parsed_way.forward_travel_mode,
forward_classes,
turn_lane_id_forward,
road_classification,
{}));
@ -378,6 +414,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
parsed_way.backward_restricted,
split_edge,
parsed_way.backward_travel_mode,
backward_classes,
turn_lane_id_backward,
road_classification,
{}));
@ -399,9 +436,5 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
OSMNodeID{static_cast<std::uint64_t>(nodes.back().ref())}});
}
guidance::LaneDescriptionMap &&ExtractorCallbacks::moveOutLaneDescriptionMap()
{
return std::move(lane_description_map);
}
} // namespace extractor
} // namespace osrm

View File

@ -75,9 +75,6 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
const ConnectedRoad &road) const
{
const auto type = findBasicTurnType(via_edge, road);
// handle travel modes:
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
if (type == TurnType::OnRamp)
{
return {TurnType::OnRamp, getTurnDirection(road.angle)};
@ -87,6 +84,15 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
{
return {TurnType::Continue, DirectionModifier::UTurn};
}
// handle travel modes:
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
const auto in_classes = node_based_graph.GetEdgeData(via_edge).classes;
const auto out_classes = node_based_graph.GetEdgeData(road.eid).classes;
// if we just lose class flags we don't want to notify
const auto needs_notification = in_mode != out_mode || !isSubset(out_classes, in_classes);
if (type == TurnType::Turn)
{
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
@ -141,14 +147,14 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
}
else
{
return {in_mode == out_mode ? TurnType::NewName : TurnType::Notification,
return {needs_notification ? TurnType::Notification : TurnType::NewName,
getTurnDirection(road.angle)};
}
}
// name has not changed, suppress a turn here or indicate mode change
else
{
if (in_mode != out_mode)
if (needs_notification)
return {TurnType::Notification, getTurnDirection(road.angle)};
else
return {num_roads == 2 ? TurnType::NoTurn : TurnType::Suppressed,
@ -156,7 +162,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
}
}
BOOST_ASSERT(type == TurnType::Continue);
if (in_mode != out_mode)
if (needs_notification)
{
return {TurnType::Notification, getTurnDirection(road.angle)};
}

View File

@ -342,6 +342,10 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
&ExtractionWay::weight,
"road_classification",
&ExtractionWay::road_classification,
"forward_classes",
&ExtractionWay::forward_classes,
"backward_classes",
&ExtractionWay::backward_classes,
"forward_mode",
sol::property([](const ExtractionWay &way) { return way.forward_travel_mode; },
[](ExtractionWay &way, TravelMode mode) { way.forward_travel_mode = mode; }),

View File

@ -11,6 +11,7 @@
#include "customizer/edge_based_graph.hpp"
#include "extractor/class_data.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/edge_based_edge.hpp"
#include "extractor/files.hpp"
@ -253,6 +254,7 @@ void Storage::PopulateLayout(DataLayout &layout)
layout.SetBlockSize<NameID>(DataLayout::NAME_ID_LIST, nodes_number);
layout.SetBlockSize<ComponentID>(DataLayout::COMPONENT_ID_LIST, nodes_number);
layout.SetBlockSize<extractor::TravelMode>(DataLayout::TRAVEL_MODE_LIST, nodes_number);
layout.SetBlockSize<extractor::ClassData>(DataLayout::CLASSES_LIST, nodes_number);
}
if (boost::filesystem::exists(config.hsgr_data_path))
@ -614,10 +616,16 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
util::vector_view<extractor::TravelMode> travel_modes(
travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]);
auto classes_list_ptr = layout.GetBlockPtr<extractor::ClassData, true>(
memory_ptr, storage::DataLayout::CLASSES_LIST);
util::vector_view<extractor::ClassData> classes(
classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]);
extractor::EdgeBasedNodeDataView node_data(std::move(geometry_ids),
std::move(name_ids),
std::move(component_ids),
std::move(travel_modes));
std::move(travel_modes),
std::move(classes));
extractor::files::readNodeData(config.edge_based_nodes_data_path, node_data);
}

View File

@ -53,7 +53,8 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
0},
0,
3,
{intersection1}},
{intersection1},
{}},
{324,
"Central Park West",
"",
@ -74,7 +75,8 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
0},
2,
3,
{intersection2}}};
{intersection2},
{}}};
LegGeometry geometry;
geometry.locations = {{FloatLongitude{-73.981492}, FloatLatitude{40.768258}},

View File

@ -36,6 +36,7 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to)
false,
true,
TRAVEL_MODE_INACCESSIBLE,
0,
INVALID_LANE_DESCRIPTIONID};
}

View File

@ -4,11 +4,15 @@
// implements all data storage when shared memory _IS_ used
#include "contractor/query_edge.hpp"
#include "extractor/class_data.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/guidance/turn_lane_types.hpp"
#include "extractor/travel_mode.hpp"
#include "engine/algorithm.hpp"
#include "engine/datafacade/algorithm_datafacade.hpp"
#include "engine/datafacade/datafacade_base.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/turn_bearing.hpp"
@ -195,6 +199,14 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
{
return TRAVEL_MODE_INACCESSIBLE;
}
extractor::ClassData GetClassData(const NodeID /*id*/) const override final { return 0; }
std::vector<std::string> GetClasses(const extractor::ClassData /*data*/) const override final
{
return {};
}
NameID GetNameIndex(const NodeID /* id */) const override { return 0; }
StringView GetNameForID(const NameID) const override final { return {}; }

View File

@ -0,0 +1,73 @@
#include "util/bit_range.hpp"
#include "../common/range_tools.hpp"
#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(bit_range_test)
using namespace osrm;
using namespace osrm::util;
BOOST_AUTO_TEST_CASE(bit_range_8bit_test)
{
std::uint8_t value_1 = (1UL << 0) | (1UL << 1) | (1UL << 5) | (1UL << 7);
std::uint8_t value_2 = (1UL << 0);
std::uint8_t value_3 =
(1UL << 0) | (1UL << 1) | (1UL << 2) | (1UL << 3) | (1UL << 4) | (1UL << 5);
CHECK_EQUAL_RANGE(makeBitRange<std::uint8_t>(value_1), 7, 5, 1, 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint8_t>(value_2), 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint8_t>(value_3), 5, 4, 3, 2, 1, 0);
BOOST_CHECK_EQUAL(makeBitRange<std::uint8_t>(value_3).size(), 6);
BOOST_CHECK_EQUAL(makeBitRange<std::uint8_t>(0).size(), 0);
}
BOOST_AUTO_TEST_CASE(bit_range_16bit_test)
{
std::uint16_t value_1 = (1UL << 0) | (1UL << 1) | (1UL << 9) | (1UL << 15);
std::uint16_t value_2 = (1UL << 0);
std::uint16_t value_3 =
(1UL << 0) | (1UL << 1) | (1UL << 2) | (1UL << 3) | (1UL << 4) | (1UL << 5);
CHECK_EQUAL_RANGE(makeBitRange<std::uint16_t>(value_1), 15, 9, 1, 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint16_t>(value_2), 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint16_t>(value_3), 5, 4, 3, 2, 1, 0);
BOOST_CHECK_EQUAL(makeBitRange<std::uint16_t>(value_3).size(), 6);
BOOST_CHECK_EQUAL(makeBitRange<std::uint16_t>(0).size(), 0);
}
BOOST_AUTO_TEST_CASE(bit_range_32bit_test)
{
std::uint32_t value_1 = (1UL << 0) | (1UL << 1) | (1UL << 17) | (1UL << 31);
std::uint32_t value_2 = (1UL << 0);
std::uint32_t value_3 =
(1UL << 0) | (1UL << 1) | (1UL << 2) | (1UL << 3) | (1UL << 4) | (1UL << 5);
CHECK_EQUAL_RANGE(makeBitRange<std::uint32_t>(value_1), 31, 17, 1, 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint32_t>(value_2), 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint32_t>(value_3), 5, 4, 3, 2, 1, 0);
BOOST_CHECK_EQUAL(makeBitRange<std::uint32_t>(value_3).size(), 6);
BOOST_CHECK_EQUAL(makeBitRange<std::uint32_t>(0).size(), 0);
}
BOOST_AUTO_TEST_CASE(bit_range_64bit_test)
{
std::uint64_t value_1 = (1ULL << 0) | (1ULL << 1) | (1ULL << 33) | (1ULL << 63);
std::uint64_t value_2 = (1ULL << 0);
std::uint64_t value_3 =
(1ULL << 0) | (1ULL << 1) | (1ULL << 2) | (1ULL << 3) | (1ULL << 4) | (1ULL << 5);
CHECK_EQUAL_RANGE(makeBitRange<std::uint64_t>(value_1), 63, 33, 1, 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint64_t>(value_2), 0);
CHECK_EQUAL_RANGE(makeBitRange<std::uint64_t>(value_3), 5, 4, 3, 2, 1, 0);
BOOST_CHECK_EQUAL(makeBitRange<std::uint64_t>(value_3).size(), 6);
BOOST_CHECK_EQUAL(makeBitRange<std::uint64_t>(0).size(), 0);
}
BOOST_AUTO_TEST_SUITE_END()