2016-08-15 06:43:26 -04:00
|
|
|
#include "extractor/guidance/motorway_handler.hpp"
|
2016-09-06 09:47:03 -04:00
|
|
|
#include "extractor/guidance/constants.hpp"
|
2016-06-24 10:06:45 -04:00
|
|
|
#include "extractor/guidance/road_classification.hpp"
|
2016-04-08 06:49:14 -04:00
|
|
|
|
2016-12-02 04:53:22 -05:00
|
|
|
#include "util/bearing.hpp"
|
|
|
|
#include "util/guidance/name_announcements.hpp"
|
2016-04-08 06:49:14 -04:00
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
|
2016-12-02 04:53:22 -05:00
|
|
|
using osrm::util::angularDeviation;
|
|
|
|
using osrm::extractor::guidance::getTurnDirection;
|
2016-04-18 07:41:19 -04:00
|
|
|
|
2016-04-08 06:49:14 -04:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
|
|
|
namespace guidance
|
|
|
|
{
|
2016-06-24 10:06:45 -04:00
|
|
|
namespace
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
|
|
|
|
inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
|
|
|
|
{
|
2016-06-24 10:06:45 -04:00
|
|
|
return node_based_graph.GetEdgeData(eid).road_classification.IsMotorwayClass();
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
2016-06-24 10:06:45 -04:00
|
|
|
inline RoadClassification roadClass(const ConnectedRoad &road,
|
|
|
|
const util::NodeBasedDynamicGraph &graph)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
return graph.GetEdgeData(road.eid).road_classification;
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
|
|
|
|
{
|
2016-06-24 10:06:45 -04:00
|
|
|
return node_based_graph.GetEdgeData(eid).road_classification.IsRampClass();
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
|
2016-06-24 10:06:45 -04:00
|
|
|
} // namespace
|
|
|
|
|
2016-04-08 06:49:14 -04:00
|
|
|
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
2017-04-02 19:58:06 -04:00
|
|
|
const std::vector<util::Coordinate> &coordinates,
|
2016-04-22 05:31:46 -04:00
|
|
|
const util::NameTable &name_table,
|
2016-08-15 06:43:26 -04:00
|
|
|
const SuffixTable &street_name_suffix_table,
|
|
|
|
const IntersectionGenerator &intersection_generator)
|
|
|
|
: IntersectionHandler(node_based_graph,
|
2017-04-02 19:58:06 -04:00
|
|
|
coordinates,
|
2016-08-15 06:43:26 -04:00
|
|
|
name_table,
|
|
|
|
street_name_suffix_table,
|
|
|
|
intersection_generator)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MotorwayHandler::canProcess(const NodeID,
|
|
|
|
const EdgeID via_eid,
|
|
|
|
const Intersection &intersection) const
|
|
|
|
{
|
|
|
|
bool has_motorway = false;
|
|
|
|
bool has_normal_roads = false;
|
|
|
|
|
|
|
|
for (const auto &road : intersection)
|
|
|
|
{
|
|
|
|
// not merging or forking?
|
2016-11-03 05:18:27 -04:00
|
|
|
if (road.entry_allowed && angularDeviation(road.angle, STRAIGHT_ANGLE) > 60)
|
2016-04-08 06:49:14 -04:00
|
|
|
return false;
|
2016-11-03 05:18:27 -04:00
|
|
|
else if (isMotorwayClass(road.eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
if (road.entry_allowed)
|
|
|
|
has_motorway = true;
|
|
|
|
}
|
2016-11-03 05:18:27 -04:00
|
|
|
else if (!isRampClass(road.eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
has_normal_roads = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_normal_roads)
|
|
|
|
return false;
|
|
|
|
|
2016-06-24 10:06:45 -04:00
|
|
|
return has_motorway || isMotorwayClass(via_eid, node_based_graph);
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Intersection MotorwayHandler::
|
|
|
|
operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const
|
|
|
|
{
|
|
|
|
// coming from motorway
|
2016-06-24 10:06:45 -04:00
|
|
|
if (isMotorwayClass(via_eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-05-03 07:37:41 -04:00
|
|
|
intersection = fromMotorway(via_eid, std::move(intersection));
|
|
|
|
std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
|
2016-11-03 05:18:27 -04:00
|
|
|
if (road.instruction.type == TurnType::OnRamp)
|
|
|
|
road.instruction.type = TurnType::OffRamp;
|
2016-05-03 07:37:41 -04:00
|
|
|
});
|
|
|
|
return intersection;
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else // coming from a ramp
|
|
|
|
{
|
|
|
|
return fromRamp(via_eid, std::move(intersection));
|
|
|
|
// ramp merging straight onto motorway
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection intersection) const
|
|
|
|
{
|
|
|
|
const auto &in_data = node_based_graph.GetEdgeData(via_eid);
|
2016-06-24 10:06:45 -04:00
|
|
|
BOOST_ASSERT(isMotorwayClass(via_eid, node_based_graph));
|
2016-04-08 06:49:14 -04:00
|
|
|
|
|
|
|
const auto countExitingMotorways = [this](const Intersection &intersection) {
|
|
|
|
unsigned count = 0;
|
|
|
|
for (const auto &road : intersection)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
if (road.entry_allowed && isMotorwayClass(road.eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
++count;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
|
|
|
|
// find the angle that continues on our current highway
|
|
|
|
const auto getContinueAngle = [this, in_data](const Intersection &intersection) {
|
|
|
|
for (const auto &road : intersection)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
|
2016-09-22 10:42:38 -04:00
|
|
|
|
2016-10-25 15:12:10 -04:00
|
|
|
const auto same_name = !util::guidance::requiresNameAnnounced(
|
|
|
|
in_data.name_id, out_data.name_id, name_table, street_name_suffix_table);
|
2016-09-22 10:42:38 -04:00
|
|
|
|
|
|
|
if (road.angle != 0 && in_data.name_id != EMPTY_NAMEID &&
|
|
|
|
out_data.name_id != EMPTY_NAMEID && same_name &&
|
|
|
|
isMotorwayClass(road.eid, node_based_graph))
|
2016-11-03 05:18:27 -04:00
|
|
|
return road.angle;
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
2016-11-03 05:18:27 -04:00
|
|
|
return intersection[0].angle;
|
2016-04-08 06:49:14 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto getMostLikelyContinue = [this, in_data](const Intersection &intersection) {
|
2016-11-03 05:18:27 -04:00
|
|
|
double angle = intersection[0].angle;
|
2016-04-08 06:49:14 -04:00
|
|
|
double best = 180;
|
|
|
|
for (const auto &road : intersection)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
if (isMotorwayClass(road.eid, node_based_graph) &&
|
|
|
|
angularDeviation(road.angle, STRAIGHT_ANGLE) < best)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
best = angularDeviation(road.angle, STRAIGHT_ANGLE);
|
|
|
|
angle = road.angle;
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return angle;
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto findBestContinue = [&]() {
|
|
|
|
const double continue_angle = getContinueAngle(intersection);
|
2016-11-03 05:18:27 -04:00
|
|
|
if (continue_angle != intersection[0].angle)
|
2016-04-08 06:49:14 -04:00
|
|
|
return continue_angle;
|
|
|
|
else
|
|
|
|
return getMostLikelyContinue(intersection);
|
|
|
|
};
|
|
|
|
|
|
|
|
// find continue angle
|
|
|
|
const double continue_angle = findBestContinue();
|
|
|
|
// highway does not continue and has no obvious choice
|
2016-11-03 05:18:27 -04:00
|
|
|
if (continue_angle == intersection[0].angle)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
if (intersection.size() == 2)
|
|
|
|
{
|
|
|
|
// do not announce ramps at the end of a highway
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction = {TurnType::NoTurn,
|
|
|
|
getTurnDirection(intersection[1].angle)};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else if (intersection.size() == 3)
|
|
|
|
{
|
|
|
|
// splitting ramp at the end of a highway
|
|
|
|
if (intersection[1].entry_allowed && intersection[2].entry_allowed)
|
|
|
|
{
|
|
|
|
assignFork(via_eid, intersection[2], intersection[1]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ending in a passing ramp
|
|
|
|
if (intersection[1].entry_allowed)
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction = {TurnType::NoTurn,
|
|
|
|
getTurnDirection(intersection[1].angle)};
|
2016-04-08 06:49:14 -04:00
|
|
|
else
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[2].instruction = {TurnType::NoTurn,
|
|
|
|
getTurnDirection(intersection[2].angle)};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (intersection.size() == 4 &&
|
2016-06-24 10:06:45 -04:00
|
|
|
roadClass(intersection[1], node_based_graph) ==
|
|
|
|
roadClass(intersection[2], node_based_graph) &&
|
|
|
|
roadClass(intersection[2], node_based_graph) ==
|
|
|
|
roadClass(intersection[3], node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
// tripple fork at the end
|
|
|
|
assignFork(via_eid, intersection[3], intersection[2], intersection[1]);
|
|
|
|
}
|
|
|
|
|
2016-10-26 17:32:29 -04:00
|
|
|
else if (intersection.countEnterable() > 0) // check whether turns exist at all
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
// FALLBACK, this should hopefully never be reached
|
|
|
|
return fallback(std::move(intersection));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const unsigned exiting_motorways = countExitingMotorways(intersection);
|
|
|
|
|
|
|
|
if (exiting_motorways == 0)
|
|
|
|
{
|
|
|
|
// Ending in Ramp
|
|
|
|
for (auto &road : intersection)
|
|
|
|
{
|
|
|
|
if (road.entry_allowed)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
BOOST_ASSERT(isRampClass(road.eid, node_based_graph));
|
|
|
|
road.instruction = TurnInstruction::SUPPRESSED(getTurnDirection(road.angle));
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (exiting_motorways == 1)
|
|
|
|
{
|
|
|
|
// normal motorway passing some ramps or mering onto another motorway
|
|
|
|
if (intersection.size() == 2)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
BOOST_ASSERT(!isRampClass(intersection[1].eid, node_based_graph));
|
2016-04-08 06:49:14 -04:00
|
|
|
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction =
|
2016-05-27 15:05:04 -04:00
|
|
|
getInstructionForObvious(intersection.size(),
|
|
|
|
via_eid,
|
|
|
|
isThroughStreet(1, intersection),
|
|
|
|
intersection[1]);
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Normal Highway exit or merge
|
|
|
|
for (auto &road : intersection)
|
|
|
|
{
|
|
|
|
// ignore invalid uturns/other
|
|
|
|
if (!road.entry_allowed)
|
|
|
|
continue;
|
|
|
|
|
2016-11-03 05:18:27 -04:00
|
|
|
if (road.angle == continue_angle)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
road.instruction = getInstructionForObvious(
|
2016-04-11 06:51:06 -04:00
|
|
|
intersection.size(), via_eid, isThroughStreet(1, intersection), road);
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
2016-11-03 05:18:27 -04:00
|
|
|
else if (road.angle < continue_angle)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
road.instruction = {isRampClass(road.eid, node_based_graph)
|
|
|
|
? TurnType::OffRamp
|
|
|
|
: TurnType::Turn,
|
|
|
|
(road.angle < 145) ? DirectionModifier::Right
|
|
|
|
: DirectionModifier::SlightRight};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
2016-11-03 05:18:27 -04:00
|
|
|
else if (road.angle > continue_angle)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
road.instruction = {isRampClass(road.eid, node_based_graph)
|
|
|
|
? TurnType::OffRamp
|
|
|
|
: TurnType::Turn,
|
|
|
|
(road.angle > 215) ? DirectionModifier::Left
|
|
|
|
: DirectionModifier::SlightLeft};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// handle motorway forks
|
|
|
|
else if (exiting_motorways > 1)
|
|
|
|
{
|
|
|
|
if (exiting_motorways == 2 && intersection.size() == 2)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction =
|
2016-05-27 15:05:04 -04:00
|
|
|
getInstructionForObvious(intersection.size(),
|
|
|
|
via_eid,
|
|
|
|
isThroughStreet(1, intersection),
|
|
|
|
intersection[1]);
|
2016-04-08 06:49:14 -04:00
|
|
|
intersection[0].entry_allowed = false; // UTURN on the freeway
|
|
|
|
}
|
|
|
|
else if (exiting_motorways == 2)
|
|
|
|
{
|
|
|
|
// standard fork
|
|
|
|
std::size_t first_valid = std::numeric_limits<std::size_t>::max(),
|
|
|
|
second_valid = std::numeric_limits<std::size_t>::max();
|
|
|
|
for (std::size_t i = 0; i < intersection.size(); ++i)
|
|
|
|
{
|
|
|
|
if (intersection[i].entry_allowed &&
|
2016-11-03 05:18:27 -04:00
|
|
|
isMotorwayClass(intersection[i].eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
if (first_valid < intersection.size())
|
|
|
|
{
|
|
|
|
second_valid = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
first_valid = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assignFork(via_eid, intersection[second_valid], intersection[first_valid]);
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
for (std::size_t i = 0; i < intersection.size(); ++i)
|
|
|
|
{
|
|
|
|
if (intersection[i].entry_allowed &&
|
2016-11-03 05:18:27 -04:00
|
|
|
isMotorwayClass(intersection[i].eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
if (second_valid < intersection.size())
|
|
|
|
{
|
|
|
|
third_valid = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (first_valid < intersection.size())
|
|
|
|
{
|
|
|
|
second_valid = i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
first_valid = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-27 15:05:04 -04:00
|
|
|
assignFork(via_eid,
|
|
|
|
intersection[third_valid],
|
|
|
|
intersection[second_valid],
|
2016-04-08 06:49:14 -04:00
|
|
|
intersection[first_valid]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return fallback(std::move(intersection));
|
|
|
|
}
|
|
|
|
} // done for more than one highway exit
|
|
|
|
}
|
|
|
|
return intersection;
|
|
|
|
}
|
|
|
|
|
|
|
|
Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection intersection) const
|
|
|
|
{
|
2016-10-26 17:32:29 -04:00
|
|
|
auto num_valid_turns = intersection.countEnterable();
|
2016-04-08 06:49:14 -04:00
|
|
|
// ramp straight into a motorway/ramp
|
|
|
|
if (intersection.size() == 2 && num_valid_turns == 1)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
2016-11-03 05:18:27 -04:00
|
|
|
BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
|
2016-04-08 06:49:14 -04:00
|
|
|
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction = getInstructionForObvious(
|
2016-04-11 06:51:06 -04:00
|
|
|
intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]);
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else if (intersection.size() == 3)
|
|
|
|
{
|
2016-10-25 15:12:10 -04:00
|
|
|
const auto &second_intersection_data = node_based_graph.GetEdgeData(intersection[2].eid);
|
|
|
|
const auto &first_intersection_data = node_based_graph.GetEdgeData(intersection[1].eid);
|
|
|
|
const auto first_second_same_name =
|
|
|
|
!util::guidance::requiresNameAnnounced(second_intersection_data.name_id,
|
|
|
|
first_intersection_data.name_id,
|
|
|
|
name_table,
|
|
|
|
street_name_suffix_table);
|
2016-09-22 10:42:38 -04:00
|
|
|
|
2016-04-08 06:49:14 -04:00
|
|
|
// merging onto a passing highway / or two ramps merging onto the same highway
|
|
|
|
if (num_valid_turns == 1)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
|
|
|
// check order of highways
|
|
|
|
// 4
|
|
|
|
// 5 3
|
|
|
|
//
|
|
|
|
// 6 2
|
|
|
|
//
|
|
|
|
// 7 1
|
|
|
|
// 0
|
|
|
|
if (intersection[1].entry_allowed)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
|
2016-09-22 10:42:38 -04:00
|
|
|
second_intersection_data.name_id != EMPTY_NAMEID &&
|
|
|
|
first_intersection_data.name_id != EMPTY_NAMEID && first_second_same_name)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
// circular order indicates a merge to the left (0-3 onto 4
|
2016-11-03 05:18:27 -04:00
|
|
|
if (angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) <
|
2016-06-15 08:25:22 -04:00
|
|
|
2 * NARROW_TURN_ANGLE)
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction = {TurnType::Merge,
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-04-08 06:49:14 -04:00
|
|
|
else // fallback
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction = {TurnType::Merge,
|
|
|
|
getTurnDirection(intersection[1].angle)};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else // passing by the end of a motorway
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction =
|
2016-05-27 15:05:04 -04:00
|
|
|
getInstructionForObvious(intersection.size(),
|
|
|
|
via_eid,
|
|
|
|
isThroughStreet(1, intersection),
|
|
|
|
intersection[1]);
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(intersection[2].entry_allowed);
|
2016-11-03 05:18:27 -04:00
|
|
|
if (isMotorwayClass(intersection[2].eid, node_based_graph) &&
|
2016-09-22 10:42:38 -04:00
|
|
|
second_intersection_data.name_id != EMPTY_NAMEID &&
|
|
|
|
first_intersection_data.name_id != EMPTY_NAMEID && first_second_same_name)
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
// circular order (5-0) onto 4
|
2016-11-03 05:18:27 -04:00
|
|
|
if (angularDeviation(intersection[2].angle, STRAIGHT_ANGLE) <
|
2016-06-08 08:55:59 -04:00
|
|
|
2 * NARROW_TURN_ANGLE)
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[2].instruction = {TurnType::Merge,
|
|
|
|
DirectionModifier::SlightRight};
|
2016-04-08 06:49:14 -04:00
|
|
|
else // fallback
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[2].instruction = {TurnType::Merge,
|
|
|
|
getTurnDirection(intersection[2].angle)};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else // passing the end of a highway
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[2].instruction =
|
2016-05-27 15:05:04 -04:00
|
|
|
getInstructionForObvious(intersection.size(),
|
|
|
|
via_eid,
|
|
|
|
isThroughStreet(2, intersection),
|
|
|
|
intersection[2]);
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(num_valid_turns == 2);
|
|
|
|
// UTurn on ramps is not possible
|
|
|
|
BOOST_ASSERT(!intersection[0].entry_allowed);
|
|
|
|
BOOST_ASSERT(intersection[1].entry_allowed);
|
|
|
|
BOOST_ASSERT(intersection[2].entry_allowed);
|
|
|
|
// two motorways starting at end of ramp (fork)
|
|
|
|
// M M
|
|
|
|
// \ /
|
|
|
|
// |
|
|
|
|
// R
|
2016-11-03 05:18:27 -04:00
|
|
|
if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
|
|
|
|
isMotorwayClass(intersection[2].eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
assignFork(via_eid, intersection[2], intersection[1]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// continued ramp passing motorway entry
|
|
|
|
// M R
|
|
|
|
// M R
|
|
|
|
// | /
|
|
|
|
// R
|
2016-11-03 05:18:27 -04:00
|
|
|
if (isMotorwayClass(intersection[1].eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
intersection[1].instruction = {TurnType::Turn, DirectionModifier::SlightRight};
|
|
|
|
intersection[2].instruction = {TurnType::Continue,
|
|
|
|
DirectionModifier::SlightLeft};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assignFork(via_eid, intersection[2], intersection[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// On - Off Ramp on passing Motorway, Ramp onto Fork(?)
|
|
|
|
else if (intersection.size() == 4)
|
|
|
|
{
|
|
|
|
bool passed_highway_entry = false;
|
|
|
|
for (auto &road : intersection)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
if (!road.entry_allowed && isMotorwayClass(road.eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
|
|
|
passed_highway_entry = true;
|
|
|
|
}
|
2016-11-03 05:18:27 -04:00
|
|
|
else if (isMotorwayClass(road.eid, node_based_graph))
|
2016-04-08 06:49:14 -04:00
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
road.instruction = {TurnType::Merge,
|
|
|
|
passed_highway_entry ? DirectionModifier::SlightRight
|
|
|
|
: DirectionModifier::SlightLeft};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
BOOST_ASSERT(isRampClass(road.eid, node_based_graph));
|
|
|
|
road.instruction = {TurnType::OffRamp, getTurnDirection(road.angle)};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2016-12-02 04:53:22 -05:00
|
|
|
{
|
2016-04-08 06:49:14 -04:00
|
|
|
return fallback(std::move(intersection));
|
|
|
|
}
|
|
|
|
return intersection;
|
|
|
|
}
|
|
|
|
|
|
|
|
Intersection MotorwayHandler::fallback(Intersection intersection) const
|
|
|
|
{
|
|
|
|
for (auto &road : intersection)
|
|
|
|
{
|
|
|
|
if (!road.entry_allowed)
|
|
|
|
continue;
|
|
|
|
|
2016-06-24 10:06:45 -04:00
|
|
|
const auto type =
|
2016-11-03 05:18:27 -04:00
|
|
|
isMotorwayClass(road.eid, node_based_graph) ? TurnType::Merge : TurnType::Turn;
|
2016-04-08 06:49:14 -04:00
|
|
|
|
|
|
|
if (type == TurnType::Turn)
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
if (angularDeviation(road.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
|
|
|
|
road.instruction = {type, DirectionModifier::Straight};
|
2016-04-08 06:49:14 -04:00
|
|
|
else
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
road.instruction = {type,
|
|
|
|
road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
|
|
|
|
: DirectionModifier::SlightRight};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-03 05:18:27 -04:00
|
|
|
road.instruction = {type,
|
|
|
|
road.angle < STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
|
|
|
|
: DirectionModifier::SlightRight};
|
2016-04-08 06:49:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return intersection;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace guidance
|
|
|
|
} // namespace extractor
|
|
|
|
} // namespace osrm
|