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
|
||||
| waypoints | route | turns |
|
||||
| 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 util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
virtual ~IntersectionHandler();
|
||||
|
||||
virtual ~IntersectionHandler() = default;
|
||||
|
||||
// check whether the handler can actually handle the intersection
|
||||
virtual bool
|
||||
@ -51,6 +52,9 @@ class IntersectionHandler
|
||||
// Decide on a basic turn types
|
||||
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
|
||||
TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
|
||||
const EdgeID via_edge,
|
||||
|
@ -10,11 +10,6 @@ namespace extractor
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
// possible fork
|
||||
bool isFork(const ConnectedRoad &uturn,
|
||||
const ConnectedRoad &possible_right_fork,
|
||||
const ConnectedRoad &possible_left_fork);
|
||||
|
||||
// Ending in a T-Intersection
|
||||
bool isEndOfRoad(const ConnectedRoad &uturn,
|
||||
const ConnectedRoad &possible_right_turn,
|
||||
|
@ -26,7 +26,8 @@ class MotorwayHandler : public IntersectionHandler
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
~MotorwayHandler() override final;
|
||||
|
||||
~MotorwayHandler() override final = default;
|
||||
|
||||
// check whether the handler can actually handle the intersection
|
||||
bool canProcess(const NodeID nid,
|
||||
|
@ -44,7 +44,7 @@ class RoundaboutHandler : public IntersectionHandler
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
||||
~RoundaboutHandler() override final;
|
||||
~RoundaboutHandler() override final = default;
|
||||
|
||||
// check whether the handler can actually handle the intersection
|
||||
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?
|
||||
// A fork can happen between road types that are at most 1 priority apart from each other
|
||||
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)];
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/motorway_handler.hpp"
|
||||
#include "extractor/guidance/roundabout_handler.hpp"
|
||||
#include "extractor/guidance/sliproad_handler.hpp"
|
||||
#include "extractor/guidance/toolkit.hpp"
|
||||
#include "extractor/guidance/turn_classification.hpp"
|
||||
#include "extractor/guidance/turn_handler.hpp"
|
||||
@ -59,13 +60,11 @@ class TurnAnalysis
|
||||
const RoundaboutHandler roundabout_handler;
|
||||
const MotorwayHandler motorway_handler;
|
||||
const TurnHandler turn_handler;
|
||||
const SliproadHandler sliproad_handler;
|
||||
|
||||
// Utility function, setting basic turn types. Prepares for normal turn handling.
|
||||
Intersection
|
||||
setTurnTypes(const NodeID from, const EdgeID via_edge, Intersection intersection) const;
|
||||
|
||||
Intersection handleSliproads(const NodeID intersection_node_id,
|
||||
Intersection intersection) const;
|
||||
}; // class TurnAnalysis
|
||||
|
||||
} // namespace guidance
|
||||
|
@ -28,7 +28,8 @@ class TurnHandler : public IntersectionHandler
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
~TurnHandler() override final;
|
||||
|
||||
~TurnHandler() override final = default;
|
||||
|
||||
// check whether the handler can actually handle the intersection
|
||||
bool canProcess(const NodeID nid,
|
||||
@ -41,6 +42,9 @@ class TurnHandler : public IntersectionHandler
|
||||
Intersection intersection) const override final;
|
||||
|
||||
private:
|
||||
bool isObviousOfTwo(const EdgeID via_edge,
|
||||
const ConnectedRoad &road,
|
||||
const ConnectedRoad &other) const;
|
||||
// Dead end.
|
||||
Intersection handleOneWayTurn(Intersection intersection) const;
|
||||
|
||||
@ -57,8 +61,7 @@ class TurnHandler : public IntersectionHandler
|
||||
handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
|
||||
|
||||
// Classification
|
||||
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
|
||||
std::pair<std::size_t, std::size_t> findFork(const Intersection &intersection) const;
|
||||
std::pair<std::size_t, std::size_t> findFork(const EdgeID via_edge, const Intersection &intersection) const;
|
||||
|
||||
Intersection assignLeftTurns(const EdgeID via_edge,
|
||||
Intersection intersection,
|
||||
|
@ -720,34 +720,45 @@ std::vector<RouteStep> collapseTurns(std::vector<RouteStep> steps)
|
||||
// TurnType::Sliproad != TurnType::NoTurn
|
||||
if (one_back_step.maneuver.instruction.type == TurnType::Sliproad)
|
||||
{
|
||||
// Handle possible u-turns between highways that look like slip-roads
|
||||
if (steps[getPreviousIndex(one_back_index)].name_id == steps[step_index].name_id &&
|
||||
steps[step_index].name_id != EMPTY_NAMEID)
|
||||
if (current_step.maneuver.instruction.type == TurnType::Suppressed &&
|
||||
compatible(one_back_step, current_step))
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
|
||||
// Traffic light on the sliproad
|
||||
steps[one_back_index] =
|
||||
elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||
invalidateStep(steps[step_index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
if (compatible(one_back_step, current_step))
|
||||
{
|
||||
steps[one_back_index] =
|
||||
elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||
steps[one_back_index].name_id = steps[step_index].name_id;
|
||||
steps[one_back_index].name = steps[step_index].name;
|
||||
// Handle possible u-turns between highways that look like slip-roads
|
||||
if (steps[getPreviousIndex(one_back_index)].name_id == steps[step_index].name_id &&
|
||||
steps[step_index].name_id != EMPTY_NAMEID)
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
steps[one_back_index].maneuver.instruction.type = TurnType::Turn;
|
||||
}
|
||||
if (compatible(one_back_step, current_step))
|
||||
{
|
||||
steps[one_back_index] =
|
||||
elongate(std::move(steps[one_back_index]), steps[step_index]);
|
||||
steps[one_back_index].name_id = steps[step_index].name_id;
|
||||
steps[one_back_index].name = steps[step_index].name;
|
||||
|
||||
const auto exit_intersection = steps[step_index].intersections.front();
|
||||
const auto exit_bearing = exit_intersection.bearings[exit_intersection.out];
|
||||
const auto exit_intersection = steps[step_index].intersections.front();
|
||||
const auto exit_bearing = exit_intersection.bearings[exit_intersection.out];
|
||||
|
||||
const auto entry_intersection = steps[one_back_index].intersections.front();
|
||||
const auto entry_bearing = entry_intersection.bearings[entry_intersection.in];
|
||||
const auto entry_intersection = steps[one_back_index].intersections.front();
|
||||
const auto entry_bearing = entry_intersection.bearings[entry_intersection.in];
|
||||
|
||||
const double angle =
|
||||
turn_angle(util::bearing::reverseBearing(entry_bearing), exit_bearing);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
::osrm::util::guidance::getTurnDirection(angle);
|
||||
invalidateStep(steps[step_index]);
|
||||
const double angle =
|
||||
turn_angle(util::bearing::reverseBearing(entry_bearing), exit_bearing);
|
||||
steps[one_back_index].maneuver.instruction.direction_modifier =
|
||||
::osrm::util::guidance::getTurnDirection(angle);
|
||||
invalidateStep(steps[step_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Due to empty segments, we can get name-changes from A->A
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "extractor/guidance/intersection_handler.hpp"
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/intersection_handler.hpp"
|
||||
#include "extractor/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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 extractor
|
||||
} // namespace osrm
|
||||
|
@ -13,14 +13,6 @@ namespace extractor
|
||||
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 &,
|
||||
const ConnectedRoad &possible_right_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,
|
||||
const EdgeID via_eid,
|
||||
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,
|
||||
const EdgeID via_eid,
|
||||
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,
|
||||
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
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
// "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; }
|
||||
|
||||
} // 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
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
return handleOneWayTurn(std::move(intersection));
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
if (intersection.size() == 2)
|
||||
return handleTwoWayTurn(via_eid, std::move(intersection));
|
||||
return handleTwoWayTurn(via_edge, std::move(intersection));
|
||||
|
||||
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
|
||||
@ -72,56 +70,58 @@ Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection i
|
||||
return intersection;
|
||||
}
|
||||
|
||||
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 first_class =
|
||||
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
|
||||
|
||||
const auto second_class =
|
||||
node_based_graph.GetEdgeData(other.turn.eid).road_classification.road_class;
|
||||
|
||||
const bool is_ramp = isRampClass(first_class);
|
||||
const bool is_obvious_by_road_class =
|
||||
(!is_ramp && (2 * getPriority(first_class) < getPriority(second_class)) &&
|
||||
in_data.road_classification.road_class == first_class) ||
|
||||
(!isLowPriorityRoadClass(first_class) && isLowPriorityRoadClass(second_class));
|
||||
|
||||
if (is_obvious_by_road_class)
|
||||
return true;
|
||||
|
||||
const bool other_is_obvious_by_road_class =
|
||||
(!isRampClass(second_class) && (2 * getPriority(second_class) < getPriority(first_class)) &&
|
||||
in_data.road_classification.road_class == second_class) ||
|
||||
(!isLowPriorityRoadClass(second_class) && isLowPriorityRoadClass(first_class));
|
||||
|
||||
if (other_is_obvious_by_road_class)
|
||||
return false;
|
||||
|
||||
const bool turn_is_perfectly_straight =
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < std::numeric_limits<double>::epsilon();
|
||||
|
||||
if (turn_is_perfectly_straight && in_data.name_id != EMPTY_NAMEID &&
|
||||
in_data.name_id == node_based_graph.GetEdgeData(road.turn.eid).name_id)
|
||||
return true;
|
||||
|
||||
const bool is_much_narrower_than_other =
|
||||
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
|
||||
INCREASES_BY_FOURTY_PERCENT &&
|
||||
angularDeviation(angularDeviation(other.turn.angle, STRAIGHT_ANGLE),
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE)) >
|
||||
FUZZY_ANGLE_DIFFERENCE;
|
||||
|
||||
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);
|
||||
const auto isObviousOfTwo = [this, in_data](const ConnectedRoad road,
|
||||
const ConnectedRoad other) {
|
||||
const auto first_class =
|
||||
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
|
||||
|
||||
const auto second_class =
|
||||
node_based_graph.GetEdgeData(other.turn.eid).road_classification.road_class;
|
||||
|
||||
const bool is_ramp = isRampClass(first_class);
|
||||
const bool is_obvious_by_road_class =
|
||||
(!is_ramp && (2 * getPriority(first_class) < getPriority(second_class)) &&
|
||||
in_data.road_classification.road_class == first_class) ||
|
||||
(!isLowPriorityRoadClass(first_class) && isLowPriorityRoadClass(second_class));
|
||||
|
||||
if (is_obvious_by_road_class)
|
||||
return true;
|
||||
|
||||
const bool other_is_obvious_by_road_class =
|
||||
(!isRampClass(second_class) &&
|
||||
(2 * getPriority(second_class) < getPriority(first_class)) &&
|
||||
in_data.road_classification.road_class == second_class) ||
|
||||
(!isLowPriorityRoadClass(second_class) && isLowPriorityRoadClass(first_class));
|
||||
|
||||
if (other_is_obvious_by_road_class)
|
||||
return false;
|
||||
|
||||
const bool turn_is_perfectly_straight = angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
|
||||
std::numeric_limits<double>::epsilon();
|
||||
|
||||
if (turn_is_perfectly_straight && in_data.name_id != EMPTY_NAMEID &&
|
||||
in_data.name_id == node_based_graph.GetEdgeData(road.turn.eid).name_id)
|
||||
return true;
|
||||
|
||||
const bool is_much_narrower_than_other =
|
||||
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
|
||||
INCREASES_BY_FOURTY_PERCENT &&
|
||||
angularDeviation(angularDeviation(other.turn.angle, STRAIGHT_ANGLE),
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE)) >
|
||||
FUZZY_ANGLE_DIFFERENCE;
|
||||
|
||||
return is_much_narrower_than_other;
|
||||
};
|
||||
|
||||
/* Two nearly straight turns -> FORK
|
||||
OOOOOOO
|
||||
/
|
||||
@ -129,54 +129,10 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
||||
\
|
||||
OOOOOOO
|
||||
*/
|
||||
if (isFork(intersection[0], intersection[1], intersection[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]);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
}
|
||||
const auto fork_range = findFork(via_edge, intersection);
|
||||
if (fork_range.first == 1 && fork_range.second == 2)
|
||||
assignFork(via_edge, intersection[2], intersection[1]);
|
||||
|
||||
/* T Intersection
|
||||
|
||||
OOOOOOO T OOOOOOOO
|
||||
@ -185,8 +141,8 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
||||
I
|
||||
*/
|
||||
else if (isEndOfRoad(intersection[0], intersection[1], intersection[2]) &&
|
||||
!isObviousOfTwo(intersection[1], intersection[2]) &&
|
||||
!isObviousOfTwo(intersection[2], intersection[1]))
|
||||
!isObviousOfTwo(via_edge, intersection[1], intersection[2]) &&
|
||||
!isObviousOfTwo(via_edge, intersection[2], intersection[1]))
|
||||
{
|
||||
if (intersection[1].entry_allowed)
|
||||
{
|
||||
@ -206,7 +162,7 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
||||
}
|
||||
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))
|
||||
{
|
||||
intersection[1].turn.instruction = getInstructionForObvious(
|
||||
@ -218,7 +174,7 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
||||
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))
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
double straightmost_deviation = 180;
|
||||
for (std::size_t i = 0; i < intersection.size(); ++i)
|
||||
@ -358,119 +314,6 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, 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.
|
||||
// To do so, we mirror every road segment and reverse the order.
|
||||
// After the mirror and reversal / we assign right turns and
|
||||
@ -631,7 +474,8 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
|
||||
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;
|
||||
@ -650,39 +494,67 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const Intersection &in
|
||||
if (best_deviation <= NARROW_TURN_ANGLE)
|
||||
{
|
||||
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() &&
|
||||
angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
|
||||
NARROW_TURN_ANGLE &&
|
||||
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)
|
||||
(angularDeviation(intersection[left + 1].turn.angle, STRAIGHT_ANGLE) <=
|
||||
NARROW_TURN_ANGLE ||
|
||||
(angularDeviation(intersection[left].turn.angle,
|
||||
intersection[left + 1].turn.angle) <= NARROW_TURN_ANGLE &&
|
||||
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
|
||||
++left;
|
||||
while (right > 1 &&
|
||||
angularDeviation(intersection[right].turn.angle,
|
||||
intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE &&
|
||||
angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)
|
||||
while (
|
||||
right > 1 &&
|
||||
(angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_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;
|
||||
|
||||
// TODO check whether 2*NARROW_TURN is too large
|
||||
if (0 < right && right < left &&
|
||||
if (left == right)
|
||||
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,
|
||||
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) >=
|
||||
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(std::size_t{0}, std::size_t{0});
|
||||
|
Loading…
Reference in New Issue
Block a user