separate intersection generation and intersection normalization
This commit is contained in:
parent
e84a0ea37c
commit
827a1fbd7a
@ -6,9 +6,7 @@
|
|||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/query_node.hpp"
|
#include "extractor/query_node.hpp"
|
||||||
#include "extractor/restriction_map.hpp"
|
#include "extractor/restriction_map.hpp"
|
||||||
#include "extractor/suffix_table.hpp"
|
|
||||||
#include "util/attributes.hpp"
|
#include "util/attributes.hpp"
|
||||||
#include "util/name_table.hpp"
|
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
@ -25,7 +23,6 @@ namespace guidance
|
|||||||
// from it. For this all turn possibilities are analysed.
|
// from it. For this all turn possibilities are analysed.
|
||||||
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
|
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
|
||||||
// decisions.
|
// decisions.
|
||||||
|
|
||||||
class IntersectionGenerator
|
class IntersectionGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -33,9 +30,7 @@ class IntersectionGenerator
|
|||||||
const RestrictionMap &restriction_map,
|
const RestrictionMap &restriction_map,
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const CompressedEdgeContainer &compressed_edge_container,
|
const CompressedEdgeContainer &compressed_edge_container);
|
||||||
const util::NameTable &name_table,
|
|
||||||
const SuffixTable &street_name_suffix_table);
|
|
||||||
|
|
||||||
Intersection operator()(const NodeID nid, const EdgeID via_eid) const;
|
Intersection operator()(const NodeID nid, const EdgeID via_eid) const;
|
||||||
|
|
||||||
@ -54,10 +49,8 @@ class IntersectionGenerator
|
|||||||
const CoordinateExtractor &GetCoordinateExtractor() const;
|
const CoordinateExtractor &GetCoordinateExtractor() const;
|
||||||
|
|
||||||
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
|
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
|
||||||
// the
|
// the node reached from `from_node` via `via_eid`. The resulting candidates have to be analysed
|
||||||
// node reached
|
// for their actual instructions later on.
|
||||||
// from `from_node` via `via_eid`
|
|
||||||
// The resulting candidates have to be analysed for their actual instructions later on.
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
OSRM_ATTR_WARN_UNUSED
|
||||||
Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
|
Intersection GetConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
|
||||||
|
|
||||||
@ -66,47 +59,9 @@ class IntersectionGenerator
|
|||||||
const RestrictionMap &restriction_map;
|
const RestrictionMap &restriction_map;
|
||||||
const std::unordered_set<NodeID> &barrier_nodes;
|
const std::unordered_set<NodeID> &barrier_nodes;
|
||||||
const std::vector<QueryNode> &node_info_list;
|
const std::vector<QueryNode> &node_info_list;
|
||||||
|
|
||||||
|
// own state, used to find the correct coordinates along a road
|
||||||
const CoordinateExtractor coordinate_extractor;
|
const CoordinateExtractor coordinate_extractor;
|
||||||
const util::NameTable &name_table;
|
|
||||||
const SuffixTable &street_name_suffix_table;
|
|
||||||
|
|
||||||
// check if two indices in an intersection can be seen as a single road in the perceived
|
|
||||||
// intersection representation. See below for an example. Utility function for
|
|
||||||
// MergeSegregatedRoads
|
|
||||||
bool CanMerge(const NodeID intersection_node,
|
|
||||||
const Intersection &intersection,
|
|
||||||
std::size_t first_index,
|
|
||||||
std::size_t second_index) const;
|
|
||||||
|
|
||||||
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
|
|
||||||
// one.
|
|
||||||
// This function combines roads the following way:
|
|
||||||
//
|
|
||||||
// * *
|
|
||||||
// * is converted to *
|
|
||||||
// v ^ +
|
|
||||||
// v ^ +
|
|
||||||
//
|
|
||||||
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
|
|
||||||
// 160
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
Intersection MergeSegregatedRoads(const NodeID intersection_node,
|
|
||||||
Intersection intersection) const;
|
|
||||||
|
|
||||||
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
|
|
||||||
// intersection itself, it can also happen that intersections are connected to joining roads.
|
|
||||||
//
|
|
||||||
// * *
|
|
||||||
// * is converted to *
|
|
||||||
// v a --- a ---
|
|
||||||
// v ^ +
|
|
||||||
// v ^ +
|
|
||||||
// b
|
|
||||||
//
|
|
||||||
// for the local view of b at a.
|
|
||||||
OSRM_ATTR_WARN_UNUSED
|
|
||||||
Intersection AdjustForJoiningRoads(const NodeID node_at_intersection,
|
|
||||||
Intersection intersection) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
101
include/extractor/guidance/intersection_normalizer.hpp
Normal file
101
include/extractor/guidance/intersection_normalizer.hpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_
|
||||||
|
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include "util/attributes.hpp"
|
||||||
|
|
||||||
|
#include "extractor/guidance/coordinate_extractor.hpp"
|
||||||
|
#include "extractor/guidance/intersection.hpp"
|
||||||
|
#include "extractor/guidance/intersection_generator.hpp"
|
||||||
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
|
#include "extractor/suffix_table.hpp"
|
||||||
|
#include "util/name_table.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An intersection is a central part in computing guidance decisions. However the model in OSM and
|
||||||
|
* the view we want to use in guidance are not necessarily the same thing. We have to account for
|
||||||
|
* some models that are chosen explicitly in OSM and that don't actually describe how a human would
|
||||||
|
* experience an intersection.
|
||||||
|
*
|
||||||
|
* For example, if a small pedestrian island is located at a traffic light right in the middle of a
|
||||||
|
* road, OSM tends to model the road as two separate ways. A human would consider these two ways a
|
||||||
|
* single road, though. In this normalizer, we try to account for these subtle differences between
|
||||||
|
* OSM data and human perception to improve our decision base for guidance later on.
|
||||||
|
*/
|
||||||
|
class IntersectionNormalizer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const std::vector<extractor::QueryNode> &node_coordinates,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table,
|
||||||
|
const IntersectionGenerator &intersection_generator);
|
||||||
|
|
||||||
|
// The function takes an intersection an converts it to a `perceived` intersection which closer
|
||||||
|
// represents how a human might experience the intersection
|
||||||
|
OSRM_ATTR_WARN_UNUSED
|
||||||
|
Intersection operator()(const NodeID node_at_intersection, Intersection intersection) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
|
const std::vector<extractor::QueryNode> &node_coordinates;
|
||||||
|
const util::NameTable &name_table;
|
||||||
|
const SuffixTable &street_name_suffix_table;
|
||||||
|
|
||||||
|
const IntersectionGenerator &intersection_generator;
|
||||||
|
|
||||||
|
// check if two indices in an intersection can be seen as a single road in the perceived
|
||||||
|
// intersection representation. See below for an example. Utility function for
|
||||||
|
// MergeSegregatedRoads
|
||||||
|
bool CanMerge(const NodeID intersection_node,
|
||||||
|
const Intersection &intersection,
|
||||||
|
std::size_t first_index,
|
||||||
|
std::size_t second_index) const;
|
||||||
|
|
||||||
|
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
|
||||||
|
// one.
|
||||||
|
// This function combines roads the following way:
|
||||||
|
//
|
||||||
|
// * *
|
||||||
|
// * is converted to *
|
||||||
|
// v ^ +
|
||||||
|
// v ^ +
|
||||||
|
//
|
||||||
|
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
|
||||||
|
// 160
|
||||||
|
OSRM_ATTR_WARN_UNUSED
|
||||||
|
Intersection MergeSegregatedRoads(const NodeID intersection_node,
|
||||||
|
Intersection intersection) const;
|
||||||
|
|
||||||
|
// The counterpiece to mergeSegregatedRoads. While we can adjust roads that split up at the
|
||||||
|
// intersection itself, it can also happen that intersections are connected to joining roads.
|
||||||
|
//
|
||||||
|
// * *
|
||||||
|
// * is converted to *
|
||||||
|
// v a --- a ---
|
||||||
|
// v ^ +
|
||||||
|
// v ^ +
|
||||||
|
// b
|
||||||
|
//
|
||||||
|
// for the local view of b at a.
|
||||||
|
OSRM_ATTR_WARN_UNUSED
|
||||||
|
Intersection AdjustForJoiningRoads(const NodeID node_at_intersection,
|
||||||
|
Intersection intersection) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_NORMALIZER_HPP_ */
|
@ -21,9 +21,6 @@ namespace extractor
|
|||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
|
|
||||||
// forward declaration to allow interaction between the intersection generator and the graph hopper
|
|
||||||
class IntersectionGenerator;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The graph hopper is a utility that lets you find certain intersections with a node based graph,
|
* The graph hopper is a utility that lets you find certain intersections with a node based graph,
|
||||||
* accumulating information along the way
|
* accumulating information along the way
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "extractor/compressed_edge_container.hpp"
|
#include "extractor/compressed_edge_container.hpp"
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/intersection_generator.hpp"
|
#include "extractor/guidance/intersection_generator.hpp"
|
||||||
|
#include "extractor/guidance/intersection_normalizer.hpp"
|
||||||
#include "extractor/guidance/motorway_handler.hpp"
|
#include "extractor/guidance/motorway_handler.hpp"
|
||||||
#include "extractor/guidance/roundabout_handler.hpp"
|
#include "extractor/guidance/roundabout_handler.hpp"
|
||||||
#include "extractor/guidance/sliproad_handler.hpp"
|
#include "extractor/guidance/sliproad_handler.hpp"
|
||||||
@ -14,6 +15,7 @@
|
|||||||
#include "extractor/restriction_map.hpp"
|
#include "extractor/restriction_map.hpp"
|
||||||
#include "extractor/suffix_table.hpp"
|
#include "extractor/suffix_table.hpp"
|
||||||
|
|
||||||
|
#include "util/attributes.hpp"
|
||||||
#include "util/name_table.hpp"
|
#include "util/name_table.hpp"
|
||||||
#include "util/node_based_graph.hpp"
|
#include "util/node_based_graph.hpp"
|
||||||
|
|
||||||
@ -45,24 +47,41 @@ class TurnAnalysis
|
|||||||
const SuffixTable &street_name_suffix_table,
|
const SuffixTable &street_name_suffix_table,
|
||||||
const ProfileProperties &profile_properties);
|
const ProfileProperties &profile_properties);
|
||||||
|
|
||||||
// the entry into the turn analysis
|
/*
|
||||||
Intersection getIntersection(const NodeID from_node, const EdgeID via_eid) const;
|
* Returns a normalized intersection without any assigned turn types.
|
||||||
|
* This intersection can be used as input for intersection classification, turn lane assignment
|
||||||
|
* and similar.
|
||||||
|
*/
|
||||||
|
OSRM_ATTR_WARN_UNUSED
|
||||||
|
Intersection operator()(const NodeID from_node, const EdgeID via_eid) const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Post-Processing a generated intersection is useful for any intersection that was simply
|
||||||
|
* generated using an intersection generator. In the normal use case, you don't have to call
|
||||||
|
* this function.
|
||||||
|
* This function is part of the normal process of the operator().
|
||||||
|
*/
|
||||||
|
OSRM_ATTR_WARN_UNUSED
|
||||||
Intersection
|
Intersection
|
||||||
assignTurnTypes(const NodeID from_node, const EdgeID via_eid, Intersection intersection) const;
|
PostProcess(const NodeID from_node, const EdgeID via_eid, Intersection intersection) const;
|
||||||
|
|
||||||
std::vector<TurnOperation>
|
std::vector<TurnOperation>
|
||||||
transformIntersectionIntoTurns(const Intersection &intersection) const;
|
transformIntersectionIntoTurns(const Intersection &intersection) const;
|
||||||
|
|
||||||
const IntersectionGenerator &getGenerator() const;
|
const IntersectionGenerator &GetIntersectionGenerator() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||||
const IntersectionGenerator intersection_generator;
|
const IntersectionGenerator intersection_generator;
|
||||||
|
const IntersectionNormalizer intersection_normalizer;
|
||||||
const RoundaboutHandler roundabout_handler;
|
const RoundaboutHandler roundabout_handler;
|
||||||
const MotorwayHandler motorway_handler;
|
const MotorwayHandler motorway_handler;
|
||||||
const TurnHandler turn_handler;
|
const TurnHandler turn_handler;
|
||||||
const SliproadHandler sliproad_handler;
|
const SliproadHandler sliproad_handler;
|
||||||
|
|
||||||
|
Intersection
|
||||||
|
assignTurnTypes(const NodeID from_node, const EdgeID via_eid, Intersection intersection) const;
|
||||||
|
|
||||||
// Utility function, setting basic turn types. Prepares for normal turn handling.
|
// Utility function, setting basic turn types. Prepares for normal turn handling.
|
||||||
Intersection
|
Intersection
|
||||||
setTurnTypes(const NodeID from, const EdgeID via_edge, Intersection intersection) const;
|
setTurnTypes(const NodeID from, const EdgeID via_edge, Intersection intersection) const;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
|
#define OSRM_EXTRACTOR_GUIDANCE_TURN_DISCOVERY_HPP_
|
||||||
|
|
||||||
#include "extractor/guidance/intersection.hpp"
|
#include "extractor/guidance/intersection.hpp"
|
||||||
#include "extractor/guidance/turn_analysis.hpp"
|
#include "extractor/guidance/intersection_generator.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -23,7 +23,7 @@ bool findPreviousIntersection(
|
|||||||
const NodeID node,
|
const NodeID node,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
const Intersection intersection,
|
const Intersection intersection,
|
||||||
const TurnAnalysis &turn_analysis, // to generate other intersections
|
const IntersectionGenerator &intersection_generator,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
|
const util::NodeBasedDynamicGraph &node_based_graph, // query edge data
|
||||||
// output parameters, will be in an arbitrary state on failure
|
// output parameters, will be in an arbitrary state on failure
|
||||||
NodeID &result_node,
|
NodeID &result_node,
|
||||||
|
@ -375,10 +375,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
|||||||
|
|
||||||
const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
|
const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
|
||||||
++node_based_edge_counter;
|
++node_based_edge_counter;
|
||||||
auto intersection = turn_analysis.getIntersection(node_u, edge_from_u);
|
auto intersection = turn_analysis(node_u, edge_from_u);
|
||||||
BOOST_ASSERT(intersection.valid());
|
BOOST_ASSERT(intersection.valid());
|
||||||
intersection =
|
|
||||||
turn_analysis.assignTurnTypes(node_u, edge_from_u, std::move(intersection));
|
|
||||||
intersection =
|
intersection =
|
||||||
turn_lane_handler.assignTurnLanes(node_u, edge_from_u, std::move(intersection));
|
turn_lane_handler.assignTurnLanes(node_u, edge_from_u, std::move(intersection));
|
||||||
|
|
||||||
|
@ -26,22 +26,16 @@ IntersectionGenerator::IntersectionGenerator(
|
|||||||
const RestrictionMap &restriction_map,
|
const RestrictionMap &restriction_map,
|
||||||
const std::unordered_set<NodeID> &barrier_nodes,
|
const std::unordered_set<NodeID> &barrier_nodes,
|
||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const CompressedEdgeContainer &compressed_edge_container,
|
const CompressedEdgeContainer &compressed_edge_container)
|
||||||
const util::NameTable &name_table_,
|
|
||||||
const SuffixTable &street_name_suffix_table_)
|
|
||||||
: node_based_graph(node_based_graph), restriction_map(restriction_map),
|
: node_based_graph(node_based_graph), restriction_map(restriction_map),
|
||||||
barrier_nodes(barrier_nodes), node_info_list(node_info_list),
|
barrier_nodes(barrier_nodes), node_info_list(node_info_list),
|
||||||
coordinate_extractor(node_based_graph, compressed_edge_container, node_info_list),
|
coordinate_extractor(node_based_graph, compressed_edge_container, node_info_list)
|
||||||
name_table(name_table_), street_name_suffix_table(street_name_suffix_table_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection IntersectionGenerator::operator()(const NodeID from_node, const EdgeID via_eid) const
|
Intersection IntersectionGenerator::operator()(const NodeID from_node, const EdgeID via_eid) const
|
||||||
{
|
{
|
||||||
auto intersection = GetConnectedRoads(from_node, via_eid);
|
return GetConnectedRoads(from_node, via_eid);
|
||||||
const auto node_at_intersection = node_based_graph.GetTarget(via_eid);
|
|
||||||
return AdjustForJoiningRoads(
|
|
||||||
node_at_intersection, MergeSegregatedRoads(node_at_intersection, std::move(intersection)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// a
|
// a
|
||||||
@ -213,427 +207,6 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node,
|
|||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for mergability of two ways that represent the same intersection. For further information
|
|
||||||
// see interface documentation in header.
|
|
||||||
bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
|
|
||||||
const Intersection &intersection,
|
|
||||||
std::size_t first_index,
|
|
||||||
std::size_t second_index) const
|
|
||||||
{
|
|
||||||
const auto &first_data = node_based_graph.GetEdgeData(intersection[first_index].eid);
|
|
||||||
const auto &second_data = node_based_graph.GetEdgeData(intersection[second_index].eid);
|
|
||||||
|
|
||||||
// only merge named ids
|
|
||||||
if (first_data.name_id == EMPTY_NAMEID)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// need to be same name
|
|
||||||
if (second_data.name_id != EMPTY_NAMEID &&
|
|
||||||
util::guidance::requiresNameAnnounced(
|
|
||||||
first_data.name_id, second_data.name_id, name_table, street_name_suffix_table))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// compatibility is required
|
|
||||||
if (first_data.travel_mode != second_data.travel_mode)
|
|
||||||
return false;
|
|
||||||
if (first_data.road_classification != second_data.road_classification)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// may not be on a roundabout
|
|
||||||
if (first_data.roundabout || second_data.roundabout)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// exactly one of them has to be reversed
|
|
||||||
if (first_data.reversed == second_data.reversed)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// one of them needs to be invalid
|
|
||||||
if (intersection[first_index].entry_allowed && intersection[second_index].entry_allowed)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// mergeable if the angle is not too big
|
|
||||||
const auto angle_between =
|
|
||||||
angularDeviation(intersection[first_index].angle, intersection[second_index].angle);
|
|
||||||
|
|
||||||
const auto intersection_lanes = intersection.getHighestConnectedLaneCount(node_based_graph);
|
|
||||||
|
|
||||||
const auto coordinate_at_in_edge =
|
|
||||||
coordinate_extractor.GetCoordinateAlongRoad(node_at_intersection,
|
|
||||||
intersection[0].eid,
|
|
||||||
!INVERT,
|
|
||||||
node_based_graph.GetTarget(intersection[0].eid),
|
|
||||||
intersection_lanes);
|
|
||||||
|
|
||||||
const auto coordinate_at_intersection = node_info_list[node_at_intersection];
|
|
||||||
|
|
||||||
if (angle_between >= 120)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto isValidYArm = [this,
|
|
||||||
intersection,
|
|
||||||
coordinate_at_in_edge,
|
|
||||||
coordinate_at_intersection,
|
|
||||||
node_at_intersection](const std::size_t index,
|
|
||||||
const std::size_t other_index) {
|
|
||||||
const auto GetActualTarget = [&](const std::size_t index) {
|
|
||||||
EdgeID last_in_edge_id;
|
|
||||||
GetActualNextIntersection(
|
|
||||||
node_at_intersection, intersection[index].eid, nullptr, &last_in_edge_id);
|
|
||||||
return node_based_graph.GetTarget(last_in_edge_id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto target_id = GetActualTarget(index);
|
|
||||||
const auto other_target_id = GetActualTarget(other_index);
|
|
||||||
if (target_id == node_at_intersection || other_target_id == node_at_intersection)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto coordinate_at_target = node_info_list[target_id];
|
|
||||||
const auto coordinate_at_other_target = node_info_list[other_target_id];
|
|
||||||
|
|
||||||
const auto turn_angle = util::coordinate_calculation::computeAngle(
|
|
||||||
coordinate_at_in_edge, coordinate_at_intersection, coordinate_at_target);
|
|
||||||
const auto other_turn_angle = util::coordinate_calculation::computeAngle(
|
|
||||||
coordinate_at_in_edge, coordinate_at_intersection, coordinate_at_other_target);
|
|
||||||
|
|
||||||
const bool becomes_narrower =
|
|
||||||
angularDeviation(turn_angle, other_turn_angle) < NARROW_TURN_ANGLE &&
|
|
||||||
angularDeviation(turn_angle, other_turn_angle) <=
|
|
||||||
angularDeviation(intersection[index].angle, intersection[other_index].angle);
|
|
||||||
|
|
||||||
const bool has_same_deviation =
|
|
||||||
std::abs(angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) -
|
|
||||||
angularDeviation(intersection[other_index].angle, STRAIGHT_ANGLE)) <
|
|
||||||
MAXIMAL_ALLOWED_NO_TURN_DEVIATION;
|
|
||||||
|
|
||||||
return becomes_narrower || has_same_deviation;
|
|
||||||
};
|
|
||||||
|
|
||||||
const bool is_y_arm_first = isValidYArm(first_index, second_index);
|
|
||||||
const bool is_y_arm_second = isValidYArm(second_index, first_index);
|
|
||||||
|
|
||||||
// Only merge valid y-arms
|
|
||||||
if (!is_y_arm_first || !is_y_arm_second)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (angle_between < 60)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Finally, we also allow merging if all streets offer the same name, it is only three roads and
|
|
||||||
// the angle is not fully extreme:
|
|
||||||
if (intersection.size() != 3)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// since we have an intersection of size three now, there is only one index we are not looking
|
|
||||||
// at right now. The final index in the intersection is calculated next:
|
|
||||||
const std::size_t third_index = [first_index, second_index]() {
|
|
||||||
if (first_index == 0)
|
|
||||||
return second_index == 2 ? 1 : 2;
|
|
||||||
else if (first_index == 1)
|
|
||||||
return second_index == 2 ? 0 : 2;
|
|
||||||
else
|
|
||||||
return second_index == 1 ? 0 : 1;
|
|
||||||
}();
|
|
||||||
|
|
||||||
// needs to be same road coming in
|
|
||||||
const auto &third_data = node_based_graph.GetEdgeData(intersection[third_index].eid);
|
|
||||||
|
|
||||||
if (third_data.name_id != EMPTY_NAMEID &&
|
|
||||||
util::guidance::requiresNameAnnounced(
|
|
||||||
third_data.name_id, first_data.name_id, name_table, street_name_suffix_table))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// we only allow collapsing of a Y like fork. So the angle to the third index has to be
|
|
||||||
// roughly equal:
|
|
||||||
const auto y_angle_difference = angularDeviation(
|
|
||||||
angularDeviation(intersection[third_index].angle, intersection[first_index].angle),
|
|
||||||
angularDeviation(intersection[third_index].angle, intersection[second_index].angle));
|
|
||||||
|
|
||||||
// Allow larger angles if its three roads only of the same name
|
|
||||||
// This is a heuristic and might need to be revised.
|
|
||||||
const bool assume_y_intersection =
|
|
||||||
angle_between < 100 && y_angle_difference < FUZZY_ANGLE_DIFFERENCE;
|
|
||||||
return assume_y_intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Segregated Roads often merge onto a single intersection.
|
|
||||||
* While technically representing different roads, they are
|
|
||||||
* often looked at as a single road.
|
|
||||||
* Due to the merging, turn Angles seem off, wenn we compute them from the
|
|
||||||
* initial positions.
|
|
||||||
*
|
|
||||||
* b<b<b<b(1)<b<b<b
|
|
||||||
* aaaaa-b
|
|
||||||
* b>b>b>b(2)>b>b>b
|
|
||||||
*
|
|
||||||
* Would be seen as a slight turn going fro a to (2). A Sharp turn going from
|
|
||||||
* (1) to (2).
|
|
||||||
*
|
|
||||||
* In cases like these, we megre this segregated roads into a single road to
|
|
||||||
* end up with a case like:
|
|
||||||
*
|
|
||||||
* aaaaa-bbbbbb
|
|
||||||
*
|
|
||||||
* for the turn representation.
|
|
||||||
* Anything containing the first u-turn in a merge affects all other angles
|
|
||||||
* and is handled separately from all others.
|
|
||||||
*/
|
|
||||||
Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersection_node,
|
|
||||||
Intersection intersection) const
|
|
||||||
{
|
|
||||||
const auto getRight = [&](std::size_t index) {
|
|
||||||
return (index + intersection.size() - 1) % intersection.size();
|
|
||||||
};
|
|
||||||
|
|
||||||
// we only merge small angles. If the difference between both is large, we are looking at a
|
|
||||||
// bearing leading north. Such a bearing cannot be handled via the basic average. In this
|
|
||||||
// case we actually need to shift the bearing by half the difference.
|
|
||||||
const auto aroundZero = [](const double first, const double second) {
|
|
||||||
return (std::max(first, second) - std::min(first, second)) >= 180;
|
|
||||||
};
|
|
||||||
|
|
||||||
// find the angle between two other angles
|
|
||||||
const auto combineAngles = [aroundZero](const double first, const double second) {
|
|
||||||
if (!aroundZero(first, second))
|
|
||||||
return .5 * (first + second);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto offset = angularDeviation(first, second);
|
|
||||||
auto new_angle = std::max(first, second) + .5 * offset;
|
|
||||||
if (new_angle > 360)
|
|
||||||
return new_angle - 360;
|
|
||||||
return new_angle;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto merge = [combineAngles](const ConnectedRoad &first,
|
|
||||||
const ConnectedRoad &second) -> ConnectedRoad {
|
|
||||||
ConnectedRoad result = first.entry_allowed ? first : second;
|
|
||||||
result.angle = combineAngles(first.angle, second.angle);
|
|
||||||
result.bearing = combineAngles(first.bearing, second.bearing);
|
|
||||||
BOOST_ASSERT(0 <= result.angle && result.angle <= 360.0);
|
|
||||||
BOOST_ASSERT(0 <= result.bearing && result.bearing <= 360.0);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (intersection.size() <= 1)
|
|
||||||
return intersection;
|
|
||||||
|
|
||||||
const bool is_connected_to_roundabout = [this, &intersection]() {
|
|
||||||
for (const auto &road : intersection)
|
|
||||||
{
|
|
||||||
if (node_based_graph.GetEdgeData(road.eid).roundabout)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}();
|
|
||||||
|
|
||||||
// check for merges including the basic u-turn
|
|
||||||
// these result in an adjustment of all other angles. This is due to how these angles are
|
|
||||||
// perceived. Considering the following example:
|
|
||||||
//
|
|
||||||
// c b
|
|
||||||
// Y
|
|
||||||
// a
|
|
||||||
//
|
|
||||||
// coming from a to b (given a road that splits at the fork into two one-ways), the turn is not
|
|
||||||
// considered as a turn but rather as going straight.
|
|
||||||
// Now if we look at the situation merging:
|
|
||||||
//
|
|
||||||
// a b
|
|
||||||
// \ /
|
|
||||||
// e - + - d
|
|
||||||
// |
|
|
||||||
// c
|
|
||||||
//
|
|
||||||
// With a,b representing the same road, the intersection itself represents a classif for way
|
|
||||||
// intersection so we handle it like
|
|
||||||
//
|
|
||||||
// (a),b
|
|
||||||
// |
|
|
||||||
// e - + - d
|
|
||||||
// |
|
|
||||||
// c
|
|
||||||
//
|
|
||||||
// To be able to consider this adjusted representation down the line, we merge some roads.
|
|
||||||
// If the merge occurs at the u-turn edge, we need to adjust all angles, though, since they are
|
|
||||||
// with respect to the now changed perceived location of a. If we move (a) to the left, we add
|
|
||||||
// the difference to all angles. Otherwise we subtract it.
|
|
||||||
bool merged_first = false;
|
|
||||||
// these result in an adjustment of all other angles
|
|
||||||
if (CanMerge(intersection_node, intersection, 0, intersection.size() - 1))
|
|
||||||
{
|
|
||||||
merged_first = true;
|
|
||||||
// moving `a` to the left
|
|
||||||
const double correction_factor = (360 - intersection[intersection.size() - 1].angle) / 2;
|
|
||||||
for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
|
|
||||||
intersection[i].angle += correction_factor;
|
|
||||||
|
|
||||||
// FIXME if we have a left-sided country, we need to switch this off and enable it
|
|
||||||
// below
|
|
||||||
intersection[0] = merge(intersection.front(), intersection.back());
|
|
||||||
intersection[0].angle = 0;
|
|
||||||
intersection.pop_back();
|
|
||||||
}
|
|
||||||
else if (CanMerge(intersection_node, intersection, 0, 1))
|
|
||||||
{
|
|
||||||
merged_first = true;
|
|
||||||
// moving `a` to the right
|
|
||||||
const double correction_factor = (intersection[1].angle) / 2;
|
|
||||||
for (std::size_t i = 2; i < intersection.size(); ++i)
|
|
||||||
intersection[i].angle -= correction_factor;
|
|
||||||
intersection[0] = merge(intersection[0], intersection[1]);
|
|
||||||
intersection[0].angle = 0;
|
|
||||||
intersection.erase(intersection.begin() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (merged_first && is_connected_to_roundabout)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We are merging a u-turn against the direction of a roundabout
|
|
||||||
*
|
|
||||||
* -----------> roundabout
|
|
||||||
* / \
|
|
||||||
* out in
|
|
||||||
*
|
|
||||||
* These cases have to be disabled, even if they are not forbidden specifically by a
|
|
||||||
* relation
|
|
||||||
*/
|
|
||||||
intersection[0].entry_allowed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// a merge including the first u-turn requires an adjustment of the turn angles
|
|
||||||
// therefore these are handled prior to this step
|
|
||||||
for (std::size_t index = 2; index < intersection.size(); ++index)
|
|
||||||
{
|
|
||||||
if (CanMerge(intersection_node, intersection, index, getRight(index)))
|
|
||||||
{
|
|
||||||
intersection[getRight(index)] =
|
|
||||||
merge(intersection[getRight(index)], intersection[index]);
|
|
||||||
intersection.erase(intersection.begin() + index);
|
|
||||||
--index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(std::begin(intersection),
|
|
||||||
std::end(intersection),
|
|
||||||
std::mem_fn(&ConnectedRoad::compareByAngle));
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// OSM can have some very steep angles for joining roads. Considering the following intersection:
|
|
||||||
// x
|
|
||||||
// |
|
|
||||||
// v __________c
|
|
||||||
// /
|
|
||||||
// a ---d
|
|
||||||
// \ __________b
|
|
||||||
//
|
|
||||||
// with c->d as a oneway
|
|
||||||
// and d->b as a oneway, the turn von x->d is actually a turn from x->a. So when looking at the
|
|
||||||
// intersection coming from x, we want to interpret the situation as
|
|
||||||
// x
|
|
||||||
// |
|
|
||||||
// a __ d __ v__________c
|
|
||||||
// |
|
|
||||||
// |_______________b
|
|
||||||
//
|
|
||||||
// Where we see the turn to `d` as a right turn, rather than going straight.
|
|
||||||
// We do this by adjusting the local turn angle at `x` to turn onto `d` to be reflective of this
|
|
||||||
// situation, where `v` would be the node at the intersection.
|
|
||||||
Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_intersection,
|
|
||||||
Intersection intersection) const
|
|
||||||
{
|
|
||||||
// nothing to do for dead ends
|
|
||||||
if (intersection.size() <= 1)
|
|
||||||
return intersection;
|
|
||||||
|
|
||||||
const util::Coordinate coordinate_at_intersection = node_info_list[node_at_intersection];
|
|
||||||
// never adjust u-turns
|
|
||||||
for (std::size_t index = 1; index < intersection.size(); ++index)
|
|
||||||
{
|
|
||||||
auto &road = intersection[index];
|
|
||||||
// to find out about the above situation, we need to look at the next intersection (at d in
|
|
||||||
// the example). If the initial road can be merged to the left/right, we are about to adjust
|
|
||||||
// the angle.
|
|
||||||
const auto next_intersection_along_road = GetConnectedRoads(node_at_intersection, road.eid);
|
|
||||||
|
|
||||||
if (next_intersection_along_road.size() <= 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto node_at_next_intersection = node_based_graph.GetTarget(road.eid);
|
|
||||||
const util::Coordinate coordinate_at_next_intersection =
|
|
||||||
node_info_list[node_at_next_intersection];
|
|
||||||
if (util::coordinate_calculation::haversineDistance(coordinate_at_intersection,
|
|
||||||
coordinate_at_next_intersection) > 30)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto adjustAngle = [](double angle, double offset) {
|
|
||||||
angle += offset;
|
|
||||||
if (angle > 360)
|
|
||||||
return angle - 360.;
|
|
||||||
else if (angle < 0)
|
|
||||||
return angle + 360.;
|
|
||||||
return angle;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto range = node_based_graph.GetAdjacentEdgeRange(node_at_next_intersection);
|
|
||||||
if (range.size() <= 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// the order does not matter
|
|
||||||
const auto get_offset = [](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
|
|
||||||
return 0.5 * angularDeviation(lhs.angle, rhs.angle);
|
|
||||||
};
|
|
||||||
|
|
||||||
// When offsetting angles in our turns, we don't want to get past the next turn. This
|
|
||||||
// function simply limits an offset to be at most half the distance to the next turn in the
|
|
||||||
// offfset direction
|
|
||||||
const auto get_corrected_offset = [](const double offset,
|
|
||||||
const ConnectedRoad &road,
|
|
||||||
const ConnectedRoad &next_road_in_offset_direction) {
|
|
||||||
const auto offset_limit =
|
|
||||||
angularDeviation(road.angle, next_road_in_offset_direction.angle);
|
|
||||||
// limit the offset with an additional buffer
|
|
||||||
return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit
|
|
||||||
: offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
// check if the u-turn edge at the next intersection could be merged to the left/right. If
|
|
||||||
// this is the case and the road is not far away (see previous distance check), if
|
|
||||||
// influences the perceived angle.
|
|
||||||
if (CanMerge(node_at_next_intersection, next_intersection_along_road, 0, 1))
|
|
||||||
{
|
|
||||||
const auto offset =
|
|
||||||
get_offset(next_intersection_along_road[0], next_intersection_along_road[1]);
|
|
||||||
|
|
||||||
const auto corrected_offset =
|
|
||||||
get_corrected_offset(offset, road, intersection[(index + 1) % intersection.size()]);
|
|
||||||
// at the target intersection, we merge to the right, so we need to shift the current
|
|
||||||
// angle to the left
|
|
||||||
road.angle = adjustAngle(road.angle, corrected_offset);
|
|
||||||
road.bearing = adjustAngle(road.bearing, corrected_offset);
|
|
||||||
}
|
|
||||||
else if (CanMerge(node_at_next_intersection,
|
|
||||||
next_intersection_along_road,
|
|
||||||
0,
|
|
||||||
next_intersection_along_road.size() - 1))
|
|
||||||
{
|
|
||||||
const auto offset =
|
|
||||||
get_offset(next_intersection_along_road[0],
|
|
||||||
next_intersection_along_road[next_intersection_along_road.size() - 1]);
|
|
||||||
|
|
||||||
const auto corrected_offset =
|
|
||||||
get_corrected_offset(offset, road, intersection[index - 1]);
|
|
||||||
// at the target intersection, we merge to the left, so we need to shift the current
|
|
||||||
// angle to the right
|
|
||||||
road.angle = adjustAngle(road.angle, -corrected_offset);
|
|
||||||
road.bearing = adjustAngle(road.bearing, -corrected_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
Intersection
|
Intersection
|
||||||
IntersectionGenerator::GetActualNextIntersection(const NodeID starting_node,
|
IntersectionGenerator::GetActualNextIntersection(const NodeID starting_node,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
|
455
src/extractor/guidance/intersection_normalizer.cpp
Normal file
455
src/extractor/guidance/intersection_normalizer.cpp
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
#include "extractor/guidance/intersection_normalizer.hpp"
|
||||||
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
IntersectionNormalizer::IntersectionNormalizer(
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const std::vector<extractor::QueryNode> &node_coordinates,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table,
|
||||||
|
const IntersectionGenerator &intersection_generator)
|
||||||
|
: node_based_graph(node_based_graph), node_coordinates(node_coordinates),
|
||||||
|
name_table(name_table), street_name_suffix_table(street_name_suffix_table),
|
||||||
|
intersection_generator(intersection_generator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Intersection IntersectionNormalizer::operator()(const NodeID node_at_intersection,
|
||||||
|
Intersection intersection) const
|
||||||
|
{
|
||||||
|
return AdjustForJoiningRoads(
|
||||||
|
node_at_intersection, MergeSegregatedRoads(node_at_intersection, std::move(intersection)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for mergability of two ways that represent the same intersection. For further
|
||||||
|
// information
|
||||||
|
// see interface documentation in header.
|
||||||
|
bool IntersectionNormalizer::CanMerge(const NodeID node_at_intersection,
|
||||||
|
const Intersection &intersection,
|
||||||
|
std::size_t first_index,
|
||||||
|
std::size_t second_index) const
|
||||||
|
{
|
||||||
|
const auto &first_data = node_based_graph.GetEdgeData(intersection[first_index].eid);
|
||||||
|
const auto &second_data = node_based_graph.GetEdgeData(intersection[second_index].eid);
|
||||||
|
|
||||||
|
// only merge named ids
|
||||||
|
if (first_data.name_id == EMPTY_NAMEID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// need to be same name
|
||||||
|
if (second_data.name_id != EMPTY_NAMEID &&
|
||||||
|
util::guidance::requiresNameAnnounced(
|
||||||
|
first_data.name_id, second_data.name_id, name_table, street_name_suffix_table))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// compatibility is required
|
||||||
|
if (first_data.travel_mode != second_data.travel_mode)
|
||||||
|
return false;
|
||||||
|
if (first_data.road_classification != second_data.road_classification)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// may not be on a roundabout
|
||||||
|
if (first_data.roundabout || second_data.roundabout)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// exactly one of them has to be reversed
|
||||||
|
if (first_data.reversed == second_data.reversed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// one of them needs to be invalid
|
||||||
|
if (intersection[first_index].entry_allowed && intersection[second_index].entry_allowed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// mergeable if the angle is not too big
|
||||||
|
const auto angle_between =
|
||||||
|
angularDeviation(intersection[first_index].angle, intersection[second_index].angle);
|
||||||
|
|
||||||
|
const auto intersection_lanes = intersection.getHighestConnectedLaneCount(node_based_graph);
|
||||||
|
|
||||||
|
const auto coordinate_at_in_edge =
|
||||||
|
intersection_generator.GetCoordinateExtractor().GetCoordinateAlongRoad(
|
||||||
|
node_at_intersection,
|
||||||
|
intersection[0].eid,
|
||||||
|
!INVERT,
|
||||||
|
node_based_graph.GetTarget(intersection[0].eid),
|
||||||
|
intersection_lanes);
|
||||||
|
|
||||||
|
const auto coordinate_at_intersection = node_coordinates[node_at_intersection];
|
||||||
|
|
||||||
|
if (angle_between >= 120)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto isValidYArm = [this,
|
||||||
|
intersection,
|
||||||
|
coordinate_at_in_edge,
|
||||||
|
coordinate_at_intersection,
|
||||||
|
node_at_intersection](const std::size_t index,
|
||||||
|
const std::size_t other_index) {
|
||||||
|
const auto GetActualTarget = [&](const std::size_t index) {
|
||||||
|
EdgeID last_in_edge_id;
|
||||||
|
intersection_generator.GetActualNextIntersection(
|
||||||
|
node_at_intersection, intersection[index].eid, nullptr, &last_in_edge_id);
|
||||||
|
return node_based_graph.GetTarget(last_in_edge_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto target_id = GetActualTarget(index);
|
||||||
|
const auto other_target_id = GetActualTarget(other_index);
|
||||||
|
if (target_id == node_at_intersection || other_target_id == node_at_intersection)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto coordinate_at_target = node_coordinates[target_id];
|
||||||
|
const auto coordinate_at_other_target = node_coordinates[other_target_id];
|
||||||
|
|
||||||
|
const auto turn_angle = util::coordinate_calculation::computeAngle(
|
||||||
|
coordinate_at_in_edge, coordinate_at_intersection, coordinate_at_target);
|
||||||
|
const auto other_turn_angle = util::coordinate_calculation::computeAngle(
|
||||||
|
coordinate_at_in_edge, coordinate_at_intersection, coordinate_at_other_target);
|
||||||
|
|
||||||
|
const bool becomes_narrower =
|
||||||
|
angularDeviation(turn_angle, other_turn_angle) < NARROW_TURN_ANGLE &&
|
||||||
|
angularDeviation(turn_angle, other_turn_angle) <=
|
||||||
|
angularDeviation(intersection[index].angle, intersection[other_index].angle);
|
||||||
|
|
||||||
|
const bool has_same_deviation =
|
||||||
|
std::abs(angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) -
|
||||||
|
angularDeviation(intersection[other_index].angle, STRAIGHT_ANGLE)) <
|
||||||
|
MAXIMAL_ALLOWED_NO_TURN_DEVIATION;
|
||||||
|
return becomes_narrower || has_same_deviation;
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool is_y_arm_first = isValidYArm(first_index, second_index);
|
||||||
|
const bool is_y_arm_second = isValidYArm(second_index, first_index);
|
||||||
|
|
||||||
|
// Only merge valid y-arms
|
||||||
|
if (!is_y_arm_first || !is_y_arm_second)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (angle_between < 60)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Finally, we also allow merging if all streets offer the same name, it is only three roads and
|
||||||
|
// the angle is not fully extreme:
|
||||||
|
if (intersection.size() != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// since we have an intersection of size three now, there is only one index we are not looking
|
||||||
|
// at right now. The final index in the intersection is calculated next:
|
||||||
|
const std::size_t third_index = [first_index, second_index]() {
|
||||||
|
if (first_index == 0)
|
||||||
|
return second_index == 2 ? 1 : 2;
|
||||||
|
else if (first_index == 1)
|
||||||
|
return second_index == 2 ? 0 : 2;
|
||||||
|
else
|
||||||
|
return second_index == 1 ? 0 : 1;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// needs to be same road coming in
|
||||||
|
const auto &third_data = node_based_graph.GetEdgeData(intersection[third_index].eid);
|
||||||
|
|
||||||
|
if (third_data.name_id != EMPTY_NAMEID &&
|
||||||
|
util::guidance::requiresNameAnnounced(
|
||||||
|
third_data.name_id, first_data.name_id, name_table, street_name_suffix_table))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// we only allow collapsing of a Y like fork. So the angle to the third index has to be
|
||||||
|
// roughly equal:
|
||||||
|
const auto y_angle_difference = angularDeviation(
|
||||||
|
angularDeviation(intersection[third_index].angle, intersection[first_index].angle),
|
||||||
|
angularDeviation(intersection[third_index].angle, intersection[second_index].angle));
|
||||||
|
// Allow larger angles if its three roads only of the same name
|
||||||
|
// This is a heuristic and might need to be revised.
|
||||||
|
const bool assume_y_intersection =
|
||||||
|
angle_between < 100 && y_angle_difference < FUZZY_ANGLE_DIFFERENCE;
|
||||||
|
return assume_y_intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Segregated Roads often merge onto a single intersection.
|
||||||
|
* While technically representing different roads, they are
|
||||||
|
* often looked at as a single road.
|
||||||
|
* Due to the merging, turn Angles seem off, wenn we compute them from the
|
||||||
|
* initial positions.
|
||||||
|
*
|
||||||
|
* b<b<b<b(1)<b<b<b
|
||||||
|
* aaaaa-b
|
||||||
|
* b>b>b>b(2)>b>b>b
|
||||||
|
*
|
||||||
|
* Would be seen as a slight turn going fro a to (2). A Sharp turn going from
|
||||||
|
* (1) to (2).
|
||||||
|
*
|
||||||
|
* In cases like these, we megre this segregated roads into a single road to
|
||||||
|
* end up with a case like:
|
||||||
|
*
|
||||||
|
* aaaaa-bbbbbb
|
||||||
|
*
|
||||||
|
* for the turn representation.
|
||||||
|
* Anything containing the first u-turn in a merge affects all other angles
|
||||||
|
* and is handled separately from all others.
|
||||||
|
*/
|
||||||
|
Intersection IntersectionNormalizer::MergeSegregatedRoads(const NodeID intersection_node,
|
||||||
|
Intersection intersection) const
|
||||||
|
{
|
||||||
|
const auto getRight = [&](std::size_t index) {
|
||||||
|
return (index + intersection.size() - 1) % intersection.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
// we only merge small angles. If the difference between both is large, we are looking at a
|
||||||
|
// bearing leading north. Such a bearing cannot be handled via the basic average. In this
|
||||||
|
// case we actually need to shift the bearing by half the difference.
|
||||||
|
const auto aroundZero = [](const double first, const double second) {
|
||||||
|
return (std::max(first, second) - std::min(first, second)) >= 180;
|
||||||
|
};
|
||||||
|
|
||||||
|
// find the angle between two other angles
|
||||||
|
const auto combineAngles = [aroundZero](const double first, const double second) {
|
||||||
|
if (!aroundZero(first, second))
|
||||||
|
return .5 * (first + second);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto offset = angularDeviation(first, second);
|
||||||
|
auto new_angle = std::max(first, second) + .5 * offset;
|
||||||
|
if (new_angle > 360)
|
||||||
|
return new_angle - 360;
|
||||||
|
return new_angle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto merge = [combineAngles](const ConnectedRoad &first,
|
||||||
|
const ConnectedRoad &second) -> ConnectedRoad {
|
||||||
|
ConnectedRoad result = first.entry_allowed ? first : second;
|
||||||
|
result.angle = combineAngles(first.angle, second.angle);
|
||||||
|
result.bearing = combineAngles(first.bearing, second.bearing);
|
||||||
|
BOOST_ASSERT(0 <= result.angle && result.angle <= 360.0);
|
||||||
|
BOOST_ASSERT(0 <= result.bearing && result.bearing <= 360.0);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (intersection.size() <= 1)
|
||||||
|
return intersection;
|
||||||
|
|
||||||
|
const bool is_connected_to_roundabout = [this, &intersection]() {
|
||||||
|
for (const auto &road : intersection)
|
||||||
|
{
|
||||||
|
if (node_based_graph.GetEdgeData(road.eid).roundabout)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// check for merges including the basic u-turn
|
||||||
|
// these result in an adjustment of all other angles. This is due to how these angles are
|
||||||
|
// perceived. Considering the following example:
|
||||||
|
//
|
||||||
|
// c b
|
||||||
|
// Y
|
||||||
|
// a
|
||||||
|
//
|
||||||
|
// coming from a to b (given a road that splits at the fork into two one-ways), the turn is not
|
||||||
|
// considered as a turn but rather as going straight.
|
||||||
|
// Now if we look at the situation merging:
|
||||||
|
//
|
||||||
|
// a b
|
||||||
|
// \ /
|
||||||
|
// e - + - d
|
||||||
|
// |
|
||||||
|
// c
|
||||||
|
//
|
||||||
|
// With a,b representing the same road, the intersection itself represents a classif for way
|
||||||
|
// intersection so we handle it like
|
||||||
|
//
|
||||||
|
// (a),b
|
||||||
|
// |
|
||||||
|
// e - + - d
|
||||||
|
// |
|
||||||
|
// c
|
||||||
|
//
|
||||||
|
// To be able to consider this adjusted representation down the line, we merge some roads.
|
||||||
|
// If the merge occurs at the u-turn edge, we need to adjust all angles, though, since they are
|
||||||
|
// with respect to the now changed perceived location of a. If we move (a) to the left, we add
|
||||||
|
// the difference to all angles. Otherwise we subtract it.
|
||||||
|
bool merged_first = false;
|
||||||
|
// these result in an adjustment of all other angles
|
||||||
|
if (CanMerge(intersection_node, intersection, 0, intersection.size() - 1))
|
||||||
|
{
|
||||||
|
merged_first = true;
|
||||||
|
// moving `a` to the left
|
||||||
|
const double correction_factor = (360 - intersection[intersection.size() - 1].angle) / 2;
|
||||||
|
for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
|
||||||
|
intersection[i].angle += correction_factor;
|
||||||
|
|
||||||
|
// FIXME if we have a left-sided country, we need to switch this off and enable it
|
||||||
|
// below
|
||||||
|
intersection[0] = merge(intersection.front(), intersection.back());
|
||||||
|
intersection[0].angle = 0;
|
||||||
|
intersection.pop_back();
|
||||||
|
}
|
||||||
|
else if (CanMerge(intersection_node, intersection, 0, 1))
|
||||||
|
{
|
||||||
|
merged_first = true;
|
||||||
|
// moving `a` to the right
|
||||||
|
const double correction_factor = (intersection[1].angle) / 2;
|
||||||
|
for (std::size_t i = 2; i < intersection.size(); ++i)
|
||||||
|
intersection[i].angle -= correction_factor;
|
||||||
|
intersection[0] = merge(intersection[0], intersection[1]);
|
||||||
|
intersection[0].angle = 0;
|
||||||
|
intersection.erase(intersection.begin() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (merged_first && is_connected_to_roundabout)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are merging a u-turn against the direction of a roundabout
|
||||||
|
*
|
||||||
|
* -----------> roundabout
|
||||||
|
* / \
|
||||||
|
* out in
|
||||||
|
*
|
||||||
|
* These cases have to be disabled, even if they are not forbidden specifically by a
|
||||||
|
* relation
|
||||||
|
*/
|
||||||
|
intersection[0].entry_allowed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a merge including the first u-turn requires an adjustment of the turn angles
|
||||||
|
// therefore these are handled prior to this step
|
||||||
|
for (std::size_t index = 2; index < intersection.size(); ++index)
|
||||||
|
{
|
||||||
|
if (CanMerge(intersection_node, intersection, index, getRight(index)))
|
||||||
|
{
|
||||||
|
intersection[getRight(index)] =
|
||||||
|
merge(intersection[getRight(index)], intersection[index]);
|
||||||
|
intersection.erase(intersection.begin() + index);
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(std::begin(intersection),
|
||||||
|
std::end(intersection),
|
||||||
|
std::mem_fn(&ConnectedRoad::compareByAngle));
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OSM can have some very steep angles for joining roads. Considering the following intersection:
|
||||||
|
// x
|
||||||
|
// |
|
||||||
|
// v __________c
|
||||||
|
// /
|
||||||
|
// a ---d
|
||||||
|
// \ __________b
|
||||||
|
//
|
||||||
|
// with c->d as a oneway
|
||||||
|
// and d->b as a oneway, the turn von x->d is actually a turn from x->a. So when looking at the
|
||||||
|
// intersection coming from x, we want to interpret the situation as
|
||||||
|
// x
|
||||||
|
// |
|
||||||
|
// a __ d __ v__________c
|
||||||
|
// |
|
||||||
|
// |_______________b
|
||||||
|
//
|
||||||
|
// Where we see the turn to `d` as a right turn, rather than going straight.
|
||||||
|
// We do this by adjusting the local turn angle at `x` to turn onto `d` to be reflective of this
|
||||||
|
// situation, where `v` would be the node at the intersection.
|
||||||
|
Intersection IntersectionNormalizer::AdjustForJoiningRoads(const NodeID node_at_intersection,
|
||||||
|
Intersection intersection) const
|
||||||
|
{
|
||||||
|
// nothing to do for dead ends
|
||||||
|
if (intersection.size() <= 1)
|
||||||
|
return intersection;
|
||||||
|
|
||||||
|
const util::Coordinate coordinate_at_intersection = node_coordinates[node_at_intersection];
|
||||||
|
// never adjust u-turns
|
||||||
|
for (std::size_t index = 1; index < intersection.size(); ++index)
|
||||||
|
{
|
||||||
|
auto &road = intersection[index];
|
||||||
|
// to find out about the above situation, we need to look at the next intersection (at d in
|
||||||
|
// the example). If the initial road can be merged to the left/right, we are about to adjust
|
||||||
|
// the angle.
|
||||||
|
const auto next_intersection_along_road =
|
||||||
|
intersection_generator(node_at_intersection, road.eid);
|
||||||
|
|
||||||
|
if (next_intersection_along_road.size() <= 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto node_at_next_intersection = node_based_graph.GetTarget(road.eid);
|
||||||
|
const util::Coordinate coordinate_at_next_intersection =
|
||||||
|
node_coordinates[node_at_next_intersection];
|
||||||
|
if (util::coordinate_calculation::haversineDistance(coordinate_at_intersection,
|
||||||
|
coordinate_at_next_intersection) > 30)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto adjustAngle = [](double angle, double offset) {
|
||||||
|
angle += offset;
|
||||||
|
if (angle > 360)
|
||||||
|
return angle - 360.;
|
||||||
|
else if (angle < 0)
|
||||||
|
return angle + 360.;
|
||||||
|
return angle;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto range = node_based_graph.GetAdjacentEdgeRange(node_at_next_intersection);
|
||||||
|
if (range.size() <= 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// the order does not matter
|
||||||
|
const auto get_offset = [](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
|
||||||
|
return 0.5 * angularDeviation(lhs.angle, rhs.angle);
|
||||||
|
};
|
||||||
|
|
||||||
|
// When offsetting angles in our turns, we don't want to get past the next turn. This
|
||||||
|
// function simply limits an offset to be at most half the distance to the next turn in the
|
||||||
|
// offfset direction
|
||||||
|
const auto get_corrected_offset = [](const double offset,
|
||||||
|
const ConnectedRoad &road,
|
||||||
|
const ConnectedRoad &next_road_in_offset_direction) {
|
||||||
|
const auto offset_limit =
|
||||||
|
angularDeviation(road.angle, next_road_in_offset_direction.angle);
|
||||||
|
// limit the offset with an additional buffer
|
||||||
|
return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit
|
||||||
|
: offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if the u-turn edge at the next intersection could be merged to the left/right. If
|
||||||
|
// this is the case and the road is not far away (see previous distance check), if
|
||||||
|
// influences the perceived angle.
|
||||||
|
if (CanMerge(node_at_next_intersection, next_intersection_along_road, 0, 1))
|
||||||
|
{
|
||||||
|
const auto offset =
|
||||||
|
get_offset(next_intersection_along_road[0], next_intersection_along_road[1]);
|
||||||
|
|
||||||
|
const auto corrected_offset =
|
||||||
|
get_corrected_offset(offset, road, intersection[(index + 1) % intersection.size()]);
|
||||||
|
// at the target intersection, we merge to the right, so we need to shift the current
|
||||||
|
// angle to the left
|
||||||
|
road.angle = adjustAngle(road.angle, corrected_offset);
|
||||||
|
road.bearing = adjustAngle(road.bearing, corrected_offset);
|
||||||
|
}
|
||||||
|
else if (CanMerge(node_at_next_intersection,
|
||||||
|
next_intersection_along_road,
|
||||||
|
0,
|
||||||
|
next_intersection_along_road.size() - 1))
|
||||||
|
{
|
||||||
|
const auto offset =
|
||||||
|
get_offset(next_intersection_along_road[0],
|
||||||
|
next_intersection_along_road[next_intersection_along_road.size() - 1]);
|
||||||
|
|
||||||
|
const auto corrected_offset =
|
||||||
|
get_corrected_offset(offset, road, intersection[index - 1]);
|
||||||
|
// at the target intersection, we merge to the left, so we need to shift the current
|
||||||
|
// angle to the right
|
||||||
|
road.angle = adjustAngle(road.angle, -corrected_offset);
|
||||||
|
road.bearing = adjustAngle(road.bearing, -corrected_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
@ -43,9 +43,12 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
|||||||
restriction_map,
|
restriction_map,
|
||||||
barrier_nodes,
|
barrier_nodes,
|
||||||
node_info_list,
|
node_info_list,
|
||||||
compressed_edge_container,
|
compressed_edge_container),
|
||||||
name_table,
|
intersection_normalizer(node_based_graph,
|
||||||
street_name_suffix_table),
|
node_info_list,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table,
|
||||||
|
intersection_generator),
|
||||||
roundabout_handler(node_based_graph,
|
roundabout_handler(node_based_graph,
|
||||||
node_info_list,
|
node_info_list,
|
||||||
compressed_edge_container,
|
compressed_edge_container,
|
||||||
@ -121,9 +124,18 @@ TurnAnalysis::transformIntersectionIntoTurns(const Intersection &intersection) c
|
|||||||
return turns;
|
return turns;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection TurnAnalysis::getIntersection(const NodeID from_nid, const EdgeID via_eid) const
|
Intersection TurnAnalysis::operator()(const NodeID from_nid, const EdgeID via_eid) const
|
||||||
{
|
{
|
||||||
return intersection_generator(from_nid, via_eid);
|
return PostProcess(from_nid, via_eid, intersection_generator(from_nid, via_eid));
|
||||||
|
}
|
||||||
|
|
||||||
|
Intersection TurnAnalysis::PostProcess(const NodeID from_node,
|
||||||
|
const EdgeID via_eid,
|
||||||
|
Intersection intersection) const
|
||||||
|
{
|
||||||
|
const auto node_at_intersection = node_based_graph.GetTarget(via_eid);
|
||||||
|
return assignTurnTypes(
|
||||||
|
from_node, via_eid, intersection_normalizer(node_at_intersection, std::move(intersection)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets basic turn types as fallback for otherwise unhandled turns
|
// Sets basic turn types as fallback for otherwise unhandled turns
|
||||||
@ -145,7 +157,10 @@ TurnAnalysis::setTurnTypes(const NodeID from_nid, const EdgeID, Intersection int
|
|||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IntersectionGenerator &TurnAnalysis::getGenerator() const { return intersection_generator; }
|
const IntersectionGenerator &TurnAnalysis::GetIntersectionGenerator() const
|
||||||
|
{
|
||||||
|
return intersection_generator;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
} // namespace extractor
|
} // namespace extractor
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "extractor/guidance/turn_discovery.hpp"
|
#include "extractor/guidance/turn_discovery.hpp"
|
||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
#include "util/coordinate_calculation.hpp"
|
#include "util/coordinate_calculation.hpp"
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@ -14,7 +15,7 @@ namespace lanes
|
|||||||
bool findPreviousIntersection(const NodeID node_v,
|
bool findPreviousIntersection(const NodeID node_v,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
const Intersection intersection,
|
const Intersection intersection,
|
||||||
const TurnAnalysis &turn_analysis,
|
const IntersectionGenerator &intersection_generator,
|
||||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
// output parameters
|
// output parameters
|
||||||
NodeID &result_node,
|
NodeID &result_node,
|
||||||
@ -35,7 +36,7 @@ bool findPreviousIntersection(const NodeID node_v,
|
|||||||
*/
|
*/
|
||||||
const constexpr double COMBINE_DISTANCE_CUTOFF = 30;
|
const constexpr double COMBINE_DISTANCE_CUTOFF = 30;
|
||||||
|
|
||||||
const auto coordinate_extractor = turn_analysis.getGenerator().GetCoordinateExtractor();
|
const auto coordinate_extractor = intersection_generator.GetCoordinateExtractor();
|
||||||
const auto via_edge_length = util::coordinate_calculation::getLength(
|
const auto via_edge_length = util::coordinate_calculation::getLength(
|
||||||
coordinate_extractor.GetForwardCoordinatesAlongRoad(node_v, via_edge),
|
coordinate_extractor.GetForwardCoordinatesAlongRoad(node_v, via_edge),
|
||||||
&util::coordinate_calculation::haversineDistance);
|
&util::coordinate_calculation::haversineDistance);
|
||||||
@ -49,8 +50,7 @@ bool findPreviousIntersection(const NodeID node_v,
|
|||||||
// (looking at the reverse direction).
|
// (looking at the reverse direction).
|
||||||
const auto node_w = node_based_graph.GetTarget(via_edge);
|
const auto node_w = node_based_graph.GetTarget(via_edge);
|
||||||
const auto u_turn_at_node_w = intersection[0].eid;
|
const auto u_turn_at_node_w = intersection[0].eid;
|
||||||
const auto node_v_reverse_intersection =
|
const auto node_v_reverse_intersection = intersection_generator(node_w, u_turn_at_node_w);
|
||||||
turn_analysis.getIntersection(node_w, u_turn_at_node_w);
|
|
||||||
|
|
||||||
// Continue along the straightmost turn. If there is no straight turn, we cannot find a valid
|
// Continue along the straightmost turn. If there is no straight turn, we cannot find a valid
|
||||||
// previous intersection.
|
// previous intersection.
|
||||||
@ -59,12 +59,13 @@ bool findPreviousIntersection(const NodeID node_v,
|
|||||||
|
|
||||||
// TODO evaluate if narrow turn is the right criterion here... Might be that other angles are
|
// TODO evaluate if narrow turn is the right criterion here... Might be that other angles are
|
||||||
// valid
|
// valid
|
||||||
if (angularDeviation(straightmost_at_v_in_reverse->angle, STRAIGHT_ANGLE) > GROUP_ANGLE)
|
if (util::guidance::angularDeviation(straightmost_at_v_in_reverse->angle, STRAIGHT_ANGLE) >
|
||||||
|
GROUP_ANGLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto node_u = node_based_graph.GetTarget(straightmost_at_v_in_reverse->eid);
|
const auto node_u = node_based_graph.GetTarget(straightmost_at_v_in_reverse->eid);
|
||||||
const auto node_u_reverse_intersection =
|
const auto node_u_reverse_intersection =
|
||||||
turn_analysis.getIntersection(node_v, straightmost_at_v_in_reverse->eid);
|
intersection_generator(node_v, straightmost_at_v_in_reverse->eid);
|
||||||
|
|
||||||
// now check that the u-turn at the given intersection connects to via-edge
|
// now check that the u-turn at the given intersection connects to via-edge
|
||||||
// The u-turn at the now found intersection should, hopefully, represent the previous edge.
|
// The u-turn at the now found intersection should, hopefully, represent the previous edge.
|
||||||
@ -80,7 +81,7 @@ bool findPreviousIntersection(const NodeID node_v,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
result_intersection = turn_analysis.getIntersection(node_u, result_via_edge);
|
result_intersection = intersection_generator(node_u, result_via_edge);
|
||||||
const auto check_via_edge =
|
const auto check_via_edge =
|
||||||
result_intersection.end() !=
|
result_intersection.end() !=
|
||||||
std::find_if(result_intersection.begin(),
|
std::find_if(result_intersection.begin(),
|
||||||
@ -94,9 +95,6 @@ bool findPreviousIntersection(const NodeID node_v,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
result_intersection =
|
|
||||||
turn_analysis.assignTurnTypes(node_u, result_via_edge, std::move(result_intersection));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,13 +189,15 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
|
|||||||
if (findPreviousIntersection(at,
|
if (findPreviousIntersection(at,
|
||||||
via_edge,
|
via_edge,
|
||||||
intersection,
|
intersection,
|
||||||
turn_analysis,
|
turn_analysis.GetIntersectionGenerator(),
|
||||||
node_based_graph,
|
node_based_graph,
|
||||||
previous_node,
|
previous_node,
|
||||||
previous_via_edge,
|
previous_via_edge,
|
||||||
previous_intersection))
|
previous_intersection))
|
||||||
{
|
{
|
||||||
extractLaneData(previous_via_edge, previous_description_id, previous_lane_data);
|
extractLaneData(previous_via_edge, previous_description_id, previous_lane_data);
|
||||||
|
previous_intersection = turn_analysis.PostProcess(
|
||||||
|
previous_node, previous_via_edge, std::move(previous_intersection));
|
||||||
for (std::size_t road_index = 0; road_index < previous_intersection.size(); ++road_index)
|
for (std::size_t road_index = 0; road_index < previous_intersection.size(); ++road_index)
|
||||||
{
|
{
|
||||||
const auto &road = previous_intersection[road_index];
|
const auto &road = previous_intersection[road_index];
|
||||||
@ -540,9 +542,7 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
|
|||||||
|
|
||||||
// find out about the next intersection. To check for valid matches, we also need the turn
|
// find out about the next intersection. To check for valid matches, we also need the turn
|
||||||
// types
|
// types
|
||||||
auto next_intersection = turn_analysis.getIntersection(at, straightmost->eid);
|
const auto next_intersection = turn_analysis(at, straightmost->eid);
|
||||||
next_intersection =
|
|
||||||
turn_analysis.assignTurnTypes(at, straightmost->eid, std::move(next_intersection));
|
|
||||||
|
|
||||||
// check where we can match turn lanes
|
// check where we can match turn lanes
|
||||||
std::size_t straightmost_tag_index = turn_lane_data.size();
|
std::size_t straightmost_tag_index = turn_lane_data.size();
|
||||||
|
Loading…
Reference in New Issue
Block a user