improve sliproad / fork handling
This commit is contained in:
parent
1309dd2a0f
commit
9e323d2d42
@ -167,3 +167,34 @@ Feature: Slipways and Dedicated Turn Lanes
|
|||||||
When I route I should get
|
When I route I should get
|
||||||
| waypoints | route | turns |
|
| waypoints | route | turns |
|
||||||
| a,o | Schwarzwaldstrasse (L561),Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive |
|
| a,o | Schwarzwaldstrasse (L561),Ettlinger Allee,Ettlinger Allee | depart,turn right,arrive |
|
||||||
|
|
||||||
|
Scenario: Traffic Lights everywhere
|
||||||
|
#http://map.project-osrm.org/?z=18¢er=48.995336%2C8.383813&loc=48.995467%2C8.384548&loc=48.995115%2C8.382761&hl=en&alt=0
|
||||||
|
Given the node map
|
||||||
|
| a | | | k | l | | | j | |
|
||||||
|
| | | | | | d | b | c | i |
|
||||||
|
| | | | | | | | | |
|
||||||
|
| | | | | | | e | g | |
|
||||||
|
| | | | | | | | | |
|
||||||
|
| | | | | | | | | |
|
||||||
|
| | | | | | | | h | |
|
||||||
|
| | | | | | | | | |
|
||||||
|
| | | | | | | | f | |
|
||||||
|
|
||||||
|
And the nodes
|
||||||
|
| node | highway |
|
||||||
|
| b | traffic_signals |
|
||||||
|
| e | traffic_signals |
|
||||||
|
| g | traffic_signals |
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | name | oneway |
|
||||||
|
| aklbci | secondary | Ebertstrasse | yes |
|
||||||
|
| kdeh | secondary_link | | yes |
|
||||||
|
| jcghf | primary | Brauerstrasse | yes |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,i | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||||
|
| a,l | Ebertstrasse,Ebertstrasse | depart,arrive |
|
||||||
|
| a,f | Ebertstrasse,Brauerstrasse,Brauerstrasse | depart,turn right,arrive |
|
||||||
|
@ -29,7 +29,8 @@ class IntersectionHandler
|
|||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
virtual ~IntersectionHandler();
|
|
||||||
|
virtual ~IntersectionHandler() = default;
|
||||||
|
|
||||||
// check whether the handler can actually handle the intersection
|
// check whether the handler can actually handle the intersection
|
||||||
virtual bool
|
virtual bool
|
||||||
@ -51,6 +52,9 @@ class IntersectionHandler
|
|||||||
// Decide on a basic turn types
|
// Decide on a basic turn types
|
||||||
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
TurnType::Enum findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
|
||||||
|
|
||||||
|
// Find the most obvious turn to follow
|
||||||
|
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
|
||||||
|
|
||||||
// Get the Instruction for an obvious turn
|
// Get the Instruction for an obvious turn
|
||||||
TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
|
TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
|
||||||
const EdgeID via_edge,
|
const EdgeID via_edge,
|
||||||
|
@ -10,11 +10,6 @@ namespace extractor
|
|||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
|
|
||||||
// possible fork
|
|
||||||
bool isFork(const ConnectedRoad &uturn,
|
|
||||||
const ConnectedRoad &possible_right_fork,
|
|
||||||
const ConnectedRoad &possible_left_fork);
|
|
||||||
|
|
||||||
// Ending in a T-Intersection
|
// Ending in a T-Intersection
|
||||||
bool isEndOfRoad(const ConnectedRoad &uturn,
|
bool isEndOfRoad(const ConnectedRoad &uturn,
|
||||||
const ConnectedRoad &possible_right_turn,
|
const ConnectedRoad &possible_right_turn,
|
||||||
|
@ -26,7 +26,8 @@ class MotorwayHandler : public IntersectionHandler
|
|||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
~MotorwayHandler() override final;
|
|
||||||
|
~MotorwayHandler() override final = default;
|
||||||
|
|
||||||
// check whether the handler can actually handle the intersection
|
// check whether the handler can actually handle the intersection
|
||||||
bool canProcess(const NodeID nid,
|
bool canProcess(const NodeID nid,
|
||||||
|
@ -44,7 +44,7 @@ class RoundaboutHandler : public IntersectionHandler
|
|||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
~RoundaboutHandler() override final;
|
~RoundaboutHandler() override final = default;
|
||||||
|
|
||||||
// check whether the handler can actually handle the intersection
|
// check whether the handler can actually handle the intersection
|
||||||
bool canProcess(const NodeID from_nid,
|
bool canProcess(const NodeID from_nid,
|
||||||
|
53
include/extractor/guidance/sliproad_handler.hpp
Normal file
53
include/extractor/guidance/sliproad_handler.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef OSRM_EXTRACTOR_GUIDANCE_SLIPROAD_HANDLER_HPP_
|
||||||
|
#define OSRM_EXTRACTOR_GUIDANCE_SLIPROAD_HANDLER_HPP_
|
||||||
|
|
||||||
|
#include "extractor/guidance/intersection.hpp"
|
||||||
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
|
#include "extractor/guidance/intersection_generator.hpp"
|
||||||
|
#include "extractor/query_node.hpp"
|
||||||
|
|
||||||
|
#include "util/name_table.hpp"
|
||||||
|
#include "util/node_based_graph.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
// Intersection handlers deal with all issues related to intersections.
|
||||||
|
// They assign appropriate turn operations to the TurnOperations.
|
||||||
|
class SliproadHandler : public IntersectionHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SliproadHandler(const IntersectionGenerator &intersection_generator,
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const std::vector<QueryNode> &node_info_list,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table);
|
||||||
|
|
||||||
|
~SliproadHandler() override final = default;
|
||||||
|
|
||||||
|
// check whether the handler can actually handle the intersection
|
||||||
|
bool canProcess(const NodeID /*nid*/,
|
||||||
|
const EdgeID /*via_eid*/,
|
||||||
|
const Intersection & /*intersection*/) const override final;
|
||||||
|
|
||||||
|
// process the intersection
|
||||||
|
Intersection operator()(const NodeID nid,
|
||||||
|
const EdgeID via_eid,
|
||||||
|
Intersection intersection) const override final;
|
||||||
|
private:
|
||||||
|
const IntersectionGenerator &intersection_generator;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
||||||
|
|
||||||
|
#endif /*OSRM_EXTRACTOR_GUIDANCE_SLIPROAD_HANDLER_HPP_*/
|
@ -428,7 +428,7 @@ inline int getPriority(const FunctionalRoadClass road_class)
|
|||||||
// They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
|
// They are used in Fork-Discovery. Possibly should be moved to profiles post v5?
|
||||||
// A fork can happen between road types that are at most 1 priority apart from each other
|
// A fork can happen between road types that are at most 1 priority apart from each other
|
||||||
const constexpr int road_priority[] = {
|
const constexpr int road_priority[] = {
|
||||||
10, 0, 10, 2, 10, 4, 10, 6, 10, 8, 10, 11, 10, 12, 10, 14};
|
14, 0, 14, 2, 14, 4, 14, 6, 14, 8, 10, 11, 10, 12, 10, 14};
|
||||||
return road_priority[static_cast<int>(road_class)];
|
return road_priority[static_cast<int>(road_class)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "extractor/guidance/intersection_generator.hpp"
|
#include "extractor/guidance/intersection_generator.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/toolkit.hpp"
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
#include "extractor/guidance/turn_classification.hpp"
|
#include "extractor/guidance/turn_classification.hpp"
|
||||||
#include "extractor/guidance/turn_handler.hpp"
|
#include "extractor/guidance/turn_handler.hpp"
|
||||||
@ -59,13 +60,11 @@ class TurnAnalysis
|
|||||||
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;
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
Intersection handleSliproads(const NodeID intersection_node_id,
|
|
||||||
Intersection intersection) const;
|
|
||||||
}; // class TurnAnalysis
|
}; // class TurnAnalysis
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
@ -28,7 +28,8 @@ class TurnHandler : public IntersectionHandler
|
|||||||
const std::vector<QueryNode> &node_info_list,
|
const std::vector<QueryNode> &node_info_list,
|
||||||
const util::NameTable &name_table,
|
const util::NameTable &name_table,
|
||||||
const SuffixTable &street_name_suffix_table);
|
const SuffixTable &street_name_suffix_table);
|
||||||
~TurnHandler() override final;
|
|
||||||
|
~TurnHandler() override final = default;
|
||||||
|
|
||||||
// check whether the handler can actually handle the intersection
|
// check whether the handler can actually handle the intersection
|
||||||
bool canProcess(const NodeID nid,
|
bool canProcess(const NodeID nid,
|
||||||
@ -41,6 +42,9 @@ class TurnHandler : public IntersectionHandler
|
|||||||
Intersection intersection) const override final;
|
Intersection intersection) const override final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool isObviousOfTwo(const EdgeID via_edge,
|
||||||
|
const ConnectedRoad &road,
|
||||||
|
const ConnectedRoad &other) const;
|
||||||
// Dead end.
|
// Dead end.
|
||||||
Intersection handleOneWayTurn(Intersection intersection) const;
|
Intersection handleOneWayTurn(Intersection intersection) const;
|
||||||
|
|
||||||
@ -57,8 +61,7 @@ class TurnHandler : public IntersectionHandler
|
|||||||
handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
|
handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
|
||||||
|
|
||||||
// Classification
|
// Classification
|
||||||
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
|
std::pair<std::size_t, std::size_t> findFork(const EdgeID via_edge, const Intersection &intersection) const;
|
||||||
std::pair<std::size_t, std::size_t> findFork(const Intersection &intersection) const;
|
|
||||||
|
|
||||||
Intersection assignLeftTurns(const EdgeID via_edge,
|
Intersection assignLeftTurns(const EdgeID via_edge,
|
||||||
Intersection intersection,
|
Intersection intersection,
|
||||||
|
@ -719,6 +719,16 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
|||||||
// Handle sliproads from motorways in urban areas, save from modifying depart, since
|
// Handle sliproads from motorways in urban areas, save from modifying depart, since
|
||||||
// TurnType::Sliproad != TurnType::NoTurn
|
// TurnType::Sliproad != TurnType::NoTurn
|
||||||
if (one_back_step.maneuver.instruction.type == TurnType::Sliproad)
|
if (one_back_step.maneuver.instruction.type == TurnType::Sliproad)
|
||||||
|
{
|
||||||
|
if (current_step.maneuver.instruction.type == TurnType::Suppressed &&
|
||||||
|
compatible(one_back_step, current_step))
|
||||||
|
{
|
||||||
|
// Traffic light on the sliproad
|
||||||
|
steps[one_back_index] =
|
||||||
|
elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||||
|
invalidateStep(steps[step_index]);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Handle possible u-turns between highways that look like slip-roads
|
// Handle possible u-turns between highways that look like slip-roads
|
||||||
if (steps[getPreviousIndex(one_back_index)].name_id == steps[step_index].name_id &&
|
if (steps[getPreviousIndex(one_back_index)].name_id == steps[step_index].name_id &&
|
||||||
@ -750,6 +760,7 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
|||||||
invalidateStep(steps[step_index]);
|
invalidateStep(steps[step_index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Due to empty segments, we can get name-changes from A->A
|
// Due to empty segments, we can get name-changes from A->A
|
||||||
// These have to be handled in post-processing
|
// These have to be handled in post-processing
|
||||||
else if (isCollapsableInstruction(current_step.maneuver.instruction) &&
|
else if (isCollapsableInstruction(current_step.maneuver.instruction) &&
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "extractor/guidance/intersection_handler.hpp"
|
|
||||||
#include "extractor/guidance/constants.hpp"
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/guidance/intersection_handler.hpp"
|
||||||
#include "extractor/guidance/toolkit.hpp"
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
|
||||||
#include "util/guidance/toolkit.hpp"
|
#include "util/guidance/toolkit.hpp"
|
||||||
@ -34,8 +34,6 @@ IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IntersectionHandler::~IntersectionHandler() = default;
|
|
||||||
|
|
||||||
std::size_t IntersectionHandler::countValid(const Intersection &intersection) const
|
std::size_t IntersectionHandler::countValid(const Intersection &intersection) const
|
||||||
{
|
{
|
||||||
return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road) {
|
return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road) {
|
||||||
@ -322,6 +320,115 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||||
|
const Intersection &intersection) const
|
||||||
|
{
|
||||||
|
// no obvious road
|
||||||
|
if (intersection.size() == 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// a single non u-turn is obvious
|
||||||
|
if (intersection.size() == 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// at least three roads
|
||||||
|
std::size_t best = 0;
|
||||||
|
double best_deviation = 180;
|
||||||
|
|
||||||
|
std::size_t best_continue = 0;
|
||||||
|
double best_continue_deviation = 180;
|
||||||
|
|
||||||
|
const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||||
|
for (std::size_t i = 1; i < intersection.size(); ++i)
|
||||||
|
{
|
||||||
|
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
|
||||||
|
if (intersection[i].entry_allowed && deviation < best_deviation)
|
||||||
|
{
|
||||||
|
best_deviation = deviation;
|
||||||
|
best = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
|
||||||
|
auto continue_class = node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
|
||||||
|
.road_classification.road_class;
|
||||||
|
if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
|
||||||
|
(best_continue == 0 || continue_class > out_data.road_classification.road_class ||
|
||||||
|
(deviation < best_continue_deviation &&
|
||||||
|
out_data.road_classification.road_class == continue_class)))
|
||||||
|
{
|
||||||
|
best_continue_deviation = deviation;
|
||||||
|
best_continue = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (best_deviation >= 2 * NARROW_TURN_ANGLE)
|
||||||
|
return 0;
|
||||||
|
// has no obvious continued road
|
||||||
|
if (best_continue == 0 || best_continue_deviation >= 2 * NARROW_TURN_ANGLE ||
|
||||||
|
(node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
|
||||||
|
.road_classification.road_class ==
|
||||||
|
node_based_graph.GetEdgeData(intersection[best].turn.eid)
|
||||||
|
.road_classification.road_class &&
|
||||||
|
std::abs(best_continue_deviation) > 1 && best_deviation / best_continue_deviation < 0.75))
|
||||||
|
{
|
||||||
|
// Find left/right deviation
|
||||||
|
const double left_deviation = angularDeviation(
|
||||||
|
intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
|
||||||
|
const double right_deviation =
|
||||||
|
angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
|
||||||
|
|
||||||
|
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||||
|
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
||||||
|
return best;
|
||||||
|
|
||||||
|
// other narrow turns?
|
||||||
|
if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
|
||||||
|
FUZZY_ANGLE_DIFFERENCE)
|
||||||
|
return 0;
|
||||||
|
if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
|
||||||
|
STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Well distinct turn that is nearly straight
|
||||||
|
if ((left_deviation / best_deviation >= DISTINCTION_RATIO ||
|
||||||
|
(left_deviation > best_deviation &&
|
||||||
|
!intersection[(best + 1) % intersection.size()].entry_allowed)) &&
|
||||||
|
(right_deviation / best_deviation >= DISTINCTION_RATIO ||
|
||||||
|
(right_deviation > best_deviation && !intersection[best - 1].entry_allowed)))
|
||||||
|
{
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double deviation =
|
||||||
|
angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE);
|
||||||
|
const auto &continue_data =
|
||||||
|
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
|
||||||
|
if (std::abs(deviation) < 1)
|
||||||
|
return best_continue;
|
||||||
|
|
||||||
|
// check if any other similar best continues exist
|
||||||
|
for (std::size_t i = 1; i < intersection.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i == best_continue || !intersection[i].entry_allowed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE) / deviation < 1.1 &&
|
||||||
|
continue_data.road_classification.road_class ==
|
||||||
|
node_based_graph.GetEdgeData(intersection[i].turn.eid)
|
||||||
|
.road_classification.road_class)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return best_continue; // no obvious turn
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
} // namespace extractor
|
} // namespace extractor
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
@ -13,14 +13,6 @@ namespace extractor
|
|||||||
namespace guidance
|
namespace guidance
|
||||||
{
|
{
|
||||||
|
|
||||||
bool isFork(const ConnectedRoad &,
|
|
||||||
const ConnectedRoad &possible_right_fork,
|
|
||||||
const ConnectedRoad &possible_left_fork)
|
|
||||||
{
|
|
||||||
return angularDeviation(possible_right_fork.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
|
||||||
angularDeviation(possible_left_fork.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEndOfRoad(const ConnectedRoad &,
|
bool isEndOfRoad(const ConnectedRoad &,
|
||||||
const ConnectedRoad &possible_right_turn,
|
const ConnectedRoad &possible_right_turn,
|
||||||
const ConnectedRoad &possible_left_turn)
|
const ConnectedRoad &possible_left_turn)
|
||||||
|
@ -47,8 +47,6 @@ MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_g
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MotorwayHandler::~MotorwayHandler() = default;
|
|
||||||
|
|
||||||
bool MotorwayHandler::canProcess(const NodeID,
|
bool MotorwayHandler::canProcess(const NodeID,
|
||||||
const EdgeID via_eid,
|
const EdgeID via_eid,
|
||||||
const Intersection &intersection) const
|
const Intersection &intersection) const
|
||||||
|
@ -31,8 +31,6 @@ RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_bas
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
RoundaboutHandler::~RoundaboutHandler() = default;
|
|
||||||
|
|
||||||
bool RoundaboutHandler::canProcess(const NodeID from_nid,
|
bool RoundaboutHandler::canProcess(const NodeID from_nid,
|
||||||
const EdgeID via_eid,
|
const EdgeID via_eid,
|
||||||
const Intersection &intersection) const
|
const Intersection &intersection) const
|
||||||
|
192
src/extractor/guidance/sliproad_handler.cpp
Normal file
192
src/extractor/guidance/sliproad_handler.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#include "extractor/guidance/constants.hpp"
|
||||||
|
#include "extractor/guidance/intersection_scenario_three_way.hpp"
|
||||||
|
#include "extractor/guidance/sliproad_handler.hpp"
|
||||||
|
#include "extractor/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
#include "util/guidance/toolkit.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
||||||
|
using osrm::util::guidance::getTurnDirection;
|
||||||
|
using osrm::util::guidance::angularDeviation;
|
||||||
|
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace extractor
|
||||||
|
{
|
||||||
|
namespace guidance
|
||||||
|
{
|
||||||
|
|
||||||
|
SliproadHandler::SliproadHandler(const IntersectionGenerator &intersection_generator,
|
||||||
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||||
|
const std::vector<QueryNode> &node_info_list,
|
||||||
|
const util::NameTable &name_table,
|
||||||
|
const SuffixTable &street_name_suffix_table)
|
||||||
|
: IntersectionHandler(node_based_graph, node_info_list, name_table, street_name_suffix_table),
|
||||||
|
intersection_generator(intersection_generator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// included for interface reasons only
|
||||||
|
bool SliproadHandler::canProcess(const NodeID /*nid*/,
|
||||||
|
const EdgeID /*via_eid*/,
|
||||||
|
const Intersection & /*intersection*/) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intersection SliproadHandler::
|
||||||
|
operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection) const
|
||||||
|
{
|
||||||
|
auto intersection_node_id = node_based_graph.GetTarget(source_edge_id);
|
||||||
|
|
||||||
|
// if there is no turn, there is no sliproad
|
||||||
|
if (intersection.size() <= 2)
|
||||||
|
return intersection;
|
||||||
|
|
||||||
|
const auto obvious_turn_index = findObviousTurn(source_edge_id, intersection);
|
||||||
|
const auto &next_road = intersection[obvious_turn_index];
|
||||||
|
|
||||||
|
const auto linkTest = [this, next_road](const ConnectedRoad &road) {
|
||||||
|
return !node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed &&
|
||||||
|
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE &&
|
||||||
|
!hasRoundaboutType(road.turn.instruction) &&
|
||||||
|
angularDeviation(next_road.turn.angle, road.turn.angle) >
|
||||||
|
std::numeric_limits<double>::epsilon();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool hasNarrow =
|
||||||
|
std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end();
|
||||||
|
if (!hasNarrow)
|
||||||
|
return intersection;
|
||||||
|
|
||||||
|
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
|
||||||
|
|
||||||
|
const bool hasNext = obvious_turn_index != 0;
|
||||||
|
if (!hasNext)
|
||||||
|
return intersection;
|
||||||
|
|
||||||
|
// check whether the continue road is valid
|
||||||
|
const auto check_valid = [this, source_edge_data](const ConnectedRoad &road) {
|
||||||
|
const auto road_edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||||
|
// Test to see if the source edge and the one we're looking at are the same road
|
||||||
|
return road_edge_data.road_classification.road_class ==
|
||||||
|
source_edge_data.road_classification.road_class &&
|
||||||
|
road_edge_data.name_id != EMPTY_NAMEID &&
|
||||||
|
road_edge_data.name_id == source_edge_data.name_id && road.entry_allowed;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!check_valid(next_road))
|
||||||
|
return intersection;
|
||||||
|
|
||||||
|
// Threshold check, if the intersection is too far away, don't bother continuing
|
||||||
|
const auto &next_road_data = node_based_graph.GetEdgeData(next_road.turn.eid);
|
||||||
|
if (next_road_data.distance > MAX_SLIPROAD_THRESHOLD)
|
||||||
|
{
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
auto next_intersection_node = node_based_graph.GetTarget(next_road.turn.eid);
|
||||||
|
|
||||||
|
const auto next_road_next_intersection = [&]() {
|
||||||
|
auto intersection = intersection_generator(intersection_node_id, next_road.turn.eid);
|
||||||
|
auto in_edge = next_road.turn.eid;
|
||||||
|
// skip over traffic lights
|
||||||
|
if (intersection.size() == 2)
|
||||||
|
{
|
||||||
|
const auto node = node_based_graph.GetTarget(in_edge);
|
||||||
|
in_edge = intersection[1].turn.eid;
|
||||||
|
next_intersection_node = node_based_graph.GetTarget(in_edge);
|
||||||
|
intersection = intersection_generator(node, in_edge);
|
||||||
|
}
|
||||||
|
return intersection;
|
||||||
|
}();
|
||||||
|
|
||||||
|
std::unordered_set<NameID> target_road_names;
|
||||||
|
|
||||||
|
for (const auto &road : next_road_next_intersection)
|
||||||
|
{
|
||||||
|
const auto &target_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||||
|
target_road_names.insert(target_data.name_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &road : intersection)
|
||||||
|
{
|
||||||
|
if (linkTest(road))
|
||||||
|
{
|
||||||
|
EdgeID candidate_in = road.turn.eid;
|
||||||
|
const auto target_intersection = [&](NodeID node) {
|
||||||
|
auto intersection = intersection_generator(node, candidate_in);
|
||||||
|
// skip over traffic lights
|
||||||
|
if (intersection.size() == 2)
|
||||||
|
{
|
||||||
|
node = node_based_graph.GetTarget(candidate_in);
|
||||||
|
candidate_in = intersection[1].turn.eid;
|
||||||
|
intersection = intersection_generator(node, candidate_in);
|
||||||
|
}
|
||||||
|
return intersection;
|
||||||
|
}(intersection_node_id);
|
||||||
|
|
||||||
|
for (const auto &candidate_road : target_intersection)
|
||||||
|
{
|
||||||
|
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid);
|
||||||
|
if (target_road_names.count(candidate_data.name_id) > 0)
|
||||||
|
{
|
||||||
|
if (node_based_graph.GetTarget(candidate_road.turn.eid) ==
|
||||||
|
next_intersection_node)
|
||||||
|
{
|
||||||
|
road.turn.instruction.type = TurnType::Sliproad;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto skip_traffic_light_intersection =
|
||||||
|
intersection_generator(node_based_graph.GetTarget(candidate_in), candidate_road.turn.eid);
|
||||||
|
if (skip_traffic_light_intersection.size() == 2 &&
|
||||||
|
node_based_graph.GetTarget(
|
||||||
|
skip_traffic_light_intersection[1].turn.eid) ==
|
||||||
|
next_intersection_node)
|
||||||
|
{
|
||||||
|
|
||||||
|
road.turn.instruction.type = TurnType::Sliproad;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_road.turn.instruction.type == TurnType::Fork)
|
||||||
|
{
|
||||||
|
const auto &next_data = node_based_graph.GetEdgeData(next_road.turn.eid);
|
||||||
|
if (next_data.name_id == source_edge_data.name_id)
|
||||||
|
{
|
||||||
|
if (angularDeviation(next_road.turn.angle, STRAIGHT_ANGLE) < 5)
|
||||||
|
intersection[obvious_turn_index].turn.instruction.type = TurnType::Suppressed;
|
||||||
|
else
|
||||||
|
intersection[obvious_turn_index].turn.instruction.type = TurnType::Continue;
|
||||||
|
intersection[obvious_turn_index].turn.instruction.direction_modifier =
|
||||||
|
getTurnDirection(intersection[obvious_turn_index].turn.angle);
|
||||||
|
}
|
||||||
|
else if (next_data.name_id != EMPTY_NAMEID)
|
||||||
|
{
|
||||||
|
intersection[obvious_turn_index].turn.instruction.type = TurnType::NewName;
|
||||||
|
intersection[obvious_turn_index].turn.instruction.direction_modifier =
|
||||||
|
getTurnDirection(intersection[obvious_turn_index].turn.angle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
intersection[obvious_turn_index].turn.instruction.type = TurnType::Suppressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace guidance
|
||||||
|
} // namespace extractor
|
||||||
|
} // namespace osrm
|
@ -49,7 +49,12 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
|||||||
name_table,
|
name_table,
|
||||||
street_name_suffix_table),
|
street_name_suffix_table),
|
||||||
motorway_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table),
|
motorway_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table),
|
||||||
turn_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table)
|
turn_handler(node_based_graph, node_info_list, name_table, street_name_suffix_table),
|
||||||
|
sliproad_handler(intersection_generator,
|
||||||
|
node_based_graph,
|
||||||
|
node_info_list,
|
||||||
|
name_table,
|
||||||
|
street_name_suffix_table)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +83,7 @@ Intersection TurnAnalysis::assignTurnTypes(const NodeID from_nid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle sliproads
|
// Handle sliproads
|
||||||
intersection = handleSliproads(via_eid, std::move(intersection));
|
intersection = sliproad_handler(from_nid, via_eid, std::move(intersection));
|
||||||
|
|
||||||
// Turn On Ramps Into Off Ramps, if we come from a motorway-like road
|
// Turn On Ramps Into Off Ramps, if we come from a motorway-like road
|
||||||
if (isMotorwayClass(node_based_graph.GetEdgeData(via_eid).road_classification.road_class))
|
if (isMotorwayClass(node_based_graph.GetEdgeData(via_eid).road_classification.road_class))
|
||||||
@ -127,135 +132,6 @@ TurnAnalysis::setTurnTypes(const NodeID from_nid, const EdgeID, Intersection int
|
|||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Sliproads" occur when we've got a link between two roads (MOTORWAY_LINK, etc), but
|
|
||||||
// the two roads are *also* directly connected shortly afterwards.
|
|
||||||
// In these cases, we tag the turn-type as "sliproad", and then in post-processing
|
|
||||||
// we emit a "turn", instead of "take the ramp"+"merge"
|
|
||||||
Intersection TurnAnalysis::handleSliproads(const EdgeID source_edge_id,
|
|
||||||
Intersection intersection) const
|
|
||||||
{
|
|
||||||
auto intersection_node_id = node_based_graph.GetTarget(source_edge_id);
|
|
||||||
|
|
||||||
const auto linkTest = [this](const ConnectedRoad &road) {
|
|
||||||
return !node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed &&
|
|
||||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE &&
|
|
||||||
!hasRoundaboutType(road.turn.instruction);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool hasNarrow =
|
|
||||||
std::find_if(intersection.begin(), intersection.end(), linkTest) != intersection.end();
|
|
||||||
if (!hasNarrow)
|
|
||||||
return intersection;
|
|
||||||
|
|
||||||
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
|
|
||||||
|
|
||||||
// Find the continuation of the intersection we're on
|
|
||||||
auto next_road = std::find_if(
|
|
||||||
intersection.begin(),
|
|
||||||
intersection.end(),
|
|
||||||
[this, source_edge_data](const ConnectedRoad &road) {
|
|
||||||
const auto road_edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
|
||||||
// Test to see if the source edge and the one we're looking at are the same road
|
|
||||||
return road_edge_data.road_classification.road_class ==
|
|
||||||
source_edge_data.road_classification.road_class &&
|
|
||||||
road_edge_data.name_id != EMPTY_NAMEID &&
|
|
||||||
road_edge_data.name_id == source_edge_data.name_id && road.entry_allowed &&
|
|
||||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE;
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool hasNext = next_road != intersection.end();
|
|
||||||
if (!hasNext)
|
|
||||||
{
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Threshold check, if the intersection is too far away, don't bother continuing
|
|
||||||
const auto &next_road_data = node_based_graph.GetEdgeData(next_road->turn.eid);
|
|
||||||
if (next_road_data.distance > MAX_SLIPROAD_THRESHOLD)
|
|
||||||
{
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto next_intersection_node = node_based_graph.GetTarget(next_road->turn.eid);
|
|
||||||
|
|
||||||
const auto next_road_next_intersection = [&]() {
|
|
||||||
auto intersection = intersection_generator(intersection_node_id, next_road->turn.eid);
|
|
||||||
auto in_edge = next_road->turn.eid;
|
|
||||||
//skip over traffic lights
|
|
||||||
if(intersection.size() == 2)
|
|
||||||
{
|
|
||||||
const auto node = node_based_graph.GetTarget(in_edge);
|
|
||||||
in_edge = intersection[1].turn.eid;
|
|
||||||
next_intersection_node = node_based_graph.GetTarget(in_edge);
|
|
||||||
intersection = intersection_generator(node, in_edge);
|
|
||||||
}
|
|
||||||
return intersection;
|
|
||||||
}();
|
|
||||||
|
|
||||||
std::unordered_set<NameID> target_road_names;
|
|
||||||
|
|
||||||
for (const auto &road : next_road_next_intersection)
|
|
||||||
{
|
|
||||||
const auto &target_data = node_based_graph.GetEdgeData(road.turn.eid);
|
|
||||||
target_road_names.insert(target_data.name_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &road : intersection)
|
|
||||||
{
|
|
||||||
if (linkTest(road))
|
|
||||||
{
|
|
||||||
const auto target_intersection = [&](NodeID node, EdgeID eid) {
|
|
||||||
auto intersection = intersection_generator(node, eid);
|
|
||||||
//skip over traffic lights
|
|
||||||
if(intersection.size() == 2)
|
|
||||||
{
|
|
||||||
node = node_based_graph.GetTarget(eid);
|
|
||||||
eid = intersection[1].turn.eid;
|
|
||||||
intersection = intersection_generator(node, eid);
|
|
||||||
}
|
|
||||||
return intersection;
|
|
||||||
}(intersection_node_id, road.turn.eid);
|
|
||||||
|
|
||||||
for (const auto &candidate_road : target_intersection)
|
|
||||||
{
|
|
||||||
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid);
|
|
||||||
if (target_road_names.count(candidate_data.name_id) > 0 &&
|
|
||||||
node_based_graph.GetTarget(candidate_road.turn.eid) == next_intersection_node)
|
|
||||||
{
|
|
||||||
road.turn.instruction.type = TurnType::Sliproad;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_road->turn.instruction.type == TurnType::Fork)
|
|
||||||
{
|
|
||||||
const auto &next_data = node_based_graph.GetEdgeData(next_road->turn.eid);
|
|
||||||
if (next_data.name_id == source_edge_data.name_id)
|
|
||||||
{
|
|
||||||
if (angularDeviation(next_road->turn.angle, STRAIGHT_ANGLE) < 5)
|
|
||||||
next_road->turn.instruction.type = TurnType::Suppressed;
|
|
||||||
else
|
|
||||||
next_road->turn.instruction.type = TurnType::Continue;
|
|
||||||
next_road->turn.instruction.direction_modifier =
|
|
||||||
getTurnDirection(next_road->turn.angle);
|
|
||||||
}
|
|
||||||
else if (next_data.name_id != EMPTY_NAMEID)
|
|
||||||
{
|
|
||||||
next_road->turn.instruction.type = TurnType::NewName;
|
|
||||||
next_road->turn.instruction.direction_modifier =
|
|
||||||
getTurnDirection(next_road->turn.angle);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
next_road->turn.instruction.type = TurnType::Suppressed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersection;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IntersectionGenerator &TurnAnalysis::getGenerator() const { return intersection_generator; }
|
const IntersectionGenerator &TurnAnalysis::getGenerator() const { return intersection_generator; }
|
||||||
|
|
||||||
} // namespace guidance
|
} // namespace guidance
|
||||||
|
@ -29,32 +29,30 @@ TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TurnHandler::~TurnHandler() = default;
|
|
||||||
|
|
||||||
bool TurnHandler::canProcess(const NodeID, const EdgeID, const Intersection &) const
|
bool TurnHandler::canProcess(const NodeID, const EdgeID, const Intersection &) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection TurnHandler::
|
Intersection TurnHandler::
|
||||||
operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const
|
operator()(const NodeID, const EdgeID via_edge, Intersection intersection) const
|
||||||
{
|
{
|
||||||
if (intersection.size() == 1)
|
if (intersection.size() == 1)
|
||||||
return handleOneWayTurn(std::move(intersection));
|
return handleOneWayTurn(std::move(intersection));
|
||||||
|
|
||||||
if (intersection[0].entry_allowed)
|
if (intersection[0].entry_allowed)
|
||||||
{
|
{
|
||||||
intersection[0].turn.instruction = {findBasicTurnType(via_eid, intersection[0]),
|
intersection[0].turn.instruction = {findBasicTurnType(via_edge, intersection[0]),
|
||||||
DirectionModifier::UTurn};
|
DirectionModifier::UTurn};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersection.size() == 2)
|
if (intersection.size() == 2)
|
||||||
return handleTwoWayTurn(via_eid, std::move(intersection));
|
return handleTwoWayTurn(via_edge, std::move(intersection));
|
||||||
|
|
||||||
if (intersection.size() == 3)
|
if (intersection.size() == 3)
|
||||||
return handleThreeWayTurn(via_eid, std::move(intersection));
|
return handleThreeWayTurn(via_edge, std::move(intersection));
|
||||||
|
|
||||||
return handleComplexTurn(via_eid, std::move(intersection));
|
return handleComplexTurn(via_edge, std::move(intersection));
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection TurnHandler::handleOneWayTurn(Intersection intersection) const
|
Intersection TurnHandler::handleOneWayTurn(Intersection intersection) const
|
||||||
@ -72,14 +70,11 @@ Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection i
|
|||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const
|
bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
|
||||||
|
const ConnectedRoad &road,
|
||||||
|
const ConnectedRoad &other) const
|
||||||
{
|
{
|
||||||
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||||
const auto &first_data = node_based_graph.GetEdgeData(intersection[1].turn.eid);
|
|
||||||
const auto &second_data = node_based_graph.GetEdgeData(intersection[2].turn.eid);
|
|
||||||
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
|
||||||
const auto isObviousOfTwo = [this, in_data](const ConnectedRoad road,
|
|
||||||
const ConnectedRoad other) {
|
|
||||||
const auto first_class =
|
const auto first_class =
|
||||||
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
|
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
|
||||||
|
|
||||||
@ -96,16 +91,15 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
const bool other_is_obvious_by_road_class =
|
const bool other_is_obvious_by_road_class =
|
||||||
(!isRampClass(second_class) &&
|
(!isRampClass(second_class) && (2 * getPriority(second_class) < getPriority(first_class)) &&
|
||||||
(2 * getPriority(second_class) < getPriority(first_class)) &&
|
|
||||||
in_data.road_classification.road_class == second_class) ||
|
in_data.road_classification.road_class == second_class) ||
|
||||||
(!isLowPriorityRoadClass(second_class) && isLowPriorityRoadClass(first_class));
|
(!isLowPriorityRoadClass(second_class) && isLowPriorityRoadClass(first_class));
|
||||||
|
|
||||||
if (other_is_obvious_by_road_class)
|
if (other_is_obvious_by_road_class)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const bool turn_is_perfectly_straight = angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
|
const bool turn_is_perfectly_straight =
|
||||||
std::numeric_limits<double>::epsilon();
|
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < std::numeric_limits<double>::epsilon();
|
||||||
|
|
||||||
if (turn_is_perfectly_straight && in_data.name_id != EMPTY_NAMEID &&
|
if (turn_is_perfectly_straight && in_data.name_id != EMPTY_NAMEID &&
|
||||||
in_data.name_id == node_based_graph.GetEdgeData(road.turn.eid).name_id)
|
in_data.name_id == node_based_graph.GetEdgeData(road.turn.eid).name_id)
|
||||||
@ -120,8 +114,14 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
FUZZY_ANGLE_DIFFERENCE;
|
FUZZY_ANGLE_DIFFERENCE;
|
||||||
|
|
||||||
return is_much_narrower_than_other;
|
return is_much_narrower_than_other;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const
|
||||||
|
{
|
||||||
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||||
|
const auto &first_data = node_based_graph.GetEdgeData(intersection[1].turn.eid);
|
||||||
|
const auto &second_data = node_based_graph.GetEdgeData(intersection[2].turn.eid);
|
||||||
|
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
||||||
/* Two nearly straight turns -> FORK
|
/* Two nearly straight turns -> FORK
|
||||||
OOOOOOO
|
OOOOOOO
|
||||||
/
|
/
|
||||||
@ -129,54 +129,10 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
\
|
\
|
||||||
OOOOOOO
|
OOOOOOO
|
||||||
*/
|
*/
|
||||||
if (isFork(intersection[0], intersection[1], intersection[2]))
|
const auto fork_range = findFork(via_edge, intersection);
|
||||||
{
|
if (fork_range.first == 1 && fork_range.second == 2)
|
||||||
if (intersection[1].entry_allowed && intersection[2].entry_allowed)
|
|
||||||
{
|
|
||||||
const auto left_class = node_based_graph.GetEdgeData(intersection[2].turn.eid)
|
|
||||||
.road_classification.road_class;
|
|
||||||
const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
|
|
||||||
.road_classification.road_class;
|
|
||||||
if (isObviousOfTwo(intersection[1], intersection[2]) &&
|
|
||||||
(second_data.name_id != in_data.name_id ||
|
|
||||||
first_data.name_id == second_data.name_id))
|
|
||||||
{
|
|
||||||
intersection[1].turn.instruction =
|
|
||||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
|
|
||||||
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
||||||
DirectionModifier::SlightLeft};
|
|
||||||
}
|
|
||||||
else if (isObviousOfTwo(intersection[2], intersection[1]) &&
|
|
||||||
(first_data.name_id != in_data.name_id ||
|
|
||||||
first_data.name_id == second_data.name_id))
|
|
||||||
{
|
|
||||||
intersection[2].turn.instruction =
|
|
||||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
|
|
||||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
||||||
DirectionModifier::SlightRight};
|
|
||||||
}
|
|
||||||
else if (canBeSeenAsFork(left_class, right_class))
|
|
||||||
{
|
|
||||||
assignFork(via_edge, intersection[2], intersection[1]);
|
assignFork(via_edge, intersection[2], intersection[1]);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
||||||
DirectionModifier::SlightRight};
|
|
||||||
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
||||||
DirectionModifier::SlightLeft};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (intersection[1].entry_allowed)
|
|
||||||
intersection[1].turn.instruction =
|
|
||||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
|
|
||||||
if (intersection[2].entry_allowed)
|
|
||||||
intersection[2].turn.instruction =
|
|
||||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* T Intersection
|
/* T Intersection
|
||||||
|
|
||||||
OOOOOOO T OOOOOOOO
|
OOOOOOO T OOOOOOOO
|
||||||
@ -185,8 +141,8 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
I
|
I
|
||||||
*/
|
*/
|
||||||
else if (isEndOfRoad(intersection[0], intersection[1], intersection[2]) &&
|
else if (isEndOfRoad(intersection[0], intersection[1], intersection[2]) &&
|
||||||
!isObviousOfTwo(intersection[1], intersection[2]) &&
|
!isObviousOfTwo(via_edge, intersection[1], intersection[2]) &&
|
||||||
!isObviousOfTwo(intersection[2], intersection[1]))
|
!isObviousOfTwo(via_edge, intersection[2], intersection[1]))
|
||||||
{
|
{
|
||||||
if (intersection[1].entry_allowed)
|
if (intersection[1].entry_allowed)
|
||||||
{
|
{
|
||||||
@ -206,7 +162,7 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isObviousOfTwo(intersection[1], intersection[2]) &&
|
if (isObviousOfTwo(via_edge, intersection[1], intersection[2]) &&
|
||||||
(in_data.name_id != second_data.name_id || first_data.name_id == second_data.name_id))
|
(in_data.name_id != second_data.name_id || first_data.name_id == second_data.name_id))
|
||||||
{
|
{
|
||||||
intersection[1].turn.instruction = getInstructionForObvious(
|
intersection[1].turn.instruction = getInstructionForObvious(
|
||||||
@ -218,7 +174,7 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
getTurnDirection(intersection[1].turn.angle)};
|
getTurnDirection(intersection[1].turn.angle)};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isObviousOfTwo(intersection[2], intersection[1]) &&
|
if (isObviousOfTwo(via_edge, intersection[2], intersection[1]) &&
|
||||||
(in_data.name_id != first_data.name_id || first_data.name_id == second_data.name_id))
|
(in_data.name_id != first_data.name_id || first_data.name_id == second_data.name_id))
|
||||||
{
|
{
|
||||||
intersection[2].turn.instruction = getInstructionForObvious(
|
intersection[2].turn.instruction = getInstructionForObvious(
|
||||||
@ -236,7 +192,7 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
|||||||
Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection intersection) const
|
Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection intersection) const
|
||||||
{
|
{
|
||||||
const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
|
const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
|
||||||
const auto fork_range = findFork(intersection);
|
const auto fork_range = findFork(via_edge, intersection);
|
||||||
std::size_t straightmost_turn = 0;
|
std::size_t straightmost_turn = 0;
|
||||||
double straightmost_deviation = 180;
|
double straightmost_deviation = 180;
|
||||||
for (std::size_t i = 0; i < intersection.size(); ++i)
|
for (std::size_t i = 0; i < intersection.size(); ++i)
|
||||||
@ -358,119 +314,6 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
|
|||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t TurnHandler::findObviousTurn(const EdgeID via_edge,
|
|
||||||
const Intersection &intersection) const
|
|
||||||
{
|
|
||||||
// no obvious road
|
|
||||||
if (intersection.size() == 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// a single non u-turn is obvious
|
|
||||||
if (intersection.size() == 2)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// at least three roads
|
|
||||||
std::size_t best = 0;
|
|
||||||
double best_deviation = 180;
|
|
||||||
|
|
||||||
std::size_t best_continue = 0;
|
|
||||||
double best_continue_deviation = 180;
|
|
||||||
|
|
||||||
const EdgeData &in_data = node_based_graph.GetEdgeData(via_edge);
|
|
||||||
const auto in_class = in_data.road_classification.road_class;
|
|
||||||
for (std::size_t i = 1; i < intersection.size(); ++i)
|
|
||||||
{
|
|
||||||
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
|
|
||||||
if (intersection[i].entry_allowed && deviation < best_deviation)
|
|
||||||
{
|
|
||||||
best_deviation = deviation;
|
|
||||||
best = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
|
|
||||||
auto continue_class = node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
|
|
||||||
.road_classification.road_class;
|
|
||||||
if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
|
|
||||||
(best_continue == 0 || (continue_class > out_data.road_classification.road_class &&
|
|
||||||
in_class != continue_class) ||
|
|
||||||
(deviation < best_continue_deviation &&
|
|
||||||
(out_data.road_classification.road_class == continue_class ||
|
|
||||||
in_class == out_data.road_classification.road_class))))
|
|
||||||
{
|
|
||||||
best_continue_deviation = deviation;
|
|
||||||
best_continue = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (best_deviation >= 2 * NARROW_TURN_ANGLE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// has no obvious continued road
|
|
||||||
if (best_continue == 0 || best_continue_deviation >= 2 * NARROW_TURN_ANGLE ||
|
|
||||||
(node_based_graph.GetEdgeData(intersection[best_continue].turn.eid)
|
|
||||||
.road_classification.road_class ==
|
|
||||||
node_based_graph.GetEdgeData(intersection[best].turn.eid)
|
|
||||||
.road_classification.road_class &&
|
|
||||||
std::abs(best_continue_deviation) > 1 && best_deviation / best_continue_deviation < 0.75))
|
|
||||||
{
|
|
||||||
// Find left/right deviation
|
|
||||||
const double left_deviation = angularDeviation(
|
|
||||||
intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
|
|
||||||
const double right_deviation =
|
|
||||||
angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
|
|
||||||
|
|
||||||
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
|
||||||
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
|
||||||
return best;
|
|
||||||
|
|
||||||
// other narrow turns?
|
|
||||||
if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
|
|
||||||
FUZZY_ANGLE_DIFFERENCE)
|
|
||||||
return 0;
|
|
||||||
if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
|
|
||||||
STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Well distinct turn that is nearly straight
|
|
||||||
if ((left_deviation / best_deviation >= DISTINCTION_RATIO ||
|
|
||||||
(left_deviation > best_deviation &&
|
|
||||||
!intersection[(best + 1) % intersection.size()].entry_allowed)) &&
|
|
||||||
(right_deviation / best_deviation >= DISTINCTION_RATIO ||
|
|
||||||
(right_deviation > best_deviation && !intersection[best - 1].entry_allowed)))
|
|
||||||
{
|
|
||||||
return best;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const double deviation =
|
|
||||||
angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE);
|
|
||||||
const auto &continue_data =
|
|
||||||
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
|
|
||||||
if (std::abs(deviation) < 1)
|
|
||||||
return best_continue;
|
|
||||||
|
|
||||||
// check if any other similar best continues exist
|
|
||||||
for (std::size_t i = 1; i < intersection.size(); ++i)
|
|
||||||
{
|
|
||||||
if (i == best_continue || !intersection[i].entry_allowed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE) / deviation < 1.1 &&
|
|
||||||
continue_data.road_classification.road_class ==
|
|
||||||
node_based_graph.GetEdgeData(intersection[i].turn.eid)
|
|
||||||
.road_classification.road_class)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return best_continue; // no obvious turn
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assignment of left turns hands of to right turns.
|
// Assignment of left turns hands of to right turns.
|
||||||
// To do so, we mirror every road segment and reverse the order.
|
// To do so, we mirror every road segment and reverse the order.
|
||||||
// After the mirror and reversal / we assign right turns and
|
// After the mirror and reversal / we assign right turns and
|
||||||
@ -631,7 +474,8 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
|
|||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::size_t, std::size_t> TurnHandler::findFork(const Intersection &intersection) const
|
std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
|
||||||
|
const Intersection &intersection) const
|
||||||
{
|
{
|
||||||
|
|
||||||
std::size_t best = 0;
|
std::size_t best = 0;
|
||||||
@ -650,39 +494,67 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const Intersection &in
|
|||||||
if (best_deviation <= NARROW_TURN_ANGLE)
|
if (best_deviation <= NARROW_TURN_ANGLE)
|
||||||
{
|
{
|
||||||
std::size_t left = best, right = best;
|
std::size_t left = best, right = best;
|
||||||
if (intersection[best].turn.angle >= 180)
|
|
||||||
{
|
|
||||||
// due to best > 1, we can safely decrement right
|
|
||||||
--right;
|
|
||||||
if (angularDeviation(intersection[right].turn.angle, STRAIGHT_ANGLE) >
|
|
||||||
NARROW_TURN_ANGLE)
|
|
||||||
return std::make_pair(std::size_t{0}, std::size_t{0});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++left;
|
|
||||||
if (left >= intersection.size() ||
|
|
||||||
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE)
|
|
||||||
return std::make_pair(std::size_t{0}, std::size_t{0});
|
|
||||||
}
|
|
||||||
while (left + 1 < intersection.size() &&
|
while (left + 1 < intersection.size() &&
|
||||||
angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
|
(angularDeviation(intersection[left + 1].turn.angle, STRAIGHT_ANGLE) <=
|
||||||
NARROW_TURN_ANGLE &&
|
NARROW_TURN_ANGLE ||
|
||||||
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)
|
(angularDeviation(intersection[left].turn.angle,
|
||||||
|
intersection[left + 1].turn.angle) <= NARROW_TURN_ANGLE &&
|
||||||
|
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
|
||||||
++left;
|
++left;
|
||||||
while (right > 1 &&
|
while (
|
||||||
angularDeviation(intersection[right].turn.angle,
|
right > 1 &&
|
||||||
intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE &&
|
(angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <=
|
||||||
angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)
|
NARROW_TURN_ANGLE ||
|
||||||
|
(angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) <
|
||||||
|
NARROW_TURN_ANGLE &&
|
||||||
|
angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
|
||||||
--right;
|
--right;
|
||||||
|
|
||||||
// TODO check whether 2*NARROW_TURN is too large
|
if (left == right)
|
||||||
if (0 < right && right < left &&
|
return std::make_pair(std::size_t{0}, std::size_t{0});
|
||||||
|
|
||||||
|
const bool valid_indices = 0 < right && right < left;
|
||||||
|
const bool separated_at_left_side =
|
||||||
angularDeviation(intersection[left].turn.angle,
|
angularDeviation(intersection[left].turn.angle,
|
||||||
intersection[(left + 1) % intersection.size()].turn.angle) >=
|
intersection[(left + 1) % intersection.size()].turn.angle) >=
|
||||||
GROUP_ANGLE &&
|
GROUP_ANGLE;
|
||||||
|
const bool separated_at_right_side =
|
||||||
|
right > 0 &&
|
||||||
angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
|
angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
|
||||||
GROUP_ANGLE)
|
GROUP_ANGLE;
|
||||||
|
|
||||||
|
const bool not_more_than_three = (left - right) <= 2;
|
||||||
|
const bool has_obvious = [&]() {
|
||||||
|
if (left - right == 1)
|
||||||
|
{
|
||||||
|
return isObviousOfTwo(via_edge, intersection[left], intersection[right]) ||
|
||||||
|
isObviousOfTwo(via_edge, intersection[right], intersection[left]);
|
||||||
|
}
|
||||||
|
else if (left - right == 2)
|
||||||
|
{
|
||||||
|
return isObviousOfTwo(via_edge, intersection[right + 1], intersection[right]) ||
|
||||||
|
isObviousOfTwo(via_edge, intersection[right], intersection[right + 1]) ||
|
||||||
|
isObviousOfTwo(via_edge, intersection[left], intersection[right + 1]) ||
|
||||||
|
isObviousOfTwo(via_edge, intersection[right + 1], intersection[left]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const bool has_compatible_classes = [&]() {
|
||||||
|
const bool ramp_class =
|
||||||
|
isLinkClass(node_based_graph.GetEdgeData(intersection[right].turn.eid)
|
||||||
|
.road_classification.road_class);
|
||||||
|
for (std::size_t index = right + 1; index <= left; ++index)
|
||||||
|
if (ramp_class !=
|
||||||
|
isLinkClass(node_based_graph.GetEdgeData(intersection[index].turn.eid)
|
||||||
|
.road_classification.road_class))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// TODO check whether 2*NARROW_TURN is too large
|
||||||
|
if (valid_indices && separated_at_left_side && separated_at_right_side &&
|
||||||
|
not_more_than_three && !has_obvious && has_compatible_classes)
|
||||||
return std::make_pair(right, left);
|
return std::make_pair(right, left);
|
||||||
}
|
}
|
||||||
return std::make_pair(std::size_t{0}, std::size_t{0});
|
return std::make_pair(std::size_t{0}, std::size_t{0});
|
||||||
|
Loading…
Reference in New Issue
Block a user