link ConnectedRoad and TurnOperation via class hierarchy

and empower intersection by adding basic functionality to pod type
refactor extractor/toolkit into intersection
This commit is contained in:
Moritz Kobitzsch 2016-11-03 10:18:27 +01:00
parent 388d84a89e
commit cd03877c90
26 changed files with 665 additions and 661 deletions

View File

@ -75,6 +75,32 @@ template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, It
return fn; return fn;
} }
LaneID inline numLanesToTheRight(const engine::guidance::RouteStep &step)
{
return step.intersections.front().lanes.first_lane_from_the_right;
}
LaneID inline numLanesToTheLeft(const engine::guidance::RouteStep &step)
{
LaneID const total = step.intersections.front().lane_description.size();
return total - (step.intersections.front().lanes.lanes_in_turn +
step.intersections.front().lanes.first_lane_from_the_right);
}
auto inline lanesToTheLeft(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_left = numLanesToTheLeft(step);
return boost::make_iterator_range(description.begin(), description.begin() + num_lanes_left);
}
auto inline lanesToTheRight(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_right = numLanesToTheRight(step);
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
}
} // namespace guidance } // namespace guidance
} // namespace engine } // namespace engine
} // namespace osrm } // namespace osrm

View File

@ -6,6 +6,7 @@
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "util/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp" // EdgeID #include "util/typedefs.hpp" // EdgeID
namespace osrm namespace osrm
@ -18,7 +19,7 @@ namespace guidance
// Every Turn Operation describes a way of switching onto a segment, indicated by an EdgeID. The // Every Turn Operation describes a way of switching onto a segment, indicated by an EdgeID. The
// associated turn is described by an angle and an instruction that is used to announce it. // associated turn is described by an angle and an instruction that is used to announce it.
// The Turn Operation indicates what is exposed to the outside of the turn analysis. // The Turn Operation indicates what is exposed to the outside of the turn analysis.
struct TurnOperation final struct TurnOperation
{ {
EdgeID eid; EdgeID eid;
double angle; double angle;
@ -48,13 +49,23 @@ struct TurnOperation final
// aaaaaaaa // aaaaaaaa
// //
// We would perceive a->c as a sharp turn, a->b as a slight turn, and b->c as a slight turn. // We would perceive a->c as a sharp turn, a->b as a slight turn, and b->c as a slight turn.
struct ConnectedRoad final struct ConnectedRoad final : public TurnOperation
{ {
using Base = TurnOperation;
ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false); ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
// a turn may be relevant to good instructions, even if we cannot enter the road // a turn may be relevant to good instructions, even if we cannot enter the road
bool entry_allowed; bool entry_allowed;
TurnOperation turn;
// used to sort the set of connected roads (we require sorting throughout turn handling)
bool compareByAngle(const ConnectedRoad &other) const;
// make a left turn into an equivalent right turn and vice versa
void mirror();
OSRM_ATTR_WARN_UNUSED
ConnectedRoad getMirroredCopy() const;
}; };
// small helper function to print the content of a connected road // small helper function to print the content of a connected road
@ -64,25 +75,24 @@ struct Intersection final : public std::vector<ConnectedRoad>
{ {
using Base = std::vector<ConnectedRoad>; using Base = std::vector<ConnectedRoad>;
inline Base::iterator findClosestTurn(double angle) /*
{ * find the turn whose angle offers the least angularDeviation to the specified angle
return std::min_element(this->begin(), * E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
this->end(), * 80 over the difference of 90 to the 90 degree turn)
[angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { */
return util::guidance::angularDeviation(lhs.turn.angle, angle) < Base::iterator findClosestTurn(double angle);
util::guidance::angularDeviation(rhs.turn.angle, angle); Base::const_iterator findClosestTurn(double angle) const;
});
}
inline Base::const_iterator findClosestTurn(double angle) const /*
{ * Check validity of the intersection object. We assume a few basic properties every set of
return std::min_element(this->begin(), * connected roads should follow throughout guidance pre-processing. This utility function
this->end(), * allows checking intersections for validity
[angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { */
return util::guidance::angularDeviation(lhs.turn.angle, angle) < bool valid() const;
util::guidance::angularDeviation(rhs.turn.angle, angle);
}); // given all possible turns, which is the highest connected number of lanes per turn. This value
} // is used, for example, during generation of intersections.
std::uint8_t getHighestConnectedLaneCount(const util::NodeBasedDynamicGraph &) const;
}; };
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle); Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle);

View File

@ -18,12 +18,9 @@
#include "extractor/guidance/road_classification.hpp" #include "extractor/guidance/road_classification.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/route_step.hpp"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <map>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
@ -51,26 +48,6 @@ using util::guidance::leavesRoundabout;
// To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection // To simplify handling of Left/Right hand turns, we can mirror turns and write an intersection
// handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand // handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand
// turn and vice versa. // turn and vice versa.
OSRM_ATTR_WARN_UNUSED
inline ConnectedRoad mirror(ConnectedRoad road)
{
const constexpr DirectionModifier::Enum mirrored_modifiers[] = {DirectionModifier::UTurn,
DirectionModifier::SharpLeft,
DirectionModifier::Left,
DirectionModifier::SlightLeft,
DirectionModifier::Straight,
DirectionModifier::SlightRight,
DirectionModifier::Right,
DirectionModifier::SharpRight};
if (angularDeviation(road.turn.angle, 0) > std::numeric_limits<double>::epsilon())
{
road.turn.angle = 360 - road.turn.angle;
road.turn.instruction.direction_modifier =
mirrored_modifiers[road.turn.instruction.direction_modifier];
}
return road;
}
inline bool hasRoundaboutType(const TurnInstruction instruction) inline bool hasRoundaboutType(const TurnInstruction instruction)
{ {
@ -184,42 +161,6 @@ inline std::string applyAccessTokens(std::string lane_string, const std::string
return result_string; return result_string;
} }
LaneID inline numLanesToTheRight(const engine::guidance::RouteStep &step)
{
return step.intersections.front().lanes.first_lane_from_the_right;
}
LaneID inline numLanesToTheLeft(const engine::guidance::RouteStep &step)
{
LaneID const total = step.intersections.front().lane_description.size();
return total - (step.intersections.front().lanes.lanes_in_turn +
step.intersections.front().lanes.first_lane_from_the_right);
}
auto inline lanesToTheLeft(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_left = numLanesToTheLeft(step);
return boost::make_iterator_range(description.begin(), description.begin() + num_lanes_left);
}
auto inline lanesToTheRight(const engine::guidance::RouteStep &step)
{
const auto &description = step.intersections.front().lane_description;
LaneID num_lanes_right = numLanesToTheRight(step);
return boost::make_iterator_range(description.end() - num_lanes_right, description.end());
}
inline std::uint8_t getLaneCountAtIntersection(const NodeID intersection_node,
const util::NodeBasedDynamicGraph &node_based_graph)
{
std::uint8_t lanes = 0;
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(intersection_node))
lanes = std::max(
lanes, node_based_graph.GetEdgeData(onto_edge).road_classification.GetNumberOfLanes());
return lanes;
}
inline bool obviousByRoadClass(const RoadClassification in_classification, inline bool obviousByRoadClass(const RoadClassification in_classification,
const RoadClassification obvious_candidate, const RoadClassification obvious_candidate,
const RoadClassification compare_candidate) const RoadClassification compare_candidate)
@ -282,6 +223,16 @@ leastSquareRegression(const std::vector<util::Coordinate> &coordinates)
return {regression_first, regression_end}; return {regression_first, regression_end};
} }
inline std::uint8_t getLaneCountAtIntersection(const NodeID intersection_node,
const util::NodeBasedDynamicGraph &node_based_graph)
{
std::uint8_t lanes = 0;
for (const EdgeID onto_edge : node_based_graph.GetAdjacentEdgeRange(intersection_node))
lanes = std::max(
lanes, node_based_graph.GetEdgeData(onto_edge).road_classification.GetNumberOfLanes());
return lanes;
}
} // namespace guidance } // namespace guidance
} // namespace extractor } // namespace extractor
} // namespace osrm } // namespace osrm

View File

@ -23,12 +23,12 @@ namespace api
struct ParsedURL; struct ParsedURL;
} }
class ServiceHandlerInterface class ServiceHandlerInterface
{ {
public: public:
virtual ~ServiceHandlerInterface() {} virtual ~ServiceHandlerInterface() {}
virtual engine::Status RunQuery(api::ParsedURL parsed_url, service::BaseService::ResultT & result) = 0; virtual engine::Status RunQuery(api::ParsedURL parsed_url,
service::BaseService::ResultT &result) = 0;
}; };
class ServiceHandler final : public ServiceHandlerInterface class ServiceHandler final : public ServiceHandlerInterface

View File

@ -73,8 +73,7 @@ inline void print(const NodeBasedDynamicGraph &node_based_graph,
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
std::cout << "\t" << toString(road) << "\n"; std::cout << "\t" << toString(road) << "\n";
std::cout << "\t\t" std::cout << "\t\t" << node_based_graph.GetEdgeData(road.eid).road_classification.ToString()
<< node_based_graph.GetEdgeData(road.turn.eid).road_classification.ToString()
<< "\n"; << "\n";
} }
std::cout << std::flush; std::cout << std::flush;

View File

@ -42,7 +42,6 @@ unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometri
return util::viewport::getFittedZoom(south_west, north_east); return util::viewport::getFittedZoom(south_west, north_east);
} }
} }
std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries, std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
@ -62,7 +61,8 @@ std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &l
using GeometryIter = decltype(overview_geometry)::const_iterator; using GeometryIter = decltype(overview_geometry)::const_iterator;
auto leg_reverse_index = leg_geometries.size(); auto leg_reverse_index = leg_geometries.size();
const auto insert_without_overlap = [&leg_reverse_index, &overview_geometry](GeometryIter begin, GeometryIter end) { const auto insert_without_overlap = [&leg_reverse_index, &overview_geometry](GeometryIter begin,
GeometryIter end) {
// not the last leg // not the last leg
if (leg_reverse_index > 1) if (leg_reverse_index > 1)
{ {
@ -77,7 +77,8 @@ std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &l
const auto zoom_level = std::min(18u, calculateOverviewZoomLevel(leg_geometries)); const auto zoom_level = std::min(18u, calculateOverviewZoomLevel(leg_geometries));
for (const auto &geometry : leg_geometries) for (const auto &geometry : leg_geometries)
{ {
const auto simplified = douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level); const auto simplified =
douglasPeucker(geometry.locations.begin(), geometry.locations.end(), zoom_level);
insert_without_overlap(simplified.begin(), simplified.end()); insert_without_overlap(simplified.begin(), simplified.end());
} }
} }

View File

@ -2,7 +2,7 @@
#include "util/group_by.hpp" #include "util/group_by.hpp"
#include "util/guidance/toolkit.hpp" #include "util/guidance/toolkit.hpp"
#include "extractor/guidance/toolkit.hpp" #include "engine/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/post_processing.hpp" #include "engine/guidance/post_processing.hpp"
@ -16,8 +16,6 @@ namespace DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::isLeftTurn; using osrm::util::guidance::isLeftTurn;
using osrm::util::guidance::isRightTurn; using osrm::util::guidance::isRightTurn;
using osrm::extractor::guidance::numLanesToTheRight;
using osrm::extractor::guidance::numLanesToTheLeft;
namespace osrm namespace osrm
{ {

View File

@ -1,7 +1,7 @@
#include "engine/guidance/post_processing.hpp" #include "engine/guidance/post_processing.hpp"
#include "extractor/guidance/constants.hpp" #include "extractor/guidance/constants.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_instruction.hpp" #include "extractor/guidance/turn_instruction.hpp"
#include "engine/guidance/toolkit.hpp"
#include "engine/guidance/assemble_steps.hpp" #include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/lane_processing.hpp" #include "engine/guidance/lane_processing.hpp"
@ -1599,13 +1599,13 @@ std::vector<RouteStep> collapseUseLane(std::vector<RouteStep> steps)
// the lane description is given left to right, lanes are counted from the right. // the lane description is given left to right, lanes are counted from the right.
// Therefore we access the lane description using the reverse iterator // Therefore we access the lane description using the reverse iterator
auto right_most_lanes = extractor::guidance::lanesToTheRight(step); auto right_most_lanes = lanesToTheRight(step);
if (!right_most_lanes.empty() && containsTag(right_most_lanes.front(), if (!right_most_lanes.empty() && containsTag(right_most_lanes.front(),
(extractor::guidance::TurnLaneType::straight | (extractor::guidance::TurnLaneType::straight |
extractor::guidance::TurnLaneType::none))) extractor::guidance::TurnLaneType::none)))
return false; return false;
auto left_most_lanes = extractor::guidance::lanesToTheLeft(step); auto left_most_lanes = lanesToTheLeft(step);
if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(), if (!left_most_lanes.empty() && containsTag(left_most_lanes.back(),
(extractor::guidance::TurnLaneType::straight | (extractor::guidance::TurnLaneType::straight |
extractor::guidance::TurnLaneType::none))) extractor::guidance::TurnLaneType::none)))

View File

@ -376,6 +376,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u); const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
++node_based_edge_counter; ++node_based_edge_counter;
auto intersection = turn_analysis.getIntersection(node_u, edge_from_u); auto intersection = turn_analysis.getIntersection(node_u, edge_from_u);
BOOST_ASSERT(intersection.valid());
intersection = intersection =
turn_analysis.assignTurnTypes(node_u, edge_from_u, std::move(intersection)); turn_analysis.assignTurnTypes(node_u, edge_from_u, std::move(intersection));
intersection = intersection =
@ -462,7 +463,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn_instruction, turn_instruction,
entry_class_id, entry_class_id,
edge_data1.travel_mode, edge_data1.travel_mode,
util::guidance::TurnBearing(intersection[0].turn.bearing), util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing)); util::guidance::TurnBearing(turn.bearing));
} }
else if (is_encoded_backwards) else if (is_encoded_backwards)
@ -476,7 +477,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn_instruction, turn_instruction,
entry_class_id, entry_class_id,
edge_data1.travel_mode, edge_data1.travel_mode,
util::guidance::TurnBearing(intersection[0].turn.bearing), util::guidance::TurnBearing(intersection[0].bearing),
util::guidance::TurnBearing(turn.bearing)); util::guidance::TurnBearing(turn.bearing));
} }

View File

