2016-03-01 16:30:31 -05:00
|
|
|
#include "extractor/guidance/turn_analysis.hpp"
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-02-26 11:33:18 -05:00
|
|
|
#include "util/simple_logger.hpp"
|
2016-03-03 09:36:03 -05:00
|
|
|
#include "util/coordinate.hpp"
|
2016-02-26 11:33:18 -05:00
|
|
|
|
|
|
|
#include <cstddef>
|
2016-03-04 06:17:06 -05:00
|
|
|
#include <limits>
|
2016-03-04 09:10:33 -05:00
|
|
|
#include <iomanip>
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-02-25 08:40:26 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
2016-03-01 16:30:31 -05:00
|
|
|
namespace guidance
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
|
|
|
// configuration of turn classification
|
|
|
|
const bool constexpr INVERT = true;
|
|
|
|
|
|
|
|
// what angle is interpreted as going straight
|
|
|
|
const double constexpr STRAIGHT_ANGLE = 180.;
|
|
|
|
// if a turn deviates this much from going straight, it will be kept straight
|
2016-03-07 08:52:26 -05:00
|
|
|
const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
|
2016-02-25 08:40:26 -05:00
|
|
|
// angle that lies between two nearly indistinguishable roads
|
2016-03-07 08:52:26 -05:00
|
|
|
const double constexpr NARROW_TURN_ANGLE = 30.;
|
|
|
|
const double constexpr GROUP_ANGLE = 90;
|
2016-02-25 08:40:26 -05:00
|
|
|
// angle difference that can be classified as straight, if its the only narrow turn
|
2016-02-26 11:33:18 -05:00
|
|
|
const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
|
2016-02-25 08:40:26 -05:00
|
|
|
const double constexpr DISTINCTION_RATIO = 2;
|
2016-02-26 11:33:18 -05:00
|
|
|
const unsigned constexpr INVALID_NAME_ID = 0;
|
2016-02-25 08:40:26 -05:00
|
|
|
|
|
|
|
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed)
|
|
|
|
: turn(turn), entry_allowed(entry_allowed)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:30:33 -05:00
|
|
|
bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
|
|
|
return !from.IsCompatibleTo(to);
|
|
|
|
}
|
|
|
|
|
2016-03-03 09:36:03 -05:00
|
|
|
struct Localizer
|
|
|
|
{
|
|
|
|
const std::vector<QueryNode> *node_info_list = nullptr;
|
|
|
|
|
|
|
|
util::Coordinate operator()(const NodeID nid)
|
|
|
|
{
|
|
|
|
if (node_info_list)
|
|
|
|
{
|
|
|
|
return {(*node_info_list)[nid].lon, (*node_info_list)[nid].lat};
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Localizer localizer;
|
|
|
|
|
2016-03-08 06:40:45 -05:00
|
|
|
TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
|
|
|
const std::vector<QueryNode> &node_info_list,
|
|
|
|
const RestrictionMap &restriction_map,
|
|
|
|
const std::unordered_set<NodeID> &barrier_nodes,
|
2016-03-16 10:47:33 -04:00
|
|
|
const CompressedEdgeContainer &compressed_edge_container,
|
|
|
|
const util::NameTable &name_table)
|
2016-03-08 06:40:45 -05:00
|
|
|
: node_based_graph(node_based_graph), node_info_list(node_info_list),
|
|
|
|
restriction_map(restriction_map), barrier_nodes(barrier_nodes),
|
2016-03-16 10:47:33 -04:00
|
|
|
compressed_edge_container(compressed_edge_container), name_table(name_table)
|
2016-03-08 06:40:45 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
// some small tool functions to simplify decisions down the line
|
2016-03-08 06:40:45 -05:00
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
inline FunctionalRoadClass roadClass(const ConnectedRoad &road,
|
2016-03-07 08:52:26 -05:00
|
|
|
const util::NodeBasedDynamicGraph &graph)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return graph.GetEdgeData(road.turn.eid).road_classification.road_class;
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
|
2016-03-08 06:40:45 -05:00
|
|
|
inline bool isMotorwayClass(FunctionalRoadClass road_class)
|
|
|
|
{
|
|
|
|
return road_class == FunctionalRoadClass::MOTORWAY || road_class == FunctionalRoadClass::TRUNK;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
|
|
|
|
{
|
|
|
|
return isMotorwayClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
|
|
|
|
{
|
|
|
|
return isRampClass(node_based_graph.GetEdgeData(eid).road_classification.road_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeID via_edge) const
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-03 09:36:03 -05:00
|
|
|
localizer.node_info_list = &node_info_list;
|
2016-03-17 09:09:09 -04:00
|
|
|
auto intersection = getConnectedRoads(from, via_edge);
|
2016-02-25 12:31:29 -05:00
|
|
|
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto &in_edge_data = node_based_graph.GetEdgeData(via_edge);
|
2016-02-26 11:33:18 -05:00
|
|
|
|
|
|
|
// main priority: roundabouts
|
2016-02-25 12:31:29 -05:00
|
|
|
bool on_roundabout = in_edge_data.roundabout;
|
|
|
|
bool can_enter_roundabout = false;
|
2016-03-30 03:53:17 -04:00
|
|
|
bool can_exit_roundabout_separately = false;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto &road : intersection)
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-08 05:30:33 -05:00
|
|
|
// only check actual outgoing edges
|
|
|
|
if (edge_data.reversed)
|
2016-03-07 04:38:13 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (edge_data.roundabout)
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
|
|
|
can_enter_roundabout = true;
|
|
|
|
}
|
2016-03-30 03:53:17 -04:00
|
|
|
// Exiting roundabouts at an entry point is technically a data-modelling issue.
|
|
|
|
// This workaround handles cases in which an exit follows the entry.
|
|
|
|
// To correctly represent perceived exits, we only count exits leading to a
|
|
|
|
// separate vertex than the one we are coming from that are in the direction of
|
|
|
|
// the roundabout.
|
|
|
|
// The sorting of the angles represents a problem for left-sided driving, though.
|
|
|
|
// FIXME in case of left-sided driving, we have to check whether we can enter the
|
|
|
|
// roundabout later in the cycle, rather than prior.
|
|
|
|
else if (node_based_graph.GetTarget(road.turn.eid) != from && !can_enter_roundabout)
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
2016-03-30 03:53:17 -04:00
|
|
|
can_exit_roundabout_separately = true;
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (on_roundabout || can_enter_roundabout)
|
|
|
|
{
|
2016-03-30 03:53:17 -04:00
|
|
|
intersection = handleRoundabouts(via_edge, on_roundabout, can_exit_roundabout_separately,
|
2016-03-17 09:09:09 -04:00
|
|
|
std::move(intersection));
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
// set initial defaults for normal turns and modifier based on angle
|
|
|
|
intersection = setTurnTypes(from, via_edge, std::move(intersection));
|
|
|
|
if (isMotorwayJunction(via_edge, intersection))
|
|
|
|
{
|
|
|
|
intersection = handleMotorwayJunction(via_edge, std::move(intersection));
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (intersection.size() == 1)
|
|
|
|
{
|
|
|
|
intersection = handleOneWayTurn(std::move(intersection));
|
|
|
|
}
|
|
|
|
else if (intersection.size() == 2)
|
|
|
|
{
|
|
|
|
intersection = handleTwoWayTurn(via_edge, std::move(intersection));
|
|
|
|
}
|
|
|
|
else if (intersection.size() == 3)
|
|
|
|
{
|
|
|
|
intersection = handleThreeWayTurn(via_edge, std::move(intersection));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
intersection = handleComplexTurn(via_edge, std::move(intersection));
|
|
|
|
}
|
|
|
|
// complex intersection, potentially requires conflict resolution
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<TurnOperation> turns;
|
|
|
|
for (auto road : intersection)
|
|
|
|
if (road.entry_allowed)
|
|
|
|
turns.emplace_back(road.turn);
|
|
|
|
|
|
|
|
return turns;
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road)
|
2016-03-05 12:17:24 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return road.entry_allowed;
|
2016-03-05 12:17:24 -05:00
|
|
|
});
|
|
|
|
}
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleRoundabouts(const EdgeID via_edge,
|
2016-03-08 06:40:45 -05:00
|
|
|
const bool on_roundabout,
|
2016-03-30 03:53:17 -04:00
|
|
|
const bool can_exit_roundabout_separately,
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
|
|
|
// TODO requires differentiation between roundabouts and rotaries
|
2016-02-26 11:33:18 -05:00
|
|
|
// detect via radius (get via circle through three vertices)
|
2016-03-05 12:17:24 -05:00
|
|
|
NodeID node_v = node_based_graph.GetTarget(via_edge);
|
2016-02-25 12:31:29 -05:00
|
|
|
if (on_roundabout)
|
|
|
|
{
|
|
|
|
// Shoule hopefully have only a single exit and continue
|
|
|
|
// at least for cars. How about bikes?
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
auto &turn = road.turn;
|
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-02-25 12:31:29 -05:00
|
|
|
if (out_data.roundabout)
|
|
|
|
{
|
|
|
|
// TODO can forks happen in roundabouts? E.g. required lane changes
|
2016-03-05 12:17:24 -05:00
|
|
|
if (1 == node_based_graph.GetDirectedOutDegree(node_v))
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
|
|
|
// No turn possible.
|
2016-03-17 09:09:09 -04:00
|
|
|
turn.instruction = TurnInstruction::NO_TURN();
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
turn.instruction =
|
|
|
|
TurnInstruction::REMAIN_ROUNDABOUT(getTurnDirection(turn.angle));
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
turn.instruction = TurnInstruction::EXIT_ROUNDABOUT(getTurnDirection(turn.angle));
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!road.entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
continue;
|
2016-03-17 09:09:09 -04:00
|
|
|
auto &turn = road.turn;
|
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
|
2016-02-25 12:31:29 -05:00
|
|
|
if (out_data.roundabout)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(getTurnDirection(turn.angle));
|
2016-03-30 03:53:17 -04:00
|
|
|
if (can_exit_roundabout_separately)
|
2016-02-25 12:31:29 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (turn.instruction.type == TurnType::EnterRotary)
|
|
|
|
turn.instruction.type = TurnType::EnterRotaryAtExit;
|
|
|
|
if (turn.instruction.type == TurnType::EnterRoundabout)
|
|
|
|
turn.instruction.type = TurnType::EnterRoundaboutAtExit;
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
turn.instruction = {TurnType::EnterAndExitRoundabout, getTurnDirection(turn.angle)};
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-25 12:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-03 09:36:03 -05:00
|
|
|
|
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< "road: " << road.toString() << " Name: " << out_data.name_id
|
2016-03-03 09:36:03 -05:00
|
|
|
<< " Road Class: " << (int)out_data.road_classification.road_class
|
2016-03-17 09:09:09 -04:00
|
|
|
<< " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
|
2016-03-03 09:36:03 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!road.entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
continue;
|
2016-03-03 09:36:03 -05:00
|
|
|
|
2016-03-08 06:40:45 -05:00
|
|
|
const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
|
|
|
|
? TurnType::Merge
|
|
|
|
: TurnType::Turn;
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
|
|
|
|
road.turn.instruction = {type, DirectionModifier::Straight};
|
2016-02-26 11:33:18 -05:00
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {type,
|
|
|
|
road.turn.angle > STRAIGHT_ANGLE
|
|
|
|
? DirectionModifier::SlightLeft
|
|
|
|
: DirectionModifier::SlightRight};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-22 11:27:18 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-03-08 06:40:45 -05:00
|
|
|
BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
unsigned count = 0;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (road.entry_allowed && detail::isMotorwayClass(road.turn.eid, node_based_graph))
|
2016-02-26 11:33:18 -05:00
|
|
|
++count;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
|
|
|
|
// find the angle that continues on our current highway
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
|
|
|
if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
|
2016-03-08 06:40:45 -05:00
|
|
|
in_data.name_id != 0 &&
|
|
|
|
detail::isMotorwayClass(out_data.road_classification.road_class))
|
2016-03-17 09:09:09 -04:00
|
|
|
return road.turn.angle;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection[0].turn.angle;
|
2016-02-26 11:33:18 -05:00
|
|
|
};
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto getMostLikelyContinue =
|
|
|
|
[this, in_data](const std::vector<ConnectedRoad> &intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
double angle = intersection[0].turn.angle;
|
2016-02-26 11:33:18 -05:00
|
|
|
double best = 180;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-08 06:40:45 -05:00
|
|
|
if (detail::isMotorwayClass(out_data.road_classification.road_class) &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
|
|
|
|
angle = road.turn.angle;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return angle;
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto findBestContinue = [&]()
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const double continue_angle = getContinueAngle(intersection);
|
|
|
|
if (continue_angle != intersection[0].turn.angle)
|
2016-02-26 11:33:18 -05:00
|
|
|
return continue_angle;
|
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
return getMostLikelyContinue(intersection);
|
2016-02-26 11:33:18 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// find continue angle
|
|
|
|
const double continue_angle = findBestContinue();
|
|
|
|
|
|
|
|
// highway does not continue and has no obvious choice
|
2016-03-17 09:09:09 -04:00
|
|
|
if (continue_angle == intersection[0].turn.angle)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection.size() == 2)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// do not announce ramps at the end of a highway
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::NoTurn,
|
|
|
|
getTurnDirection(intersection[1].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() == 3)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// splitting ramp at the end of a highway
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed && intersection[2].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[2], intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ending in a passing ramp
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
intersection[1].turn.instruction = {
|
|
|
|
TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {
|
|
|
|
TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() == 4 &&
|
|
|
|
detail::roadClass(intersection[1], node_based_graph) ==
|
|
|
|
detail::roadClass(intersection[2], node_based_graph) &&
|
|
|
|
detail::roadClass(intersection[2], node_based_graph) ==
|
|
|
|
detail::roadClass(intersection[3], node_based_graph))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// tripple fork at the end
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[3], intersection[2], intersection[1]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (countValid(intersection) > 0) // check whether turns exist at all
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// FALLBACK, this should hopefully never be reached
|
2016-03-05 12:17:24 -05:00
|
|
|
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
2016-03-03 09:36:03 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-04 09:10:33 -05:00
|
|
|
<< "Fallback reached from motorway at " << std::setprecision(12)
|
|
|
|
<< toFloating(coord.lat) << " " << toFloating(coord.lon) << ", no continue angle, "
|
2016-03-17 09:09:09 -04:00
|
|
|
<< intersection.size() << " roads, " << countValid(intersection) << " valid ones.";
|
|
|
|
fallbackTurnAssignmentMotorway(intersection);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const unsigned exiting_motorways = countExitingMotorways(intersection);
|
2016-02-26 11:33:18 -05:00
|
|
|
|
|
|
|
if (exiting_motorways == 0)
|
|
|
|
{
|
|
|
|
// Ending in Ramp
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (road.entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(detail::isRampClass(road.turn.eid, node_based_graph));
|
|
|
|
road.turn.instruction =
|
|
|
|
TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (exiting_motorways == 1)
|
|
|
|
{
|
|
|
|
// normal motorway passing some ramps or mering onto another motorway
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection.size() == 2)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// continue on the same highway
|
2016-03-17 09:09:09 -04:00
|
|
|
bool continues = (getContinueAngle(intersection) != intersection[0].turn.angle);
|
2016-02-26 11:33:18 -05:00
|
|
|
// Normal Highway exit or merge
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// ignore invalid uturns/other
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!road.entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
continue;
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (road.turn.angle == continue_angle)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
if (continues)
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction =
|
2016-03-01 16:30:31 -05:00
|
|
|
TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
|
2016-02-26 11:33:18 -05:00
|
|
|
else // TODO handle turn direction correctly
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {TurnType::Merge, DirectionModifier::Straight};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (road.turn.angle < continue_angle)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {
|
|
|
|
detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
|
2016-03-08 06:40:45 -05:00
|
|
|
: TurnType::Turn,
|
2016-03-17 09:09:09 -04:00
|
|
|
(road.turn.angle < 145) ? DirectionModifier::Right
|
2016-03-01 16:30:31 -05:00
|
|
|
: DirectionModifier::SlightRight};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (road.turn.angle > continue_angle)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {
|
|
|
|
detail::isRampClass(road.turn.eid, node_based_graph) ? TurnType::Ramp
|
2016-03-08 06:40:45 -05:00
|
|
|
: TurnType::Turn,
|
2016-03-17 09:09:09 -04:00
|
|
|
(road.turn.angle > 215) ? DirectionModifier::Left
|
2016-03-01 16:30:31 -05:00
|
|
|
: DirectionModifier::SlightLeft};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// handle motorway forks
|
|
|
|
else if (exiting_motorways > 1)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (exiting_motorways == 2 && intersection.size() == 2)
|
2016-03-03 09:36:03 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
2016-03-03 09:36:03 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-04 06:17:06 -05:00
|
|
|
<< "Disabled U-Turn on a freeway at "
|
2016-03-05 12:17:24 -05:00
|
|
|
<< localizer(node_based_graph.GetTarget(via_edge));
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[0].entry_allowed = false; // UTURN on the freeway
|
2016-03-03 09:36:03 -05:00
|
|
|
}
|
2016-03-04 06:17:06 -05:00
|
|
|
else if (exiting_motorways == 2)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-04 06:17:06 -05:00
|
|
|
// standard fork
|
|
|
|
std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
|
|
|
|
second_valid = std::numeric_limits<std::size_t>::max();
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = 0; i < intersection.size(); ++i)
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[i].entry_allowed &&
|
|
|
|
detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (first_valid < intersection.size())
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
|
|
|
second_valid = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
first_valid = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[second_valid], intersection[first_valid]);
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
|
|
|
else if (exiting_motorways == 3)
|
|
|
|
{
|
|
|
|
// triple fork
|
|
|
|
std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
|
|
|
|
second_valid = std::numeric_limits<std::size_t>::max(),
|
|
|
|
third_valid = std::numeric_limits<std::size_t>::max();
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = 0; i < intersection.size(); ++i)
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[i].entry_allowed &&
|
|
|
|
detail::isMotorwayClass(intersection[i].turn.eid, node_based_graph))
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (second_valid < intersection.size())
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
|
|
|
third_valid = i;
|
|
|
|
break;
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (first_valid < intersection.size())
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
|
|
|
second_valid = i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
first_valid = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[third_valid], intersection[second_valid],
|
|
|
|
intersection[first_valid]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-05 12:17:24 -05:00
|
|
|
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
2016-03-04 06:17:06 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Found motorway junction with more than "
|
2016-03-17 09:09:09 -04:00
|
|
|
"2 exiting motorways or additional ramps at " << std::setprecision(12)
|
|
|
|
<< toFloating(coord.lat) << " " << toFloating(coord.lon);
|
|
|
|
fallbackTurnAssignmentMotorway(intersection);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
} // done for more than one highway exit
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-22 11:27:18 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
auto num_valid_turns = countValid(intersection);
|
2016-02-26 11:33:18 -05:00
|
|
|
// ramp straight into a motorway/ramp
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection.size() == 2 && num_valid_turns == 1)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
|
|
|
BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() == 3)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// merging onto a passing highway / or two ramps merging onto the same highway
|
|
|
|
if (num_valid_turns == 1)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
2016-02-26 11:33:18 -05:00
|
|
|
// check order of highways
|
|
|
|
// 4
|
|
|
|
// 5 3
|
|
|
|
//
|
|
|
|
// 6 2
|
|
|
|
//
|
|
|
|
// 7 1
|
|
|
|
// 0
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph))
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// circular order indicates a merge to the left (0-3 onto 4
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
|
2016-02-26 11:33:18 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Merge,
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-02-26 11:33:18 -05:00
|
|
|
else // fallback
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {
|
|
|
|
TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else // passing by the end of a motorway
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(intersection[2].entry_allowed);
|
|
|
|
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
// circular order (5-0) onto 4
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
|
2016-02-26 11:33:18 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {TurnType::Merge,
|
|
|
|
DirectionModifier::SlightRight};
|
2016-02-26 11:33:18 -05:00
|
|
|
else // fallback
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {
|
|
|
|
TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else // passing the end of a highway
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-05 13:31:59 -05:00
|
|
|
BOOST_ASSERT(num_valid_turns == 2);
|
2016-02-26 11:33:18 -05:00
|
|
|
// UTurn on ramps is not possible
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
|
|
|
BOOST_ASSERT(intersection[1].entry_allowed);
|
|
|
|
BOOST_ASSERT(intersection[2].entry_allowed);
|
2016-02-26 11:33:18 -05:00
|
|
|
// two motorways starting at end of ramp (fork)
|
|
|
|
// M M
|
|
|
|
// \ /
|
|
|
|
// |
|
|
|
|
// R
|
2016-03-17 09:09:09 -04:00
|
|
|
if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
|
|
|
|
detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[2], intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// continued ramp passing motorway entry
|
|
|
|
// M R
|
|
|
|
// M R
|
|
|
|
// | /
|
|
|
|
// R
|
2016-03-17 09:09:09 -04:00
|
|
|
if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
|
2016-03-08 06:40:45 -05:00
|
|
|
.road_classification.road_class))
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Merge,
|
|
|
|
DirectionModifier::SlightRight};
|
|
|
|
intersection[2].turn.instruction = {TurnType::Fork,
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Fork,
|
|
|
|
DirectionModifier::SlightRight};
|
|
|
|
intersection[2].turn.instruction = {TurnType::Merge,
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-03 09:36:03 -05:00
|
|
|
// On - Off Ramp on passing Motorway, Ramp onto Fork(?)
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() == 4)
|
2016-03-03 09:36:03 -05:00
|
|
|
{
|
|
|
|
bool passed_highway_entry = false;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-03-03 09:36:03 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
|
|
|
|
if (!road.entry_allowed &&
|
2016-03-08 06:40:45 -05:00
|
|
|
detail::isMotorwayClass(edge_data.road_classification.road_class))
|
2016-03-03 09:36:03 -05:00
|
|
|
{
|
|
|
|
passed_highway_entry = true;
|
|
|
|
}
|
2016-03-08 06:40:45 -05:00
|
|
|
else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
|
2016-03-03 09:36:03 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {TurnType::Merge,
|
|
|
|
passed_highway_entry ? DirectionModifier::SlightRight
|
2016-03-03 09:36:03 -05:00
|
|
|
: DirectionModifier::SlightLeft};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(isRampClass(edge_data.road_classification.road_class));
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {TurnType::Ramp, getTurnDirection(road.turn.angle)};
|
2016-03-03 09:36:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-26 11:33:18 -05:00
|
|
|
else
|
|
|
|
{ // FALLBACK, hopefully this should never been reached
|
2016-03-03 09:36:03 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING) << "Reached fallback on motorway ramp with "
|
2016-03-17 09:09:09 -04:00
|
|
|
<< intersection.size() << " roads and "
|
|
|
|
<< countValid(intersection) << " valid turns.";
|
|
|
|
fallbackTurnAssignmentMotorway(intersection);
|
|
|
|
}
|
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-22 11:27:18 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleMotorwayJunction(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
// BOOST_ASSERT(!intersection[0].entry_allowed); //This fails due to @themarex handling of dead
|
|
|
|
// end
|
2016-03-01 16:30:31 -05:00
|
|
|
// streets
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-02-26 11:33:18 -05:00
|
|
|
|
|
|
|
// coming from motorway
|
2016-03-08 06:40:45 -05:00
|
|
|
if (detail::isMotorwayClass(in_data.road_classification.road_class))
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return handleFromMotorway(via_edge, std::move(intersection));
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else // coming from a ramp
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return handleMotorwayRamp(via_edge, std::move(intersection));
|
2016-02-26 11:33:18 -05:00
|
|
|
// ramp merging straight onto motorway
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
bool TurnAnalysis::isMotorwayJunction(const EdgeID via_edge,
|
|
|
|
const std::vector<ConnectedRoad> &intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-03 09:36:03 -05:00
|
|
|
bool has_motorway = false;
|
|
|
|
bool has_normal_roads = false;
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto &road : intersection)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-03 09:36:03 -05:00
|
|
|
// not merging or forking?
|
2016-03-17 09:09:09 -04:00
|
|
|
if ((angularDeviation(road.turn.angle, 0) > 35 &&
|
|
|
|
angularDeviation(road.turn.angle, 180) > 35) ||
|
|
|
|
(road.entry_allowed && angularDeviation(road.turn.angle, 0) < 35))
|
2016-03-03 09:36:03 -05:00
|
|
|
return false;
|
2016-03-04 06:17:06 -05:00
|
|
|
else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
|
|
|
|
out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (road.entry_allowed)
|
2016-03-04 06:17:06 -05:00
|
|
|
has_motorway = true;
|
|
|
|
}
|
|
|
|
else if (!isRampClass(out_data.road_classification.road_class))
|
2016-03-03 09:36:03 -05:00
|
|
|
has_normal_roads = true;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-03 09:36:03 -05:00
|
|
|
if (has_normal_roads)
|
|
|
|
return false;
|
|
|
|
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-03-03 09:36:03 -05:00
|
|
|
return has_motorway ||
|
|
|
|
in_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
|
2016-02-26 11:33:18 -05:00
|
|
|
in_data.road_classification.road_class == FunctionalRoadClass::TRUNK;
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
TurnType TurnAnalysis::findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &road) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-04 10:36:58 -05:00
|
|
|
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-04 09:10:33 -05:00
|
|
|
bool on_ramp = isRampClass(in_data.road_classification.road_class);
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-04 09:10:33 -05:00
|
|
|
bool onto_ramp = isRampClass(out_data.road_classification.road_class);
|
|
|
|
|
2016-03-08 05:30:33 -05:00
|
|
|
if (!on_ramp && onto_ramp)
|
2016-03-04 09:10:33 -05:00
|
|
|
return TurnType::Ramp;
|
|
|
|
|
|
|
|
if (in_data.name_id == out_data.name_id && in_data.name_id != INVALID_NAME_ID)
|
|
|
|
{
|
|
|
|
return TurnType::Continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TurnType::Turn;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads,
|
2016-03-08 06:40:45 -05:00
|
|
|
const EdgeID via_edge,
|
2016-03-17 09:09:09 -04:00
|
|
|
const ConnectedRoad &road) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto type = findBasicTurnType(via_edge, road);
|
2016-04-01 05:39:47 -04:00
|
|
|
// handle travel modes:
|
|
|
|
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
|
|
|
|
const auto out_mode = node_based_graph.GetEdgeData(road.turn.eid).travel_mode;
|
2016-03-07 05:09:21 -05:00
|
|
|
if (type == TurnType::Ramp)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return {TurnType::Ramp, getTurnDirection(road.turn.angle)};
|
2016-03-07 05:09:21 -05:00
|
|
|
}
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(road.turn.angle, 0) < 0.01)
|
2016-03-07 05:09:21 -05:00
|
|
|
{
|
2016-02-26 11:33:18 -05:00
|
|
|
return {TurnType::Turn, DirectionModifier::UTurn};
|
|
|
|
}
|
2016-03-07 05:09:21 -05:00
|
|
|
if (type == TurnType::Turn)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-07 08:52:26 -05:00
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-16 10:47:33 -04:00
|
|
|
if (in_data.name_id != out_data.name_id &&
|
2016-03-18 14:21:13 -04:00
|
|
|
requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
|
|
|
|
name_table.GetNameForID(out_data.name_id)))
|
2016-03-17 09:09:09 -04:00
|
|
|
return {TurnType::NewName, getTurnDirection(road.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
else
|
2016-04-01 05:39:47 -04:00
|
|
|
{
|
|
|
|
if (in_mode == out_mode)
|
|
|
|
return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
|
|
|
|
else
|
|
|
|
return {TurnType::Notification, getTurnDirection(road.turn.angle)};
|
|
|
|
}
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-07 05:09:21 -05:00
|
|
|
BOOST_ASSERT(type == TurnType::Continue);
|
2016-04-01 05:39:47 -04:00
|
|
|
if (in_mode != out_mode)
|
|
|
|
{
|
|
|
|
return {TurnType::Notification, getTurnDirection(road.turn.angle)};
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
if (num_roads > 2)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return {TurnType::NoTurn, getTurnDirection(road.turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleOneWayTurn(std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleTwoWayTurn(const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
|
|
|
|
|
|
|
if (intersection[1].turn.instruction.type == TurnType::Suppressed)
|
|
|
|
intersection[1].turn.instruction.type = TurnType::NoTurn;
|
|
|
|
|
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
2016-03-18 11:19:55 -04:00
|
|
|
const auto isObviousOfTwo = [](const ConnectedRoad road, const ConnectedRoad other)
|
2016-03-17 09:09:09 -04:00
|
|
|
{
|
2016-03-18 11:19:55 -04:00
|
|
|
return (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85) ||
|
2016-03-22 11:27:18 -04:00
|
|
|
(angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
|
|
|
|
std::numeric_limits<double>::epsilon()) ||
|
2016-03-17 09:09:09 -04:00
|
|
|
(angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
|
2016-03-18 11:19:55 -04:00
|
|
|
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
|
2016-02-29 10:24:42 -05:00
|
|
|
1.4);
|
2016-02-26 11:33:18 -05:00
|
|
|
};
|
2016-03-16 10:47:33 -04:00
|
|
|
|
2016-03-03 08:28:59 -05:00
|
|
|
/* Two nearly straight turns -> FORK
|
|
|
|
OOOOOOO
|
|
|
|
/
|
|
|
|
IIIIII
|
|
|
|
\
|
|
|
|
OOOOOOO
|
|
|
|
*/
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed && intersection[2].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
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;
|
2016-03-16 10:47:33 -04:00
|
|
|
if (canBeSeenAsFork(left_class, right_class))
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[2], intersection[1]);
|
2016-03-16 10:47:33 -04:00
|
|
|
else if (getPriority(left_class) > getPriority(right_class))
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
|
|
|
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-03-16 10:47:33 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
|
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
DirectionModifier::SlightRight};
|
2016-03-16 10:47:33 -04:00
|
|
|
}
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
|
|
|
if (intersection[2].entry_allowed)
|
|
|
|
intersection[2].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-07 05:09:21 -05:00
|
|
|
/* T Intersection
|
|
|
|
|
|
|
|
OOOOOOO T OOOOOOOO
|
|
|
|
I
|
|
|
|
I
|
|
|
|
I
|
|
|
|
*/
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
|
2016-02-26 11:33:18 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
|
|
|
|
intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
|
2016-02-26 11:33:18 -05:00
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Right};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[2].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[2]))
|
2016-03-08 06:40:45 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
|
2016-02-26 11:33:18 -05:00
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {TurnType::Ramp, DirectionModifier::Left};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-07 05:09:21 -05:00
|
|
|
/* T Intersection, Cross left
|
|
|
|
O
|
|
|
|
O
|
|
|
|
O
|
|
|
|
IIIIIIII - OOOOOOOOOO
|
|
|
|
*/
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[2].turn.angle, 270) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
|
2016-02-26 11:33:18 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
|
|
|
|
intersection[1].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[2].entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
|
|
DirectionModifier::Left};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-07 05:09:21 -05:00
|
|
|
/* T Intersection, Cross right
|
|
|
|
|
|
|
|
IIIIIIII T OOOOOOOOOO
|
|
|
|
O
|
|
|
|
O
|
|
|
|
O
|
|
|
|
*/
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[1].turn.angle, 90) < NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >
|
2016-02-26 11:33:18 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[2].entry_allowed)
|
|
|
|
intersection[2].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
|
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
DirectionModifier::Right};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
// merge onto a through street
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id &&
|
|
|
|
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
|
|
|
|
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn, const ConnectedRoad other)
|
|
|
|
-> TurnInstruction
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
|
|
|
return {isObviousOfTwo(turn, other) ? TurnType::Merge : TurnType::Turn,
|
2016-03-17 09:09:09 -04:00
|
|
|
getTurnDirection(turn.turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
|
|
|
|
intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// other street merges from the left
|
2016-03-05 12:17:24 -05:00
|
|
|
else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
|
|
|
|
node_based_graph.GetEdgeData(via_edge).name_id ==
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (isObviousOfTwo(intersection[1], intersection[2]))
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction =
|
2016-03-01 16:30:31 -05:00
|
|
|
TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Continue,
|
|
|
|
getTurnDirection(intersection[1].turn.angle)};
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {TurnType::Turn,
|
|
|
|
getTurnDirection(intersection[2].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
// other street merges from the right
|
2016-03-05 12:17:24 -05:00
|
|
|
else if (INVALID_NAME_ID != node_based_graph.GetEdgeData(via_edge).name_id &&
|
|
|
|
node_based_graph.GetEdgeData(via_edge).name_id ==
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (isObviousOfTwo(intersection[2], intersection[1]))
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction =
|
2016-03-01 16:30:31 -05:00
|
|
|
TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {TurnType::Continue,
|
|
|
|
getTurnDirection(intersection[2].turn.angle)};
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Turn,
|
|
|
|
getTurnDirection(intersection[1].turn.angle)};
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
2016-02-29 10:24:42 -05:00
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (isObviousOfTwo(intersection[1], intersection[2]))
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-04-01 05:39:47 -04:00
|
|
|
intersection[1].turn.instruction = getInstructionForObvious(3,via_edge,intersection[1]);
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {TurnType::Turn,
|
|
|
|
getTurnDirection(intersection[1].turn.angle)};
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (isObviousOfTwo(intersection[2], intersection[1]))
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-04-01 05:39:47 -04:00
|
|
|
intersection[2].turn.instruction = getInstructionForObvious(3,via_edge,intersection[2]);
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {TurnType::Turn,
|
|
|
|
getTurnDirection(intersection[2].turn.angle)};
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-22 11:27:18 -04:00
|
|
|
// unnamed intersections or basic three way turn
|
2016-02-26 11:33:18 -05:00
|
|
|
|
2016-03-22 11:27:18 -04:00
|
|
|
// remain at basic turns
|
|
|
|
// TODO handle obviousness, Handle Merges
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-07 08:52:26 -05:00
|
|
|
void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge,
|
2016-03-17 09:09:09 -04:00
|
|
|
ConnectedRoad &left,
|
|
|
|
ConnectedRoad &right) const
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// single turn of both is valid (don't change the valid one)
|
|
|
|
// or multiple identical angles -> bad OSM intersection
|
2016-03-17 09:09:09 -04:00
|
|
|
if ((!left.entry_allowed || !right.entry_allowed) || (left.turn.angle == right.turn.angle))
|
|
|
|
{
|
|
|
|
if (left.entry_allowed)
|
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
getTurnDirection(left.turn.angle)};
|
|
|
|
if (right.entry_allowed)
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
getTurnDirection(right.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight ||
|
|
|
|
getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft ||
|
|
|
|
getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight)
|
2016-03-16 10:47:33 -04:00
|
|
|
{
|
|
|
|
const auto left_class =
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
|
2016-03-16 10:47:33 -04:00
|
|
|
const auto right_class =
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
|
2016-03-16 10:47:33 -04:00
|
|
|
if (canBeSeenAsFork(left_class, right_class))
|
|
|
|
assignFork(via_edge, left, right);
|
|
|
|
else if (getPriority(left_class) > getPriority(right_class))
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
// FIXME this should possibly know about the actual roads?
|
|
|
|
right.turn.instruction = getInstructionForObvious(4, via_edge, right);
|
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-03-16 10:47:33 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
// FIXME this should possibly know about the actual roads?
|
|
|
|
left.turn.instruction = getInstructionForObvious(4, via_edge, left);
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
DirectionModifier::SlightRight};
|
2016-03-16 10:47:33 -04:00
|
|
|
}
|
|
|
|
}
|
2016-03-07 08:52:26 -05:00
|
|
|
|
|
|
|
const auto left_type = findBasicTurnType(via_edge, left);
|
|
|
|
const auto right_type = findBasicTurnType(via_edge, right);
|
|
|
|
// Two Right Turns
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(left.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// Keep left perfect, shift right
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::Right};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::SharpRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(right.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// Keep Right perfect, shift left
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::SlightRight};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::Right};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Two Right Turns
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(left.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// Keep left perfect, shift right
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::Left};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(right.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// Keep Right perfect, shift left
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::Left};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Both turns?
|
|
|
|
if (TurnType::Ramp != left_type && TurnType::Ramp != right_type)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (left.turn.angle < STRAIGHT_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {TurnType::FirstTurn, getTurnDirection(left.turn.angle)};
|
|
|
|
right.turn.instruction = {TurnType::SecondTurn, getTurnDirection(right.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {TurnType::SecondTurn, getTurnDirection(left.turn.angle)};
|
|
|
|
right.turn.instruction = {TurnType::FirstTurn, getTurnDirection(right.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Shift the lesser penalty
|
2016-03-17 09:09:09 -04:00
|
|
|
if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::Left};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::Right};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::SharpRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (getTurnDirection(left.turn.angle) == DirectionModifier::Right)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(left.turn.angle, 90) > angularDeviation(right.turn.angle, 90))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::SlightRight};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::Right};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::Right};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::SharpRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(left.turn.angle, 270) > angularDeviation(right.turn.angle, 270))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::Left};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {left_type, DirectionModifier::Left};
|
|
|
|
right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-03-04 09:10:33 -05:00
|
|
|
static int fallback_count = 0;
|
2016-03-17 09:09:09 -04:00
|
|
|
const std::size_t obvious_index = findObviousTurn(via_edge, intersection);
|
|
|
|
const auto fork_range = findFork(intersection);
|
2016-03-07 08:52:26 -05:00
|
|
|
std::size_t straightmost_turn = 0;
|
|
|
|
double straightmost_deviation = 180;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = 0; i < intersection.size(); ++i)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
|
2016-03-07 08:52:26 -05:00
|
|
|
if (deviation < straightmost_deviation)
|
|
|
|
{
|
|
|
|
straightmost_deviation = deviation;
|
|
|
|
straightmost_turn = i;
|
2016-03-04 09:10:33 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-07 08:52:26 -05:00
|
|
|
|
|
|
|
if (obvious_index != 0)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[obvious_index].turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, intersection[obvious_index]);
|
2016-03-07 08:52:26 -05:00
|
|
|
|
|
|
|
// assign left/right turns
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
|
|
|
|
intersection = assignRightTurns(via_edge, std::move(intersection), obvious_index);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else if (fork_range.first != 0 && fork_range.second - fork_range.first <= 2) // found fork
|
2016-03-04 09:10:33 -05:00
|
|
|
{
|
2016-03-07 08:52:26 -05:00
|
|
|
if (fork_range.second - fork_range.first == 1)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
auto &left = intersection[fork_range.second];
|
|
|
|
auto &right = intersection[fork_range.first];
|
2016-03-16 10:47:33 -04:00
|
|
|
const auto left_class =
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class;
|
2016-03-16 10:47:33 -04:00
|
|
|
const auto right_class =
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class;
|
2016-03-16 10:47:33 -04:00
|
|
|
if (canBeSeenAsFork(left_class, right_class))
|
|
|
|
assignFork(via_edge, left, right);
|
|
|
|
else if (getPriority(left_class) > getPriority(right_class))
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
right.turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, right);
|
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-03-16 10:47:33 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction =
|
|
|
|
getInstructionForObvious(intersection.size(), via_edge, left);
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
DirectionModifier::SlightRight};
|
2016-03-16 10:47:33 -04:00
|
|
|
}
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else if (fork_range.second - fork_range.second == 2)
|
2016-03-04 09:10:33 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
assignFork(via_edge, intersection[fork_range.second],
|
|
|
|
intersection[fork_range.first + 1], intersection[fork_range.first]);
|
2016-03-04 09:10:33 -05:00
|
|
|
}
|
2016-03-07 08:52:26 -05:00
|
|
|
// assign left/right turns
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection = assignLeftTurns(via_edge, std::move(intersection), fork_range.second + 1);
|
|
|
|
intersection = assignRightTurns(via_edge, std::move(intersection), fork_range.first);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else if (straightmost_deviation < FUZZY_ANGLE_DIFFERENCE &&
|
2016-03-17 09:09:09 -04:00
|
|
|
!intersection[straightmost_turn].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// invalid straight turn
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
|
|
|
|
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
|
2016-03-04 09:10:33 -05:00
|
|
|
}
|
2016-03-07 08:52:26 -05:00
|
|
|
// no straight turn
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[straightmost_turn].turn.angle > 180)
|
2016-03-04 09:10:33 -05:00
|
|
|
{
|
2016-03-07 08:52:26 -05:00
|
|
|
// at most three turns on either side
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn);
|
|
|
|
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
|
2016-03-04 09:10:33 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[straightmost_turn].turn.angle < 180)
|
2016-03-04 09:10:33 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
|
|
|
|
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
|
2016-03-04 09:10:33 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fallback_count++ < 10)
|
|
|
|
{
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
2016-03-07 08:52:26 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Resolved to keep fallback on complex turn assignment at "
|
|
|
|
<< std::setprecision(12) << toFloating(coord.lat) << " " << toFloating(coord.lon)
|
|
|
|
<< "Straightmost: " << straightmost_turn;
|
|
|
|
;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto &road : intersection)
|
2016-03-04 09:10:33 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-07 08:52:26 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< "road: " << road.toString() << " Name: " << out_data.name_id
|
2016-03-04 09:10:33 -05:00
|
|
|
<< " Road Class: " << (int)out_data.road_classification.road_class
|
2016-03-17 09:09:09 -04:00
|
|
|
<< " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
|
2016-03-04 09:10:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
// Sets basic turn types as fallback for otherwise unhandled turns
|
|
|
|
std::vector<ConnectedRoad> TurnAnalysis::setTurnTypes(const NodeID from,
|
|
|
|
const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection) const
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!road.entry_allowed)
|
2016-02-26 11:33:18 -05:00
|
|
|
continue;
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
const EdgeID onto_edge = road.turn.eid;
|
|
|
|
const NodeID to_node = node_based_graph.GetTarget(onto_edge);
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = (from == to_node)
|
|
|
|
? TurnInstruction{TurnType::Turn, DirectionModifier::UTurn}
|
|
|
|
: TurnInstruction{findBasicTurnType(via_edge, road),
|
|
|
|
getTurnDirection(road.turn.angle)};
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
|
|
|
|
2016-03-16 13:11:55 -04:00
|
|
|
// a
|
|
|
|
// |
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// For an intersection from_node --via_edi--> turn_node ----> c
|
|
|
|
// ^
|
|
|
|
// |
|
|
|
|
// |
|
|
|
|
// b
|
|
|
|
// This functions returns _all_ turns as if the graph was undirected.
|
|
|
|
// That means we not only get (from_node, turn_node, c) in the above example
|
|
|
|
// but also (from_node, turn_node, a), (from_node, turn_node, b). These turns are
|
|
|
|
// marked as invalid and only needed for intersection classification.
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_node,
|
2016-03-08 06:40:45 -05:00
|
|
|
const EdgeID via_eid) const
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad> intersection;
|
2016-03-05 12:17:24 -05:00
|
|
|
const NodeID turn_node = node_based_graph.GetTarget(via_eid);
|
2016-02-25 08:40:26 -05:00
|
|
|
const NodeID only_restriction_to_node =
|
2016-03-05 12:17:24 -05:00
|
|
|
restriction_map.CheckForEmanatingIsOnlyTurn(from_node, turn_node);
|
2016-02-25 08:40:26 -05:00
|
|
|
const bool is_barrier_node = barrier_nodes.find(turn_node) != barrier_nodes.end();
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
bool has_uturn_edge = false;
|
2016-03-05 12:17:24 -05:00
|
|
|
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(onto_edge != SPECIAL_EDGEID);
|
2016-03-05 12:17:24 -05:00
|
|
|
const NodeID to_node = node_based_graph.GetTarget(onto_edge);
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-15 19:32:00 -04:00
|
|
|
bool turn_is_valid =
|
2016-03-16 13:11:55 -04:00
|
|
|
// reverse edges are never valid turns because the resulting turn would look like this:
|
|
|
|
// from_node --via_edge--> turn_node <--onto_edge-- to_node
|
|
|
|
// however we need this for capture intersection shape for incoming one-ways
|
|
|
|
!node_based_graph.GetEdgeData(onto_edge).reversed &&
|
2016-03-15 19:32:00 -04:00
|
|
|
// we are not turning over a barrier
|
|
|
|
(!is_barrier_node || from_node == to_node) &&
|
2016-02-25 08:40:26 -05:00
|
|
|
// We are at an only_-restriction but not at the right turn.
|
2016-03-15 19:32:00 -04:00
|
|
|
(only_restriction_to_node == SPECIAL_NODEID || to_node == only_restriction_to_node) &&
|
|
|
|
// the turn is not restricted
|
|
|
|
!restriction_map.CheckIfTurnIsRestricted(from_node, turn_node, to_node);
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-15 19:32:00 -04:00
|
|
|
auto angle = 0.;
|
|
|
|
if (from_node == to_node)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-15 19:32:00 -04:00
|
|
|
if (turn_is_valid && !is_barrier_node)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-15 19:32:00 -04:00
|
|
|
// we only add u-turns for dead-end streets.
|
|
|
|
if (node_based_graph.GetOutDegree(turn_node) > 1)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
|
|
|
auto number_of_emmiting_bidirectional_edges = 0;
|
2016-03-05 12:17:24 -05:00
|
|
|
for (auto edge : node_based_graph.GetAdjacentEdgeRange(turn_node))
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-05 12:17:24 -05:00
|
|
|
auto target = node_based_graph.GetTarget(edge);
|
|
|
|
auto reverse_edge = node_based_graph.FindEdge(target, turn_node);
|
2016-03-15 19:32:00 -04:00
|
|
|
BOOST_ASSERT(reverse_edge != SPECIAL_EDGEID);
|
2016-03-05 12:17:24 -05:00
|
|
|
if (!node_based_graph.GetEdgeData(reverse_edge).reversed)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
|
|
|
++number_of_emmiting_bidirectional_edges;
|
|
|
|
}
|
|
|
|
}
|
2016-03-15 19:32:00 -04:00
|
|
|
// is a dead-end
|
|
|
|
turn_is_valid = number_of_emmiting_bidirectional_edges <= 1;
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
has_uturn_edge = true;
|
2016-03-15 19:32:00 -04:00
|
|
|
BOOST_ASSERT(angle >= 0. && angle < std::numeric_limits<double>::epsilon());
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
2016-03-15 19:32:00 -04:00
|
|
|
else
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-15 19:32:00 -04:00
|
|
|
// unpack first node of second segment if packed
|
|
|
|
const auto first_coordinate = getRepresentativeCoordinate(
|
|
|
|
from_node, turn_node, via_eid, INVERT, compressed_edge_container, node_info_list);
|
|
|
|
const auto third_coordinate = getRepresentativeCoordinate(
|
|
|
|
turn_node, to_node, onto_edge, !INVERT, compressed_edge_container, node_info_list);
|
|
|
|
angle = util::coordinate_calculation::computeAngle(
|
|
|
|
first_coordinate, node_info_list[turn_node], third_coordinate);
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angle < std::numeric_limits<double>::epsilon())
|
|
|
|
has_uturn_edge = true;
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection.push_back(ConnectedRoad(
|
|
|
|
TurnOperation{onto_edge, angle, {TurnType::Invalid, DirectionModifier::UTurn}},
|
|
|
|
turn_is_valid));
|
2016-02-25 08:40:26 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
// We hit the case of a street leading into nothing-ness. Since the code here assumes that this
|
|
|
|
// will
|
|
|
|
// never happen we add an artificial invalid uturn in this case.
|
|
|
|
if (!has_uturn_edge)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection.push_back(
|
|
|
|
{TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
|
|
|
|
{
|
|
|
|
return first.turn.angle < second.turn.angle;
|
2016-02-25 08:40:26 -05:00
|
|
|
};
|
2016-03-17 09:09:09 -04:00
|
|
|
std::sort(std::begin(intersection), std::end(intersection), ByAngle);
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(intersection[0].turn.angle >= 0. &&
|
|
|
|
intersection[0].turn.angle < std::numeric_limits<double>::epsilon());
|
2016-03-15 19:32:00 -04:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
return mergeSegregatedRoads(std::move(intersection));
|
2016-02-26 11:33:18 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
/*
|
|
|
|
* Segregated Roads often merge onto a single intersection.
|
|
|
|
* While technically representing different roads, they are
|
|
|
|
* often looked at as a single road.
|
|
|
|
* Due to the merging, turn Angles seem off, wenn we compute them from the
|
|
|
|
* initial positions.
|
|
|
|
*
|
|
|
|
* b<b<b<b(1)<b<b<b
|
|
|
|
* aaaaa-b
|
|
|
|
* b>b>b>b(2)>b>b>b
|
|
|
|
*
|
|
|
|
* Would be seen as a slight turn going fro a to (2). A Sharp turn going from
|
|
|
|
* (1) to (2).
|
|
|
|
*
|
|
|
|
* In cases like these, we megre this segregated roads into a single road to
|
|
|
|
* end up with a case like:
|
|
|
|
*
|
|
|
|
* aaaaa-bbbbbb
|
|
|
|
*
|
|
|
|
* for the turn representation.
|
|
|
|
* Anything containing the first u-turn in a merge affects all other angles
|
|
|
|
* and is handled separately from all others.
|
|
|
|
*/
|
|
|
|
std::vector<ConnectedRoad>
|
|
|
|
TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const
|
2016-02-26 11:33:18 -05:00
|
|
|
{
|
2016-02-25 08:40:26 -05:00
|
|
|
const auto getRight = [&](std::size_t index)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return (index + intersection.size() - 1) % intersection.size();
|
2016-02-25 08:40:26 -05:00
|
|
|
};
|
2016-02-29 10:24:42 -05:00
|
|
|
|
|
|
|
const auto mergable = [&](std::size_t first, std::size_t second) -> bool
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
|
|
|
|
const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
|
2016-02-29 10:24:42 -05:00
|
|
|
|
|
|
|
return first_data.name_id != INVALID_NAME_ID && first_data.name_id == second_data.name_id &&
|
|
|
|
!first_data.roundabout && !second_data.roundabout &&
|
|
|
|
first_data.travel_mode == second_data.travel_mode &&
|
|
|
|
first_data.road_classification == second_data.road_classification &&
|
|
|
|
// compatible threshold
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[first].turn.angle, intersection[second].turn.angle) <
|
|
|
|
60 &&
|
2016-02-29 10:24:42 -05:00
|
|
|
first_data.reversed != second_data.reversed;
|
|
|
|
};
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto merge = [](const ConnectedRoad &first, const ConnectedRoad &second) -> ConnectedRoad
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!first.entry_allowed)
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
ConnectedRoad result = second;
|
|
|
|
result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
|
|
|
|
if (first.turn.angle - second.turn.angle > 180)
|
|
|
|
result.turn.angle += 180;
|
|
|
|
if (result.turn.angle > 360)
|
|
|
|
result.turn.angle -= 360;
|
2016-02-29 10:24:42 -05:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(!second.entry_allowed);
|
|
|
|
ConnectedRoad result = first;
|
|
|
|
result.turn.angle = (first.turn.angle + second.turn.angle) / 2;
|
2016-02-29 10:24:42 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (first.turn.angle - second.turn.angle > 180)
|
|
|
|
result.turn.angle += 180;
|
|
|
|
if (result.turn.angle > 360)
|
|
|
|
result.turn.angle -= 360;
|
2016-02-29 10:24:42 -05:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2016-02-25 08:40:26 -05:00
|
|
|
};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection.size() == 1)
|
|
|
|
return intersection;
|
2016-02-29 10:24:42 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
// check for merges including the basic u-turn
|
|
|
|
// these result in an adjustment of all other angles
|
|
|
|
if (mergable(0, intersection.size() - 1))
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
|
|
|
// std::cout << "First merge" << std::endl;
|
|
|
|
const double correction_factor =
|
2016-03-17 09:09:09 -04:00
|
|
|
(360 - intersection[intersection.size() - 1].turn.angle) / 2;
|
|
|
|
for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
|
|
|
|
intersection[i].turn.angle += correction_factor;
|
|
|
|
intersection[0] = merge(intersection.front(), intersection.back());
|
|
|
|
intersection[0].turn.angle = 0;
|
|
|
|
intersection.pop_back();
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
|
|
|
else if (mergable(0, 1))
|
|
|
|
{
|
|
|
|
// std::cout << "First merge" << std::endl;
|
2016-03-17 09:09:09 -04:00
|
|
|
const double correction_factor = (intersection[1].turn.angle) / 2;
|
|
|
|
for (std::size_t i = 2; i < intersection.size(); ++i)
|
|
|
|
intersection[i].turn.angle += correction_factor;
|
|
|
|
intersection[0] = merge(intersection[0], intersection[1]);
|
|
|
|
intersection[0].turn.angle = 0;
|
|
|
|
intersection.erase(intersection.begin() + 1);
|
2016-02-29 10:24:42 -05:00
|
|
|
}
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
// a merge including the first u-turn requres an adjustment of the turn angles
|
|
|
|
// therefore these are handled prior to this step
|
|
|
|
for (std::size_t index = 2; index < intersection.size(); ++index)
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-02-29 10:24:42 -05:00
|
|
|
if (mergable(index, getRight(index)))
|
2016-02-25 08:40:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[getRight(index)] =
|
|
|
|
merge(intersection[getRight(index)], intersection[index]);
|
|
|
|
intersection.erase(intersection.begin() + index);
|
2016-02-25 08:40:26 -05:00
|
|
|
--index;
|
|
|
|
}
|
|
|
|
}
|
2016-02-29 10:24:42 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
|
2016-02-29 10:24:42 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
return first.turn.angle < second.turn.angle;
|
2016-02-29 10:24:42 -05:00
|
|
|
};
|
2016-03-17 09:09:09 -04:00
|
|
|
std::sort(std::begin(intersection), std::end(intersection), ByAngle);
|
|
|
|
return intersection;
|
2016-03-01 09:26:13 -05:00
|
|
|
}
|
|
|
|
|
2016-03-08 06:40:45 -05:00
|
|
|
void TurnAnalysis::assignFork(const EdgeID via_edge,
|
2016-03-17 09:09:09 -04:00
|
|
|
ConnectedRoad &left,
|
|
|
|
ConnectedRoad &right) const
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-05 12:17:24 -05:00
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-03-08 05:30:33 -05:00
|
|
|
const bool low_priority_left = isLowPriorityRoadClass(
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(left.turn.eid).road_classification.road_class);
|
2016-03-08 05:30:33 -05:00
|
|
|
const bool low_priority_right = isLowPriorityRoadClass(
|
2016-03-17 09:09:09 -04:00
|
|
|
node_based_graph.GetEdgeData(right.turn.eid).road_classification.road_class);
|
2016-03-22 11:27:18 -04:00
|
|
|
if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
|
|
|
angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
|
|
|
|
{
|
|
|
|
// left side is actually straight
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(left.turn.eid);
|
2016-03-22 11:27:18 -04:00
|
|
|
if (requiresAnnouncement(in_data, out_data))
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-22 11:27:18 -04:00
|
|
|
if (low_priority_right && !low_priority_left)
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-22 11:27:18 -04:00
|
|
|
left.turn.instruction = getInstructionForObvious(3, via_edge, left);
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
DirectionModifier::SlightRight};
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
2016-03-08 05:30:33 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (low_priority_left && !low_priority_right)
|
2016-03-22 11:27:18 -04:00
|
|
|
{
|
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
DirectionModifier::SlightLeft};
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
DirectionModifier::SlightRight};
|
|
|
|
}
|
2016-03-08 05:30:33 -05:00
|
|
|
else
|
2016-03-22 11:27:18 -04:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
|
2016-03-22 11:27:18 -04:00
|
|
|
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
|
|
|
|
}
|
2016-03-08 05:30:33 -05:00
|
|
|
}
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
2016-03-22 11:27:18 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
DirectionModifier::SlightRight};
|
|
|
|
}
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
2016-03-22 11:27:18 -04:00
|
|
|
else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
|
|
|
|
MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
|
|
|
angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
|
|
|
|
{
|
|
|
|
// right side is actually straight
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid);
|
|
|
|
if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
|
|
|
|
MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
|
|
|
angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-08 05:30:33 -05:00
|
|
|
if (requiresAnnouncement(in_data, out_data))
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-08 05:30:33 -05:00
|
|
|
if (low_priority_left && !low_priority_right)
|
2016-03-22 11:27:18 -04:00
|
|
|
{
|
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-03-17 09:09:09 -04:00
|
|
|
right.turn.instruction = getInstructionForObvious(3, via_edge, right);
|
2016-03-22 11:27:18 -04:00
|
|
|
}
|
2016-03-08 05:30:33 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (low_priority_right && !low_priority_left)
|
2016-03-22 11:27:18 -04:00
|
|
|
{
|
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
DirectionModifier::SlightLeft};
|
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
DirectionModifier::SlightRight};
|
|
|
|
}
|
2016-03-08 05:30:33 -05:00
|
|
|
else
|
2016-03-22 11:27:18 -04:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
|
2016-03-22 11:27:18 -04:00
|
|
|
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
|
|
|
|
}
|
2016-03-08 05:30:33 -05:00
|
|
|
}
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
|
2016-03-22 11:27:18 -04:00
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-22 11:27:18 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// left side of fork
|
|
|
|
if (low_priority_right && !low_priority_left)
|
|
|
|
left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
|
2016-03-04 06:17:06 -05:00
|
|
|
else
|
|
|
|
{
|
2016-03-08 05:30:33 -05:00
|
|
|
if (low_priority_left && !low_priority_right)
|
2016-03-22 11:27:18 -04:00
|
|
|
left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
|
2016-03-08 05:30:33 -05:00
|
|
|
else
|
2016-03-22 11:27:18 -04:00
|
|
|
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
|
|
|
|
}
|
|
|
|
|
|
|
|
// right side of fork
|
|
|
|
if (low_priority_left && !low_priority_right)
|
|
|
|
right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (low_priority_right && !low_priority_left)
|
|
|
|
right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
|
|
|
|
else
|
|
|
|
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-08 06:40:45 -05:00
|
|
|
void TurnAnalysis::assignFork(const EdgeID via_edge,
|
2016-03-17 09:09:09 -04:00
|
|
|
ConnectedRoad &left,
|
|
|
|
ConnectedRoad ¢er,
|
|
|
|
ConnectedRoad &right) const
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-07 08:52:26 -05:00
|
|
|
// TODO handle low priority road classes in a reasonable way
|
2016-03-17 09:09:09 -04:00
|
|
|
if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
|
|
|
|
if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(center.turn.eid);
|
2016-03-07 08:52:26 -05:00
|
|
|
if (requiresAnnouncement(in_data, out_data))
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2016-03-04 06:17:06 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (left.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (right.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
assignFork(via_edge, left, right);
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (center.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
assignFork(via_edge, left, center);
|
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
|
|
|
getTurnDirection(left.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (right.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (center.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
assignFork(via_edge, center, right);
|
|
|
|
else
|
2016-03-17 09:09:09 -04:00
|
|
|
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
|
|
|
getTurnDirection(right.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (center.entry_allowed)
|
|
|
|
center.turn.instruction = {findBasicTurnType(via_edge, center),
|
|
|
|
getTurnDirection(center.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t TurnAnalysis::findObviousTurn(const EdgeID via_edge,
|
2016-03-17 09:09:09 -04:00
|
|
|
const std::vector<ConnectedRoad> &intersection) const
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
// no obvious road
|
|
|
|
if (intersection.size() == 1)
|
2016-03-07 08:52:26 -05:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// a single non u-turn is obvious
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection.size() == 2)
|
2016-03-07 08:52:26 -05:00
|
|
|
return 1;
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
// at least three roads
|
2016-03-07 08:52:26 -05:00
|
|
|
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);
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = 1; i < intersection.size(); ++i)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
|
|
|
|
if (intersection[i].entry_allowed && deviation < best_deviation)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
best_deviation = deviation;
|
|
|
|
best = i;
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid);
|
|
|
|
if (intersection[i].entry_allowed && out_data.name_id == in_data.name_id &&
|
2016-03-07 08:52:26 -05:00
|
|
|
deviation < best_continue_deviation)
|
|
|
|
{
|
|
|
|
best_continue_deviation = deviation;
|
|
|
|
best_continue = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (best == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (best_deviation >= 2 * NARROW_TURN_ANGLE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// TODO incorporate road class in decision
|
|
|
|
if (best != 0 && best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
|
|
|
{
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
// has no obvious continued road
|
|
|
|
if (best_continue == 0 || true)
|
|
|
|
{
|
|
|
|
// Find left/right deviation
|
|
|
|
const double left_deviation = angularDeviation(
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[(best + 1) % intersection.size()].turn.angle, STRAIGHT_ANGLE);
|
2016-03-07 08:52:26 -05:00
|
|
|
const double right_deviation =
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE);
|
2016-03-07 08:52:26 -05:00
|
|
|
|
|
|
|
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
|
|
|
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
|
|
|
return best;
|
|
|
|
|
|
|
|
// other narrow turns?
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[best - 1].turn.angle, STRAIGHT_ANGLE) <=
|
2016-03-07 08:52:26 -05:00
|
|
|
FUZZY_ANGLE_DIFFERENCE)
|
|
|
|
return 0;
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[(best + 1) % intersection.size()].turn.angle,
|
2016-03-07 08:52:26 -05:00
|
|
|
STRAIGHT_ANGLE) <= FUZZY_ANGLE_DIFFERENCE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Well distinct turn that is nearly straight
|
|
|
|
if (left_deviation / best_deviation >= DISTINCTION_RATIO &&
|
|
|
|
right_deviation / best_deviation >= DISTINCTION_RATIO)
|
|
|
|
{
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; // no obvious turn
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<std::size_t, std::size_t>
|
2016-03-17 09:09:09 -04:00
|
|
|
TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
|
|
|
|
std::size_t best = 0;
|
|
|
|
double best_deviation = 180;
|
|
|
|
|
|
|
|
// TODO handle road classes
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = 1; i < intersection.size(); ++i)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
|
|
|
|
if (intersection[i].entry_allowed && deviation < best_deviation)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
best_deviation = deviation;
|
|
|
|
best = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (best_deviation <= NARROW_TURN_ANGLE)
|
|
|
|
{
|
|
|
|
std::size_t left = best, right = best;
|
2016-03-17 09:09:09 -04:00
|
|
|
while (left + 1 < intersection.size() &&
|
|
|
|
angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
|
2016-03-07 08:52:26 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
|
|
|
++left;
|
|
|
|
while (right > 1 &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[right].turn.angle,
|
|
|
|
intersection[right - 1].turn.angle) < NARROW_TURN_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
--right;
|
|
|
|
|
|
|
|
// TODO check whether 2*NARROW_TURN is too large
|
|
|
|
if (right < left &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[left].turn.angle,
|
|
|
|
intersection[(left + 1) % intersection.size()].turn.angle) >=
|
2016-03-07 08:52:26 -05:00
|
|
|
2 * NARROW_TURN_ANGLE &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
|
2016-03-07 08:52:26 -05:00
|
|
|
2 * NARROW_TURN_ANGLE)
|
|
|
|
return std::make_pair(right, left);
|
|
|
|
}
|
|
|
|
return std::make_pair(0llu, 0llu);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can only assign three turns
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection,
|
2016-03-07 08:52:26 -05:00
|
|
|
const std::size_t starting_at) const
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto count_valid = [&intersection, starting_at]()
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
std::size_t count = 0;
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = starting_at; i < intersection.size(); ++i)
|
|
|
|
if (intersection[i].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
++count;
|
|
|
|
return count;
|
|
|
|
};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (starting_at == intersection.size() || count_valid() == 0)
|
|
|
|
return intersection;
|
2016-03-07 08:52:26 -05:00
|
|
|
// handle single turn
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection.size() - starting_at == 1)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!intersection[starting_at].entry_allowed)
|
|
|
|
return intersection;
|
2016-03-07 08:52:26 -05:00
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) >
|
2016-03-07 08:52:26 -05:00
|
|
|
NARROW_TURN_ANGLE &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[starting_at].turn.angle, 0) > NARROW_TURN_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// assign left turn
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]), DirectionModifier::Left};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (angularDeviation(intersection[starting_at].turn.angle, STRAIGHT_ANGLE) <=
|
2016-03-07 08:52:26 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]),
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::SlightLeft};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]),
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::SharpLeft};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// two turns on at the side
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() - starting_at == 2)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
|
|
|
|
const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
|
2016-03-07 08:52:26 -05:00
|
|
|
if (first_direction == second_direction)
|
|
|
|
{
|
|
|
|
// conflict
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[starting_at + 1],
|
|
|
|
intersection[starting_at]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
|
|
|
|
intersection[starting_at + 1].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() - starting_at == 3)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto first_direction = getTurnDirection(intersection[starting_at].turn.angle);
|
|
|
|
const auto second_direction = getTurnDirection(intersection[starting_at + 1].turn.angle);
|
|
|
|
const auto third_direction = getTurnDirection(intersection[starting_at + 2].turn.angle);
|
2016-03-07 08:52:26 -05:00
|
|
|
if (first_direction != second_direction && second_direction != third_direction)
|
|
|
|
{
|
|
|
|
// implies first != third, based on the angles and clockwise order
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[starting_at].entry_allowed)
|
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
|
|
|
|
if (intersection[starting_at + 1].entry_allowed)
|
|
|
|
intersection[starting_at + 1].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
|
|
|
|
if (intersection[starting_at + 2].entry_allowed)
|
|
|
|
intersection[starting_at + 2].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 2]), second_direction};
|
|
|
|
}
|
|
|
|
else if (2 >= (intersection[starting_at].entry_allowed +
|
|
|
|
intersection[starting_at + 1].entry_allowed +
|
|
|
|
intersection[starting_at + 2].entry_allowed))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// at least one invalid turn
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!intersection[starting_at].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[starting_at + 2],
|
|
|
|
intersection[starting_at + 1]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (!intersection[starting_at + 1].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[starting_at + 2],
|
|
|
|
intersection[starting_at]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[starting_at + 1],
|
|
|
|
intersection[starting_at]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[starting_at].entry_allowed &&
|
|
|
|
intersection[starting_at + 1].entry_allowed &&
|
|
|
|
intersection[starting_at + 2].entry_allowed &&
|
|
|
|
angularDeviation(intersection[starting_at].turn.angle,
|
|
|
|
intersection[starting_at + 1].turn.angle) >= NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[starting_at + 1].turn.angle,
|
|
|
|
intersection[starting_at + 2].turn.angle) >= NARROW_TURN_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]),
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::SlightLeft};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at + 1].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 1]),
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::Left};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at + 2].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 2]),
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::SharpLeft};
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[starting_at].entry_allowed &&
|
|
|
|
intersection[starting_at + 1].entry_allowed &&
|
|
|
|
intersection[starting_at + 2].entry_allowed &&
|
2016-03-07 08:52:26 -05:00
|
|
|
((first_direction == second_direction && second_direction == third_direction) ||
|
|
|
|
(third_direction == second_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[starting_at].turn.angle,
|
|
|
|
intersection[starting_at + 1].turn.angle) < GROUP_ANGLE) ||
|
2016-03-07 08:52:26 -05:00
|
|
|
(second_direction == first_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[starting_at + 1].turn.angle,
|
|
|
|
intersection[starting_at + 2].turn.angle) < GROUP_ANGLE)))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
|
|
|
|
? FirstRamp
|
|
|
|
: FirstTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
second_direction};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at + 1].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
|
2016-03-07 08:52:26 -05:00
|
|
|
? SecondRamp
|
|
|
|
: SecondTurn,
|
|
|
|
second_direction};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at + 2].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
|
2016-03-07 08:52:26 -05:00
|
|
|
? ThirdRamp
|
|
|
|
: ThirdTurn,
|
|
|
|
second_direction};
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[starting_at].entry_allowed &&
|
|
|
|
intersection[starting_at + 1].entry_allowed &&
|
|
|
|
intersection[starting_at + 2].entry_allowed &&
|
2016-03-07 08:52:26 -05:00
|
|
|
((third_direction == second_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[starting_at].turn.angle,
|
|
|
|
intersection[starting_at + 1].turn.angle) >= GROUP_ANGLE) ||
|
2016-03-07 08:52:26 -05:00
|
|
|
(second_direction == first_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[starting_at + 1].turn.angle,
|
|
|
|
intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// conflict one side with an additional very sharp turn
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[starting_at + 1].turn.angle,
|
|
|
|
intersection[starting_at + 2].turn.angle) >= GROUP_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[starting_at + 1],
|
|
|
|
intersection[starting_at]);
|
|
|
|
intersection[starting_at + 2].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
|
|
|
|
handleDistinctConflict(via_edge, intersection[starting_at + 2],
|
|
|
|
intersection[starting_at + 1]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ((first_direction == second_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at].entry_allowed !=
|
|
|
|
intersection[starting_at + 1].entry_allowed) ||
|
2016-03-07 08:52:26 -05:00
|
|
|
(second_direction == third_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[starting_at + 1].entry_allowed !=
|
|
|
|
intersection[starting_at + 2].entry_allowed))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// no conflict, due to conflict being restricted to valid/invalid
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[starting_at].entry_allowed)
|
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at]), first_direction};
|
|
|
|
if (intersection[starting_at + 1].entry_allowed)
|
|
|
|
intersection[starting_at + 1].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
|
|
|
|
if (intersection[starting_at + 2].entry_allowed)
|
|
|
|
intersection[starting_at + 2].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Reached fallback for left turns, size 3: " << std::setprecision(12)
|
|
|
|
<< toFloating(coord.lat) << " " << toFloating(coord.lon);
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto road : intersection)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-07 08:52:26 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< "\troad: " << road.toString() << " Name: " << out_data.name_id
|
2016-03-07 08:52:26 -05:00
|
|
|
<< " Road Class: " << (int)out_data.road_classification.road_class
|
2016-03-17 09:09:09 -04:00
|
|
|
<< " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
for (std::size_t i = starting_at; i < intersection.size(); ++i)
|
|
|
|
if (intersection[i].entry_allowed)
|
|
|
|
intersection[i].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[i]),
|
|
|
|
getTurnDirection(intersection[i].turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection.size() - starting_at == 4)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[starting_at].entry_allowed)
|
|
|
|
intersection[starting_at].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at].turn.eid, node_based_graph)
|
|
|
|
? FirstRamp
|
|
|
|
: FirstTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::Left};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[starting_at + 1].entry_allowed)
|
|
|
|
intersection[starting_at + 1].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at + 1].turn.eid, node_based_graph)
|
2016-03-07 08:52:26 -05:00
|
|
|
? SecondRamp
|
|
|
|
: SecondTurn,
|
|
|
|
DirectionModifier::Left};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[starting_at + 2].entry_allowed)
|
|
|
|
intersection[starting_at + 2].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at + 2].turn.eid, node_based_graph)
|
2016-03-07 08:52:26 -05:00
|
|
|
? ThirdRamp
|
|
|
|
: ThirdTurn,
|
|
|
|
DirectionModifier::Left};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[starting_at + 3].entry_allowed)
|
|
|
|
intersection[starting_at + 3].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[starting_at + 3].turn.eid, node_based_graph)
|
2016-03-07 08:52:26 -05:00
|
|
|
? FourthRamp
|
|
|
|
: FourthTurn,
|
|
|
|
DirectionModifier::Left};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
for (auto &road : intersection)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!road.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
continue;
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
|
2016-03-07 08:52:26 -05:00
|
|
|
: Turn,
|
2016-03-17 09:09:09 -04:00
|
|
|
getTurnDirection(road.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Reached fallback for left turns (" << starting_at << ") " << std::setprecision(12)
|
|
|
|
<< toFloating(coord.lat) << " " << toFloating(coord.lon);
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto road : intersection)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-07 08:52:26 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< "\troad: " << road.toString() << " Name: " << out_data.name_id
|
2016-03-07 08:52:26 -05:00
|
|
|
<< " Road Class: " << (int)out_data.road_classification.road_class
|
2016-03-17 09:09:09 -04:00
|
|
|
<< " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// can only assign three turns
|
2016-03-17 09:09:09 -04:00
|
|
|
std::vector<ConnectedRoad> TurnAnalysis::assignRightTurns(const EdgeID via_edge,
|
|
|
|
std::vector<ConnectedRoad> intersection,
|
|
|
|
const std::size_t up_to) const
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
BOOST_ASSERT(up_to <= intersection.size());
|
|
|
|
const auto count_valid = [&intersection, up_to]()
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
std::size_t count = 0;
|
|
|
|
for (std::size_t i = 1; i < up_to; ++i)
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[i].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
++count;
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
if (up_to <= 1 || count_valid() == 0)
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-03-07 08:52:26 -05:00
|
|
|
// handle single turn
|
|
|
|
if (up_to == 2)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE &&
|
|
|
|
angularDeviation(intersection[1].turn.angle, 0) > NARROW_TURN_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// assign left turn
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
DirectionModifier::Right};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
DirectionModifier::SlightRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
DirectionModifier::SharpRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (up_to == 3)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto first_direction = getTurnDirection(intersection[1].turn.angle);
|
|
|
|
const auto second_direction = getTurnDirection(intersection[2].turn.angle);
|
2016-03-07 08:52:26 -05:00
|
|
|
if (first_direction == second_direction)
|
|
|
|
{
|
|
|
|
// conflict
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[2], intersection[1]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
first_direction};
|
|
|
|
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
|
|
second_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (up_to == 4)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto first_direction = getTurnDirection(intersection[1].turn.angle);
|
|
|
|
const auto second_direction = getTurnDirection(intersection[2].turn.angle);
|
|
|
|
const auto third_direction = getTurnDirection(intersection[3].turn.angle);
|
2016-03-07 08:52:26 -05:00
|
|
|
if (first_direction != second_direction && second_direction != third_direction)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
first_direction};
|
|
|
|
if (intersection[2].entry_allowed)
|
|
|
|
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
|
|
second_direction};
|
|
|
|
if (intersection[3].entry_allowed)
|
|
|
|
intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
|
|
|
|
third_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (2 >= (intersection[1].entry_allowed + intersection[2].entry_allowed +
|
|
|
|
intersection[3].entry_allowed))
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
|
|
|
// at least a single invalid
|
2016-03-17 09:09:09 -04:00
|
|
|
if (!intersection[3].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[2], intersection[1]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (!intersection[1].entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[3], intersection[2]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else // handles one-valid as well as two valid (1,3)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[3], intersection[1]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
|
|
|
|
intersection[3].entry_allowed &&
|
|
|
|
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
|
2016-03-07 08:52:26 -05:00
|
|
|
NARROW_TURN_ANGLE &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
|
2016-03-07 08:52:26 -05:00
|
|
|
NARROW_TURN_ANGLE)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
DirectionModifier::SharpRight};
|
|
|
|
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
|
|
DirectionModifier::Right};
|
|
|
|
intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
|
|
|
|
DirectionModifier::SlightRight};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
|
|
|
|
intersection[3].entry_allowed &&
|
2016-03-07 08:52:26 -05:00
|
|
|
((first_direction == second_direction && second_direction == third_direction) ||
|
|
|
|
(first_direction == second_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) <
|
2016-03-07 08:52:26 -05:00
|
|
|
GROUP_ANGLE) ||
|
|
|
|
(second_direction == third_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) <
|
2016-03-07 08:52:26 -05:00
|
|
|
GROUP_ANGLE)))
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? ThirdRamp
|
|
|
|
: ThirdTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
second_direction};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? SecondRamp
|
|
|
|
: SecondTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
second_direction};
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[3].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? FirstRamp
|
|
|
|
: FirstTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
second_direction};
|
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
else if (intersection[1].entry_allowed && intersection[2].entry_allowed &&
|
|
|
|
intersection[3].entry_allowed &&
|
2016-03-07 08:52:26 -05:00
|
|
|
((first_direction == second_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
|
2016-03-07 08:52:26 -05:00
|
|
|
GROUP_ANGLE) ||
|
|
|
|
(second_direction == third_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
|
2016-03-07 08:52:26 -05:00
|
|
|
GROUP_ANGLE)))
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
|
|
|
|
GROUP_ANGLE)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
handleDistinctConflict(via_edge, intersection[2], intersection[1]);
|
|
|
|
intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
|
|
|
|
third_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
first_direction};
|
|
|
|
handleDistinctConflict(via_edge, intersection[3], intersection[2]);
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((first_direction == second_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[1].entry_allowed != intersection[2].entry_allowed) ||
|
2016-03-07 08:52:26 -05:00
|
|
|
(second_direction == third_direction &&
|
2016-03-17 09:09:09 -04:00
|
|
|
intersection[2].entry_allowed != intersection[3].entry_allowed))
|
|
|
|
{
|
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
|
|
|
first_direction};
|
|
|
|
if (intersection[2].entry_allowed)
|
|
|
|
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
|
|
|
second_direction};
|
|
|
|
if (intersection[3].entry_allowed)
|
|
|
|
intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
|
|
|
|
third_direction};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
2016-03-04 06:17:06 -05:00
|
|
|
else
|
|
|
|
{
|
2016-03-07 08:52:26 -05:00
|
|
|
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Reached fallback for right turns, size 3: " << std::setprecision(12)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< toFloating(coord.lat) << " " << toFloating(coord.lon)
|
|
|
|
<< " Valids: " << (intersection[1].entry_allowed + intersection[2].entry_allowed +
|
|
|
|
intersection[3].entry_allowed);
|
|
|
|
for (const auto road : intersection)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-07 08:52:26 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< "\troad: " << road.toString() << " Name: " << out_data.name_id
|
2016-03-07 08:52:26 -05:00
|
|
|
<< " Road Class: " << (int)out_data.road_classification.road_class
|
2016-03-17 09:09:09 -04:00
|
|
|
<< " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for (std::size_t i = 1; i < up_to; ++i)
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[i].entry_allowed)
|
|
|
|
intersection[i].turn.instruction = {
|
|
|
|
findBasicTurnType(via_edge, intersection[i]),
|
|
|
|
getTurnDirection(intersection[i].turn.angle)};
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-07 08:52:26 -05:00
|
|
|
else if (up_to == 5)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[4].entry_allowed)
|
|
|
|
intersection[4].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[4].turn.eid, node_based_graph) ? FirstRamp
|
|
|
|
: FirstTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::Right};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[3].entry_allowed)
|
|
|
|
intersection[3].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[3].turn.eid, node_based_graph) ? SecondRamp
|
|
|
|
: SecondTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::Right};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[2].entry_allowed)
|
|
|
|
intersection[2].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[2].turn.eid, node_based_graph) ? ThirdRamp
|
|
|
|
: ThirdTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::Right};
|
2016-03-17 09:09:09 -04:00
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
intersection[1].turn.instruction = {
|
|
|
|
detail::isRampClass(intersection[1].turn.eid, node_based_graph) ? FourthRamp
|
|
|
|
: FourthTurn,
|
2016-03-07 08:52:26 -05:00
|
|
|
DirectionModifier::Right};
|
|
|
|
}
|
2016-03-04 06:17:06 -05:00
|
|
|
else
|
|
|
|
{
|
2016-03-07 08:52:26 -05:00
|
|
|
for (std::size_t i = 1; i < up_to; ++i)
|
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
auto &road = intersection[i];
|
|
|
|
if (!road.entry_allowed)
|
2016-03-07 08:52:26 -05:00
|
|
|
continue;
|
2016-03-17 09:09:09 -04:00
|
|
|
road.turn.instruction = {detail::isRampClass(road.turn.eid, node_based_graph) ? Ramp
|
2016-03-07 08:52:26 -05:00
|
|
|
: Turn,
|
2016-03-17 09:09:09 -04:00
|
|
|
getTurnDirection(road.turn.angle)};
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
|
|
|
util::SimpleLogger().Write(logWARNING)
|
|
|
|
<< "Reached fallback for right turns (" << up_to << ") " << std::setprecision(12)
|
|
|
|
<< toFloating(coord.lat) << " " << toFloating(coord.lon);
|
2016-03-17 09:09:09 -04:00
|
|
|
for (const auto road : intersection)
|
2016-03-07 08:52:26 -05:00
|
|
|
{
|
2016-03-17 09:09:09 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
2016-03-07 08:52:26 -05:00
|
|
|
util::SimpleLogger().Write(logWARNING)
|
2016-03-17 09:09:09 -04:00
|
|
|
<< "\troad: " << road.toString() << " Name: " << out_data.name_id
|
2016-03-07 08:52:26 -05:00
|
|
|
<< " Road Class: " << (int)out_data.road_classification.road_class
|
2016-03-17 09:09:09 -04:00
|
|
|
<< " At: " << localizer(node_based_graph.GetTarget(road.turn.eid));
|
2016-03-07 08:52:26 -05:00
|
|
|
}
|
|
|
|
*/
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
2016-03-17 09:09:09 -04:00
|
|
|
return intersection;
|
2016-03-04 06:17:06 -05:00
|
|
|
}
|
|
|
|
|
2016-03-01 16:30:31 -05:00
|
|
|
} // namespace guidance
|
2016-02-25 08:40:26 -05:00
|
|
|
} // namespace extractor
|
2016-02-26 11:33:18 -05:00
|
|
|
} // namespace osrm
|