Split intersection analysis and guidance code
Intersection analysis occupy in osrm::extractor::intersection namespace and guidance code osrm::guidance
This commit is contained in:
@@ -2,14 +2,16 @@
|
||||
#include "extractor/conditional_turn_penalty.hpp"
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/files.hpp"
|
||||
#include "extractor/intersection/intersection_analysis.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "extractor/serialization.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
#include "guidance/files.hpp"
|
||||
#include "guidance/turn_analysis.hpp"
|
||||
#include "guidance/turn_data_container.hpp"
|
||||
#include "guidance/turn_lane_handler.hpp"
|
||||
|
||||
#include "extractor/intersection/intersection_analysis.hpp"
|
||||
|
||||
#include "extractor/serialization.hpp"
|
||||
#include "storage/io.hpp"
|
||||
|
||||
#include "util/assert.hpp"
|
||||
@@ -73,7 +75,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
guidance::LaneDescriptionMap &lane_description_map)
|
||||
extractor::LaneDescriptionMap &lane_description_map)
|
||||
: m_edge_based_node_container(node_data_container), m_number_of_edge_based_nodes(0),
|
||||
m_coordinates(coordinates), m_node_based_graph(std::move(node_based_graph)),
|
||||
m_barrier_nodes(barrier_nodes), m_traffic_lights(traffic_lights),
|
||||
@@ -424,19 +426,19 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
storage::io::FileWriter turn_penalties_index_file(turn_penalties_index_filename,
|
||||
storage::io::FileWriter::HasNoFingerprint);
|
||||
|
||||
TurnDataExternalContainer turn_data_container;
|
||||
guidance::TurnDataExternalContainer turn_data_container;
|
||||
|
||||
SuffixTable street_name_suffix_table(scripting_environment);
|
||||
const auto &turn_lanes_data = transformTurnLaneMapIntoArrays(lane_description_map);
|
||||
guidance::MergableRoadDetector mergable_road_detector(m_node_based_graph,
|
||||
m_edge_based_node_container,
|
||||
m_coordinates,
|
||||
m_compressed_edge_container,
|
||||
node_restriction_map,
|
||||
m_barrier_nodes,
|
||||
turn_lanes_data,
|
||||
name_table,
|
||||
street_name_suffix_table);
|
||||
intersection::MergableRoadDetector mergable_road_detector(m_node_based_graph,
|
||||
m_edge_based_node_container,
|
||||
m_coordinates,
|
||||
m_compressed_edge_container,
|
||||
node_restriction_map,
|
||||
m_barrier_nodes,
|
||||
turn_lanes_data,
|
||||
name_table,
|
||||
street_name_suffix_table);
|
||||
|
||||
// Loop over all turns and generate new set of edges.
|
||||
// Three nested loop look super-linear, but we are dealing with a (kind of)
|
||||
@@ -526,8 +528,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
{
|
||||
std::size_t nodes_processed = 0;
|
||||
|
||||
std::vector<TurnData> continuous_turn_data; // populate answers from guidance
|
||||
std::vector<TurnData> delayed_turn_data; // populate answers from guidance
|
||||
std::vector<guidance::TurnData> continuous_turn_data; // populate answers from guidance
|
||||
std::vector<guidance::TurnData> delayed_turn_data; // populate answers from guidance
|
||||
};
|
||||
using TurnsPipelineBufferPtr = std::shared_ptr<TurnsPipelineBuffer>;
|
||||
|
||||
@@ -607,7 +609,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
// compute weight and duration penalties
|
||||
const auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
||||
const auto is_uturn = guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn;
|
||||
const auto is_uturn =
|
||||
guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn;
|
||||
|
||||
ExtractionTurn extracted_turn(
|
||||
// general info
|
||||
@@ -810,7 +813,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
};
|
||||
|
||||
// all connected roads on the right of a u turn
|
||||
const auto is_uturn = guidance::getTurnDirection(turn->angle) == guidance::DirectionModifier::UTurn;
|
||||
const auto is_uturn = guidance::getTurnDirection(turn->angle) ==
|
||||
guidance::DirectionModifier::UTurn;
|
||||
if (is_uturn)
|
||||
{
|
||||
if (turn != intersection_view.begin())
|
||||
@@ -876,10 +880,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// a via way restriction. If that should be the case, we switch the id
|
||||
// of the edge-based-node for the target to the ID of the duplicated
|
||||
// node associated with the turn. (e.g. ab via bc switches bc to bc_dup)
|
||||
const auto turn_angle = util::bearing::angleBetween(
|
||||
incoming_bearing,
|
||||
findEdgeBearing(edge_geometries, outgoing_edge.edge));
|
||||
|
||||
auto const target_id = way_restriction_map.RemapIfRestricted(
|
||||
nbe_to_ebn_mapping[outgoing_edge.edge],
|
||||
incoming_edge.node,
|
||||
@@ -1094,10 +1094,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto turning_off_via_way =
|
||||
way_restriction_map.IsViaWay(incoming_edge.node, intersection_node);
|
||||
|
||||
// Save reversed incoming bearing to compute turn angles
|
||||
const auto reversed_incoming_bearing = util::bearing::reverse(
|
||||
findEdgeBearing(edge_geometries, incoming_edge.edge));
|
||||
|
||||
for (const auto &outgoing_edge : outgoing_edges)
|
||||
{
|
||||
if (!intersection::isTurnAllowed(m_node_based_graph,
|
||||
@@ -1120,12 +1116,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
OSRM_ASSERT(turn != intersection.end(),
|
||||
m_coordinates[intersection_node]);
|
||||
|
||||
buffer->continuous_turn_data.push_back(
|
||||
TurnData{turn->instruction,
|
||||
turn->lane_data_id,
|
||||
entry_class_id,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
util::guidance::TurnBearing(turn->bearing)});
|
||||
buffer->continuous_turn_data.push_back(guidance::TurnData{
|
||||
turn->instruction,
|
||||
turn->lane_data_id,
|
||||
entry_class_id,
|
||||
util::guidance::TurnBearing(intersection[0].bearing),
|
||||
util::guidance::TurnBearing(turn->bearing)});
|
||||
|
||||
// when turning off a a via-way turn restriction, we need to not only
|
||||
// handle the normal edges for the way, but also add turns for every
|
||||
@@ -1155,7 +1151,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
if (restriction.condition.empty())
|
||||
continue;
|
||||
|
||||
buffer->delayed_turn_data.push_back(TurnData{
|
||||
buffer->delayed_turn_data.push_back(guidance::TurnData{
|
||||
turn->instruction,
|
||||
turn->lane_data_id,
|
||||
entry_class_id,
|
||||
@@ -1164,7 +1160,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->delayed_turn_data.push_back(TurnData{
|
||||
buffer->delayed_turn_data.push_back(guidance::TurnData{
|
||||
turn->instruction,
|
||||
turn->lane_data_id,
|
||||
entry_class_id,
|
||||
@@ -1212,7 +1208,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
// Last part of the pipeline puts all the calculated data into the serial buffers
|
||||
util::Percent guidance_progress(log, node_count);
|
||||
std::vector<TurnData> delayed_turn_data;
|
||||
std::vector<guidance::TurnData> delayed_turn_data;
|
||||
|
||||
tbb::filter_t<TurnsPipelineBufferPtr, void> guidance_output_stage(
|
||||
tbb::filter::serial_in_order, [&](auto buffer) {
|
||||
@@ -1320,7 +1316,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
util::Log() << "done.";
|
||||
|
||||
files::writeTurnData(turn_data_filename, turn_data_container);
|
||||
guidance::files::writeTurnData(turn_data_filename, turn_data_container);
|
||||
|
||||
util::Log() << "Generated " << m_edge_based_node_segments.size() << " edge based node segments";
|
||||
util::Log() << "Node-based graph contains " << node_based_edge_counter << " edges";
|
||||
|
||||
@@ -196,7 +196,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
: tbb::task_scheduler_init::automatic);
|
||||
BOOST_ASSERT(init.is_active());
|
||||
|
||||
guidance::LaneDescriptionMap turn_lane_map;
|
||||
LaneDescriptionMap turn_lane_map;
|
||||
std::vector<TurnRestriction> turn_restrictions;
|
||||
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
|
||||
std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
|
||||
@@ -345,7 +345,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::tuple<guidance::LaneDescriptionMap,
|
||||
std::tuple<LaneDescriptionMap,
|
||||
std::vector<TurnRestriction>,
|
||||
std::vector<ConditionalTurnRestriction>>
|
||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
@@ -394,7 +394,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
// Extraction containers and restriction parser
|
||||
ExtractionContainers extraction_containers;
|
||||
ExtractorCallbacks::ClassesMap classes_map;
|
||||
guidance::LaneDescriptionMap turn_lane_map;
|
||||
LaneDescriptionMap turn_lane_map;
|
||||
auto extractor_callbacks =
|
||||
std::make_unique<ExtractorCallbacks>(extraction_containers,
|
||||
classes_map,
|
||||
@@ -673,7 +673,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
// might have to be updated to add new lane combinations
|
||||
guidance::LaneDescriptionMap &turn_lane_map,
|
||||
LaneDescriptionMap &turn_lane_map,
|
||||
// for calculating turn penalties
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
// output data
|
||||
@@ -731,9 +731,9 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
|
||||
{
|
||||
std::vector<std::uint32_t> turn_lane_offsets;
|
||||
std::vector<guidance::TurnLaneType::Mask> turn_lane_masks;
|
||||
std::vector<TurnLaneType::Mask> turn_lane_masks;
|
||||
std::tie(turn_lane_offsets, turn_lane_masks) =
|
||||
guidance::transformTurnLaneMapIntoArrays(turn_lane_map);
|
||||
transformTurnLaneMapIntoArrays(turn_lane_map);
|
||||
files::writeTurnLaneDescriptions(
|
||||
config.GetPath(".osrm.tls"), turn_lane_offsets, turn_lane_masks);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "guidance/road_classification.hpp"
|
||||
#include "extractor/road_classification.hpp"
|
||||
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/guidance/turn_lanes.hpp"
|
||||
@@ -29,13 +29,9 @@ namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
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,
|
||||
LaneDescriptionMap &lane_description_map,
|
||||
const ProfileProperties &properties)
|
||||
: external_memory(extraction_containers_), classes_map(classes_map),
|
||||
lane_description_map(lane_description_map),
|
||||
@@ -260,9 +256,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
for (auto iter = tokens.begin(); iter != tokens.end(); ++iter)
|
||||
{
|
||||
tokenizer inner_tokens(*iter, inner_sep);
|
||||
guidance::TurnLaneType::Mask lane_mask = inner_tokens.begin() == inner_tokens.end()
|
||||
? TurnLaneType::none
|
||||
: TurnLaneType::empty;
|
||||
TurnLaneType::Mask lane_mask = inner_tokens.begin() == inner_tokens.end()
|
||||
? TurnLaneType::none
|
||||
: TurnLaneType::empty;
|
||||
for (auto token_itr = inner_tokens.begin(); token_itr != inner_tokens.end();
|
||||
++token_itr)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-7
@@ -1,13 +1,10 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_
|
||||
|
||||
#include "util/guidance/name_announcements.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
// check if two name ids can be seen as identical (in presence of refs/others)
|
||||
@@ -16,7 +13,7 @@ namespace guidance
|
||||
bool HaveIdenticalNames(const NameID lhs,
|
||||
const NameID rhs,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
const extractor::SuffixTable &street_name_suffix_table)
|
||||
{
|
||||
const auto non_empty = (lhs != EMPTY_NAMEID) && (rhs != EMPTY_NAMEID);
|
||||
|
||||
@@ -29,5 +26,3 @@ bool HaveIdenticalNames(const NameID lhs,
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif /*OSRM_EXTRACTOR_GUIDANCE_HAVE_IDENTICAL_NAMES_HPP_*/
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "guidance/intersection.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <boost/range/adaptors.hpp>
|
||||
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
bool IntersectionViewData::CompareByAngle(const IntersectionViewData &other) const
|
||||
{
|
||||
return angle < other.angle;
|
||||
}
|
||||
|
||||
std::string toString(const IntersectionShapeData &shape)
|
||||
{
|
||||
std::string result =
|
||||
"[shape] " + std::to_string(shape.eid) + " bearing: " + std::to_string(shape.bearing);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string toString(const IntersectionViewData &view)
|
||||
{
|
||||
std::string result = "[view] ";
|
||||
result += std::to_string(view.eid);
|
||||
result += " allows entry: ";
|
||||
result += std::to_string(view.entry_allowed);
|
||||
result += " angle: ";
|
||||
result += std::to_string(view.angle);
|
||||
result += " bearing: ";
|
||||
result += std::to_string(view.bearing);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace intersection
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "extractor/intersection/intersection_analysis.hpp"
|
||||
#include "extractor/intersection/coordinate_extractor.hpp"
|
||||
|
||||
#include "util/assert.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include "guidance/coordinate_extractor.hpp"
|
||||
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
|
||||
namespace osrm
|
||||
@@ -116,8 +115,6 @@ std::pair<bool, double> findMergedBearing(const util::NodeBasedDynamicGraph &gra
|
||||
// Function returns a pair with a flag and a value of bearing for merged roads
|
||||
// If the flag is false the bearing must not be used as a merged value at neighbor intersections
|
||||
|
||||
using guidance::STRAIGHT_ANGLE;
|
||||
using guidance::MAXIMAL_ALLOWED_NO_TURN_DEVIATION;
|
||||
using util::bearing::angleBetween;
|
||||
using util::angularDeviation;
|
||||
|
||||
@@ -166,7 +163,7 @@ std::pair<bool, double> findMergedBearing(const util::NodeBasedDynamicGraph &gra
|
||||
return {true, merged_bearing};
|
||||
}
|
||||
|
||||
bool isRoadsPairMergeable(const guidance::MergableRoadDetector &detector,
|
||||
bool isRoadsPairMergeable(const MergableRoadDetector &detector,
|
||||
const IntersectionEdgeGeometries &edge_geometries,
|
||||
const NodeID intersection_node,
|
||||
const std::size_t index)
|
||||
@@ -212,8 +209,7 @@ getIntersectionOutgoingGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||
IntersectionEdgeGeometries edge_geometries;
|
||||
|
||||
// TODO: keep CoordinateExtractor to reproduce bearings, simplify later
|
||||
const guidance::CoordinateExtractor coordinate_extractor(
|
||||
graph, compressed_geometries, node_coordinates);
|
||||
const CoordinateExtractor coordinate_extractor(graph, compressed_geometries, node_coordinates);
|
||||
|
||||
const auto max_lanes_intersection = getIntersectionLanes(graph, intersection_node);
|
||||
|
||||
@@ -263,7 +259,7 @@ std::pair<IntersectionEdgeGeometries, std::unordered_set<EdgeID>>
|
||||
getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const guidance::MergableRoadDetector &detector,
|
||||
const MergableRoadDetector &detector,
|
||||
const NodeID intersection_node)
|
||||
{
|
||||
IntersectionEdgeGeometries edge_geometries = getIntersectionOutgoingGeometries<false>(
|
||||
@@ -462,7 +458,7 @@ bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const IntersectionEdgeGeometries &geometries,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &from,
|
||||
const IntersectionEdge &to)
|
||||
{
|
||||
@@ -567,7 +563,7 @@ bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
|
||||
|
||||
if (std::any_of(turn_lanes.begin() + turn_lane_offsets[lane_description_id],
|
||||
turn_lanes.begin() + turn_lane_offsets[lane_description_id + 1],
|
||||
[](const auto &lane) { return lane & guidance::TurnLaneType::uturn; }))
|
||||
[](const auto &lane) { return lane & TurnLaneType::uturn; }))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -620,16 +616,15 @@ bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
|
||||
}
|
||||
|
||||
// The function adapts intersection geometry data to TurnAnalysis
|
||||
guidance::IntersectionView
|
||||
convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const IntersectionEdgeGeometries &edge_geometries,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge,
|
||||
const IntersectionEdges &outgoing_edges,
|
||||
const std::unordered_set<EdgeID> &merged_edges)
|
||||
IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const IntersectionEdgeGeometries &edge_geometries,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge,
|
||||
const IntersectionEdges &outgoing_edges,
|
||||
const std::unordered_set<EdgeID> &merged_edges)
|
||||
{
|
||||
using util::bearing::angleBetween;
|
||||
|
||||
@@ -637,9 +632,9 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
const auto incoming_bearing = edge_it->perceived_bearing;
|
||||
const auto initial_incoming_bearing = edge_it->initial_bearing;
|
||||
|
||||
using IntersectionViewDataWithAngle = std::pair<guidance::IntersectionViewData, double>;
|
||||
using IntersectionViewDataWithAngle = std::pair<IntersectionViewData, double>;
|
||||
std::vector<IntersectionViewDataWithAngle> pre_intersection_view;
|
||||
guidance::IntersectionViewData uturn{{SPECIAL_EDGEID, 0., 0.}, false, 0.};
|
||||
IntersectionViewData uturn{{SPECIAL_EDGEID, 0., 0.}, false, 0.};
|
||||
std::size_t allowed_uturns_number = 0;
|
||||
for (const auto &outgoing_edge : outgoing_edges)
|
||||
{
|
||||
@@ -678,7 +673,7 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
|
||||
const auto is_uturn_angle = is_uturn(turn_angle);
|
||||
|
||||
guidance::IntersectionViewData road{
|
||||
IntersectionViewData road{
|
||||
{outgoing_edge.edge, outgoing_bearing, segment_length}, is_turn_allowed, turn_angle};
|
||||
|
||||
if (graph.GetTarget(outgoing_edge.edge) == incoming_edge.node)
|
||||
@@ -733,7 +728,7 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
}
|
||||
|
||||
// Copy intersection view data
|
||||
guidance::IntersectionView intersection_view;
|
||||
IntersectionView intersection_view;
|
||||
intersection_view.reserve(pre_intersection_view.size());
|
||||
std::transform(pre_intersection_view.begin(),
|
||||
pre_intersection_view.end(),
|
||||
@@ -757,15 +752,14 @@ convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
|
||||
// marked as invalid and only needed for intersection classification.
|
||||
template <bool USE_CLOSE_COORDINATE>
|
||||
guidance::IntersectionView
|
||||
getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge)
|
||||
IntersectionView getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge)
|
||||
{
|
||||
const auto intersection_node = graph.GetTarget(incoming_edge.edge);
|
||||
const auto &outgoing_edges = intersection::getOutgoingEdges(graph, intersection_node);
|
||||
@@ -800,24 +794,24 @@ getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
|
||||
std::unordered_set<EdgeID>());
|
||||
}
|
||||
|
||||
template guidance::IntersectionView
|
||||
template IntersectionView
|
||||
getConnectedRoads<false>(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge);
|
||||
|
||||
template guidance::IntersectionView
|
||||
template IntersectionView
|
||||
getConnectedRoads<true>(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge);
|
||||
|
||||
IntersectionEdge skipDegreeTwoNodes(const util::NodeBasedDynamicGraph &graph, IntersectionEdge road)
|
||||
|
||||
@@ -0,0 +1,620 @@
|
||||
#include "extractor/intersection/mergable_road_detector.hpp"
|
||||
#include "extractor/intersection/intersection_analysis.hpp"
|
||||
#include "extractor/intersection/node_based_graph_walker.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
#include "guidance/constants.hpp"
|
||||
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/guidance/name_announcements.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
// check a connected road for equality of a name
|
||||
// returns 'true' if no equality because this is used as a filter elsewhere, i.e. filter if fn
|
||||
// returns 'true'
|
||||
inline auto makeCheckRoadForName(const NameID name_id,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &suffix_table)
|
||||
{
|
||||
return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table](
|
||||
const MergableRoadDetector::MergableRoadData &road) {
|
||||
// since we filter here, we don't want any other name than the one we are looking for
|
||||
const auto road_name_id =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id;
|
||||
const auto road_name_empty = name_table.GetNameForID(road_name_id).empty();
|
||||
const auto in_name_empty = name_table.GetNameForID(name_id).empty();
|
||||
if (in_name_empty || road_name_empty)
|
||||
return true;
|
||||
const auto requires_announcement =
|
||||
util::guidance::requiresNameAnnounced(
|
||||
name_id, road_name_id, name_table, suffix_table) ||
|
||||
util::guidance::requiresNameAnnounced(road_name_id, name_id, name_table, suffix_table);
|
||||
|
||||
return requires_announcement;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
MergableRoadDetector::MergableRoadDetector(
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const extractor::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
|
||||
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
|
||||
turn_lanes_data(turn_lanes_data), name_table(name_table),
|
||||
street_name_suffix_table(street_name_suffix_table),
|
||||
coordinate_extractor(node_based_graph, compressed_geometries, node_coordinates)
|
||||
{
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
|
||||
const IntersectionShapeData &lhs,
|
||||
const IntersectionShapeData &rhs) const
|
||||
{
|
||||
// roads should be somewhat close
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return false;
|
||||
|
||||
const auto &lhs_edge = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const auto &rhs_edge = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto &lhs_edge_data = node_data_container.GetAnnotation(lhs_edge.annotation_data);
|
||||
const auto &rhs_edge_data = node_data_container.GetAnnotation(rhs_edge.annotation_data);
|
||||
|
||||
// and they need to describe the same road
|
||||
if ((lhs_edge.reversed == rhs_edge.reversed) ||
|
||||
!EdgeDataSupportsMerge(lhs_edge.flags, rhs_edge.flags, lhs_edge_data, rhs_edge_data))
|
||||
return false;
|
||||
|
||||
/* don't use any circular links, since they mess up detection we jump out early.
|
||||
*
|
||||
* / -- \
|
||||
* a ---- b - - /
|
||||
*/
|
||||
const auto road_target = [this](const MergableRoadData &road) {
|
||||
return node_based_graph.GetTarget(road.eid);
|
||||
};
|
||||
|
||||
// TODO might have to skip over trivial intersections
|
||||
if (road_target(lhs) == intersection_node || road_target(rhs) == intersection_node)
|
||||
return false;
|
||||
|
||||
// Don't merge turning circles/traffic loops
|
||||
if (IsTrafficLoop(intersection_node, lhs) || IsTrafficLoop(intersection_node, rhs))
|
||||
return false;
|
||||
|
||||
// needs to be checked prior to link roads, since connections can seem like links
|
||||
if (IsTrafficIsland(intersection_node, lhs, rhs))
|
||||
return true;
|
||||
|
||||
// Don't merge link roads
|
||||
if (IsLinkRoad(intersection_node, lhs) || IsLinkRoad(intersection_node, rhs))
|
||||
return false;
|
||||
|
||||
// check if we simply split up prior to an intersection
|
||||
if (IsNarrowTriangle(intersection_node, lhs, rhs))
|
||||
return true;
|
||||
|
||||
// finally check if two roads describe the direction
|
||||
return HaveSameDirection(intersection_node, lhs, rhs) &&
|
||||
!IsCircularShape(intersection_node, lhs, rhs);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
// needs to be far away
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return true;
|
||||
else // or it cannot have the same name
|
||||
return !HaveIdenticalNames(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||
.name_id,
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
|
||||
.name_id,
|
||||
name_table,
|
||||
street_name_suffix_table);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::EdgeDataSupportsMerge(
|
||||
const NodeBasedEdgeClassification &lhs_flags,
|
||||
const NodeBasedEdgeClassification &rhs_flags,
|
||||
const NodeBasedEdgeAnnotation &lhs_annotation,
|
||||
const NodeBasedEdgeAnnotation &rhs_annotation) const
|
||||
{
|
||||
// roundabouts are special, simply don't hurt them. We might not want to bear the
|
||||
// consequences
|
||||
if (lhs_flags.roundabout || rhs_flags.roundabout)
|
||||
return false;
|
||||
|
||||
/* The travel mode should be the same for both roads. If we were to merge different travel
|
||||
* modes, we would hide information/run the risk of loosing valid choices (e.g. short period
|
||||
* of pushing)
|
||||
*/
|
||||
if (lhs_annotation.travel_mode != rhs_annotation.travel_mode)
|
||||
return false;
|
||||
|
||||
// we require valid names
|
||||
if (!HaveIdenticalNames(
|
||||
lhs_annotation.name_id, rhs_annotation.name_id, name_table, street_name_suffix_table))
|
||||
return false;
|
||||
|
||||
return lhs_flags.road_classification == rhs_flags.road_classification;
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsTrafficLoop(const NodeID intersection_node,
|
||||
const MergableRoadData &road) const
|
||||
{
|
||||
const auto connection =
|
||||
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, road.eid});
|
||||
return intersection_node == node_based_graph.GetTarget(connection.edge);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
// selection data to the right and left
|
||||
const auto constexpr SMALL_RANDOM_HOPLIMIT = 5;
|
||||
IntersectionFinderAccumulator left_accumulator(SMALL_RANDOM_HOPLIMIT,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data),
|
||||
right_accumulator(SMALL_RANDOM_HOPLIMIT,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
|
||||
/* Standard following the straightmost road
|
||||
* Since both items have the same id, we can `select` based on any setup
|
||||
*/
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires entry=*/false,
|
||||
false);
|
||||
|
||||
NodeBasedGraphWalker graph_walker(node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector);
|
||||
/* if the intersection does not have a right turn, we continue onto the next one once
|
||||
* (skipping over a single small side street)
|
||||
*/
|
||||
if (angularDeviation(left_accumulator.intersection.findClosestTurn(ORTHOGONAL_ANGLE)->angle,
|
||||
ORTHOGONAL_ANGLE) > NARROW_TURN_ANGLE)
|
||||
{
|
||||
graph_walker.TraverseRoad(
|
||||
node_based_graph.GetTarget(left_accumulator.via_edge_id),
|
||||
left_accumulator.intersection.findClosestTurn(STRAIGHT_ANGLE)->eid,
|
||||
left_accumulator,
|
||||
selector);
|
||||
}
|
||||
const auto distance_to_triangle = util::coordinate_calculation::haversineDistance(
|
||||
node_coordinates[intersection_node],
|
||||
node_coordinates[node_based_graph.GetTarget(left_accumulator.via_edge_id)]);
|
||||
|
||||
// don't move too far down the road
|
||||
const constexpr auto RANGE_TO_TRIANGLE_LIMIT = 80;
|
||||
if (distance_to_triangle > RANGE_TO_TRIANGLE_LIMIT)
|
||||
return false;
|
||||
|
||||
graph_walker.TraverseRoad(intersection_node, rhs.eid, right_accumulator, selector);
|
||||
if (angularDeviation(right_accumulator.intersection.findClosestTurn(270)->angle, 270) >
|
||||
NARROW_TURN_ANGLE)
|
||||
{
|
||||
graph_walker.TraverseRoad(
|
||||
node_based_graph.GetTarget(right_accumulator.via_edge_id),
|
||||
right_accumulator.intersection.findClosestTurn(STRAIGHT_ANGLE)->eid,
|
||||
right_accumulator,
|
||||
selector);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!left_accumulator.intersection.empty() && !right_accumulator.intersection.empty());
|
||||
|
||||
// find the closes resembling a right turn
|
||||
const auto connector_turn = left_accumulator.intersection.findClosestTurn(ORTHOGONAL_ANGLE);
|
||||
/* check if that right turn connects to the right_accumulator intersection (i.e. we have a
|
||||
* triangle)
|
||||
* a connection should be somewhat to the right, when looking at the left side of the
|
||||
* triangle
|
||||
*
|
||||
* b ..... c
|
||||
* \ /
|
||||
* \ /
|
||||
* \ /
|
||||
* a
|
||||
*
|
||||
* e.g. here when looking at `a,b`, a narrow triangle should offer a turn to the right, when
|
||||
* we want to connect to c
|
||||
*/
|
||||
if (angularDeviation(connector_turn->angle, ORTHOGONAL_ANGLE) > NARROW_TURN_ANGLE)
|
||||
return false;
|
||||
|
||||
const auto num_lanes = [this](const MergableRoadData &road) {
|
||||
return std::max<std::uint8_t>(
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification.GetNumberOfLanes(), 1);
|
||||
};
|
||||
|
||||
// the width we can bridge at the intersection
|
||||
const auto assumed_road_width = (num_lanes(lhs) + num_lanes(rhs)) * ASSUMED_LANE_WIDTH;
|
||||
const constexpr auto MAXIMAL_ALLOWED_TRAFFIC_ISLAND_WIDTH = 10;
|
||||
const auto distance_between_triangle_corners = util::coordinate_calculation::haversineDistance(
|
||||
node_coordinates[node_based_graph.GetTarget(left_accumulator.via_edge_id)],
|
||||
node_coordinates[node_based_graph.GetTarget(right_accumulator.via_edge_id)]);
|
||||
if (distance_between_triangle_corners >
|
||||
(assumed_road_width + MAXIMAL_ALLOWED_TRAFFIC_ISLAND_WIDTH))
|
||||
return false;
|
||||
|
||||
// check if both intersections are connected
|
||||
IntersectionFinderAccumulator connect_accumulator(SMALL_RANDOM_HOPLIMIT,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
graph_walker.TraverseRoad(node_based_graph.GetTarget(left_accumulator.via_edge_id),
|
||||
connector_turn->eid,
|
||||
connect_accumulator,
|
||||
selector);
|
||||
|
||||
// the if both items are connected
|
||||
return node_based_graph.GetTarget(connect_accumulator.via_edge_id) ==
|
||||
node_based_graph.GetTarget(right_accumulator.via_edge_id);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
NodeBasedGraphWalker graph_walker(node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires_entry=*/false,
|
||||
false);
|
||||
graph_walker.TraverseRoad(intersection_node, edge_id, accumulator, selector);
|
||||
|
||||
return std::make_pair(accumulator.accumulated_length, accumulator.coordinates);
|
||||
};
|
||||
|
||||
std::vector<util::Coordinate> coordinates_to_the_left, coordinates_to_the_right;
|
||||
double distance_traversed_to_the_left, distance_traversed_to_the_right;
|
||||
|
||||
std::tie(distance_traversed_to_the_left, coordinates_to_the_left) =
|
||||
getCoordinatesAlongWay(lhs.eid, distance_to_extract);
|
||||
|
||||
std::tie(distance_traversed_to_the_right, coordinates_to_the_right) =
|
||||
getCoordinatesAlongWay(rhs.eid, distance_to_extract);
|
||||
|
||||
const auto connect_again = (coordinates_to_the_left.back() == coordinates_to_the_right.back());
|
||||
|
||||
// Tuning parameter to detect and don't merge roads close to circular shapes
|
||||
// if the area to squared circumference ratio is between the lower bound and 1/(4π)
|
||||
// that correspond to isoperimetric inequality 4πA ≤ L² or lower bound ≤ A/L² ≤ 1/(4π).
|
||||
// The lower bound must be larger enough to allow merging of square-shaped intersections
|
||||
// with A/L² = 1/16 or 78.6%
|
||||
// The condition suppresses roads merging for intersections like
|
||||
// . .
|
||||
// . .
|
||||
// ---- ----
|
||||
// . .
|
||||
// . .
|
||||
// but will allow roads merging for intersections like
|
||||
// -------
|
||||
// / \
|
||||
// ---- ----
|
||||
// \ /
|
||||
// -------
|
||||
const auto constexpr CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND = 0.85 / (4 * M_PI);
|
||||
if (connect_again && coordinates_to_the_left.front() == coordinates_to_the_left.back())
|
||||
{ // if the left and right roads connect again and are closed polygons ...
|
||||
const auto area = util::coordinate_calculation::computeArea(coordinates_to_the_left);
|
||||
const auto perimeter = distance_traversed_to_the_left;
|
||||
const auto area_to_squared_perimeter_ratio = std::abs(area) / (perimeter * perimeter);
|
||||
|
||||
// then don't merge roads if A/L² is greater than the lower bound
|
||||
BOOST_ASSERT(area_to_squared_perimeter_ratio <= 1. / (4 * M_PI));
|
||||
if (area_to_squared_perimeter_ratio >= CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return false;
|
||||
|
||||
// Find a coordinate following a road that is far away
|
||||
NodeBasedGraphWalker graph_walker(node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires_entry=*/false,
|
||||
true);
|
||||
graph_walker.TraverseRoad(intersection_node, edge_id, accumulator, selector);
|
||||
|
||||
return std::make_pair(accumulator.accumulated_length, accumulator.coordinates);
|
||||
};
|
||||
|
||||
std::vector<util::Coordinate> coordinates_to_the_left, coordinates_to_the_right;
|
||||
double distance_traversed_to_the_left, distance_traversed_to_the_right;
|
||||
|
||||
std::tie(distance_traversed_to_the_left, coordinates_to_the_left) =
|
||||
getCoordinatesAlongWay(lhs.eid, distance_to_extract);
|
||||
|
||||
// tuned parameter, if we didn't get as far as 40 meters, we might barely look past an
|
||||
// intersection.
|
||||
const auto constexpr MINIMUM_LENGTH_FOR_PARALLEL_DETECTION = 40;
|
||||
// quit early if the road is not very long
|
||||
if (distance_traversed_to_the_left <= MINIMUM_LENGTH_FOR_PARALLEL_DETECTION)
|
||||
return false;
|
||||
|
||||
std::tie(distance_traversed_to_the_right, coordinates_to_the_right) =
|
||||
getCoordinatesAlongWay(rhs.eid, distance_to_extract);
|
||||
|
||||
if (distance_traversed_to_the_right <= MINIMUM_LENGTH_FOR_PARALLEL_DETECTION)
|
||||
return false;
|
||||
|
||||
const auto connect_again = (coordinates_to_the_left.back() == coordinates_to_the_right.back());
|
||||
// sampling to correctly weight longer segments in regression calculations
|
||||
const auto constexpr SAMPLE_INTERVAL = 5;
|
||||
coordinates_to_the_left = coordinate_extractor.SampleCoordinates(
|
||||
std::move(coordinates_to_the_left), distance_to_extract, SAMPLE_INTERVAL);
|
||||
|
||||
coordinates_to_the_right = coordinate_extractor.SampleCoordinates(
|
||||
std::move(coordinates_to_the_right), distance_to_extract, SAMPLE_INTERVAL);
|
||||
|
||||
/* extract the number of lanes for a road
|
||||
* restricts a vector to the last two thirds of the length
|
||||
*/
|
||||
const auto prune = [](auto &data_vector) {
|
||||
BOOST_ASSERT(data_vector.size() >= 3);
|
||||
// erase the first third of the vector
|
||||
data_vector.erase(data_vector.begin(), data_vector.begin() + data_vector.size() / 3);
|
||||
};
|
||||
|
||||
/* if the coordinates meet up again, e.g. due to a split and join, pruning can have a negative
|
||||
* effect. We therefore only prune away the beginning, if the roads don't meet up again as well.
|
||||
*/
|
||||
if (!connect_again)
|
||||
{
|
||||
prune(coordinates_to_the_left);
|
||||
prune(coordinates_to_the_right);
|
||||
}
|
||||
|
||||
const auto are_parallel =
|
||||
util::coordinate_calculation::areParallel(coordinates_to_the_left.begin(),
|
||||
coordinates_to_the_left.end(),
|
||||
coordinates_to_the_right.begin(),
|
||||
coordinates_to_the_right.end());
|
||||
|
||||
if (!are_parallel)
|
||||
return false;
|
||||
|
||||
// compare reference distance:
|
||||
const auto distance_mid_left_to_right = util::coordinate_calculation::findClosestDistance(
|
||||
coordinates_to_the_left[coordinates_to_the_left.size() / 2],
|
||||
coordinates_to_the_right.begin(),
|
||||
coordinates_to_the_right.end());
|
||||
const auto distance_mid_right_to_left = util::coordinate_calculation::findClosestDistance(
|
||||
coordinates_to_the_right[coordinates_to_the_right.size() / 2],
|
||||
coordinates_to_the_left.begin(),
|
||||
coordinates_to_the_left.end());
|
||||
const auto distance_between_roads =
|
||||
std::min(distance_mid_left_to_right, distance_mid_right_to_left);
|
||||
|
||||
const auto lane_count_lhs = std::max<int>(
|
||||
1, node_based_graph.GetEdgeData(lhs.eid).flags.road_classification.GetNumberOfLanes());
|
||||
const auto lane_count_rhs = std::max<int>(
|
||||
1, node_based_graph.GetEdgeData(rhs.eid).flags.road_classification.GetNumberOfLanes());
|
||||
|
||||
const auto combined_road_width = 0.5 * (lane_count_lhs + lane_count_rhs) * ASSUMED_LANE_WIDTH;
|
||||
const auto constexpr MAXIMAL_ALLOWED_SEPARATION_WIDTH = 12;
|
||||
|
||||
return distance_between_roads <= combined_road_width + MAXIMAL_ALLOWED_SEPARATION_WIDTH;
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const
|
||||
{
|
||||
/* compute the set of all intersection_nodes along the way of an edge, until it reaches a
|
||||
* location with the same name repeatet at least three times
|
||||
*/
|
||||
const auto left_connection =
|
||||
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, lhs.eid});
|
||||
const auto right_connection =
|
||||
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, rhs.eid});
|
||||
|
||||
const auto left_candidate = node_based_graph.GetTarget(left_connection.edge);
|
||||
const auto right_candidate = node_based_graph.GetTarget(right_connection.edge);
|
||||
|
||||
const auto candidate_is_valid =
|
||||
left_candidate == right_candidate && left_candidate != intersection_node;
|
||||
|
||||
if (!candidate_is_valid)
|
||||
return false;
|
||||
|
||||
// check if all entries at the destination or at the source are the same
|
||||
const auto all_same_name_and_degree_three = [this](const NodeID nid) {
|
||||
// check if the intersection found has degree three
|
||||
if (node_based_graph.GetOutDegree(nid) != 3)
|
||||
return false;
|
||||
|
||||
// check if all items share a name
|
||||
const auto range = node_based_graph.GetAdjacentEdgeRange(nid);
|
||||
const auto required_name_id =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(range.front()).annotation_data)
|
||||
.name_id;
|
||||
|
||||
const auto has_required_name = [this, required_name_id](const auto edge_id) {
|
||||
const auto road_name_id =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id;
|
||||
const auto &road_name_empty = name_table.GetNameForID(road_name_id).empty();
|
||||
const auto &required_name_empty = name_table.GetNameForID(required_name_id).empty();
|
||||
if (required_name_empty && road_name_empty)
|
||||
return false;
|
||||
return !util::guidance::requiresNameAnnounced(
|
||||
required_name_id, road_name_id, name_table, street_name_suffix_table) ||
|
||||
!util::guidance::requiresNameAnnounced(
|
||||
road_name_id, required_name_id, name_table, street_name_suffix_table);
|
||||
};
|
||||
|
||||
/* the beautiful way would be:
|
||||
* return range.end() == std::find_if_not(range.begin(), range.end(), has_required_name);
|
||||
* but that does not work due to range concepts
|
||||
*/
|
||||
for (const auto eid : range)
|
||||
if (!has_required_name(eid))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto degree_three_connect_in = all_same_name_and_degree_three(intersection_node);
|
||||
const auto degree_three_connect_out = all_same_name_and_degree_three(left_candidate);
|
||||
|
||||
if (!degree_three_connect_in && !degree_three_connect_out)
|
||||
return false;
|
||||
|
||||
const auto distance_between_candidates = util::coordinate_calculation::haversineDistance(
|
||||
node_coordinates[intersection_node], node_coordinates[left_candidate]);
|
||||
|
||||
const auto both_split_join = degree_three_connect_in && degree_three_connect_out;
|
||||
|
||||
// allow longer separations if both are joining directly
|
||||
// widths are chosen via tuning on traffic islands
|
||||
return both_split_join ? (distance_between_candidates < 30)
|
||||
: (distance_between_candidates < 15);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
|
||||
const MergableRoadData &road) const
|
||||
{
|
||||
const auto next_intersection_parameters =
|
||||
intersection::skipDegreeTwoNodes(node_based_graph, {intersection_node, road.eid});
|
||||
const auto next_intersection_along_road =
|
||||
intersection::getConnectedRoads<false>(node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data,
|
||||
next_intersection_parameters);
|
||||
const auto extract_name_id = [this](const MergableRoadData &road) {
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id;
|
||||
};
|
||||
|
||||
const auto requested_name_id = extract_name_id(road);
|
||||
const auto next_road_along_path = next_intersection_along_road.findClosestTurn(
|
||||
STRAIGHT_ANGLE,
|
||||
makeCheckRoadForName(requested_name_id,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
name_table,
|
||||
street_name_suffix_table));
|
||||
|
||||
// we need to have a continuing road to successfully detect a link road
|
||||
if (next_road_along_path == next_intersection_along_road.end())
|
||||
return false;
|
||||
|
||||
const auto opposite_of_next_road_along_path = next_intersection_along_road.findClosestTurn(
|
||||
util::restrictAngleToValidRange(next_road_along_path->angle + STRAIGHT_ANGLE));
|
||||
|
||||
// we cannot be looking at the same road we came from
|
||||
if (node_based_graph.GetTarget(opposite_of_next_road_along_path->eid) ==
|
||||
next_intersection_parameters.node)
|
||||
return false;
|
||||
|
||||
/* check if the opposite of the next road decision was sane. It could have been just as well our
|
||||
* incoming road.
|
||||
*/
|
||||
if (angularDeviation(angularDeviation(next_road_along_path->angle, STRAIGHT_ANGLE),
|
||||
angularDeviation(opposite_of_next_road_along_path->angle, 0)) <
|
||||
FUZZY_ANGLE_DIFFERENCE)
|
||||
return false;
|
||||
|
||||
// near straight road that continues
|
||||
return angularDeviation(opposite_of_next_road_along_path->angle, next_road_along_path->angle) >=
|
||||
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE) &&
|
||||
(node_based_graph.GetEdgeData(next_road_along_path->eid).reversed ==
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid).reversed) &&
|
||||
EdgeDataSupportsMerge(
|
||||
node_based_graph.GetEdgeData(next_road_along_path->eid).flags,
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid).flags,
|
||||
node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(next_road_along_path->eid).annotation_data),
|
||||
node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid)
|
||||
.annotation_data));
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
@@ -0,0 +1,294 @@
|
||||
#include "extractor/intersection/node_based_graph_walker.hpp"
|
||||
#include "extractor/intersection/intersection_analysis.hpp"
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
NodeBasedGraphWalker::NodeBasedGraphWalker(
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data)
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
node_coordinates(node_coordinates), compressed_geometries(compressed_geometries),
|
||||
node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes),
|
||||
turn_lanes_data(turn_lanes_data)
|
||||
{
|
||||
}
|
||||
|
||||
LengthLimitedCoordinateAccumulator::LengthLimitedCoordinateAccumulator(
|
||||
const CoordinateExtractor &coordinate_extractor, const double max_length)
|
||||
: accumulated_length(0), coordinate_extractor(coordinate_extractor), max_length(max_length)
|
||||
{
|
||||
}
|
||||
|
||||
bool LengthLimitedCoordinateAccumulator::terminate() { return accumulated_length >= max_length; }
|
||||
|
||||
// update the accumulator
|
||||
void LengthLimitedCoordinateAccumulator::update(const NodeID from_node,
|
||||
const EdgeID via_edge,
|
||||
const NodeID /*to_node*/)
|
||||
|
||||
{
|
||||
auto current_coordinates =
|
||||
coordinate_extractor.GetForwardCoordinatesAlongRoad(from_node, via_edge);
|
||||
|
||||
const auto length =
|
||||
util::coordinate_calculation::getLength(current_coordinates.begin(),
|
||||
current_coordinates.end(),
|
||||
util::coordinate_calculation::haversineDistance);
|
||||
|
||||
// in case we get too many coordinates, we limit them to our desired length
|
||||
if (length + accumulated_length > max_length)
|
||||
current_coordinates = coordinate_extractor.TrimCoordinatesToLength(
|
||||
std::move(current_coordinates), max_length - accumulated_length);
|
||||
|
||||
coordinates.insert(coordinates.end(), current_coordinates.begin(), current_coordinates.end());
|
||||
|
||||
accumulated_length += length;
|
||||
accumulated_length = std::min(accumulated_length, max_length);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
SelectRoadByNameOnlyChoiceAndStraightness::SelectRoadByNameOnlyChoiceAndStraightness(
|
||||
const NameID desired_name_id, const bool requires_entry)
|
||||
: desired_name_id(desired_name_id), requires_entry(requires_entry)
|
||||
{
|
||||
}
|
||||
|
||||
boost::optional<EdgeID> SelectRoadByNameOnlyChoiceAndStraightness::
|
||||
operator()(const NodeID /*nid*/,
|
||||
const EdgeID /*via_edge_id*/,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const
|
||||
{
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
||||
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
||||
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
||||
const auto score = [&](const IntersectionViewData &road) {
|
||||
double result_score = 0;
|
||||
// since angular deviation is limited by 0-180, we add 360 for invalid
|
||||
if (requires_entry && !road.entry_allowed)
|
||||
result_score += 360.;
|
||||
|
||||
// 180 for undesired name-ids
|
||||
if (desired_name_id !=
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id)
|
||||
result_score += 180;
|
||||
|
||||
return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
};
|
||||
|
||||
return score(lhs) < score(rhs);
|
||||
};
|
||||
|
||||
const auto min_element =
|
||||
std::min_element(std::next(std::begin(intersection)), std::end(intersection), comparator);
|
||||
|
||||
if (min_element == intersection.end() || (requires_entry && !min_element->entry_allowed))
|
||||
return {};
|
||||
else
|
||||
return (*min_element).eid;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
SelectStraightmostRoadByNameAndOnlyChoice::SelectStraightmostRoadByNameAndOnlyChoice(
|
||||
const NameID desired_name_id,
|
||||
const double initial_bearing,
|
||||
const bool requires_entry,
|
||||
const bool stop_on_ambiguous_turns)
|
||||
: desired_name_id(desired_name_id), initial_bearing(initial_bearing),
|
||||
requires_entry(requires_entry), stop_on_ambiguous_turns(stop_on_ambiguous_turns)
|
||||
{
|
||||
}
|
||||
|
||||
boost::optional<EdgeID> SelectStraightmostRoadByNameAndOnlyChoice::
|
||||
operator()(const NodeID /*nid*/,
|
||||
const EdgeID /*via_edge_id*/,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const
|
||||
{
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
if (intersection.size() == 1)
|
||||
return {};
|
||||
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
||||
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
||||
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
||||
const auto score = [&](const IntersectionViewData &road) {
|
||||
double result_score = 0;
|
||||
// since angular deviation is limited by 0-180, we add 360 for invalid
|
||||
if (requires_entry && !road.entry_allowed)
|
||||
result_score += 360.;
|
||||
|
||||
// 180 for undesired name-ids
|
||||
if (desired_name_id !=
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id)
|
||||
result_score += 180;
|
||||
|
||||
return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
};
|
||||
|
||||
return score(lhs) < score(rhs);
|
||||
};
|
||||
|
||||
const auto count_desired_name =
|
||||
std::count_if(std::begin(intersection), std::end(intersection), [&](const auto &road) {
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id == desired_name_id;
|
||||
});
|
||||
if (count_desired_name > 2)
|
||||
return {};
|
||||
|
||||
const auto min_element =
|
||||
std::min_element(std::next(std::begin(intersection)), std::end(intersection), comparator);
|
||||
|
||||
const auto is_valid_choice = !requires_entry || min_element->entry_allowed;
|
||||
|
||||
if (!is_valid_choice)
|
||||
return {};
|
||||
|
||||
// only road exiting or continuing in the same general direction
|
||||
const auto has_valid_angle =
|
||||
((intersection.size() == 2 ||
|
||||
intersection.findClosestTurn(STRAIGHT_ANGLE) == min_element) &&
|
||||
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE) &&
|
||||
angularDeviation(initial_bearing, min_element->bearing) < NARROW_TURN_ANGLE;
|
||||
|
||||
if (has_valid_angle)
|
||||
return (*min_element).eid;
|
||||
|
||||
// in some cases, stronger turns are appropriate. We allow turns of just a bit over 90 degrees,
|
||||
// if it's not a end of road situation. These angles come into play where roads split into dual
|
||||
// carriage-ways.
|
||||
//
|
||||
// e - - f
|
||||
// a - - - - b
|
||||
// c - - d
|
||||
// |
|
||||
// g
|
||||
//
|
||||
// is technically
|
||||
//
|
||||
//
|
||||
// a - - - - b (ce) - - (fg)
|
||||
// |
|
||||
// g
|
||||
const auto is_only_choice_with_same_name =
|
||||
count_desired_name <= 2 && // <= in case we come from a bridge, otherwise we have a u-turn
|
||||
// and the outgoing edge
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(min_element->eid).annotation_data)
|
||||
.name_id == desired_name_id &&
|
||||
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < 100; // don't do crazy turns
|
||||
|
||||
// do not allow major turns in the road, if other similar turns are present
|
||||
// e.g.a turn at the end of the road:
|
||||
//
|
||||
// a - - a - - a - b - b
|
||||
// |
|
||||
// a - - a
|
||||
// |
|
||||
// c
|
||||
//
|
||||
// Such a turn can never be part of a merge
|
||||
// We check if there is a similar turn to the other side. If such a turn exists, we consider the
|
||||
// continuation of the road not possible
|
||||
if (stop_on_ambiguous_turns &&
|
||||
util::angularDeviation(STRAIGHT_ANGLE, min_element->angle) > GROUP_ANGLE)
|
||||
{
|
||||
auto opposite = intersection.findClosestTurn(util::bearing::reverse(min_element->angle));
|
||||
auto opposite_deviation = util::angularDeviation(min_element->angle, opposite->angle);
|
||||
// d - - - - c - - - -e
|
||||
// |
|
||||
// |
|
||||
// a - - - - b
|
||||
// from b-c onto min_element d with opposite side e
|
||||
if (opposite_deviation > (180 - FUZZY_ANGLE_DIFFERENCE))
|
||||
return {};
|
||||
|
||||
// e
|
||||
// |
|
||||
// a - - - - b - - - - -d
|
||||
// doing a left turn while straight is a choice
|
||||
auto const best = intersection.findClosestTurn(STRAIGHT_ANGLE);
|
||||
if (util::angularDeviation(best->angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
|
||||
return {};
|
||||
}
|
||||
|
||||
return is_only_choice_with_same_name ? boost::optional<EdgeID>(min_element->eid) : boost::none;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
IntersectionFinderAccumulator::IntersectionFinderAccumulator(
|
||||
const std::uint8_t hop_limit,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data)
|
||||
: hops(0), hop_limit(hop_limit), node_based_graph(node_based_graph),
|
||||
node_data_container(node_data_container), node_coordinates(node_coordinates),
|
||||
compressed_geometries(compressed_geometries), node_restriction_map(node_restriction_map),
|
||||
barrier_nodes(barrier_nodes), turn_lanes_data(turn_lanes_data)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntersectionFinderAccumulator::terminate()
|
||||
{
|
||||
if (intersection.size() > 2 || hops == hop_limit)
|
||||
{
|
||||
hops = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void IntersectionFinderAccumulator::update(const NodeID from_node,
|
||||
const EdgeID via_edge,
|
||||
const NodeID /*to_node*/)
|
||||
{
|
||||
++hops;
|
||||
nid = from_node;
|
||||
via_edge_id = via_edge;
|
||||
|
||||
intersection = intersection::getConnectedRoads<true>(node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data,
|
||||
{from_node, via_edge});
|
||||
}
|
||||
|
||||
} // namespace intersection
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/raster_source.hpp"
|
||||
#include "extractor/restriction_parser.hpp"
|
||||
|
||||
#include "guidance/turn_instruction.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/exception.hpp"
|
||||
#include "util/log.hpp"
|
||||
@@ -135,27 +138,27 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
|
||||
context.state.new_enum("road_priority_class",
|
||||
"motorway",
|
||||
extractor::guidance::RoadPriorityClass::MOTORWAY,
|
||||
extractor::RoadPriorityClass::MOTORWAY,
|
||||
"trunk",
|
||||
extractor::guidance::RoadPriorityClass::TRUNK,
|
||||
extractor::RoadPriorityClass::TRUNK,
|
||||
"primary",
|
||||
extractor::guidance::RoadPriorityClass::PRIMARY,
|
||||
extractor::RoadPriorityClass::PRIMARY,
|
||||
"secondary",
|
||||
extractor::guidance::RoadPriorityClass::SECONDARY,
|
||||
extractor::RoadPriorityClass::SECONDARY,
|
||||
"tertiary",
|
||||
extractor::guidance::RoadPriorityClass::TERTIARY,
|
||||
extractor::RoadPriorityClass::TERTIARY,
|
||||
"main_residential",
|
||||
extractor::guidance::RoadPriorityClass::MAIN_RESIDENTIAL,
|
||||
extractor::RoadPriorityClass::MAIN_RESIDENTIAL,
|
||||
"side_residential",
|
||||
extractor::guidance::RoadPriorityClass::SIDE_RESIDENTIAL,
|
||||
extractor::RoadPriorityClass::SIDE_RESIDENTIAL,
|
||||
"link_road",
|
||||
extractor::guidance::RoadPriorityClass::LINK_ROAD,
|
||||
extractor::RoadPriorityClass::LINK_ROAD,
|
||||
"bike_path",
|
||||
extractor::guidance::RoadPriorityClass::BIKE_PATH,
|
||||
extractor::RoadPriorityClass::BIKE_PATH,
|
||||
"foot_path",
|
||||
extractor::guidance::RoadPriorityClass::FOOT_PATH,
|
||||
extractor::RoadPriorityClass::FOOT_PATH,
|
||||
"connectivity",
|
||||
extractor::guidance::RoadPriorityClass::CONNECTIVITY);
|
||||
extractor::RoadPriorityClass::CONNECTIVITY);
|
||||
|
||||
context.state.new_enum("item_type",
|
||||
"node",
|
||||
@@ -263,23 +266,20 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"barrier",
|
||||
&ExtractionNode::barrier);
|
||||
|
||||
context.state.new_usertype<guidance::RoadClassification>(
|
||||
context.state.new_usertype<RoadClassification>(
|
||||
"RoadClassification",
|
||||
"motorway_class",
|
||||
sol::property(&guidance::RoadClassification::IsMotorwayClass,
|
||||
&guidance::RoadClassification::SetMotorwayFlag),
|
||||
sol::property(&RoadClassification::IsMotorwayClass, &RoadClassification::SetMotorwayFlag),
|
||||
"link_class",
|
||||
sol::property(&guidance::RoadClassification::IsLinkClass,
|
||||
&guidance::RoadClassification::SetLinkClass),
|
||||
sol::property(&RoadClassification::IsLinkClass, &RoadClassification::SetLinkClass),
|
||||
"may_be_ignored",
|
||||
sol::property(&guidance::RoadClassification::IsLowPriorityRoadClass,
|
||||
&guidance::RoadClassification::SetLowPriorityFlag),
|
||||
sol::property(&RoadClassification::IsLowPriorityRoadClass,
|
||||
&RoadClassification::SetLowPriorityFlag),
|
||||
"road_priority_class",
|
||||
sol::property(&guidance::RoadClassification::GetClass,
|
||||
&guidance::RoadClassification::SetClass),
|
||||
sol::property(&RoadClassification::GetClass, &RoadClassification::SetClass),
|
||||
"num_lanes",
|
||||
sol::property(&guidance::RoadClassification::GetNumberOfLanes,
|
||||
&guidance::RoadClassification::SetNumberOfLanes));
|
||||
sol::property(&RoadClassification::GetNumberOfLanes,
|
||||
&RoadClassification::SetNumberOfLanes));
|
||||
|
||||
context.state.new_usertype<ExtractionWay>(
|
||||
"ResultWay",
|
||||
@@ -573,16 +573,16 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
sol::property([](const ExtractionTurn &turn) {
|
||||
if (turn.number_of_roads > 2 || turn.source_mode != turn.target_mode ||
|
||||
turn.is_u_turn)
|
||||
return guidance::TurnType::Turn;
|
||||
return osrm::guidance::TurnType::Turn;
|
||||
else
|
||||
return guidance::TurnType::NoTurn;
|
||||
return osrm::guidance::TurnType::NoTurn;
|
||||
}),
|
||||
"direction_modifier",
|
||||
sol::property([](const ExtractionTurn &turn) {
|
||||
if (turn.is_u_turn)
|
||||
return guidance::DirectionModifier::UTurn;
|
||||
return osrm::guidance::DirectionModifier::UTurn;
|
||||
else
|
||||
return guidance::DirectionModifier::Straight;
|
||||
return osrm::guidance::DirectionModifier::Straight;
|
||||
}),
|
||||
"has_traffic_light",
|
||||
&ExtractionTurn::has_traffic_light,
|
||||
@@ -599,77 +599,77 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
|
||||
context.state.new_enum("turn_type",
|
||||
"invalid",
|
||||
extractor::guidance::TurnType::Invalid,
|
||||
osrm::guidance::TurnType::Invalid,
|
||||
"new_name",
|
||||
extractor::guidance::TurnType::NewName,
|
||||
osrm::guidance::TurnType::NewName,
|
||||
"continue",
|
||||
extractor::guidance::TurnType::Continue,
|
||||
osrm::guidance::TurnType::Continue,
|
||||
"turn",
|
||||
extractor::guidance::TurnType::Turn,
|
||||
osrm::guidance::TurnType::Turn,
|
||||
"merge",
|
||||
extractor::guidance::TurnType::Merge,
|
||||
osrm::guidance::TurnType::Merge,
|
||||
"on_ramp",
|
||||
extractor::guidance::TurnType::OnRamp,
|
||||
osrm::guidance::TurnType::OnRamp,
|
||||
"off_ramp",
|
||||
extractor::guidance::TurnType::OffRamp,
|
||||
osrm::guidance::TurnType::OffRamp,
|
||||
"fork",
|
||||
extractor::guidance::TurnType::Fork,
|
||||
osrm::guidance::TurnType::Fork,
|
||||
"end_of_road",
|
||||
extractor::guidance::TurnType::EndOfRoad,
|
||||
osrm::guidance::TurnType::EndOfRoad,
|
||||
"notification",
|
||||
extractor::guidance::TurnType::Notification,
|
||||
osrm::guidance::TurnType::Notification,
|
||||
"enter_roundabout",
|
||||
extractor::guidance::TurnType::EnterRoundabout,
|
||||
osrm::guidance::TurnType::EnterRoundabout,
|
||||
"enter_and_exit_roundabout",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundabout,
|
||||
osrm::guidance::TurnType::EnterAndExitRoundabout,
|
||||
"enter_rotary",
|
||||
extractor::guidance::TurnType::EnterRotary,
|
||||
osrm::guidance::TurnType::EnterRotary,
|
||||
"enter_and_exit_rotary",
|
||||
extractor::guidance::TurnType::EnterAndExitRotary,
|
||||
osrm::guidance::TurnType::EnterAndExitRotary,
|
||||
"enter_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersection,
|
||||
osrm::guidance::TurnType::EnterRoundaboutIntersection,
|
||||
"enter_and_exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::EnterAndExitRoundaboutIntersection,
|
||||
osrm::guidance::TurnType::EnterAndExitRoundaboutIntersection,
|
||||
"use_lane",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
osrm::guidance::TurnType::Suppressed,
|
||||
"no_turn",
|
||||
extractor::guidance::TurnType::NoTurn,
|
||||
osrm::guidance::TurnType::NoTurn,
|
||||
"suppressed",
|
||||
extractor::guidance::TurnType::Suppressed,
|
||||
osrm::guidance::TurnType::Suppressed,
|
||||
"enter_roundabout_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutAtExit,
|
||||
osrm::guidance::TurnType::EnterRoundaboutAtExit,
|
||||
"exit_roundabout",
|
||||
extractor::guidance::TurnType::ExitRoundabout,
|
||||
osrm::guidance::TurnType::ExitRoundabout,
|
||||
"enter_rotary_at_exit",
|
||||
extractor::guidance::TurnType::EnterRotaryAtExit,
|
||||
osrm::guidance::TurnType::EnterRotaryAtExit,
|
||||
"exit_rotary",
|
||||
extractor::guidance::TurnType::ExitRotary,
|
||||
osrm::guidance::TurnType::ExitRotary,
|
||||
"enter_roundabout_intersection_at_exit",
|
||||
extractor::guidance::TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
osrm::guidance::TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
"exit_roundabout_intersection",
|
||||
extractor::guidance::TurnType::ExitRoundaboutIntersection,
|
||||
osrm::guidance::TurnType::ExitRoundaboutIntersection,
|
||||
"stay_on_roundabout",
|
||||
extractor::guidance::TurnType::StayOnRoundabout,
|
||||
osrm::guidance::TurnType::StayOnRoundabout,
|
||||
"sliproad",
|
||||
extractor::guidance::TurnType::Sliproad);
|
||||
osrm::guidance::TurnType::Sliproad);
|
||||
|
||||
context.state.new_enum("direction_modifier",
|
||||
"u_turn",
|
||||
extractor::guidance::DirectionModifier::UTurn,
|
||||
osrm::guidance::DirectionModifier::UTurn,
|
||||
"sharp_right",
|
||||
extractor::guidance::DirectionModifier::SharpRight,
|
||||
osrm::guidance::DirectionModifier::SharpRight,
|
||||
"right",
|
||||
extractor::guidance::DirectionModifier::Right,
|
||||
osrm::guidance::DirectionModifier::Right,
|
||||
"slight_right",
|
||||
extractor::guidance::DirectionModifier::SlightRight,
|
||||
osrm::guidance::DirectionModifier::SlightRight,
|
||||
"straight",
|
||||
extractor::guidance::DirectionModifier::Straight,
|
||||
osrm::guidance::DirectionModifier::Straight,
|
||||
"slight_left",
|
||||
extractor::guidance::DirectionModifier::SlightLeft,
|
||||
osrm::guidance::DirectionModifier::SlightLeft,
|
||||
"left",
|
||||
extractor::guidance::DirectionModifier::Left,
|
||||
osrm::guidance::DirectionModifier::Left,
|
||||
"sharp_left",
|
||||
extractor::guidance::DirectionModifier::SharpLeft);
|
||||
osrm::guidance::DirectionModifier::SharpLeft);
|
||||
};
|
||||
|
||||
switch (context.api_version)
|
||||
|
||||
Reference in New Issue
Block a user