@ -24,8 +24,7 @@ operator()(const NodeID intersection_node,
{ {
// request the number of lanes. This process needs to be in sync with what happens over at // request the number of lanes. This process needs to be in sync with what happens over at
// intersection_generator // intersection_generator
const auto intersection_lanes = const auto intersection_lanes = intersection.getHighestConnectedLaneCount(node_based_graph);
extractor::guidance::getLaneCountAtIntersection(intersection_node, node_based_graph);
std::vector<util::Coordinate> coordinates; std::vector<util::Coordinate> coordinates;
coordinates.reserve(intersection.size()); coordinates.reserve(intersection.size());
@ -33,9 +32,9 @@ operator()(const NodeID intersection_node,
const auto road_to_coordinate = [&](const extractor::guidance::ConnectedRoad &connected_road) { const auto road_to_coordinate = [&](const extractor::guidance::ConnectedRoad &connected_road) {
const constexpr auto FORWARD = false; const constexpr auto FORWARD = false;
const auto to_node = node_based_graph.GetTarget(connected_road.turn.eid); const auto to_node = node_based_graph.GetTarget(connected_road.eid);
return coordinate_extractor.GetCoordinateAlongRoad( return coordinate_extractor.GetCoordinateAlongRoad(
intersection_node, connected_road.turn.eid, FORWARD, to_node, intersection_lanes); intersection_node, connected_road.eid, FORWARD, to_node, intersection_lanes);
}; };
std::transform(intersection.begin(), std::transform(intersection.begin(),

View File

@ -1,6 +1,13 @@
#include "extractor/guidance/intersection.hpp" #include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <algorithm>
#include <functional>
#include <limits>
namespace osrm namespace osrm
{ {
namespace extractor namespace extractor
@ -9,44 +16,101 @@ namespace guidance
{ {
ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed) ConnectedRoad::ConnectedRoad(const TurnOperation turn, const bool entry_allowed)
: entry_allowed(entry_allowed), turn(turn) : TurnOperation(turn), entry_allowed(entry_allowed)
{ {
} }
bool ConnectedRoad::compareByAngle(const ConnectedRoad &other) const { return angle < other.angle; }
void ConnectedRoad::mirror()
{
const constexpr DirectionModifier::Enum mirrored_modifiers[] = {DirectionModifier::UTurn,
DirectionModifier::SharpLeft,
DirectionModifier::Left,
DirectionModifier::SlightLeft,
DirectionModifier::Straight,
DirectionModifier::SlightRight,
DirectionModifier::Right,
DirectionModifier::SharpRight};
static_assert(sizeof(mirrored_modifiers) / sizeof(DirectionModifier::Enum) ==
DirectionModifier::MaxDirectionModifier,
"The list of mirrored modifiers needs to match the available modifiers in size.");
if (angularDeviation(angle, 0) > std::numeric_limits<double>::epsilon())
{
angle = 360 - angle;
instruction.direction_modifier = mirrored_modifiers[instruction.direction_modifier];
}
}
ConnectedRoad ConnectedRoad::getMirroredCopy() const
{
ConnectedRoad copy(*this);
copy.mirror();
return copy;
}
std::string toString(const ConnectedRoad &road) std::string toString(const ConnectedRoad &road)
{ {
std::string result = "[connection] "; std::string result = "[connection] ";
result += std::to_string(road.turn.eid); result += std::to_string(road.eid);
result += " allows entry: "; result += " allows entry: ";
result += std::to_string(road.entry_allowed); result += std::to_string(road.entry_allowed);
result += " angle: "; result += " angle: ";
result += std::to_string(road.turn.angle); result += std::to_string(road.angle);
result += " bearing: "; result += " bearing: ";
result += std::to_string(road.turn.bearing); result += std::to_string(road.bearing);
result += " instruction: "; result += " instruction: ";
result += std::to_string(static_cast<std::int32_t>(road.turn.instruction.type)) + " " + result += std::to_string(static_cast<std::int32_t>(road.instruction.type)) + " " +
std::to_string(static_cast<std::int32_t>(road.turn.instruction.direction_modifier)) + std::to_string(static_cast<std::int32_t>(road.instruction.direction_modifier)) + " " +
" " + std::to_string(static_cast<std::int32_t>(road.turn.lane_data_id)); std::to_string(static_cast<std::int32_t>(road.lane_data_id));
return result; return result;
} }
Intersection::iterator findClosestTurn(Intersection &intersection, const double angle) Intersection::Base::iterator Intersection::findClosestTurn(double angle)
{ {
return std::min_element(intersection.begin(), // use the const operator to avoid code duplication
intersection.end(), return begin() +
[angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { std::distance(cbegin(), static_cast<const Intersection *>(this)->findClosestTurn(angle));
return angularDeviation(lhs.turn.angle, angle) < }
angularDeviation(rhs.turn.angle, angle);
Intersection::Base::const_iterator Intersection::findClosestTurn(double angle) const
{
return std::min_element(
begin(), end(), [angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
return util::guidance::angularDeviation(lhs.angle, angle) <
util::guidance::angularDeviation(rhs.angle, angle);
}); });
} }
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle)
bool Intersection::valid() const
{ {
return std::min_element(intersection.cbegin(), return !empty() &&
intersection.cend(), std::is_sorted(begin(), end(), std::mem_fn(&ConnectedRoad::compareByAngle)) &&
[angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { operator[](0).angle < std::numeric_limits<double>::epsilon();
return angularDeviation(lhs.turn.angle, angle) < }
angularDeviation(rhs.turn.angle, angle);
}); std::uint8_t Intersection::getHighestConnectedLaneCount(
const util::NodeBasedDynamicGraph &node_based_graph) const
{
BOOST_ASSERT(valid()); // non empty()
std::vector<ConnectedRoad> test;
const auto to_lane_count = [&](const ConnectedRoad &road) {
return node_based_graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes();
};
// boost::range::transformed sadly does not work with lamdas since they are not copy
// constructable. We need to work around this :(
std::uint8_t max_lanes = 0;
const auto extract_maximal_value = [&max_lanes](std::uint8_t value) {
max_lanes = std::max(max_lanes, value);
return false;
};
const auto view = test | boost::adaptors::transformed(to_lane_count);
boost::range::find_if(view, extract_maximal_value);
return max_lanes;
} }
} // namespace guidance } // namespace guidance

View File

@ -3,6 +3,7 @@
#include "extractor/guidance/toolkit.hpp" #include "extractor/guidance/toolkit.hpp"
#include <algorithm> #include <algorithm>
#include <functional>
#include <iomanip> #include <iomanip>
#include <iterator> #include <iterator>
#include <limits> #include <limits>
@ -179,13 +180,12 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node,
false}); false});
} }
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) { std::sort(std::begin(intersection),
return first.turn.angle < second.turn.angle; std::end(intersection),
}; std::mem_fn(&ConnectedRoad::compareByAngle));
std::sort(std::begin(intersection), std::end(intersection), ByAngle);
BOOST_ASSERT(intersection[0].turn.angle >= 0. && BOOST_ASSERT(intersection[0].angle >= 0. &&
intersection[0].turn.angle < std::numeric_limits<double>::epsilon()); intersection[0].angle < std::numeric_limits<double>::epsilon());
const auto valid_count = const auto valid_count =
boost::count_if(intersection, [](const ConnectedRoad &road) { return road.entry_allowed; }); boost::count_if(intersection, [](const ConnectedRoad &road) { return road.entry_allowed; });
@ -196,13 +196,13 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node,
// that was inserted together with setting uturn_could_be_valid flag // that was inserted together with setting uturn_could_be_valid flag
std::size_t self_u_turn = 0; std::size_t self_u_turn = 0;
while (self_u_turn < intersection.size() && while (self_u_turn < intersection.size() &&
intersection[self_u_turn].turn.angle < std::numeric_limits<double>::epsilon() && intersection[self_u_turn].angle < std::numeric_limits<double>::epsilon() &&
from_node != node_based_graph.GetTarget(intersection[self_u_turn].turn.eid)) from_node != node_based_graph.GetTarget(intersection[self_u_turn].eid))
{ {
++self_u_turn; ++self_u_turn;
} }
BOOST_ASSERT(from_node == node_based_graph.GetTarget(intersection[self_u_turn].turn.eid)); BOOST_ASSERT(from_node == node_based_graph.GetTarget(intersection[self_u_turn].eid));
intersection[self_u_turn].entry_allowed = true; intersection[self_u_turn].entry_allowed = true;
} }
return intersection; return intersection;
@ -215,8 +215,8 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
std::size_t first_index, std::size_t first_index,
std::size_t second_index) const std::size_t second_index) const
{ {
const auto &first_data = node_based_graph.GetEdgeData(intersection[first_index].turn.eid); const auto &first_data = node_based_graph.GetEdgeData(intersection[first_index].eid);
const auto &second_data = node_based_graph.GetEdgeData(intersection[second_index].turn.eid); const auto &second_data = node_based_graph.GetEdgeData(intersection[second_index].eid);
// only merge named ids // only merge named ids
if (first_data.name_id == EMPTY_NAMEID) if (first_data.name_id == EMPTY_NAMEID)
@ -245,17 +245,16 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
return false; return false;
// mergeable if the angle is not too big // mergeable if the angle is not too big
const auto angle_between = angularDeviation(intersection[first_index].turn.angle, const auto angle_between =
intersection[second_index].turn.angle); angularDeviation(intersection[first_index].angle, intersection[second_index].angle);
const auto intersection_lanes = const auto intersection_lanes = intersection.getHighestConnectedLaneCount(node_based_graph);
getLaneCountAtIntersection(node_at_intersection, node_based_graph);
const auto coordinate_at_in_edge = coordinate_extractor.GetCoordinateAlongRoad( const auto coordinate_at_in_edge =
node_at_intersection, coordinate_extractor.GetCoordinateAlongRoad(node_at_intersection,
intersection[0].turn.eid, intersection[0].eid,
!INVERT, !INVERT,
node_based_graph.GetTarget(intersection[0].turn.eid), node_based_graph.GetTarget(intersection[0].eid),
intersection_lanes); intersection_lanes);
const auto coordinate_at_intersection = node_info_list[node_at_intersection]; const auto coordinate_at_intersection = node_info_list[node_at_intersection];
@ -272,7 +271,7 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
const auto GetActualTarget = [&](const std::size_t index) { const auto GetActualTarget = [&](const std::size_t index) {
EdgeID last_in_edge_id; EdgeID last_in_edge_id;
GetActualNextIntersection( GetActualNextIntersection(
node_at_intersection, intersection[index].turn.eid, nullptr, &last_in_edge_id); node_at_intersection, intersection[index].eid, nullptr, &last_in_edge_id);
return node_based_graph.GetTarget(last_in_edge_id); return node_based_graph.GetTarget(last_in_edge_id);
}; };
@ -292,12 +291,11 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
const bool becomes_narrower = const bool becomes_narrower =
angularDeviation(turn_angle, other_turn_angle) < NARROW_TURN_ANGLE && angularDeviation(turn_angle, other_turn_angle) < NARROW_TURN_ANGLE &&
angularDeviation(turn_angle, other_turn_angle) <= angularDeviation(turn_angle, other_turn_angle) <=
angularDeviation(intersection[index].turn.angle, angularDeviation(intersection[index].angle, intersection[other_index].angle);
intersection[other_index].turn.angle);
const bool has_same_deviation = const bool has_same_deviation =
std::abs(angularDeviation(intersection[index].turn.angle, STRAIGHT_ANGLE) - std::abs(angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) -
angularDeviation(intersection[other_index].turn.angle, STRAIGHT_ANGLE)) < angularDeviation(intersection[other_index].angle, STRAIGHT_ANGLE)) <
MAXIMAL_ALLOWED_NO_TURN_DEVIATION; MAXIMAL_ALLOWED_NO_TURN_DEVIATION;
return becomes_narrower || has_same_deviation; return becomes_narrower || has_same_deviation;
@ -330,17 +328,14 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
}(); }();
// needs to be same road coming in // needs to be same road coming in
if (node_based_graph.GetEdgeData(intersection[third_index].turn.eid).name_id != if (node_based_graph.GetEdgeData(intersection[third_index].eid).name_id != first_data.name_id)
first_data.name_id)
return false; return false;
// we only allow collapsing of a Y like fork. So the angle to the third index has to be // we only allow collapsing of a Y like fork. So the angle to the third index has to be
// roughly equal: // roughly equal:
const auto y_angle_difference = const auto y_angle_difference = angularDeviation(
angularDeviation(angularDeviation(intersection[third_index].turn.angle, angularDeviation(intersection[third_index].angle, intersection[first_index].angle),
intersection[first_index].turn.angle), angularDeviation(intersection[third_index].angle, intersection[second_index].angle));
angularDeviation(intersection[third_index].turn.angle,
intersection[second_index].turn.angle));
// Allow larger angles if its three roads only of the same name // Allow larger angles if its three roads only of the same name
// This is a heuristic and might need to be revised. // This is a heuristic and might need to be revised.
@ -403,10 +398,10 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
const auto merge = [combineAngles](const ConnectedRoad &first, const auto merge = [combineAngles](const ConnectedRoad &first,
const ConnectedRoad &second) -> ConnectedRoad { const ConnectedRoad &second) -> ConnectedRoad {
ConnectedRoad result = first.entry_allowed ? first : second; ConnectedRoad result = first.entry_allowed ? first : second;
result.turn.angle = combineAngles(first.turn.angle, second.turn.angle); result.angle = combineAngles(first.angle, second.angle);
result.turn.bearing = combineAngles(first.turn.bearing, second.turn.bearing); result.bearing = combineAngles(first.bearing, second.bearing);
BOOST_ASSERT(0 <= result.turn.angle && result.turn.angle <= 360.0); BOOST_ASSERT(0 <= result.angle && result.angle <= 360.0);
BOOST_ASSERT(0 <= result.turn.bearing && result.turn.bearing <= 360.0); BOOST_ASSERT(0 <= result.bearing && result.bearing <= 360.0);
return result; return result;
}; };
@ -416,7 +411,7 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
const bool is_connected_to_roundabout = [this, &intersection]() { const bool is_connected_to_roundabout = [this, &intersection]() {
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
if (node_based_graph.GetEdgeData(road.turn.eid).roundabout) if (node_based_graph.GetEdgeData(road.eid).roundabout)
return true; return true;
} }
return false; return false;
@ -459,26 +454,25 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
{ {
merged_first = true; merged_first = true;
// moving `a` to the left // moving `a` to the left
const double correction_factor = const double correction_factor = (360 - intersection[intersection.size() - 1].angle) / 2;
(360 - intersection[intersection.size() - 1].turn.angle) / 2;
for (std::size_t i = 1; i + 1 < intersection.size(); ++i) for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
intersection[i].turn.angle += correction_factor; intersection[i].angle += correction_factor;
// FIXME if we have a left-sided country, we need to switch this off and enable it // FIXME if we have a left-sided country, we need to switch this off and enable it
// below // below
intersection[0] = merge(intersection.front(), intersection.back()); intersection[0] = merge(intersection.front(), intersection.back());
intersection[0].turn.angle = 0; intersection[0].angle = 0;
intersection.pop_back(); intersection.pop_back();
} }
else if (CanMerge(intersection_node, intersection, 0, 1)) else if (CanMerge(intersection_node, intersection, 0, 1))
{ {
merged_first = true; merged_first = true;
// moving `a` to the right // moving `a` to the right
const double correction_factor = (intersection[1].turn.angle) / 2; const double correction_factor = (intersection[1].angle) / 2;
for (std::size_t i = 2; i < intersection.size(); ++i) for (std::size_t i = 2; i < intersection.size(); ++i)
intersection[i].turn.angle -= correction_factor; intersection[i].angle -= correction_factor;
intersection[0] = merge(intersection[0], intersection[1]); intersection[0] = merge(intersection[0], intersection[1]);
intersection[0].turn.angle = 0; intersection[0].angle = 0;
intersection.erase(intersection.begin() + 1); intersection.erase(intersection.begin() + 1);
} }
@ -510,10 +504,9 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
} }
} }
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) { std::sort(std::begin(intersection),
return first.turn.angle < second.turn.angle; std::end(intersection),
}; std::mem_fn(&ConnectedRoad::compareByAngle));
std::sort(std::begin(intersection), std::end(intersection), ByAngle);
return intersection; return intersection;
} }
@ -552,13 +545,12 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
// to find out about the above situation, we need to look at the next intersection (at d in // to find out about the above situation, we need to look at the next intersection (at d in
// the example). If the initial road can be merged to the left/right, we are about to adjust // the example). If the initial road can be merged to the left/right, we are about to adjust
// the angle. // the angle.
const auto next_intersection_along_road = const auto next_intersection_along_road = GetConnectedRoads(node_at_intersection, road.eid);
GetConnectedRoads(node_at_intersection, road.turn.eid);
if (next_intersection_along_road.size() <= 1) if (next_intersection_along_road.size() <= 1)
continue; continue;
const auto node_at_next_intersection = node_based_graph.GetTarget(road.turn.eid); const auto node_at_next_intersection = node_based_graph.GetTarget(road.eid);
const util::Coordinate coordinate_at_next_intersection = const util::Coordinate coordinate_at_next_intersection =
node_info_list[node_at_next_intersection]; node_info_list[node_at_next_intersection];
if (util::coordinate_calculation::haversineDistance(coordinate_at_intersection, if (util::coordinate_calculation::haversineDistance(coordinate_at_intersection,
@ -580,7 +572,7 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
// the order does not matter // the order does not matter
const auto get_offset = [](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { const auto get_offset = [](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
return 0.5 * angularDeviation(lhs.turn.angle, rhs.turn.angle); return 0.5 * angularDeviation(lhs.angle, rhs.angle);
}; };
// When offsetting angles in our turns, we don't want to get past the next turn. This // When offsetting angles in our turns, we don't want to get past the next turn. This
@ -590,7 +582,7 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
const ConnectedRoad &road, const ConnectedRoad &road,
const ConnectedRoad &next_road_in_offset_direction) { const ConnectedRoad &next_road_in_offset_direction) {
const auto offset_limit = const auto offset_limit =
angularDeviation(road.turn.angle, next_road_in_offset_direction.turn.angle); angularDeviation(road.angle, next_road_in_offset_direction.angle);
// limit the offset with an additional buffer // limit the offset with an additional buffer
return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit
: offset; : offset;
@ -608,8 +600,8 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
get_corrected_offset(offset, road, intersection[(index + 1) % intersection.size()]); get_corrected_offset(offset, road, intersection[(index + 1) % intersection.size()]);
// at the target intersection, we merge to the right, so we need to shift the current // at the target intersection, we merge to the right, so we need to shift the current
// angle to the left // angle to the left
road.turn.angle = adjustAngle(road.turn.angle, corrected_offset); road.angle = adjustAngle(road.angle, corrected_offset);
road.turn.bearing = adjustAngle(road.turn.bearing, corrected_offset); road.bearing = adjustAngle(road.bearing, corrected_offset);
} }
else if (CanMerge(node_at_next_intersection, else if (CanMerge(node_at_next_intersection,
next_intersection_along_road, next_intersection_along_road,
@ -624,8 +616,8 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
get_corrected_offset(offset, road, intersection[index - 1]); get_corrected_offset(offset, road, intersection[index - 1]);
// at the target intersection, we merge to the left, so we need to shift the current // at the target intersection, we merge to the left, so we need to shift the current
// angle to the right // angle to the right
road.turn.angle = adjustAngle(road.turn.angle, -corrected_offset); road.angle = adjustAngle(road.angle, -corrected_offset);
road.turn.bearing = adjustAngle(road.turn.bearing, -corrected_offset); road.bearing = adjustAngle(road.bearing, -corrected_offset);
} }
} }
return intersection; return intersection;
@ -653,11 +645,11 @@ IntersectionGenerator::GetActualNextIntersection(const NodeID starting_node,
while (visited_nodes.count(node_at_intersection) == 0 && while (visited_nodes.count(node_at_intersection) == 0 &&
(result.size() == 2 && (result.size() == 2 &&
node_based_graph.GetEdgeData(via_edge).IsCompatibleTo( node_based_graph.GetEdgeData(via_edge).IsCompatibleTo(
node_based_graph.GetEdgeData(result[1].turn.eid)))) node_based_graph.GetEdgeData(result[1].eid))))
{ {
visited_nodes.insert(node_at_intersection); visited_nodes.insert(node_at_intersection);
node_at_intersection = node_based_graph.GetTarget(incoming_edge); node_at_intersection = node_based_graph.GetTarget(incoming_edge);
incoming_edge = result[1].turn.eid; incoming_edge = result[1].eid;
result = GetConnectedRoads(node_at_intersection, incoming_edge); result = GetConnectedRoads(node_at_intersection, incoming_edge);
// When looping back to the original node, we obviously are in a loop. Stop there. // When looping back to the original node, we obviously are in a loop. Stop there.

View File

@ -50,7 +50,7 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
{ {
const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &in_data = node_based_graph.GetEdgeData(via_edge);
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(road.eid);
bool on_ramp = in_data.road_classification.IsRampClass(); bool on_ramp = in_data.road_classification.IsRampClass();
@ -75,20 +75,20 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
const auto type = findBasicTurnType(via_edge, road); const auto type = findBasicTurnType(via_edge, road);
// handle travel modes: // handle travel modes:
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode; 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; const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
if (type == TurnType::OnRamp) if (type == TurnType::OnRamp)
{ {
return {TurnType::OnRamp, getTurnDirection(road.turn.angle)}; return {TurnType::OnRamp, getTurnDirection(road.angle)};
} }
if (angularDeviation(road.turn.angle, 0) < 0.01) if (angularDeviation(road.angle, 0) < 0.01)
{ {
return {TurnType::Turn, DirectionModifier::UTurn}; return {TurnType::Turn, DirectionModifier::UTurn};
} }
if (type == TurnType::Turn) if (type == TurnType::Turn)
{ {
const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &in_data = node_based_graph.GetEdgeData(via_edge);
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(road.eid);
if (in_data.name_id != out_data.name_id && if (in_data.name_id != out_data.name_id &&
util::guidance::requiresNameAnnounced(name_table.GetNameForID(in_data.name_id), util::guidance::requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
name_table.GetRefForID(in_data.name_id), name_table.GetRefForID(in_data.name_id),
@ -104,7 +104,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
// that could potentially also offer different choices // that could potentially also offer different choices
if (out_data.road_classification.IsMotorwayClass()) if (out_data.road_classification.IsMotorwayClass())
return {TurnType::Merge, return {TurnType::Merge,
road.turn.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightRight road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightRight
: DirectionModifier::SlightLeft}; : DirectionModifier::SlightLeft};
else if (in_data.road_classification.IsRampClass() && else if (in_data.road_classification.IsRampClass() &&
out_data.road_classification.IsRampClass()) out_data.road_classification.IsRampClass())
@ -113,7 +113,7 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
// cannot reach this, since all ramps are exposing the same travel type. But we // cannot reach this, since all ramps are exposing the same travel type. But we
// could see toll-type at some point. // could see toll-type at some point.
return {in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification, return {in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification,
getTurnDirection(road.turn.angle)}; getTurnDirection(road.angle)};
} }
else else
{ {
@ -129,40 +129,40 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
// precalculated distance value. // precalculated distance value.
const auto distance = util::coordinate_calculation::haversineDistance( const auto distance = util::coordinate_calculation::haversineDistance(
node_info_list[node_based_graph.GetTarget(via_edge)], node_info_list[node_based_graph.GetTarget(via_edge)],
node_info_list[node_based_graph.GetTarget(road.turn.eid)]); node_info_list[node_based_graph.GetTarget(road.eid)]);
return {TurnType::Turn, return {
(angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < TurnType::Turn,
FUZZY_ANGLE_DIFFERENCE || (angularDeviation(road.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE ||
distance > 2 * MAX_COLLAPSE_DISTANCE) distance > 2 * MAX_COLLAPSE_DISTANCE)
? DirectionModifier::Straight ? DirectionModifier::Straight
: getTurnDirection(road.turn.angle)}; : getTurnDirection(road.angle)};
} }
} }
else else
{ {
return {in_mode == out_mode ? TurnType::NewName : TurnType::Notification, return {in_mode == out_mode ? TurnType::NewName : TurnType::Notification,
getTurnDirection(road.turn.angle)}; getTurnDirection(road.angle)};
} }
} }
// name has not changed, suppress a turn here or indicate mode change // name has not changed, suppress a turn here or indicate mode change
else else
{ {
return {in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification, return {in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification,
getTurnDirection(road.turn.angle)}; getTurnDirection(road.angle)};
} }
} }
BOOST_ASSERT(type == TurnType::Continue); BOOST_ASSERT(type == TurnType::Continue);
if (in_mode != out_mode) if (in_mode != out_mode)
{ {
return {TurnType::Notification, getTurnDirection(road.turn.angle)}; return {TurnType::Notification, getTurnDirection(road.angle)};
} }
if (num_roads > 2) if (num_roads > 2)
{ {
return {TurnType::Suppressed, getTurnDirection(road.turn.angle)}; return {TurnType::Suppressed, getTurnDirection(road.angle)};
} }
else else
{ {
return {TurnType::NoTurn, getTurnDirection(road.turn.angle)}; return {TurnType::NoTurn, getTurnDirection(road.angle)};
} }
} }
@ -172,107 +172,105 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
{ {
const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &in_data = node_based_graph.GetEdgeData(via_edge);
const bool low_priority_left = const bool low_priority_left =
node_based_graph.GetEdgeData(left.turn.eid).road_classification.IsLowPriorityRoadClass(); node_based_graph.GetEdgeData(left.eid).road_classification.IsLowPriorityRoadClass();
const bool low_priority_right = const bool low_priority_right =
node_based_graph.GetEdgeData(right.turn.eid).road_classification.IsLowPriorityRoadClass(); node_based_graph.GetEdgeData(right.eid).road_classification.IsLowPriorityRoadClass();
if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION && if ((angularDeviation(left.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)) angularDeviation(right.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
{ {
// left side is actually straight // left side is actually straight
const auto &out_data = node_based_graph.GetEdgeData(left.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(left.eid);
if (detail::requiresAnnouncement(in_data, out_data)) if (detail::requiresAnnouncement(in_data, out_data))
{ {
if (low_priority_right && !low_priority_left) if (low_priority_right && !low_priority_left)
{ {
left.turn.instruction = getInstructionForObvious(3, via_edge, false, left); left.instruction = getInstructionForObvious(3, via_edge, false, left);
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
else else
{ {
if (low_priority_left && !low_priority_right) if (low_priority_left && !low_priority_right)
{ {
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
else else
{ {
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft}; left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight}; right.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
} }
} }
} }
else else
{ {
left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight}; left.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
} }
else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) < else if (angularDeviation(right.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
MAXIMAL_ALLOWED_NO_TURN_DEVIATION && angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
{ {
// right side is actually straight // right side is actually straight
const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(right.eid);
if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(right.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
MAXIMAL_ALLOWED_NO_TURN_DEVIATION && angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
{ {
if (detail::requiresAnnouncement(in_data, out_data)) if (detail::requiresAnnouncement(in_data, out_data))
{ {
if (low_priority_left && !low_priority_right) if (low_priority_left && !low_priority_right)
{ {
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
right.turn.instruction = getInstructionForObvious(3, via_edge, false, right); right.instruction = getInstructionForObvious(3, via_edge, false, right);
} }
else else
{ {
if (low_priority_right && !low_priority_left) if (low_priority_right && !low_priority_left)
{ {
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
else else
{ {
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight}; right.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft}; left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
} }
} }
} }
else else
{ {
right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight}; right.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
} }
} }
// left side of fork // left side of fork
if (low_priority_right && !low_priority_left) if (low_priority_right && !low_priority_left)
left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft}; left.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
else else
{ {
if (low_priority_left && !low_priority_right) if (low_priority_left && !low_priority_right)
left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft}; left.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
else else
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft}; left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
} }
// right side of fork // right side of fork
if (low_priority_left && !low_priority_right) if (low_priority_left && !low_priority_right)
right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft}; right.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
else else
{ {
if (low_priority_right && !low_priority_left) if (low_priority_right && !low_priority_left)
right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight}; right.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
else else
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight}; right.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
} }
} }
@ -284,25 +282,25 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
// TODO handle low priority road classes in a reasonable way // TODO handle low priority road classes in a reasonable way
if (left.entry_allowed && center.entry_allowed && right.entry_allowed) if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
{ {
left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft}; left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION) if (angularDeviation(center.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
{ {
const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &in_data = node_based_graph.GetEdgeData(via_edge);
const auto &out_data = node_based_graph.GetEdgeData(center.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(center.eid);
if (detail::requiresAnnouncement(in_data, out_data)) if (detail::requiresAnnouncement(in_data, out_data))
{ {
center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight}; center.instruction = {TurnType::Fork, DirectionModifier::Straight};
} }
else else
{ {
center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight}; center.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
} }
} }
else else
{ {
center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight}; center.instruction = {TurnType::Fork, DirectionModifier::Straight};
} }
right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight}; right.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
} }
else if (left.entry_allowed) else if (left.entry_allowed)
{ {
@ -311,22 +309,20 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
else if (center.entry_allowed) else if (center.entry_allowed)
assignFork(via_edge, left, center); assignFork(via_edge, left, center);
else else
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left), getTurnDirection(left.angle)};
getTurnDirection(left.turn.angle)};
} }
else if (right.entry_allowed) else if (right.entry_allowed)
{ {
if (center.entry_allowed) if (center.entry_allowed)
assignFork(via_edge, center, right); assignFork(via_edge, center, right);
else else
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right), getTurnDirection(right.angle)};
getTurnDirection(right.turn.angle)};
} }
else else
{ {
if (center.entry_allowed) if (center.entry_allowed)
center.turn.instruction = {findBasicTurnType(via_edge, center), center.instruction = {findBasicTurnType(via_edge, center),
getTurnDirection(center.turn.angle)}; getTurnDirection(center.angle)};
} }
} }
@ -337,18 +333,17 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid,
{ {
for (std::size_t index = begin; index != end; ++index) for (std::size_t index = begin; index != end; ++index)
if (intersection[index].entry_allowed) if (intersection[index].entry_allowed)
intersection[index].turn.instruction = { intersection[index].instruction = {findBasicTurnType(via_eid, intersection[index]),
findBasicTurnType(via_eid, intersection[index]), getTurnDirection(intersection[index].angle)};
getTurnDirection(intersection[index].turn.angle)};
} }
bool IntersectionHandler::isThroughStreet(const std::size_t index, bool IntersectionHandler::isThroughStreet(const std::size_t index,
const Intersection &intersection) const const Intersection &intersection) const
{ {
if (node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id == EMPTY_NAMEID) if (node_based_graph.GetEdgeData(intersection[index].eid).name_id == EMPTY_NAMEID)
return false; return false;
const auto &data_at_index = node_based_graph.GetEdgeData(intersection[index].turn.eid); const auto &data_at_index = node_based_graph.GetEdgeData(intersection[index].eid);
// a through street cannot start at our own position -> index 1 // a through street cannot start at our own position -> index 1
for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index) for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
@ -357,11 +352,10 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index,
continue; continue;
const auto &road = intersection[road_index]; const auto &road = intersection[road_index];
const auto &road_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &road_data = node_based_graph.GetEdgeData(road.eid);
// roads have a near straight angle (180 degree) // roads have a near straight angle (180 degree)
const bool is_nearly_straight = const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
angularDeviation(road.turn.angle, intersection[index].turn.angle) >
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE); (STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
const bool have_same_name = data_at_index.name_id == road_data.name_id; const bool have_same_name = data_at_index.name_id == road_data.name_id;
@ -397,13 +391,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
for (std::size_t i = 1; i < intersection.size(); ++i) for (std::size_t i = 1; i < intersection.size(); ++i)
{ {
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE); const double deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
if (!intersection[i].entry_allowed) if (!intersection[i].entry_allowed)
continue; continue;
const auto out_data = node_based_graph.GetEdgeData(intersection[i].turn.eid); const auto out_data = node_based_graph.GetEdgeData(intersection[i].eid);
const auto continue_class = const auto continue_class =
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid).road_classification; node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification;
if (out_data.name_id == in_data.name_id && if (out_data.name_id == in_data.name_id &&
(best_continue == 0 || (best_continue == 0 ||
@ -419,7 +413,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
} }
const auto current_best_class = const auto current_best_class =
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid).road_classification; node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification;
// don't prefer low priority classes // don't prefer low priority classes
if (best != 0 && out_data.road_classification.IsLowPriorityRoadClass() && if (best != 0 && out_data.road_classification.IsLowPriorityRoadClass() &&
@ -459,7 +453,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
for (std::size_t i = 1; i < intersection.size(); ++i) for (std::size_t i = 1; i < intersection.size(); ++i)
{ {
const auto &road = intersection[i]; const auto &road = intersection[i];
if ((in_data.name_id == node_based_graph.GetEdgeData(road.turn.eid).name_id)) if ((in_data.name_id == node_based_graph.GetEdgeData(road.eid).name_id))
{ {
++count; ++count;
if (road.entry_allowed) if (road.entry_allowed)
@ -471,10 +465,10 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
}(); }();
if (0 != best_continue && best != best_continue && if (0 != best_continue && best != best_continue &&
angularDeviation(intersection[best].turn.angle, STRAIGHT_ANGLE) < angularDeviation(intersection[best].angle, STRAIGHT_ANGLE) <
MAXIMAL_ALLOWED_NO_TURN_DEVIATION && MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid).road_classification == node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
node_based_graph.GetEdgeData(intersection[best].turn.eid).road_classification) node_based_graph.GetEdgeData(intersection[best].eid).road_classification)
{ {
// if the best angle is going straight but the road is turning, we don't name anything // if the best angle is going straight but the road is turning, we don't name anything
// obvious // obvious
@ -487,14 +481,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
return std::count_if( return std::count_if(
intersection.begin() + 1, intersection.end(), [&](const ConnectedRoad &road) { intersection.begin() + 1, intersection.end(), [&](const ConnectedRoad &road) {
return (in_data.name_id == return (in_data.name_id == node_based_graph.GetEdgeData(road.eid).name_id) &&
node_based_graph.GetEdgeData(road.turn.eid).name_id) && angularDeviation(road.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
}) == num_continue_names.first; }) == num_continue_names.first;
}(); }();
// has no obvious continued road // has no obvious continued road
const auto &best_data = node_based_graph.GetEdgeData(intersection[best].turn.eid); const auto &best_data = node_based_graph.GetEdgeData(intersection[best].eid);
const auto check_non_continue = [&]() { const auto check_non_continue = [&]() {
// no continue road exists // no continue road exists
@ -512,8 +505,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
return true; return true;
// continue data now most certainly exists // continue data now most certainly exists
const auto &continue_data = const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
if (obviousByRoadClass(in_data.road_classification, if (obviousByRoadClass(in_data.road_classification,
continue_data.road_classification, continue_data.road_classification,
@ -550,7 +542,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
if (index_candidate == 0) if (index_candidate == 0)
return index_candidate; return index_candidate;
const auto &candidate_data = const auto &candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].turn.eid); node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_data.road_classification, if (obviousByRoadClass(in_data.road_classification,
best_data.road_classification, best_data.road_classification,
candidate_data.road_classification)) candidate_data.road_classification))
@ -565,7 +557,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
if (index_candidate == 0) if (index_candidate == 0)
return index_candidate; return index_candidate;
const auto candidate_data = const auto candidate_data =
node_based_graph.GetEdgeData(intersection[index_candidate].turn.eid); node_based_graph.GetEdgeData(intersection[index_candidate].eid);
if (obviousByRoadClass(in_data.road_classification, if (obviousByRoadClass(in_data.road_classification,
best_data.road_classification, best_data.road_classification,
candidate_data.road_classification)) candidate_data.road_classification))
@ -575,16 +567,16 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
}(); }();
const double left_deviation = const double left_deviation =
angularDeviation(intersection[left_index].turn.angle, STRAIGHT_ANGLE); angularDeviation(intersection[left_index].angle, STRAIGHT_ANGLE);
const double right_deviation = const double right_deviation =
angularDeviation(intersection[right_index].turn.angle, STRAIGHT_ANGLE); angularDeviation(intersection[right_index].angle, STRAIGHT_ANGLE);
if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION && if (best_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE) std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
return best; return best;
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].turn.eid); const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].turn.eid); const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
const bool obvious_to_left = const bool obvious_to_left =
left_index == 0 || obviousByRoadClass(in_data.road_classification, left_index == 0 || obviousByRoadClass(in_data.road_classification,
@ -598,7 +590,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
// if the best turn isn't narrow, but there is a nearly straight turn, we don't consider the // if the best turn isn't narrow, but there is a nearly straight turn, we don't consider the
// turn obvious // turn obvious
const auto check_narrow = [&intersection, best_deviation](const std::size_t index) { const auto check_narrow = [&intersection, best_deviation](const std::size_t index) {
return angularDeviation(intersection[index].turn.angle, STRAIGHT_ANGLE) <= return angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) <=
FUZZY_ANGLE_DIFFERENCE && FUZZY_ANGLE_DIFFERENCE &&
(best_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed); (best_deviation > NARROW_TURN_ANGLE || intersection[index].entry_allowed);
}; };
@ -624,7 +616,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
// a bit less obvious are road classes // a bit less obvious are road classes
else if (in_data.road_classification == best_data.road_classification && else if (in_data.road_classification == best_data.road_classification &&
best_data.road_classification.GetPriority() < best_data.road_classification.GetPriority() <
node_based_graph.GetEdgeData(intersection[index].turn.eid) node_based_graph.GetEdgeData(intersection[index].eid)
.road_classification.GetPriority()) .road_classification.GetPriority())
return 0.8 * DISTINCTION_RATIO; return 0.8 * DISTINCTION_RATIO;
// if road classes are the same, we use the full ratio // if road classes are the same, we use the full ratio
@ -644,9 +636,8 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
else else
{ {
const double deviation = const double deviation =
angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE); angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
const auto &continue_data = const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
if (std::abs(deviation) < 1) if (std::abs(deviation) < 1)
return best_continue; return best_continue;
@ -656,7 +647,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
if (i == best_continue || !intersection[i].entry_allowed) if (i == best_continue || !intersection[i].entry_allowed)
continue; continue;
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].turn.eid); const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
const bool is_obvious_by_road_class = const bool is_obvious_by_road_class =
obviousByRoadClass(in_data.road_classification, obviousByRoadClass(in_data.road_classification,
continue_data.road_classification, continue_data.road_classification,
@ -672,8 +663,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
continue; continue;
// perfectly straight turns prevent obviousness // perfectly straight turns prevent obviousness
const auto turn_deviation = const auto turn_deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
if (turn_deviation < FUZZY_ANGLE_DIFFERENCE) if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
return 0; return 0;
@ -708,7 +698,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
const auto node_at_intersection = node_based_graph.GetTarget(via_edge); const auto node_at_intersection = node_based_graph.GetTarget(via_edge);
const util::Coordinate coordinate_at_intersection = node_info_list[node_at_intersection]; const util::Coordinate coordinate_at_intersection = node_info_list[node_at_intersection];
const auto node_at_u_turn = node_based_graph.GetTarget(intersection[0].turn.eid); const auto node_at_u_turn = node_based_graph.GetTarget(intersection[0].eid);
const util::Coordinate coordinate_at_u_turn = node_info_list[node_at_u_turn]; const util::Coordinate coordinate_at_u_turn = node_info_list[node_at_u_turn];
const double constexpr MAX_COLLAPSE_DISTANCE = 30; const double constexpr MAX_COLLAPSE_DISTANCE = 30;
@ -720,7 +710,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
// try to find whether there is a turn going to the opposite direction of our obvious // try to find whether there is a turn going to the opposite direction of our obvious
// turn, this should be alright. // turn, this should be alright.
const auto previous_intersection = intersection_generator.GetActualNextIntersection( const auto previous_intersection = intersection_generator.GetActualNextIntersection(
node_at_intersection, intersection[0].turn.eid, nullptr, nullptr); node_at_intersection, intersection[0].eid, nullptr, nullptr);
const auto continue_road = intersection[best_continue]; const auto continue_road = intersection[best_continue];
for (const auto &comparison_road : previous_intersection) for (const auto &comparison_road : previous_intersection)
@ -729,9 +719,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
// actually represents a near 180 degree different in bearings between the two // actually represents a near 180 degree different in bearings between the two
// roads. So if there is a road that is enterable in the opposite direction just // roads. So if there is a road that is enterable in the opposite direction just
// prior, a turn is not obvious // prior, a turn is not obvious
const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.turn.eid); const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
if (angularDeviation(comparison_road.turn.angle, STRAIGHT_ANGLE) > GROUP_ANGLE && if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
angularDeviation(comparison_road.turn.angle, continue_road.turn.angle) < angularDeviation(comparison_road.angle, continue_road.angle) <
FUZZY_ANGLE_DIFFERENCE && FUZZY_ANGLE_DIFFERENCE &&
!turn_data.reversed && continue_data.CanCombineWith(turn_data)) !turn_data.reversed && continue_data.CanCombineWith(turn_data))
return 0; return 0;

View File

@ -17,9 +17,9 @@ bool isEndOfRoad(const ConnectedRoad &,
const ConnectedRoad &possible_right_turn, const ConnectedRoad &possible_right_turn,
const ConnectedRoad &possible_left_turn) const ConnectedRoad &possible_left_turn)
{ {
return angularDeviation(possible_right_turn.turn.angle, 90) < NARROW_TURN_ANGLE && return angularDeviation(possible_right_turn.angle, 90) < NARROW_TURN_ANGLE &&
angularDeviation(possible_left_turn.turn.angle, 270) < NARROW_TURN_ANGLE && angularDeviation(possible_left_turn.angle, 270) < NARROW_TURN_ANGLE &&
angularDeviation(possible_right_turn.turn.angle, possible_left_turn.turn.angle) > angularDeviation(possible_right_turn.angle, possible_left_turn.angle) >
2 * NARROW_TURN_ANGLE; 2 * NARROW_TURN_ANGLE;
} }

View File

@ -30,7 +30,7 @@ inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_
inline RoadClassification roadClass(const ConnectedRoad &road, inline RoadClassification roadClass(const ConnectedRoad &road,
const util::NodeBasedDynamicGraph &graph) const util::NodeBasedDynamicGraph &graph)
{ {
return graph.GetEdgeData(road.turn.eid).road_classification; return graph.GetEdgeData(road.eid).road_classification;
} }
inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph) inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
@ -63,14 +63,14 @@ bool MotorwayHandler::canProcess(const NodeID,
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
// not merging or forking? // not merging or forking?
if (road.entry_allowed && angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > 60) if (road.entry_allowed && angularDeviation(road.angle, STRAIGHT_ANGLE) > 60)
return false; return false;
else if (isMotorwayClass(road.turn.eid, node_based_graph)) else if (isMotorwayClass(road.eid, node_based_graph))
{ {
if (road.entry_allowed) if (road.entry_allowed)
has_motorway = true; has_motorway = true;
} }
else if (!isRampClass(road.turn.eid, node_based_graph)) else if (!isRampClass(road.eid, node_based_graph))
has_normal_roads = true; has_normal_roads = true;
} }
@ -88,8 +88,8 @@ operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const
{ {
intersection = fromMotorway(via_eid, std::move(intersection)); intersection = fromMotorway(via_eid, std::move(intersection));
std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) { std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
if (road.turn.instruction.type == TurnType::OnRamp) if (road.instruction.type == TurnType::OnRamp)
road.turn.instruction.type = TurnType::OffRamp; road.instruction.type = TurnType::OffRamp;
}); });
return intersection; return intersection;
} }
@ -109,7 +109,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
unsigned count = 0; unsigned count = 0;
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
if (road.entry_allowed && isMotorwayClass(road.turn.eid, node_based_graph)) if (road.entry_allowed && isMotorwayClass(road.eid, node_based_graph))
++count; ++count;
} }
return count; return count;
@ -119,24 +119,24 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
const auto getContinueAngle = [this, in_data](const Intersection &intersection) { const auto getContinueAngle = [this, in_data](const Intersection &intersection) {
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(road.eid);
if (road.turn.angle != 0 && in_data.name_id == out_data.name_id && if (road.angle != 0 && in_data.name_id == out_data.name_id &&
in_data.name_id != EMPTY_NAMEID && isMotorwayClass(road.turn.eid, node_based_graph)) in_data.name_id != EMPTY_NAMEID && isMotorwayClass(road.eid, node_based_graph))
return road.turn.angle; return road.angle;
} }
return intersection[0].turn.angle; return intersection[0].angle;
}; };
const auto getMostLikelyContinue = [this, in_data](const Intersection &intersection) { const auto getMostLikelyContinue = [this, in_data](const Intersection &intersection) {
double angle = intersection[0].turn.angle; double angle = intersection[0].angle;
double best = 180; double best = 180;
for (const auto &road : intersection) for (const auto &road : intersection)
{ {
if (isMotorwayClass(road.turn.eid, node_based_graph) && if (isMotorwayClass(road.eid, node_based_graph) &&
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best) angularDeviation(road.angle, STRAIGHT_ANGLE) < best)
{ {
best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE); best = angularDeviation(road.angle, STRAIGHT_ANGLE);
angle = road.turn.angle; angle = road.angle;
} }
} }
return angle; return angle;
@ -144,7 +144,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
const auto findBestContinue = [&]() { const auto findBestContinue = [&]() {
const double continue_angle = getContinueAngle(intersection); const double continue_angle = getContinueAngle(intersection);
if (continue_angle != intersection[0].turn.angle) if (continue_angle != intersection[0].angle)
return continue_angle; return continue_angle;
else else
return getMostLikelyContinue(intersection); return getMostLikelyContinue(intersection);
@ -153,13 +153,13 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
// find continue angle // find continue angle
const double continue_angle = findBestContinue(); const double continue_angle = findBestContinue();
// highway does not continue and has no obvious choice // highway does not continue and has no obvious choice
if (continue_angle == intersection[0].turn.angle) if (continue_angle == intersection[0].angle)
{ {
if (intersection.size() == 2) if (intersection.size() == 2)
{ {
// do not announce ramps at the end of a highway // do not announce ramps at the end of a highway
intersection[1].turn.instruction = {TurnType::NoTurn, intersection[1].instruction = {TurnType::NoTurn,
getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].angle)};
} }
else if (intersection.size() == 3) else if (intersection.size() == 3)
{ {
@ -172,11 +172,11 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
{ {
// ending in a passing ramp // ending in a passing ramp
if (intersection[1].entry_allowed) if (intersection[1].entry_allowed)
intersection[1].turn.instruction = { intersection[1].instruction = {TurnType::NoTurn,
TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].angle)};
else else
intersection[2].turn.instruction = { intersection[2].instruction = {TurnType::NoTurn,
TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)}; getTurnDirection(intersection[2].angle)};
} }
} }
else if (intersection.size() == 4 && else if (intersection.size() == 4 &&
@ -209,9 +209,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
{ {
if (road.entry_allowed) if (road.entry_allowed)
{ {
BOOST_ASSERT(isRampClass(road.turn.eid, node_based_graph)); BOOST_ASSERT(isRampClass(road.eid, node_based_graph));
road.turn.instruction = road.instruction = TurnInstruction::SUPPRESSED(getTurnDirection(road.angle));
TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
} }
} }
} }
@ -220,9 +219,9 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
// normal motorway passing some ramps or mering onto another motorway // normal motorway passing some ramps or mering onto another motorway
if (intersection.size() == 2) if (intersection.size() == 2)
{ {
BOOST_ASSERT(!isRampClass(intersection[1].turn.eid, node_based_graph)); BOOST_ASSERT(!isRampClass(intersection[1].eid, node_based_graph));
intersection[1].turn.instruction = intersection[1].instruction =
getInstructionForObvious(intersection.size(), getInstructionForObvious(intersection.size(),
via_eid, via_eid,
isThroughStreet(1, intersection), isThroughStreet(1, intersection),
@ -237,25 +236,25 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
if (!road.entry_allowed) if (!road.entry_allowed)
continue; continue;
if (road.turn.angle == continue_angle) if (road.angle == continue_angle)
{ {
road.turn.instruction = getInstructionForObvious( road.instruction = getInstructionForObvious(
intersection.size(), via_eid, isThroughStreet(1, intersection), road); intersection.size(), via_eid, isThroughStreet(1, intersection), road);
} }
else if (road.turn.angle < continue_angle) else if (road.angle < continue_angle)
{ {
road.turn.instruction = { road.instruction = {isRampClass(road.eid, node_based_graph)
isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp ? TurnType::OffRamp
: TurnType::Turn, : TurnType::Turn,
(road.turn.angle < 145) ? DirectionModifier::Right (road.angle < 145) ? DirectionModifier::Right
: DirectionModifier::SlightRight}; : DirectionModifier::SlightRight};
} }
else if (road.turn.angle > continue_angle) else if (road.angle > continue_angle)
{ {
road.turn.instruction = { road.instruction = {isRampClass(road.eid, node_based_graph)
isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp ? TurnType::OffRamp
: TurnType::Turn, : TurnType::Turn,
(road.turn.angle > 215) ? DirectionModifier::Left (road.angle > 215) ? DirectionModifier::Left
: DirectionModifier::SlightLeft}; : DirectionModifier::SlightLeft};
} }
} }
@ -266,7 +265,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
{ {
if (exiting_motorways == 2 && intersection.size() == 2) if (exiting_motorways == 2 && intersection.size() == 2)
{ {
intersection[1].turn.instruction = intersection[1].instruction =
getInstructionForObvious(intersection.size(), getInstructionForObvious(intersection.size(),
via_eid, via_eid,
isThroughStreet(1, intersection), isThroughStreet(1, intersection),
@ -282,7 +281,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
for (std::size_t i = 0; i < intersection.size(); ++i) for (std::size_t i = 0; i < intersection.size(); ++i)
{ {
if (intersection[i].entry_allowed && if (intersection[i].entry_allowed &&
isMotorwayClass(intersection[i].turn.eid, node_based_graph)) isMotorwayClass(intersection[i].eid, node_based_graph))
{ {
if (first_valid < intersection.size()) if (first_valid < intersection.size())
{ {
@ -306,7 +305,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
for (std::size_t i = 0; i < intersection.size(); ++i) for (std::size_t i = 0; i < intersection.size(); ++i)
{ {
if (intersection[i].entry_allowed && if (intersection[i].entry_allowed &&
isMotorwayClass(intersection[i].turn.eid, node_based_graph)) isMotorwayClass(intersection[i].eid, node_based_graph))
{ {
if (second_valid < intersection.size()) if (second_valid < intersection.size())
{ {
@ -346,9 +345,9 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
if (intersection.size() == 2 && num_valid_turns == 1) if (intersection.size() == 2 && num_valid_turns == 1)
{ {
BOOST_ASSERT(!intersection[0].entry_allowed); BOOST_ASSERT(!intersection[0].entry_allowed);
BOOST_ASSERT(isMotorwayClass(intersection[1].turn.eid, node_based_graph)); BOOST_ASSERT(isMotorwayClass(intersection[1].eid, node_based_graph));
intersection[1].turn.instruction = getInstructionForObvious( intersection[1].instruction = getInstructionForObvious(
intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]); intersection.size(), via_eid, isThroughStreet(1, intersection), intersection[1]);
} }
else if (intersection.size() == 3) else if (intersection.size() == 3)
@ -367,24 +366,23 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
// 0 // 0
if (intersection[1].entry_allowed) if (intersection[1].entry_allowed)
{ {
if (isMotorwayClass(intersection[1].turn.eid, node_based_graph) && if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id != node_based_graph.GetEdgeData(intersection[2].eid).name_id != EMPTY_NAMEID &&
EMPTY_NAMEID && node_based_graph.GetEdgeData(intersection[2].eid).name_id ==
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id == node_based_graph.GetEdgeData(intersection[1].eid).name_id)
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
{ {
// circular order indicates a merge to the left (0-3 onto 4 // circular order indicates a merge to the left (0-3 onto 4
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) <
2 * NARROW_TURN_ANGLE) 2 * NARROW_TURN_ANGLE)
intersection[1].turn.instruction = {TurnType::Merge, intersection[1].instruction = {TurnType::Merge,
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
else // fallback else // fallback
intersection[1].turn.instruction = { intersection[1].instruction = {TurnType::Merge,
TurnType::Merge, getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].angle)};
} }
else // passing by the end of a motorway else // passing by the end of a motorway
{ {
intersection[1].turn.instruction = intersection[1].instruction =
getInstructionForObvious(intersection.size(), getInstructionForObvious(intersection.size(),
via_eid, via_eid,
isThroughStreet(1, intersection), isThroughStreet(1, intersection),
@ -394,24 +392,23 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
else else
{ {
BOOST_ASSERT(intersection[2].entry_allowed); BOOST_ASSERT(intersection[2].entry_allowed);
if (isMotorwayClass(intersection[2].turn.eid, node_based_graph) && if (isMotorwayClass(intersection[2].eid, node_based_graph) &&
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id != node_based_graph.GetEdgeData(intersection[1].eid).name_id != EMPTY_NAMEID &&
EMPTY_NAMEID && node_based_graph.GetEdgeData(intersection[2].eid).name_id ==
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id == node_based_graph.GetEdgeData(intersection[1].eid).name_id)
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
{ {
// circular order (5-0) onto 4 // circular order (5-0) onto 4
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) < if (angularDeviation(intersection[2].angle, STRAIGHT_ANGLE) <
2 * NARROW_TURN_ANGLE) 2 * NARROW_TURN_ANGLE)
intersection[2].turn.instruction = {TurnType::Merge, intersection[2].instruction = {TurnType::Merge,
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
else // fallback else // fallback
intersection[2].turn.instruction = { intersection[2].instruction = {TurnType::Merge,
TurnType::Merge, getTurnDirection(intersection[2].turn.angle)}; getTurnDirection(intersection[2].angle)};
} }
else // passing the end of a highway else // passing the end of a highway
{ {
intersection[2].turn.instruction = intersection[2].instruction =
getInstructionForObvious(intersection.size(), getInstructionForObvious(intersection.size(),
via_eid, via_eid,
isThroughStreet(2, intersection), isThroughStreet(2, intersection),
@ -431,8 +428,8 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
// \ / // \ /
// | // |
// R // R
if (isMotorwayClass(intersection[1].turn.eid, node_based_graph) && if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
isMotorwayClass(intersection[2].turn.eid, node_based_graph)) isMotorwayClass(intersection[2].eid, node_based_graph))
{ {
assignFork(via_eid, intersection[2], intersection[1]); assignFork(via_eid, intersection[2], intersection[1]);
} }
@ -443,11 +440,10 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
// M R // M R
// | / // | /
// R // R
if (isMotorwayClass(intersection[1].turn.eid, node_based_graph)) if (isMotorwayClass(intersection[1].eid, node_based_graph))
{ {
intersection[1].turn.instruction = {TurnType::Turn, intersection[1].instruction = {TurnType::Turn, DirectionModifier::SlightRight};
DirectionModifier::SlightRight}; intersection[2].instruction = {TurnType::Continue,
intersection[2].turn.instruction = {TurnType::Continue,
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
else else
@ -463,20 +459,20 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
bool passed_highway_entry = false; bool passed_highway_entry = false;
for (auto &road : intersection) for (auto &road : intersection)
{ {
if (!road.entry_allowed && isMotorwayClass(road.turn.eid, node_based_graph)) if (!road.entry_allowed && isMotorwayClass(road.eid, node_based_graph))
{ {
passed_highway_entry = true; passed_highway_entry = true;
} }
else if (isMotorwayClass(road.turn.eid, node_based_graph)) else if (isMotorwayClass(road.eid, node_based_graph))
{ {
road.turn.instruction = {TurnType::Merge, road.instruction = {TurnType::Merge,
passed_highway_entry ? DirectionModifier::SlightRight passed_highway_entry ? DirectionModifier::SlightRight
: DirectionModifier::SlightLeft}; : DirectionModifier::SlightLeft};
} }
else else
{ {
BOOST_ASSERT(isRampClass(road.turn.eid, node_based_graph)); BOOST_ASSERT(isRampClass(road.eid, node_based_graph));
road.turn.instruction = {TurnType::OffRamp, getTurnDirection(road.turn.angle)}; road.instruction = {TurnType::OffRamp, getTurnDirection(road.angle)};
} }
} }
} }
@ -498,25 +494,23 @@ Intersection MotorwayHandler::fallback(Intersection intersection) const
continue; continue;
const auto type = const auto type =
isMotorwayClass(road.turn.eid, node_based_graph) ? TurnType::Merge : TurnType::Turn; isMotorwayClass(road.eid, node_based_graph) ? TurnType::Merge : TurnType::Turn;
if (type == TurnType::Turn) if (type == TurnType::Turn)
{ {
if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE) if (angularDeviation(road.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
road.turn.instruction = {type, DirectionModifier::Straight}; road.instruction = {type, DirectionModifier::Straight};
else else
{ {
road.turn.instruction = {type, road.instruction = {type,
road.turn.angle > STRAIGHT_ANGLE road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
? DirectionModifier::SlightLeft
: DirectionModifier::SlightRight}; : DirectionModifier::SlightRight};
} }
} }
else else
{ {
road.turn.instruction = {type, road.instruction = {type,
road.turn.angle < STRAIGHT_ANGLE road.angle < STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
? DirectionModifier::SlightLeft
: DirectionModifier::SlightRight}; : DirectionModifier::SlightRight};
} }
} }

View File

@ -29,13 +29,11 @@ bool LengthLimitedCoordinateAccumulator::terminate() { return accumulated_length
// update the accumulator // update the accumulator
void LengthLimitedCoordinateAccumulator::update(const NodeID from_node, void LengthLimitedCoordinateAccumulator::update(const NodeID from_node,
const EdgeID via_edge, const EdgeID via_edge,
const NodeID to_node) const NodeID /*to_node*/)
{ {
const util::NodeBasedEdgeData &edge_data = node_based_graph.GetEdgeData(via_edge); const auto current_coordinates =
coordinate_extractor.GetForwardCoordinatesAlongRoad(from_node, via_edge);
const auto current_coordinates = coordinate_extractor.GetForwardCoordinatesAlongRoad(
from_node, via_edge);
const auto length = util::coordinate_calculation::getLength( const auto length = util::coordinate_calculation::getLength(
coordinates, util::coordinate_calculation::haversineDistance); coordinates, util::coordinate_calculation::haversineDistance);
@ -77,10 +75,10 @@ operator()(const NodeID /*nid*/,
result_score += 360.; result_score += 360.;
// 180 for undesired name-ids // 180 for undesired name-ids
if (desired_name_id != node_based_graph.GetEdgeData(road.turn.eid).name_id) if (desired_name_id != node_based_graph.GetEdgeData(road.eid).name_id)
result_score += 180; result_score += 180;
return result_score + angularDeviation(road.turn.angle, STRAIGHT_ANGLE); return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
}; };
return score(lhs) < score(rhs); return score(lhs) < score(rhs);
@ -92,7 +90,7 @@ operator()(const NodeID /*nid*/,
if (min_element == intersection.end() || (requires_entry && !min_element->entry_allowed)) if (min_element == intersection.end() || (requires_entry && !min_element->entry_allowed))
return {}; return {};
else else
return min_element->turn.eid; return (*min_element).eid;
} }
} // namespace guidance } // namespace guidance

View File

@ -77,7 +77,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
++cnt, idx += step) ++cnt, idx += step)
{ {
const auto &road = intersection[idx]; const auto &road = intersection[idx];
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &edge_data = node_based_graph.GetEdgeData(road.eid);
// only check actual outgoing edges // only check actual outgoing edges
if (edge_data.reversed || !road.entry_allowed) if (edge_data.reversed || !road.entry_allowed)
continue; continue;
@ -93,7 +93,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
// the roundabout. // the roundabout.
// The sorting of the angles represents a problem for left-sided driving, though. // The sorting of the angles represents a problem for left-sided driving, though.
// FIXME requires consideration of crossing the roundabout // FIXME requires consideration of crossing the roundabout
else if (node_based_graph.GetTarget(road.turn.eid) != from_nid && !can_enter_roundabout) else if (node_based_graph.GetTarget(road.eid) != from_nid && !can_enter_roundabout)
{ {
can_exit_roundabout_separately = true; can_exit_roundabout_separately = true;
} }
@ -116,7 +116,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
++cnt, idx += step) ++cnt, idx += step)
{ {
auto &road = intersection[idx]; auto &road = intersection[idx];
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &edge_data = node_based_graph.GetEdgeData(road.eid);
// only check actual outgoing edges // only check actual outgoing edges
if (edge_data.reversed) if (edge_data.reversed)
{ {
@ -131,7 +131,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
// This workaround handles cases in which an exit precedes and entry. The resulting // This workaround handles cases in which an exit precedes and entry. The resulting
// u-turn against the roundabout direction is invalidated. // u-turn against the roundabout direction is invalidated.
// The sorting of the angles represents a problem for left-sided driving, though. // The sorting of the angles represents a problem for left-sided driving, though.
if (!edge_data.roundabout && node_based_graph.GetTarget(road.turn.eid) != from_nid && if (!edge_data.roundabout && node_based_graph.GetTarget(road.eid) != from_nid &&
past_roundabout_angle) past_roundabout_angle)
{ {
road.entry_allowed = false; road.entry_allowed = false;
@ -379,8 +379,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
++cnt, idx += step) ++cnt, idx += step)
{ {
auto &road = intersection[idx]; auto &road = intersection[idx];
auto &turn = road.turn; auto &turn = road;
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &out_data = node_based_graph.GetEdgeData(road.eid);
if (out_data.roundabout) if (out_data.roundabout)
{ {
// TODO can forks happen in roundabouts? E.g. required lane changes // TODO can forks happen in roundabouts? E.g. required lane changes
@ -419,7 +419,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
auto &road = intersection[idx]; auto &road = intersection[idx];
if (!road.entry_allowed) if (!road.entry_allowed)
continue; continue;
auto &turn = road.turn; auto &turn = road;
const auto &out_data = node_based_graph.GetEdgeData(turn.eid); const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
if (out_data.roundabout) if (out_data.roundabout)
{ {

View File

@ -53,8 +53,8 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto findNextIntersectionForRoad = const auto findNextIntersectionForRoad =
[&](const NodeID at_node, const ConnectedRoad &road, NodeID &output_node) { [&](const NodeID at_node, const ConnectedRoad &road, NodeID &output_node) {
auto intersection = intersection_generator(at_node, road.turn.eid); auto intersection = intersection_generator(at_node, road.eid);
auto in_edge = road.turn.eid; auto in_edge = road.eid;
// skip over traffic lights // skip over traffic lights
// to prevent ending up in an endless loop, we remember all visited nodes. This is // to prevent ending up in an endless loop, we remember all visited nodes. This is
// necessary, since merging of roads can actually create enterable loops of degree two // necessary, since merging of roads can actually create enterable loops of degree two
@ -71,7 +71,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
intersection.clear(); intersection.clear();
return intersection; return intersection;
} }
in_edge = intersection[1].turn.eid; in_edge = intersection[1].eid;
output_node = node_based_graph.GetTarget(in_edge); output_node = node_based_graph.GetTarget(in_edge);
intersection = intersection_generator(node, in_edge); intersection = intersection_generator(node, in_edge);
} }
@ -87,8 +87,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto index = findObviousTurn(source_edge_id, intersection); const auto index = findObviousTurn(source_edge_id, intersection);
if (index != 0) if (index != 0)
return index; return index;
else if (intersection.size() == 3 && else if (intersection.size() == 3 && intersection[1].instruction.type == TurnType::Fork)
intersection[1].turn.instruction.type == TurnType::Fork)
{ {
// Forks themselves do not contain a `obvious` turn index. If we look at a fork that has // Forks themselves do not contain a `obvious` turn index. If we look at a fork that has
// a one-sided sliproad, however, the non-sliproad can be considered `obvious`. Here we // a one-sided sliproad, however, the non-sliproad can be considered `obvious`. Here we
@ -136,10 +135,10 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto &next_road = intersection[obvious_turn_index]; const auto &next_road = intersection[obvious_turn_index];
const auto linkTest = [this, next_road](const ConnectedRoad &road) { const auto linkTest = [this, next_road](const ConnectedRoad &road) {
return !node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed && return !node_based_graph.GetEdgeData(road.eid).roundabout && road.entry_allowed &&
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE && angularDeviation(road.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE &&
!hasRoundaboutType(road.turn.instruction) && !hasRoundaboutType(road.instruction) &&
angularDeviation(next_road.turn.angle, road.turn.angle) > angularDeviation(next_road.angle, road.angle) >
std::numeric_limits<double>::epsilon(); std::numeric_limits<double>::epsilon();
}; };
@ -151,7 +150,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id); const auto source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
// check whether the continue road is valid // check whether the continue road is valid
const auto check_valid = [this, source_edge_data](const ConnectedRoad &road) { const auto check_valid = [this, source_edge_data](const ConnectedRoad &road) {
const auto road_edge_data = node_based_graph.GetEdgeData(road.turn.eid); const auto road_edge_data = node_based_graph.GetEdgeData(road.eid);
// Test to see if the source edge and the one we're looking at are the same road // Test to see if the source edge and the one we're looking at are the same road
return road_edge_data.road_classification == source_edge_data.road_classification && return road_edge_data.road_classification == source_edge_data.road_classification &&
road_edge_data.name_id != EMPTY_NAMEID && road_edge_data.name_id != EMPTY_NAMEID &&
@ -165,13 +164,13 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
const auto coordinate_extractor = intersection_generator.GetCoordinateExtractor(); const auto coordinate_extractor = intersection_generator.GetCoordinateExtractor();
const auto next_road_length = util::coordinate_calculation::getLength( const auto next_road_length = util::coordinate_calculation::getLength(
coordinate_extractor.GetForwardCoordinatesAlongRoad( coordinate_extractor.GetForwardCoordinatesAlongRoad(
node_based_graph.GetTarget(source_edge_id), next_road.turn.eid), node_based_graph.GetTarget(source_edge_id), next_road.eid),
&util::coordinate_calculation::haversineDistance); &util::coordinate_calculation::haversineDistance);
if (next_road_length > MAX_SLIPROAD_THRESHOLD) if (next_road_length > MAX_SLIPROAD_THRESHOLD)
{ {
return intersection; return intersection;
} }
auto next_intersection_node = node_based_graph.GetTarget(next_road.turn.eid); auto next_intersection_node = node_based_graph.GetTarget(next_road.eid);
const auto next_road_next_intersection = const auto next_road_next_intersection =
findNextIntersectionForRoad(intersection_node_id, next_road, next_intersection_node); findNextIntersectionForRoad(intersection_node_id, next_road, next_intersection_node);
@ -187,7 +186,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
for (const auto &road : next_road_next_intersection) for (const auto &road : next_road_next_intersection)
{ {
const auto &target_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &target_data = node_based_graph.GetEdgeData(road.eid);
target_road_names.insert(target_data.name_id); target_road_names.insert(target_data.name_id);
} }
@ -195,20 +194,20 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
{ {
if (linkTest(road)) if (linkTest(road))
{ {
EdgeID candidate_in = road.turn.eid; EdgeID candidate_in = road.eid;
const auto target_intersection = [&](NodeID node) { const auto target_intersection = [&](NodeID node) {
auto intersection = intersection_generator(node, candidate_in); auto intersection = intersection_generator(node, candidate_in);
// skip over traffic lights // skip over traffic lights
if (intersection.size() == 2) if (intersection.size() == 2)
{ {
node = node_based_graph.GetTarget(candidate_in); node = node_based_graph.GetTarget(candidate_in);
candidate_in = intersection[1].turn.eid; candidate_in = intersection[1].eid;
intersection = intersection_generator(node, candidate_in); intersection = intersection_generator(node, candidate_in);
} }
return intersection; return intersection;
}(intersection_node_id); }(intersection_node_id);
const auto link_data = node_based_graph.GetEdgeData(road.turn.eid); const auto link_data = node_based_graph.GetEdgeData(road.eid);
// Check if the road continues here // Check if the road continues here
const bool is_through_street = const bool is_through_street =
!target_intersection.empty() && !target_intersection.empty() &&
@ -216,7 +215,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
std::find_if(target_intersection.begin() + 1, std::find_if(target_intersection.begin() + 1,
target_intersection.end(), target_intersection.end(),
[this, &link_data](const ConnectedRoad &road) { [this, &link_data](const ConnectedRoad &road) {
return node_based_graph.GetEdgeData(road.turn.eid).name_id == return node_based_graph.GetEdgeData(road.eid).name_id ==
link_data.name_id; link_data.name_id;
}); });
@ -226,26 +225,24 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
for (const auto &candidate_road : target_intersection) for (const auto &candidate_road : target_intersection)
{ {
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.turn.eid); const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.eid);
if (target_road_names.count(candidate_data.name_id) > 0) if (target_road_names.count(candidate_data.name_id) > 0)
{ {
if (node_based_graph.GetTarget(candidate_road.turn.eid) == if (node_based_graph.GetTarget(candidate_road.eid) == next_intersection_node)
next_intersection_node)
{ {
road.turn.instruction.type = TurnType::Sliproad; road.instruction.type = TurnType::Sliproad;
break; break;
} }
else else
{ {
const auto skip_traffic_light_intersection = intersection_generator( const auto skip_traffic_light_intersection = intersection_generator(
node_based_graph.GetTarget(candidate_in), candidate_road.turn.eid); node_based_graph.GetTarget(candidate_in), candidate_road.eid);
if (skip_traffic_light_intersection.size() == 2 && if (skip_traffic_light_intersection.size() == 2 &&
node_based_graph.GetTarget( node_based_graph.GetTarget(skip_traffic_light_intersection[1].eid) ==
skip_traffic_light_intersection[1].turn.eid) ==
next_intersection_node) next_intersection_node)
{ {
road.turn.instruction.type = TurnType::Sliproad; road.instruction.type = TurnType::Sliproad;
break; break;
} }
} }
@ -254,27 +251,27 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
} }
} }
if (next_road.turn.instruction.type == TurnType::Fork) if (next_road.instruction.type == TurnType::Fork)
{ {
const auto &next_data = node_based_graph.GetEdgeData(next_road.turn.eid); const auto &next_data = node_based_graph.GetEdgeData(next_road.eid);
if (next_data.name_id == source_edge_data.name_id) if (next_data.name_id == source_edge_data.name_id)
{ {
if (angularDeviation(next_road.turn.angle, STRAIGHT_ANGLE) < 5) if (angularDeviation(next_road.angle, STRAIGHT_ANGLE) < 5)
intersection[obvious_turn_index].turn.instruction.type = TurnType::Suppressed; intersection[obvious_turn_index].instruction.type = TurnType::Suppressed;
else else
intersection[obvious_turn_index].turn.instruction.type = TurnType::Continue; intersection[obvious_turn_index].instruction.type = TurnType::Continue;
intersection[obvious_turn_index].turn.instruction.direction_modifier = intersection[obvious_turn_index].instruction.direction_modifier =
getTurnDirection(intersection[obvious_turn_index].turn.angle); getTurnDirection(intersection[obvious_turn_index].angle);
} }
else if (next_data.name_id != EMPTY_NAMEID) else if (next_data.name_id != EMPTY_NAMEID)
{ {
intersection[obvious_turn_index].turn.instruction.type = TurnType::NewName; intersection[obvious_turn_index].instruction.type = TurnType::NewName;
intersection[obvious_turn_index].turn.instruction.direction_modifier = intersection[obvious_turn_index].instruction.direction_modifier =
getTurnDirection(intersection[obvious_turn_index].turn.angle); getTurnDirection(intersection[obvious_turn_index].angle);
} }
else else
{ {
intersection[obvious_turn_index].turn.instruction.type = TurnType::Suppressed; intersection[obvious_turn_index].instruction.type = TurnType::Suppressed;
} }
} }

View File

@ -101,8 +101,8 @@ Intersection TurnAnalysis::assignTurnTypes(const NodeID from_nid,
if (node_based_graph.GetEdgeData(via_eid).road_classification.IsMotorwayClass()) if (node_based_graph.GetEdgeData(via_eid).road_classification.IsMotorwayClass())
{ {
std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) { std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
if (road.turn.instruction.type == TurnType::OnRamp) if (road.instruction.type == TurnType::OnRamp)
road.turn.instruction.type = TurnType::OffRamp; road.instruction.type = TurnType::OffRamp;
}); });
} }
return intersection; return intersection;
@ -114,7 +114,7 @@ TurnAnalysis::transformIntersectionIntoTurns(const Intersection &intersection) c
std::vector<TurnOperation> turns; std::vector<TurnOperation> turns;
for (auto road : intersection) for (auto road : intersection)
if (road.entry_allowed) if (road.entry_allowed)
turns.emplace_back(road.turn); turns.emplace_back(road);
return turns; return turns;
} }
@ -133,12 +133,12 @@ TurnAnalysis::setTurnTypes(const NodeID from_nid, const EdgeID, Intersection int
if (!road.entry_allowed) if (!road.entry_allowed)
continue; continue;
const EdgeID onto_edge = road.turn.eid; const EdgeID onto_edge = road.eid;
const NodeID to_nid = node_based_graph.GetTarget(onto_edge); const NodeID to_nid = node_based_graph.GetTarget(onto_edge);
road.turn.instruction = {TurnType::Turn, road.instruction = {TurnType::Turn,
(from_nid == to_nid) ? DirectionModifier::UTurn (from_nid == to_nid) ? DirectionModifier::UTurn
: getTurnDirection(road.turn.angle)}; : getTurnDirection(road.angle)};
} }
return intersection; return intersection;
} }

View File

@ -35,7 +35,7 @@ classifyIntersection(Intersection intersection)
std::sort(intersection.begin(), std::sort(intersection.begin(),
intersection.end(), intersection.end(),
[](const ConnectedRoad &left, const ConnectedRoad &right) { [](const ConnectedRoad &left, const ConnectedRoad &right) {
return left.turn.bearing < right.turn.bearing; return left.bearing < right.bearing;
}); });
util::guidance::EntryClass entry_class; util::guidance::EntryClass entry_class;
@ -46,11 +46,11 @@ classifyIntersection(Intersection intersection)
return true; return true;
DiscreteBearing last_discrete_bearing = util::guidance::BearingClass::getDiscreteBearing( DiscreteBearing last_discrete_bearing = util::guidance::BearingClass::getDiscreteBearing(
std::round(intersection.back().turn.bearing)); std::round(intersection.back().bearing));
for (const auto road : intersection) for (const auto road : intersection)
{ {
const DiscreteBearing discrete_bearing = const DiscreteBearing discrete_bearing =
util::guidance::BearingClass::getDiscreteBearing(std::round(road.turn.bearing)); util::guidance::BearingClass::getDiscreteBearing(std::round(road.bearing));
if (discrete_bearing == last_discrete_bearing) if (discrete_bearing == last_discrete_bearing)
return false; return false;
last_discrete_bearing = discrete_bearing; last_discrete_bearing = discrete_bearing;
@ -62,8 +62,8 @@ classifyIntersection(Intersection intersection)
std::size_t number = 0; std::size_t number = 0;
if (canBeDiscretized) if (canBeDiscretized)
{ {
if (util::guidance::BearingClass::getDiscreteBearing(intersection.back().turn.bearing) < if (util::guidance::BearingClass::getDiscreteBearing(intersection.back().bearing) <
util::guidance::BearingClass::getDiscreteBearing(intersection.front().turn.bearing)) util::guidance::BearingClass::getDiscreteBearing(intersection.front().bearing))
{ {
intersection.insert(intersection.begin(), intersection.back()); intersection.insert(intersection.begin(), intersection.back());
intersection.pop_back(); intersection.pop_back();
@ -73,7 +73,7 @@ classifyIntersection(Intersection intersection)
if (road.entry_allowed) if (road.entry_allowed)
entry_class.activate(number); entry_class.activate(number);
auto discrete_bearing_class = auto discrete_bearing_class =
util::guidance::BearingClass::getDiscreteBearing(std::round(road.turn.bearing)); util::guidance::BearingClass::getDiscreteBearing(std::round(road.bearing));
bearing_class.add(std::round(discrete_bearing_class * bearing_class.add(std::round(discrete_bearing_class *
util::guidance::BearingClass::discrete_step_size)); util::guidance::BearingClass::discrete_step_size));
++number; ++number;
@ -85,7 +85,7 @@ classifyIntersection(Intersection intersection)
{ {
if (road.entry_allowed) if (road.entry_allowed)
entry_class.activate(number); entry_class.activate(number);
bearing_class.add(std::round(road.turn.bearing)); bearing_class.add(std::round(road.bearing));
++number; ++number;
} }
} }

View File

@ -48,28 +48,28 @@ bool findPreviousIntersection(const NodeID node_v,
// Node -> Via_Edge -> Intersection[0 == UTURN] -> reverse_of(via_edge) -> Intersection at node // Node -> Via_Edge -> Intersection[0 == UTURN] -> reverse_of(via_edge) -> Intersection at node
// (looking at the reverse direction). // (looking at the reverse direction).
const auto node_w = node_based_graph.GetTarget(via_edge); const auto node_w = node_based_graph.GetTarget(via_edge);
const auto u_turn_at_node_w = intersection[0].turn.eid; const auto u_turn_at_node_w = intersection[0].eid;
const auto node_v_reverse_intersection = const auto node_v_reverse_intersection =
turn_analysis.getIntersection(node_w, u_turn_at_node_w); turn_analysis.getIntersection(node_w, u_turn_at_node_w);
// Continue along the straightmost turn. If there is no straight turn, we cannot find a valid // Continue along the straightmost turn. If there is no straight turn, we cannot find a valid
// previous intersection. // previous intersection.
const auto straightmost_at_v_in_reverse = const auto straightmost_at_v_in_reverse =
findClosestTurn(node_v_reverse_intersection, STRAIGHT_ANGLE); node_v_reverse_intersection.findClosestTurn(STRAIGHT_ANGLE);
// TODO evaluate if narrow turn is the right criterion here... Might be that other angles are // TODO evaluate if narrow turn is the right criterion here... Might be that other angles are
// valid // valid
if (angularDeviation(straightmost_at_v_in_reverse->turn.angle, STRAIGHT_ANGLE) > GROUP_ANGLE) if (angularDeviation(straightmost_at_v_in_reverse->angle, STRAIGHT_ANGLE) > GROUP_ANGLE)
return false; return false;
const auto node_u = node_based_graph.GetTarget(straightmost_at_v_in_reverse->turn.eid); const auto node_u = node_based_graph.GetTarget(straightmost_at_v_in_reverse->eid);
const auto node_u_reverse_intersection = const auto node_u_reverse_intersection =
turn_analysis.getIntersection(node_v, straightmost_at_v_in_reverse->turn.eid); turn_analysis.getIntersection(node_v, straightmost_at_v_in_reverse->eid);
// now check that the u-turn at the given intersection connects to via-edge // now check that the u-turn at the given intersection connects to via-edge
// The u-turn at the now found intersection should, hopefully, represent the previous edge. // The u-turn at the now found intersection should, hopefully, represent the previous edge.
result_node = node_u; result_node = node_u;
result_via_edge = node_u_reverse_intersection[0].turn.eid; result_via_edge = node_u_reverse_intersection[0].eid;
// if the edge is not traversable, we obviously don't have a previous intersection or couldn't // if the edge is not traversable, we obviously don't have a previous intersection or couldn't
// find it. // find it.
@ -85,7 +85,7 @@ bool findPreviousIntersection(const NodeID node_v,
result_intersection.end() != result_intersection.end() !=
std::find_if(result_intersection.begin(), std::find_if(result_intersection.begin(),
result_intersection.end(), result_intersection.end(),
[via_edge](const ConnectedRoad &road) { return road.turn.eid == via_edge; }); [via_edge](const ConnectedRoad &road) { return road.eid == via_edge; });
if (!check_via_edge) if (!check_via_edge)
{ {

View File

@ -47,7 +47,7 @@ operator()(const NodeID, const EdgeID via_edge, Intersection intersection) const
if (intersection[0].entry_allowed) if (intersection[0].entry_allowed)
{ {
intersection[0].turn.instruction = {findBasicTurnType(via_edge, intersection[0]), intersection[0].instruction = {findBasicTurnType(via_edge, intersection[0]),
DirectionModifier::UTurn}; DirectionModifier::UTurn};
} }
@ -62,14 +62,14 @@ operator()(const NodeID, const EdgeID via_edge, Intersection intersection) const
Intersection TurnHandler::handleOneWayTurn(Intersection intersection) const Intersection TurnHandler::handleOneWayTurn(Intersection intersection) const
{ {
BOOST_ASSERT(intersection[0].turn.angle < 0.001); BOOST_ASSERT(intersection[0].angle < 0.001);
return intersection; return intersection;
} }
Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection intersection) const Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection intersection) const
{ {
BOOST_ASSERT(intersection[0].turn.angle < 0.001); BOOST_ASSERT(intersection[0].angle < 0.001);
intersection[1].turn.instruction = intersection[1].instruction =
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]); getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
return intersection; return intersection;
@ -81,8 +81,8 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
{ {
const auto &in_data = node_based_graph.GetEdgeData(via_edge); const auto &in_data = node_based_graph.GetEdgeData(via_edge);
const auto &first_data = node_based_graph.GetEdgeData(road.turn.eid); const auto &first_data = node_based_graph.GetEdgeData(road.eid);
const auto &second_data = node_based_graph.GetEdgeData(other.turn.eid); const auto &second_data = node_based_graph.GetEdgeData(other.eid);
const auto &first_classification = first_data.road_classification; const auto &first_classification = first_data.road_classification;
const auto &second_classification = second_data.road_classification; const auto &second_classification = second_data.road_classification;
const bool is_ramp = first_classification.IsRampClass(); const bool is_ramp = first_classification.IsRampClass();
@ -107,19 +107,18 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
return false; return false;
const bool turn_is_perfectly_straight = const bool turn_is_perfectly_straight =
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < std::numeric_limits<double>::epsilon(); angularDeviation(road.angle, STRAIGHT_ANGLE) < std::numeric_limits<double>::epsilon();
if (turn_is_perfectly_straight && in_data.name_id != EMPTY_NAMEID && if (turn_is_perfectly_straight && in_data.name_id != EMPTY_NAMEID &&
in_data.name_id == node_based_graph.GetEdgeData(road.turn.eid).name_id) in_data.name_id == node_based_graph.GetEdgeData(road.eid).name_id)
return true; return true;
const bool is_much_narrower_than_other = const bool is_much_narrower_than_other =
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) / angularDeviation(other.angle, STRAIGHT_ANGLE) /
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > angularDeviation(road.angle, STRAIGHT_ANGLE) >
INCREASES_BY_FOURTY_PERCENT && INCREASES_BY_FOURTY_PERCENT &&
angularDeviation(angularDeviation(other.turn.angle, STRAIGHT_ANGLE), angularDeviation(angularDeviation(other.angle, STRAIGHT_ANGLE),
angularDeviation(road.turn.angle, STRAIGHT_ANGLE)) > angularDeviation(road.angle, STRAIGHT_ANGLE)) > FUZZY_ANGLE_DIFFERENCE;
FUZZY_ANGLE_DIFFERENCE;
return is_much_narrower_than_other; return is_much_narrower_than_other;
} }
@ -127,7 +126,7 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const
{ {
const auto obvious_index = findObviousTurn(via_edge, intersection); const auto obvious_index = findObviousTurn(via_edge, intersection);
BOOST_ASSERT(intersection[0].turn.angle < 0.001); BOOST_ASSERT(intersection[0].angle < 0.001);
/* Two nearly straight turns -> FORK /* Two nearly straight turns -> FORK
OOOOOOO OOOOOOO
/ /
@ -151,26 +150,26 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
if (intersection[1].entry_allowed) if (intersection[1].entry_allowed)
{ {
if (TurnType::OnRamp != findBasicTurnType(via_edge, intersection[1])) if (TurnType::OnRamp != findBasicTurnType(via_edge, intersection[1]))
intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right}; intersection[1].instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
else else
intersection[1].turn.instruction = {TurnType::OnRamp, DirectionModifier::Right}; intersection[1].instruction = {TurnType::OnRamp, DirectionModifier::Right};
} }
if (intersection[2].entry_allowed) if (intersection[2].entry_allowed)
{ {
if (TurnType::OnRamp != findBasicTurnType(via_edge, intersection[2])) if (TurnType::OnRamp != findBasicTurnType(via_edge, intersection[2]))
intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left}; intersection[2].instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
else else
intersection[2].turn.instruction = {TurnType::OnRamp, DirectionModifier::Left}; intersection[2].instruction = {TurnType::OnRamp, DirectionModifier::Left};
} }
} }
else if (obvious_index != 0) // has an obvious continuing road/obvious turn else if (obvious_index != 0) // has an obvious continuing road/obvious turn
{ {
const auto direction_at_one = getTurnDirection(intersection[1].turn.angle); const auto direction_at_one = getTurnDirection(intersection[1].angle);
const auto direction_at_two = getTurnDirection(intersection[2].turn.angle); const auto direction_at_two = getTurnDirection(intersection[2].angle);
if (obvious_index == 1) if (obvious_index == 1)
{ {
intersection[1].turn.instruction = getInstructionForObvious( intersection[1].instruction = getInstructionForObvious(
3, via_edge, isThroughStreet(1, intersection), intersection[1]); 3, via_edge, isThroughStreet(1, intersection), intersection[1]);
const auto second_direction = (direction_at_one == direction_at_two && const auto second_direction = (direction_at_one == direction_at_two &&
@ -178,13 +177,13 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
? DirectionModifier::SlightLeft ? DirectionModifier::SlightLeft
: direction_at_two; : direction_at_two;
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]), intersection[2].instruction = {findBasicTurnType(via_edge, intersection[2]),
second_direction}; second_direction};
} }
else else
{ {
BOOST_ASSERT(obvious_index == 2); BOOST_ASSERT(obvious_index == 2);
intersection[2].turn.instruction = getInstructionForObvious( intersection[2].instruction = getInstructionForObvious(
3, via_edge, isThroughStreet(2, intersection), intersection[2]); 3, via_edge, isThroughStreet(2, intersection), intersection[2]);
const auto first_direction = (direction_at_one == direction_at_two && const auto first_direction = (direction_at_one == direction_at_two &&
@ -192,16 +191,16 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
? DirectionModifier::SlightRight ? DirectionModifier::SlightRight
: direction_at_one; : direction_at_one;
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
first_direction}; first_direction};
} }
} }
else // basic turn assignment else // basic turn assignment
{ {
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
getTurnDirection(intersection[1].turn.angle)}; getTurnDirection(intersection[1].angle)};
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]), intersection[2].instruction = {findBasicTurnType(via_edge, intersection[2]),
getTurnDirection(intersection[2].turn.angle)}; getTurnDirection(intersection[2].angle)};
} }
return intersection; return intersection;
} }
@ -214,7 +213,7 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
double straightmost_deviation = 180; double straightmost_deviation = 180;
for (std::size_t i = 0; i < intersection.size(); ++i) for (std::size_t i = 0; i < intersection.size(); ++i)
{ {
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE); const double deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
if (deviation < straightmost_deviation) if (deviation < straightmost_deviation)
{ {
straightmost_deviation = deviation; straightmost_deviation = deviation;
@ -225,7 +224,7 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
// check whether the obvious choice is actually a through street // check whether the obvious choice is actually a through street
if (obvious_index != 0) if (obvious_index != 0)
{ {
intersection[obvious_index].turn.instruction = intersection[obvious_index].instruction =
getInstructionForObvious(intersection.size(), getInstructionForObvious(intersection.size(),
via_edge, via_edge,
isThroughStreet(obvious_index, intersection), isThroughStreet(obvious_index, intersection),
@ -242,23 +241,23 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
auto &left = intersection[fork_range.second]; auto &left = intersection[fork_range.second];
auto &right = intersection[fork_range.first]; auto &right = intersection[fork_range.first];
const auto left_classification = const auto left_classification =
node_based_graph.GetEdgeData(left.turn.eid).road_classification; node_based_graph.GetEdgeData(left.eid).road_classification;
const auto right_classification = const auto right_classification =
node_based_graph.GetEdgeData(right.turn.eid).road_classification; node_based_graph.GetEdgeData(right.eid).road_classification;
if (canBeSeenAsFork(left_classification, right_classification)) if (canBeSeenAsFork(left_classification, right_classification))
assignFork(via_edge, left, right); assignFork(via_edge, left, right);
else if (left_classification.GetPriority() > right_classification.GetPriority()) else if (left_classification.GetPriority() > right_classification.GetPriority())
{ {
right.turn.instruction = right.instruction =
getInstructionForObvious(intersection.size(), via_edge, false, right); getInstructionForObvious(intersection.size(), via_edge, false, right);
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left),
DirectionModifier::SlightLeft}; DirectionModifier::SlightLeft};
} }
else else
{ {
left.turn.instruction = left.instruction =
getInstructionForObvious(intersection.size(), via_edge, false, left); getInstructionForObvious(intersection.size(), via_edge, false, left);
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
} }
@ -281,13 +280,13 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn); intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
} }
// no straight turn // no straight turn
else if (intersection[straightmost_turn].turn.angle > 180) else if (intersection[straightmost_turn].angle > 180)
{ {
// at most three turns on either side // at most three turns on either side
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn); intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn);
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn); intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn);
} }
else if (intersection[straightmost_turn].turn.angle < 180) else if (intersection[straightmost_turn].angle < 180)
{ {
intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1); intersection = assignLeftTurns(via_edge, std::move(intersection), straightmost_turn + 1);
intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1); intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
@ -312,7 +311,7 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
BOOST_ASSERT(!intersection.empty()); BOOST_ASSERT(!intersection.empty());
for (auto &road : intersection) for (auto &road : intersection)
road = mirror(std::move(road)); road.mirror();
std::reverse(intersection.begin() + 1, intersection.end()); std::reverse(intersection.begin() + 1, intersection.end());
}; };
@ -349,8 +348,8 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
// Handle Turns 1-3 // Handle Turns 1-3
else if (up_to == 3) else if (up_to == 3)
{ {
const auto first_direction = getTurnDirection(intersection[1].turn.angle); const auto first_direction = getTurnDirection(intersection[1].angle);
const auto second_direction = getTurnDirection(intersection[2].turn.angle); const auto second_direction = getTurnDirection(intersection[2].angle);
if (first_direction == second_direction) if (first_direction == second_direction)
{ {
// conflict // conflict
@ -364,9 +363,9 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
// Handle Turns 1-4 // Handle Turns 1-4
else if (up_to == 4) else if (up_to == 4)
{ {
const auto first_direction = getTurnDirection(intersection[1].turn.angle); const auto first_direction = getTurnDirection(intersection[1].angle);
const auto second_direction = getTurnDirection(intersection[2].turn.angle); const auto second_direction = getTurnDirection(intersection[2].angle);
const auto third_direction = getTurnDirection(intersection[3].turn.angle); const auto third_direction = getTurnDirection(intersection[3].angle);
if (first_direction != second_direction && second_direction != third_direction) if (first_direction != second_direction && second_direction != third_direction)
{ {
// due to the circular order, the turn directions are unique // due to the circular order, the turn directions are unique
@ -395,28 +394,26 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
// triggered 2>= ...) // triggered 2>= ...)
// //
// Conflicting Turns, but at least farther than what we call a narrow turn // Conflicting Turns, but at least farther than what we call a narrow turn
else if (angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >= else if (angularDeviation(intersection[1].angle, intersection[2].angle) >=
NARROW_TURN_ANGLE && NARROW_TURN_ANGLE &&
angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >= angularDeviation(intersection[2].angle, intersection[3].angle) >=
NARROW_TURN_ANGLE) NARROW_TURN_ANGLE)
{ {
BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed && BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed &&
intersection[3].entry_allowed); intersection[3].entry_allowed);
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
DirectionModifier::SharpRight}; DirectionModifier::SharpRight};
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]), intersection[2].instruction = {findBasicTurnType(via_edge, intersection[2]),
DirectionModifier::Right}; DirectionModifier::Right};
intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]), intersection[3].instruction = {findBasicTurnType(via_edge, intersection[3]),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
else if (((first_direction == second_direction && second_direction == third_direction) || else if (((first_direction == second_direction && second_direction == third_direction) ||
(first_direction == second_direction && (first_direction == second_direction &&
angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) < angularDeviation(intersection[2].angle, intersection[3].angle) < GROUP_ANGLE) ||
GROUP_ANGLE) ||
(second_direction == third_direction && (second_direction == third_direction &&
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) < angularDeviation(intersection[1].angle, intersection[2].angle) < GROUP_ANGLE)))
GROUP_ANGLE)))
{ {
BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed && BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed &&
intersection[3].entry_allowed); intersection[3].entry_allowed);
@ -424,25 +421,22 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
assignTrivialTurns(via_edge, intersection, 1, up_to); assignTrivialTurns(via_edge, intersection, 1, up_to);
} }
else if (((first_direction == second_direction && else if (((first_direction == second_direction &&
angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >= angularDeviation(intersection[2].angle, intersection[3].angle) >= GROUP_ANGLE) ||
GROUP_ANGLE) ||
(second_direction == third_direction && (second_direction == third_direction &&
angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >= angularDeviation(intersection[1].angle, intersection[2].angle) >= GROUP_ANGLE)))
GROUP_ANGLE)))
{ {
BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed && BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed &&
intersection[3].entry_allowed); intersection[3].entry_allowed);
if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >= if (angularDeviation(intersection[2].angle, intersection[3].angle) >= GROUP_ANGLE)
GROUP_ANGLE)
{ {
handleDistinctConflict(via_edge, intersection[2], intersection[1]); handleDistinctConflict(via_edge, intersection[2], intersection[1]);
intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]), intersection[3].instruction = {findBasicTurnType(via_edge, intersection[3]),
third_direction}; third_direction};
} }
else else
{ {
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]), intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
first_direction}; first_direction};
handleDistinctConflict(via_edge, intersection[3], intersection[2]); handleDistinctConflict(via_edge, intersection[3], intersection[2]);
} }
@ -469,7 +463,7 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
// TODO handle road classes // TODO handle road classes
for (std::size_t i = 1; i < intersection.size(); ++i) for (std::size_t i = 1; i < intersection.size(); ++i)
{ {
const double deviation = angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE); const double deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
if (intersection[i].entry_allowed && deviation < best_deviation) if (intersection[i].entry_allowed && deviation < best_deviation)
{ {
best_deviation = deviation; best_deviation = deviation;
@ -479,20 +473,19 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
if (best_deviation <= NARROW_TURN_ANGLE) if (best_deviation <= NARROW_TURN_ANGLE)
{ {
std::size_t left = best, right = best; std::size_t left = best, right = best;
while (left + 1 < intersection.size() && while (
(angularDeviation(intersection[left + 1].turn.angle, STRAIGHT_ANGLE) <= left + 1 < intersection.size() &&
NARROW_TURN_ANGLE || (angularDeviation(intersection[left + 1].angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE ||
(angularDeviation(intersection[left].turn.angle, (angularDeviation(intersection[left].angle, intersection[left + 1].angle) <=
intersection[left + 1].turn.angle) <= NARROW_TURN_ANGLE && NARROW_TURN_ANGLE &&
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE))) angularDeviation(intersection[left].angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
++left; ++left;
while ( while (
right > 1 && right > 1 &&
(angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <= (angularDeviation(intersection[right - 1].angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE ||
NARROW_TURN_ANGLE || (angularDeviation(intersection[right].angle, intersection[right - 1].angle) <
(angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) <
NARROW_TURN_ANGLE && NARROW_TURN_ANGLE &&
angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE))) angularDeviation(intersection[right - 1].angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
--right; --right;
if (left == right) if (left == right)
@ -500,12 +493,11 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
const bool valid_indices = 0 < right && right < left; const bool valid_indices = 0 < right && right < left;
const bool separated_at_left_side = const bool separated_at_left_side =
angularDeviation(intersection[left].turn.angle, angularDeviation(intersection[left].angle,
intersection[(left + 1) % intersection.size()].turn.angle) >= intersection[(left + 1) % intersection.size()].angle) >= GROUP_ANGLE;
GROUP_ANGLE;
const bool separated_at_right_side = const bool separated_at_right_side =
right > 0 && right > 0 &&
angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >= angularDeviation(intersection[right].angle, intersection[right - 1].angle) >=
GROUP_ANGLE; GROUP_ANGLE;
const bool not_more_than_three = (left - right) <= 2; const bool not_more_than_three = (left - right) <= 2;
@ -527,28 +519,27 @@ std::pair<std::size_t, std::size_t> TurnHandler::findFork(const EdgeID via_edge,
// A fork can only happen between edges of similar types where none of the ones is obvious // A fork can only happen between edges of similar types where none of the ones is obvious
const bool has_compatible_classes = [&]() { const bool has_compatible_classes = [&]() {
const bool ramp_class = node_based_graph.GetEdgeData(intersection[right].turn.eid) const bool ramp_class = node_based_graph.GetEdgeData(intersection[right].eid)
.road_classification.IsLinkClass(); .road_classification.IsLinkClass();
for (std::size_t index = right + 1; index <= left; ++index) for (std::size_t index = right + 1; index <= left; ++index)
if (ramp_class != if (ramp_class !=
node_based_graph.GetEdgeData(intersection[index].turn.eid) node_based_graph.GetEdgeData(intersection[index].eid)
.road_classification.IsLinkClass()) .road_classification.IsLinkClass())
return false; return false;
const auto in_classification = const auto in_classification =
node_based_graph.GetEdgeData(intersection[0].turn.eid).road_classification; node_based_graph.GetEdgeData(intersection[0].eid).road_classification;
for (std::size_t base_index = right; base_index <= left; ++base_index) for (std::size_t base_index = right; base_index <= left; ++base_index)
{ {
const auto base_classification = const auto base_classification =
node_based_graph.GetEdgeData(intersection[base_index].turn.eid) node_based_graph.GetEdgeData(intersection[base_index].eid).road_classification;
.road_classification;
for (std::size_t compare_index = right; compare_index <= left; ++compare_index) for (std::size_t compare_index = right; compare_index <= left; ++compare_index)
{ {
if (base_index == compare_index) if (base_index == compare_index)
continue; continue;
const auto compare_classification = const auto compare_classification =
node_based_graph.GetEdgeData(intersection[compare_index].turn.eid) node_based_graph.GetEdgeData(intersection[compare_index].eid)
.road_classification; .road_classification;
if (obviousByRoadClass( if (obviousByRoadClass(
in_classification, base_classification, compare_classification)) in_classification, base_classification, compare_classification))
@ -589,25 +580,22 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
{ {
// single turn of both is valid (don't change the valid one) // single turn of both is valid (don't change the valid one)
// or multiple identical angles -> bad OSM intersection // or multiple identical angles -> bad OSM intersection
if ((!left.entry_allowed || !right.entry_allowed) || (left.turn.angle == right.turn.angle)) if ((!left.entry_allowed || !right.entry_allowed) || (left.angle == right.angle))
{ {
if (left.entry_allowed) if (left.entry_allowed)
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left), getTurnDirection(left.angle)};
getTurnDirection(left.turn.angle)};
if (right.entry_allowed) if (right.entry_allowed)
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right), getTurnDirection(right.angle)};
getTurnDirection(right.turn.angle)};
return; return;
} }
if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight || if (getTurnDirection(left.angle) == DirectionModifier::Straight ||
getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft || getTurnDirection(left.angle) == DirectionModifier::SlightLeft ||
getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight) getTurnDirection(right.angle) == DirectionModifier::SlightRight)
{ {
const auto left_classification = const auto left_classification = node_based_graph.GetEdgeData(left.eid).road_classification;
node_based_graph.GetEdgeData(left.turn.eid).road_classification;
const auto right_classification = const auto right_classification =
node_based_graph.GetEdgeData(right.turn.eid).road_classification; node_based_graph.GetEdgeData(right.eid).road_classification;
if (canBeSeenAsFork(left_classification, right_classification)) if (canBeSeenAsFork(left_classification, right_classification))
assignFork(via_edge, left, right); assignFork(via_edge, left, right);
else if (left_classification.GetPriority() > right_classification.GetPriority()) else if (left_classification.GetPriority() > right_classification.GetPriority())
@ -616,9 +604,8 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
// here we don't know about the intersection size. To be on the save side, // here we don't know about the intersection size. To be on the save side,
// we declare it // we declare it
// as complex (at least size 4) // as complex (at least size 4)
right.turn.instruction = getInstructionForObvious(4, via_edge, false, right); right.instruction = getInstructionForObvious(4, via_edge, false, right);
left.turn.instruction = {findBasicTurnType(via_edge, left), left.instruction = {findBasicTurnType(via_edge, left), DirectionModifier::SlightLeft};
DirectionModifier::SlightLeft};
} }
else else
{ {
@ -626,81 +613,81 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
// here we don't know about the intersection size. To be on the save side, // here we don't know about the intersection size. To be on the save side,
// we declare it // we declare it
// as complex (at least size 4) // as complex (at least size 4)
left.turn.instruction = getInstructionForObvious(4, via_edge, false, left); left.instruction = getInstructionForObvious(4, via_edge, false, left);
right.turn.instruction = {findBasicTurnType(via_edge, right), right.instruction = {findBasicTurnType(via_edge, right),
DirectionModifier::SlightRight}; DirectionModifier::SlightRight};
} }
} }
const auto left_type = findBasicTurnType(via_edge, left); const auto left_type = findBasicTurnType(via_edge, left);
const auto right_type = findBasicTurnType(via_edge, right); const auto right_type = findBasicTurnType(via_edge, right);
// Two Right Turns // Two Right Turns
if (angularDeviation(left.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION) if (angularDeviation(left.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
{ {
// Keep left perfect, shift right // Keep left perfect, shift right
left.turn.instruction = {left_type, DirectionModifier::Right}; left.instruction = {left_type, DirectionModifier::Right};
right.turn.instruction = {right_type, DirectionModifier::SharpRight}; right.instruction = {right_type, DirectionModifier::SharpRight};
return; return;
} }
if (angularDeviation(right.turn.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION) if (angularDeviation(right.angle, 90) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
{ {
// Keep Right perfect, shift left // Keep Right perfect, shift left
left.turn.instruction = {left_type, DirectionModifier::SlightRight}; left.instruction = {left_type, DirectionModifier::SlightRight};
right.turn.instruction = {right_type, DirectionModifier::Right}; right.instruction = {right_type, DirectionModifier::Right};
return; return;
} }
// Two Right Turns // Two Right Turns
if (angularDeviation(left.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION) if (angularDeviation(left.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
{ {
// Keep left perfect, shift right // Keep left perfect, shift right
left.turn.instruction = {left_type, DirectionModifier::Left}; left.instruction = {left_type, DirectionModifier::Left};
right.turn.instruction = {right_type, DirectionModifier::SlightLeft}; right.instruction = {right_type, DirectionModifier::SlightLeft};
return; return;
} }
if (angularDeviation(right.turn.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION) if (angularDeviation(right.angle, 270) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
{ {
// Keep Right perfect, shift left // Keep Right perfect, shift left
left.turn.instruction = {left_type, DirectionModifier::SharpLeft}; left.instruction = {left_type, DirectionModifier::SharpLeft};
right.turn.instruction = {right_type, DirectionModifier::Left}; right.instruction = {right_type, DirectionModifier::Left};
return; return;
} }
// Shift the lesser penalty // Shift the lesser penalty
if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft) if (getTurnDirection(left.angle) == DirectionModifier::SharpLeft)
{ {
left.turn.instruction = {left_type, DirectionModifier::SharpLeft}; left.instruction = {left_type, DirectionModifier::SharpLeft};
right.turn.instruction = {right_type, DirectionModifier::Left}; right.instruction = {right_type, DirectionModifier::Left};
return; return;
} }
if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight) if (getTurnDirection(right.angle) == DirectionModifier::SharpRight)
{ {
left.turn.instruction = {left_type, DirectionModifier::Right}; left.instruction = {left_type, DirectionModifier::Right};
right.turn.instruction = {right_type, DirectionModifier::SharpRight}; right.instruction = {right_type, DirectionModifier::SharpRight};
return; return;
} }
if (getTurnDirection(left.turn.angle) == DirectionModifier::Right) if (getTurnDirection(left.angle) == DirectionModifier::Right)
{ {
if (angularDeviation(left.turn.angle, 85) >= angularDeviation(right.turn.angle, 85)) if (angularDeviation(left.angle, 85) >= angularDeviation(right.angle, 85))
{ {
left.turn.instruction = {left_type, DirectionModifier::Right}; left.instruction = {left_type, DirectionModifier::Right};
right.turn.instruction = {right_type, DirectionModifier::SharpRight}; right.instruction = {right_type, DirectionModifier::SharpRight};
} }
else else
{ {
left.turn.instruction = {left_type, DirectionModifier::SlightRight}; left.instruction = {left_type, DirectionModifier::SlightRight};
right.turn.instruction = {right_type, DirectionModifier::Right}; right.instruction = {right_type, DirectionModifier::Right};
} }
} }
else else
{ {
if (angularDeviation(left.turn.angle, 265) >= angularDeviation(right.turn.angle, 265)) if (angularDeviation(left.angle, 265) >= angularDeviation(right.angle, 265))
{ {
left.turn.instruction = {left_type, DirectionModifier::SharpLeft}; left.instruction = {left_type, DirectionModifier::SharpLeft};
right.turn.instruction = {right_type, DirectionModifier::Left}; right.instruction = {right_type, DirectionModifier::Left};
} }
else else
{ {
left.turn.instruction = {left_type, DirectionModifier::Left}; left.instruction = {left_type, DirectionModifier::Left};
right.turn.instruction = {right_type, DirectionModifier::SlightLeft}; right.instruction = {right_type, DirectionModifier::SlightLeft};
} }
} }
} }

View File

@ -113,8 +113,8 @@ LaneDataVector augmentMultiple(const std::size_t none_index,
if (intersection[intersection_index].entry_allowed) if (intersection[intersection_index].entry_allowed)
{ {
// FIXME this probably can be only a subset of these turns here? // FIXME this probably can be only a subset of these turns here?
lane_data.push_back({tag_by_modifier[intersection[intersection_index] lane_data.push_back(
.turn.instruction.direction_modifier], {tag_by_modifier[intersection[intersection_index].instruction.direction_modifier],
lane_data[none_index].from, lane_data[none_index].from,
lane_data[none_index].to, lane_data[none_index].to,
false}); false});
@ -162,7 +162,7 @@ LaneDataVector handleRenamingSituations(const std::size_t none_index,
if (!road.entry_allowed) if (!road.entry_allowed)
continue; continue;
const auto modifier = road.turn.instruction.direction_modifier; const auto modifier = road.instruction.direction_modifier;
has_right |= modifier == DirectionModifier::Right; has_right |= modifier == DirectionModifier::Right;
has_right |= modifier == DirectionModifier::SlightRight; has_right |= modifier == DirectionModifier::SlightRight;
has_right |= modifier == DirectionModifier::SharpRight; has_right |= modifier == DirectionModifier::SharpRight;

View File

@ -167,8 +167,8 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
(intersection.size() == 2 && (intersection.size() == 2 &&
((lane_description_id != INVALID_LANE_DESCRIPTIONID && ((lane_description_id != INVALID_LANE_DESCRIPTIONID &&
lane_description_id == lane_description_id ==
node_based_graph.GetEdgeData(intersection[1].turn.eid).lane_description_id) || node_based_graph.GetEdgeData(intersection[1].eid).lane_description_id) ||
angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)); angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE));
if (is_going_straight_and_turns_continue) if (is_going_straight_and_turns_continue)
return TurnLaneScenario::NONE; return TurnLaneScenario::NONE;
@ -201,9 +201,9 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
const auto &road = previous_intersection[road_index]; const auto &road = previous_intersection[road_index];
// in case of a sliproad that is connected to road of simlar angle, we handle the // in case of a sliproad that is connected to road of simlar angle, we handle the
// turn as a combined turn // turn as a combined turn
if (road.turn.instruction.type == TurnType::Sliproad) if (road.instruction.type == TurnType::Sliproad)
{ {
if (via_edge == road.turn.eid) if (via_edge == road.eid)
return TurnLaneScenario::SLIPROAD; return TurnLaneScenario::SLIPROAD;
const auto &closest_road = [&]() { const auto &closest_road = [&]() {
@ -217,16 +217,16 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
BOOST_ASSERT(road_index + 1 < previous_intersection.size()); BOOST_ASSERT(road_index + 1 < previous_intersection.size());
return previous_intersection[road_index + 1]; return previous_intersection[road_index + 1];
} }
else if (angularDeviation(road.turn.angle, else if (angularDeviation(road.angle,
previous_intersection.at(road_index - 1).turn.angle) < previous_intersection.at(road_index - 1).angle) <
angularDeviation(road.turn.angle, angularDeviation(road.angle,
previous_intersection.at(road_index + 1).turn.angle)) previous_intersection.at(road_index + 1).angle))
return previous_intersection[road_index - 1]; return previous_intersection[road_index - 1];
else else
return previous_intersection[road_index + 1]; return previous_intersection[road_index + 1];
}(); }();
if (via_edge == closest_road.turn.eid) if (via_edge == closest_road.eid)
return TurnLaneScenario::SLIPROAD; return TurnLaneScenario::SLIPROAD;
} }
} }
@ -482,8 +482,8 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data,
all_simple &= (best_match->entry_allowed || all_simple &= (best_match->entry_allowed ||
// check for possible u-turn match on non-reversed edge // check for possible u-turn match on non-reversed edge
((match_index == 0 || match_index + 1 == intersection.size()) && ((match_index == 0 || match_index + 1 == intersection.size()) &&
!node_based_graph.GetEdgeData(best_match->turn.eid).reversed)); !node_based_graph.GetEdgeData(best_match->eid).reversed));
all_simple &= isValidMatch(data.tag, best_match->turn.instruction); all_simple &= isValidMatch(data.tag, best_match->instruction);
} }
// either all indices are matched, or we have a single none-value // either all indices are matched, or we have a single none-value
@ -527,7 +527,7 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
// Try and maitch lanes to available turns. For Turns that are not directly matchable, check // Try and maitch lanes to available turns. For Turns that are not directly matchable, check
// whether we can match them at the upcoming intersection. // whether we can match them at the upcoming intersection.
const auto straightmost = findClosestTurn(intersection, STRAIGHT_ANGLE); const auto straightmost = intersection.findClosestTurn(STRAIGHT_ANGLE);
BOOST_ASSERT(straightmost < intersection.cend()); BOOST_ASSERT(straightmost < intersection.cend());
@ -540,9 +540,9 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
// find out about the next intersection. To check for valid matches, we also need the turn // find out about the next intersection. To check for valid matches, we also need the turn
// types // types
auto next_intersection = turn_analysis.getIntersection(at, straightmost->turn.eid); auto next_intersection = turn_analysis.getIntersection(at, straightmost->eid);
next_intersection = next_intersection =
turn_analysis.assignTurnTypes(at, straightmost->turn.eid, std::move(next_intersection)); turn_analysis.assignTurnTypes(at, straightmost->eid, std::move(next_intersection));
// check where we can match turn lanes // check where we can match turn lanes
std::size_t straightmost_tag_index = turn_lane_data.size(); std::size_t straightmost_tag_index = turn_lane_data.size();
@ -554,7 +554,7 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
const auto best_match = findBestMatch(turn_lane_data[lane].tag, intersection); const auto best_match = findBestMatch(turn_lane_data[lane].tag, intersection);
if (best_match->entry_allowed && if (best_match->entry_allowed &&
isValidMatch(turn_lane_data[lane].tag, best_match->turn.instruction)) isValidMatch(turn_lane_data[lane].tag, best_match->instruction))
{ {
matched_at_first[lane] = true; matched_at_first[lane] = true;
@ -565,8 +565,7 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
const auto best_match_at_next_intersection = const auto best_match_at_next_intersection =
findBestMatch(turn_lane_data[lane].tag, next_intersection); findBestMatch(turn_lane_data[lane].tag, next_intersection);
if (best_match_at_next_intersection->entry_allowed && if (best_match_at_next_intersection->entry_allowed &&
isValidMatch(turn_lane_data[lane].tag, isValidMatch(turn_lane_data[lane].tag, best_match_at_next_intersection->instruction))
best_match_at_next_intersection->turn.instruction))
{ {
if (!matched_at_first[lane] || turn_lane_data[lane].tag == TurnLaneType::straight || if (!matched_at_first[lane] || turn_lane_data[lane].tag == TurnLaneType::straight ||
getMatchingQuality(turn_lane_data[lane].tag, *best_match) > getMatchingQuality(turn_lane_data[lane].tag, *best_match) >
@ -679,7 +678,7 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
std::find_if(previous_intersection.begin(), std::find_if(previous_intersection.begin(),
previous_intersection.end(), previous_intersection.end(),
[](const ConnectedRoad &road) { [](const ConnectedRoad &road) {
return road.turn.instruction.type == TurnType::Sliproad; return road.instruction.type == TurnType::Sliproad;
})); }));
BOOST_ASSERT(sliproad_index <= previous_intersection.size()); BOOST_ASSERT(sliproad_index <= previous_intersection.size());
@ -697,18 +696,18 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
BOOST_ASSERT(sliproad_index + 1 < previous_intersection.size()); BOOST_ASSERT(sliproad_index + 1 < previous_intersection.size());
return previous_intersection[sliproad_index + 1]; return previous_intersection[sliproad_index + 1];
} }
else if (angularDeviation(sliproad.turn.angle, else if (angularDeviation(sliproad.angle,
previous_intersection.at(sliproad_index - 1).turn.angle) < previous_intersection.at(sliproad_index - 1).angle) <
angularDeviation(sliproad.turn.angle, angularDeviation(sliproad.angle,
previous_intersection.at(sliproad_index + 1).turn.angle)) previous_intersection.at(sliproad_index + 1).angle))
return previous_intersection[sliproad_index - 1]; return previous_intersection[sliproad_index - 1];
else else
return previous_intersection[sliproad_index + 1]; return previous_intersection[sliproad_index + 1];
}(); }();
const auto main_description_id = const auto main_description_id =
node_based_graph.GetEdgeData(main_road.turn.eid).lane_description_id; node_based_graph.GetEdgeData(main_road.eid).lane_description_id;
const auto sliproad_description_id = const auto sliproad_description_id =
node_based_graph.GetEdgeData(sliproad.turn.eid).lane_description_id; node_based_graph.GetEdgeData(sliproad.eid).lane_description_id;
if (main_description_id == INVALID_LANE_DESCRIPTIONID || if (main_description_id == INVALID_LANE_DESCRIPTIONID ||
sliproad_description_id == INVALID_LANE_DESCRIPTIONID) sliproad_description_id == INVALID_LANE_DESCRIPTIONID)
@ -716,7 +715,7 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
TurnLaneDescription combined_description; TurnLaneDescription combined_description;
// is the sliproad going off to the right? // is the sliproad going off to the right?
if (main_road.turn.angle > sliproad.turn.angle) if (main_road.angle > sliproad.angle)
{ {
combined_description.insert( combined_description.insert(
combined_description.end(), combined_description.end(),

View File

@ -109,7 +109,7 @@ double getMatchingQuality(const TurnLaneType::Mask tag, const ConnectedRoad &roa
BOOST_ASSERT(static_cast<std::size_t>(modifier) < BOOST_ASSERT(static_cast<std::size_t>(modifier) <
sizeof(idealized_turn_angles) / sizeof(*idealized_turn_angles)); sizeof(idealized_turn_angles) / sizeof(*idealized_turn_angles));
const auto idealized_angle = idealized_turn_angles[modifier]; const auto idealized_angle = idealized_turn_angles[modifier];
return angularDeviation(idealized_angle, road.turn.angle); return angularDeviation(idealized_angle, road.angle);
} }
// Every tag is somewhat idealized in form of the expected angle. A through lane should go straight // Every tag is somewhat idealized in form of the expected angle. A through lane should go straight
@ -123,9 +123,9 @@ typename Intersection::const_iterator findBestMatch(const TurnLaneType::Mask tag
intersection.end(), intersection.end(),
[tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { [tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
// prefer valid matches // prefer valid matches
if (isValidMatch(tag, lhs.turn.instruction) != if (isValidMatch(tag, lhs.instruction) !=
isValidMatch(tag, rhs.turn.instruction)) isValidMatch(tag, rhs.instruction))
return isValidMatch(tag, lhs.turn.instruction); return isValidMatch(tag, lhs.instruction);
// if the entry allowed flags don't match, we select the one with // if the entry allowed flags don't match, we select the one with
// entry allowed set to true // entry allowed set to true
@ -154,8 +154,8 @@ typename Intersection::const_iterator findBestMatchForReverse(const TurnLaneType
intersection.end(), intersection.end(),
[tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) { [tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
// prefer valid matches // prefer valid matches
if (isValidMatch(tag, lhs.turn.instruction) != isValidMatch(tag, rhs.turn.instruction)) if (isValidMatch(tag, lhs.instruction) != isValidMatch(tag, rhs.instruction))
return isValidMatch(tag, lhs.turn.instruction); return isValidMatch(tag, lhs.instruction);
// if the entry allowed flags don't match, we select the one with // if the entry allowed flags don't match, we select the one with
// entry allowed set to true // entry allowed set to true
@ -182,7 +182,7 @@ bool canMatchTrivially(const Intersection &intersection, const LaneDataVector &l
if (intersection[road_index].entry_allowed) if (intersection[road_index].entry_allowed)
{ {
BOOST_ASSERT(lane_data[lane].from != INVALID_LANEID); BOOST_ASSERT(lane_data[lane].from != INVALID_LANEID);
if (!isValidMatch(lane_data[lane].tag, intersection[road_index].turn.instruction)) if (!isValidMatch(lane_data[lane].tag, intersection[road_index].instruction))
return false; return false;
if (findBestMatch(lane_data[lane].tag, intersection) != if (findBestMatch(lane_data[lane].tag, intersection) !=
@ -216,7 +216,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
lane_data_id = it->second; lane_data_id = it->second;
// set lane id instead after the switch: // set lane id instead after the switch:
road.turn.lane_data_id = lane_data_id; road.lane_data_id = lane_data_id;
}; };
if (!lane_data.empty() && lane_data.front().tag == TurnLaneType::uturn) if (!lane_data.empty() && lane_data.front().tag == TurnLaneType::uturn)
@ -225,11 +225,10 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
if (intersection[0].entry_allowed) if (intersection[0].entry_allowed)
{ {
std::size_t u_turn = 0; std::size_t u_turn = 0;
if (node_based_graph.GetEdgeData(intersection[0].turn.eid).reversed) if (node_based_graph.GetEdgeData(intersection[0].eid).reversed)
{ {
if (intersection.size() <= 1 || !intersection[1].entry_allowed || if (intersection.size() <= 1 || !intersection[1].entry_allowed ||
intersection[1].turn.instruction.direction_modifier != intersection[1].instruction.direction_modifier != DirectionModifier::SharpRight)
DirectionModifier::SharpRight)
{ {
// cannot match u-turn in a valid way // cannot match u-turn in a valid way
return intersection; return intersection;
@ -238,8 +237,8 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
road_index = 2; road_index = 2;
} }
intersection[u_turn].entry_allowed = true; intersection[u_turn].entry_allowed = true;
intersection[u_turn].turn.instruction.type = TurnType::Turn; intersection[u_turn].instruction.type = TurnType::Turn;
intersection[u_turn].turn.instruction.direction_modifier = DirectionModifier::UTurn; intersection[u_turn].instruction.direction_modifier = DirectionModifier::UTurn;
matchRoad(intersection[u_turn], lane_data.back()); matchRoad(intersection[u_turn], lane_data.back());
// continue with the first lane // continue with the first lane
@ -254,14 +253,13 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
if (intersection[road_index].entry_allowed) if (intersection[road_index].entry_allowed)
{ {
BOOST_ASSERT(lane_data[lane].from != INVALID_LANEID); BOOST_ASSERT(lane_data[lane].from != INVALID_LANEID);
BOOST_ASSERT( BOOST_ASSERT(isValidMatch(lane_data[lane].tag, intersection[road_index].instruction));
isValidMatch(lane_data[lane].tag, intersection[road_index].turn.instruction));
BOOST_ASSERT(findBestMatch(lane_data[lane].tag, intersection) == BOOST_ASSERT(findBestMatch(lane_data[lane].tag, intersection) ==
intersection.begin() + road_index); intersection.begin() + road_index);
if (TurnType::Suppressed == intersection[road_index].turn.instruction.type && if (TurnType::Suppressed == intersection[road_index].instruction.type &&
!lane_data[lane].suppress_assignment) !lane_data[lane].suppress_assignment)
intersection[road_index].turn.instruction.type = TurnType::UseLane; intersection[road_index].instruction.type = TurnType::UseLane;
matchRoad(intersection[road_index], lane_data[lane]); matchRoad(intersection[road_index], lane_data[lane]);
++lane; ++lane;
@ -272,11 +270,10 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
if (lane + 1 == lane_data.size() && lane_data.back().tag == TurnLaneType::uturn) if (lane + 1 == lane_data.size() && lane_data.back().tag == TurnLaneType::uturn)
{ {
std::size_t u_turn = 0; std::size_t u_turn = 0;
if (node_based_graph.GetEdgeData(intersection[0].turn.eid).reversed) if (node_based_graph.GetEdgeData(intersection[0].eid).reversed)
{ {
if (!intersection.back().entry_allowed || if (!intersection.back().entry_allowed ||
intersection.back().turn.instruction.direction_modifier != intersection.back().instruction.direction_modifier != DirectionModifier::SharpLeft)
DirectionModifier::SharpLeft)
{ {
// cannot match u-turn in a valid way // cannot match u-turn in a valid way
return intersection; return intersection;
@ -284,8 +281,8 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
u_turn = intersection.size() - 1; u_turn = intersection.size() - 1;
} }
intersection[u_turn].entry_allowed = true; intersection[u_turn].entry_allowed = true;
intersection[u_turn].turn.instruction.type = TurnType::Turn; intersection[u_turn].instruction.type = TurnType::Turn;
intersection[u_turn].turn.instruction.direction_modifier = DirectionModifier::UTurn; intersection[u_turn].instruction.direction_modifier = DirectionModifier::UTurn;
matchRoad(intersection[u_turn], lane_data.back()); matchRoad(intersection[u_turn], lane_data.back());
} }

View File

@ -30,7 +30,8 @@ namespace osrm
namespace server namespace server
{ {
void RequestHandler::RegisterServiceHandler(std::unique_ptr<ServiceHandlerInterface> service_handler_) void RequestHandler::RegisterServiceHandler(
std::unique_ptr<ServiceHandlerInterface> service_handler_)
{ {
service_handler = std::move(service_handler_); service_handler = std::move(service_handler_);
} }