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:
committed by
Patrick Niklaus
parent
d52d530cbe
commit
44739f2dc3
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user