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:
parent
d52d530cbe
commit
44739f2dc3
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
101
features/car/classes.feature
Normal file
101
features/car/classes.feature
Normal 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, |
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
|
22
include/extractor/class_data.hpp
Normal file
22
include/extractor/class_data.hpp
Normal 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
|
@ -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;
|
||||
|
@ -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 ¤t_way, const ExtractionWay &result_way);
|
||||
|
||||
// destroys the internal laneDescriptionMap
|
||||
guidance::LaneDescriptionMap &&moveOutLaneDescriptionMap();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
99
include/util/bit_range.hpp
Normal file
99
include/util/bit_range.hpp
Normal 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
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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',
|
||||
|
@ -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")
|
||||
|
@ -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(),
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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)};
|
||||
}
|
||||
|
@ -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; }),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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}},
|
||||
|
@ -36,6 +36,7 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to)
|
||||
false,
|
||||
true,
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
0,
|
||||
INVALID_LANE_DESCRIPTIONID};
|
||||
}
|
||||
|
||||
|
@ -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 {}; }
|
||||
|
73
unit_tests/util/bit_range.cpp
Normal file
73
unit_tests/util/bit_range.cpp
Normal 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()
|
Loading…
Reference in New Issue
Block a user