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:
		
							parent
							
								
									388d84a89e
								
							
						
					
					
						commit
						cd03877c90
					
				@ -75,6 +75,32 @@ template <typename Iter, typename Fn> inline Fn forEachRoundabout(Iter first, It
 | 
			
		||||
    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 engine
 | 
			
		||||
} // namespace osrm
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include "extractor/guidance/turn_instruction.hpp"
 | 
			
		||||
#include "util/guidance/toolkit.hpp"
 | 
			
		||||
#include "util/node_based_graph.hpp"
 | 
			
		||||
#include "util/typedefs.hpp" // EdgeID
 | 
			
		||||
 | 
			
		||||
namespace osrm
 | 
			
		||||
@ -18,7 +19,7 @@ namespace guidance
 | 
			
		||||
// 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.
 | 
			
		||||
// The Turn Operation indicates what is exposed to the outside of the turn analysis.
 | 
			
		||||
struct TurnOperation final
 | 
			
		||||
struct TurnOperation
 | 
			
		||||
{
 | 
			
		||||
    EdgeID eid;
 | 
			
		||||
    double angle;
 | 
			
		||||
@ -48,13 +49,23 @@ struct TurnOperation final
 | 
			
		||||
// aaaaaaaa
 | 
			
		||||
//
 | 
			
		||||
// 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);
 | 
			
		||||
 | 
			
		||||
    // a turn may be relevant to good instructions, even if we cannot enter the road
 | 
			
		||||
    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
 | 
			
		||||
@ -64,25 +75,24 @@ struct Intersection final : public std::vector<ConnectedRoad>
 | 
			
		||||
{
 | 
			
		||||
    using Base = std::vector<ConnectedRoad>;
 | 
			
		||||
 | 
			
		||||
    inline Base::iterator findClosestTurn(double angle)
 | 
			
		||||
    {
 | 
			
		||||
        return std::min_element(this->begin(),
 | 
			
		||||
                                this->end(),
 | 
			
		||||
                                [angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
 | 
			
		||||
                                    return util::guidance::angularDeviation(lhs.turn.angle, angle) <
 | 
			
		||||
                                           util::guidance::angularDeviation(rhs.turn.angle, angle);
 | 
			
		||||
                                });
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
     * find the turn whose angle offers the least angularDeviation to the specified angle
 | 
			
		||||
     * E.g. for turn angles [0,90,260] and a query of 180 we return the 260 degree turn (difference
 | 
			
		||||
     * 80 over the difference of 90 to the 90 degree turn)
 | 
			
		||||
     */
 | 
			
		||||
    Base::iterator findClosestTurn(double angle);
 | 
			
		||||
    Base::const_iterator findClosestTurn(double angle) const;
 | 
			
		||||
 | 
			
		||||
    inline Base::const_iterator findClosestTurn(double angle) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::min_element(this->begin(),
 | 
			
		||||
                                this->end(),
 | 
			
		||||
                                [angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
 | 
			
		||||
                                    return util::guidance::angularDeviation(lhs.turn.angle, angle) <
 | 
			
		||||
                                           util::guidance::angularDeviation(rhs.turn.angle, angle);
 | 
			
		||||
                                });
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
     * Check validity of the intersection object. We assume a few basic properties every set of
 | 
			
		||||
     * connected roads should follow throughout guidance pre-processing. This utility function
 | 
			
		||||
     * allows checking intersections for validity
 | 
			
		||||
     */
 | 
			
		||||
    bool valid() const;
 | 
			
		||||
 | 
			
		||||
    // 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);
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,9 @@
 | 
			
		||||
#include "extractor/guidance/road_classification.hpp"
 | 
			
		||||
#include "extractor/guidance/turn_instruction.hpp"
 | 
			
		||||
 | 
			
		||||
#include "engine/guidance/route_step.hpp"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#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
 | 
			
		||||
// handler only for one side. The mirror function turns a left-hand turn in a equivalent right-hand
 | 
			
		||||
// 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)
 | 
			
		||||
{
 | 
			
		||||
@ -184,42 +161,6 @@ inline std::string applyAccessTokens(std::string lane_string, const std::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,
 | 
			
		||||
                               const RoadClassification obvious_candidate,
 | 
			
		||||
                               const RoadClassification compare_candidate)
 | 
			
		||||
@ -282,6 +223,16 @@ leastSquareRegression(const std::vector<util::Coordinate> &coordinates)
 | 
			
		||||
    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 extractor
 | 
			
		||||
} // namespace osrm
 | 
			
		||||
 | 
			
		||||
@ -23,12 +23,12 @@ namespace api
 | 
			
		||||
struct ParsedURL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServiceHandlerInterface
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  public:
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
@ -73,8 +73,7 @@ inline void print(const NodeBasedDynamicGraph &node_based_graph,
 | 
			
		||||
    for (const auto &road : intersection)
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "\t" << toString(road) << "\n";
 | 
			
		||||
        std::cout << "\t\t"
 | 
			
		||||
                  << node_based_graph.GetEdgeData(road.turn.eid).road_classification.ToString()
 | 
			
		||||
        std::cout << "\t\t" << node_based_graph.GetEdgeData(road.eid).road_classification.ToString()
 | 
			
		||||
                  << "\n";
 | 
			
		||||
    }
 | 
			
		||||
    std::cout << std::flush;
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,6 @@ unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometri
 | 
			
		||||
 | 
			
		||||
    return util::viewport::getFittedZoom(south_west, north_east);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        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));
 | 
			
		||||
        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());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#include "util/group_by.hpp"
 | 
			
		||||
#include "util/guidance/toolkit.hpp"
 | 
			
		||||
 | 
			
		||||
#include "extractor/guidance/toolkit.hpp"
 | 
			
		||||
#include "engine/guidance/toolkit.hpp"
 | 
			
		||||
#include "extractor/guidance/turn_instruction.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::isRightTurn;
 | 
			
		||||
using osrm::extractor::guidance::numLanesToTheRight;
 | 
			
		||||
using osrm::extractor::guidance::numLanesToTheLeft;
 | 
			
		||||
 | 
			
		||||
namespace osrm
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#include "engine/guidance/post_processing.hpp"
 | 
			
		||||
#include "extractor/guidance/constants.hpp"
 | 
			
		||||
#include "extractor/guidance/toolkit.hpp"
 | 
			
		||||
#include "extractor/guidance/turn_instruction.hpp"
 | 
			
		||||
#include "engine/guidance/toolkit.hpp"
 | 
			
		||||
 | 
			
		||||
#include "engine/guidance/assemble_steps.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.
 | 
			
		||||
        // 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(),
 | 
			
		||||
                                                     (extractor::guidance::TurnLaneType::straight |
 | 
			
		||||
                                                      extractor::guidance::TurnLaneType::none)))
 | 
			
		||||
            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(),
 | 
			
		||||
                                                    (extractor::guidance::TurnLaneType::straight |
 | 
			
		||||
                                                     extractor::guidance::TurnLaneType::none)))
 | 
			
		||||
 | 
			
		||||
@ -376,6 +376,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
            const NodeID node_v = m_node_based_graph->GetTarget(edge_from_u);
 | 
			
		||||
            ++node_based_edge_counter;
 | 
			
		||||
            auto intersection = turn_analysis.getIntersection(node_u, edge_from_u);
 | 
			
		||||
            BOOST_ASSERT(intersection.valid());
 | 
			
		||||
            intersection =
 | 
			
		||||
                turn_analysis.assignTurnTypes(node_u, edge_from_u, std::move(intersection));
 | 
			
		||||
            intersection =
 | 
			
		||||
@ -462,7 +463,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
                        turn_instruction,
 | 
			
		||||
                        entry_class_id,
 | 
			
		||||
                        edge_data1.travel_mode,
 | 
			
		||||
                        util::guidance::TurnBearing(intersection[0].turn.bearing),
 | 
			
		||||
                        util::guidance::TurnBearing(intersection[0].bearing),
 | 
			
		||||
                        util::guidance::TurnBearing(turn.bearing));
 | 
			
		||||
                }
 | 
			
		||||
                else if (is_encoded_backwards)
 | 
			
		||||
@ -476,7 +477,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
			
		||||
                        turn_instruction,
 | 
			
		||||
                        entry_class_id,
 | 
			
		||||
                        edge_data1.travel_mode,
 | 
			
		||||
                        util::guidance::TurnBearing(intersection[0].turn.bearing),
 | 
			
		||||
                        util::guidance::TurnBearing(intersection[0].bearing),
 | 
			
		||||
                        util::guidance::TurnBearing(turn.bearing));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    // intersection_generator
 | 
			
		||||
    const auto intersection_lanes =
 | 
			
		||||
        extractor::guidance::getLaneCountAtIntersection(intersection_node, node_based_graph);
 | 
			
		||||
    const auto intersection_lanes = intersection.getHighestConnectedLaneCount(node_based_graph);
 | 
			
		||||
 | 
			
		||||
    std::vector<util::Coordinate> coordinates;
 | 
			
		||||
    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 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(
 | 
			
		||||
            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(),
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,13 @@
 | 
			
		||||
#include "extractor/guidance/intersection.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 extractor
 | 
			
		||||
@ -9,44 +16,101 @@ namespace guidance
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
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 result = "[connection] ";
 | 
			
		||||
    result += std::to_string(road.turn.eid);
 | 
			
		||||
    result += std::to_string(road.eid);
 | 
			
		||||
    result += " allows entry: ";
 | 
			
		||||
    result += std::to_string(road.entry_allowed);
 | 
			
		||||
    result += " angle: ";
 | 
			
		||||
    result += std::to_string(road.turn.angle);
 | 
			
		||||
    result += std::to_string(road.angle);
 | 
			
		||||
    result += " bearing: ";
 | 
			
		||||
    result += std::to_string(road.turn.bearing);
 | 
			
		||||
    result += std::to_string(road.bearing);
 | 
			
		||||
    result += " instruction: ";
 | 
			
		||||
    result += std::to_string(static_cast<std::int32_t>(road.turn.instruction.type)) + " " +
 | 
			
		||||
              std::to_string(static_cast<std::int32_t>(road.turn.instruction.direction_modifier)) +
 | 
			
		||||
              " " + std::to_string(static_cast<std::int32_t>(road.turn.lane_data_id));
 | 
			
		||||
    result += std::to_string(static_cast<std::int32_t>(road.instruction.type)) + " " +
 | 
			
		||||
              std::to_string(static_cast<std::int32_t>(road.instruction.direction_modifier)) + " " +
 | 
			
		||||
              std::to_string(static_cast<std::int32_t>(road.lane_data_id));
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Intersection::iterator findClosestTurn(Intersection &intersection, const double angle)
 | 
			
		||||
Intersection::Base::iterator Intersection::findClosestTurn(double angle)
 | 
			
		||||
{
 | 
			
		||||
    return std::min_element(intersection.begin(),
 | 
			
		||||
                            intersection.end(),
 | 
			
		||||
                            [angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
 | 
			
		||||
                                return angularDeviation(lhs.turn.angle, angle) <
 | 
			
		||||
                                       angularDeviation(rhs.turn.angle, angle);
 | 
			
		||||
                            });
 | 
			
		||||
    // use the const operator to avoid code duplication
 | 
			
		||||
    return begin() +
 | 
			
		||||
           std::distance(cbegin(), static_cast<const Intersection *>(this)->findClosestTurn(angle));
 | 
			
		||||
}
 | 
			
		||||
Intersection::const_iterator findClosestTurn(const Intersection &intersection, const double angle)
 | 
			
		||||
 | 
			
		||||
Intersection::Base::const_iterator Intersection::findClosestTurn(double angle) const
 | 
			
		||||
{
 | 
			
		||||
    return std::min_element(intersection.cbegin(),
 | 
			
		||||
                            intersection.cend(),
 | 
			
		||||
                            [angle](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
 | 
			
		||||
                                return angularDeviation(lhs.turn.angle, angle) <
 | 
			
		||||
                                       angularDeviation(rhs.turn.angle, angle);
 | 
			
		||||
                            });
 | 
			
		||||
    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);
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Intersection::valid() const
 | 
			
		||||
{
 | 
			
		||||
    return !empty() &&
 | 
			
		||||
           std::is_sorted(begin(), end(), std::mem_fn(&ConnectedRoad::compareByAngle)) &&
 | 
			
		||||
           operator[](0).angle < std::numeric_limits<double>::epsilon();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
#include "extractor/guidance/toolkit.hpp"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
@ -179,13 +180,12 @@ Intersection IntersectionGenerator::GetConnectedRoads(const NodeID from_node,
 | 
			
		||||
                                false});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) {
 | 
			
		||||
        return first.turn.angle < second.turn.angle;
 | 
			
		||||
    };
 | 
			
		||||
    std::sort(std::begin(intersection), std::end(intersection), ByAngle);
 | 
			
		||||
    std::sort(std::begin(intersection),
 | 
			
		||||
              std::end(intersection),
 | 
			
		||||
              std::mem_fn(&ConnectedRoad::compareByAngle));
 | 
			
		||||
 | 
			
		||||
    BOOST_ASSERT(intersection[0].turn.angle >= 0. &&
 | 
			
		||||
                 intersection[0].turn.angle < std::numeric_limits<double>::epsilon());
 | 
			
		||||
    BOOST_ASSERT(intersection[0].angle >= 0. &&
 | 
			
		||||
                 intersection[0].angle < std::numeric_limits<double>::epsilon());
 | 
			
		||||
 | 
			
		||||
    const auto valid_count =
 | 
			
		||||
        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
 | 
			
		||||
        std::size_t self_u_turn = 0;
 | 
			
		||||
        while (self_u_turn < intersection.size() &&
 | 
			
		||||
               intersection[self_u_turn].turn.angle < std::numeric_limits<double>::epsilon() &&
 | 
			
		||||
               from_node != node_based_graph.GetTarget(intersection[self_u_turn].turn.eid))
 | 
			
		||||
               intersection[self_u_turn].angle < std::numeric_limits<double>::epsilon() &&
 | 
			
		||||
               from_node != node_based_graph.GetTarget(intersection[self_u_turn].eid))
 | 
			
		||||
        {
 | 
			
		||||
            ++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;
 | 
			
		||||
    }
 | 
			
		||||
    return intersection;
 | 
			
		||||
@ -215,8 +215,8 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
 | 
			
		||||
                                     std::size_t first_index,
 | 
			
		||||
                                     std::size_t second_index) const
 | 
			
		||||
{
 | 
			
		||||
    const auto &first_data = node_based_graph.GetEdgeData(intersection[first_index].turn.eid);
 | 
			
		||||
    const auto &second_data = node_based_graph.GetEdgeData(intersection[second_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].eid);
 | 
			
		||||
 | 
			
		||||
    // only merge named ids
 | 
			
		||||
    if (first_data.name_id == EMPTY_NAMEID)
 | 
			
		||||
@ -245,18 +245,17 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // mergeable if the angle is not too big
 | 
			
		||||
    const auto angle_between = angularDeviation(intersection[first_index].turn.angle,
 | 
			
		||||
                                                intersection[second_index].turn.angle);
 | 
			
		||||
    const auto angle_between =
 | 
			
		||||
        angularDeviation(intersection[first_index].angle, intersection[second_index].angle);
 | 
			
		||||
 | 
			
		||||
    const auto intersection_lanes =
 | 
			
		||||
        getLaneCountAtIntersection(node_at_intersection, node_based_graph);
 | 
			
		||||
    const auto intersection_lanes = intersection.getHighestConnectedLaneCount(node_based_graph);
 | 
			
		||||
 | 
			
		||||
    const auto coordinate_at_in_edge = coordinate_extractor.GetCoordinateAlongRoad(
 | 
			
		||||
        node_at_intersection,
 | 
			
		||||
        intersection[0].turn.eid,
 | 
			
		||||
        !INVERT,
 | 
			
		||||
        node_based_graph.GetTarget(intersection[0].turn.eid),
 | 
			
		||||
        intersection_lanes);
 | 
			
		||||
    const auto coordinate_at_in_edge =
 | 
			
		||||
        coordinate_extractor.GetCoordinateAlongRoad(node_at_intersection,
 | 
			
		||||
                                                    intersection[0].eid,
 | 
			
		||||
                                                    !INVERT,
 | 
			
		||||
                                                    node_based_graph.GetTarget(intersection[0].eid),
 | 
			
		||||
                                                    intersection_lanes);
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
            EdgeID last_in_edge_id;
 | 
			
		||||
            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);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -292,12 +291,11 @@ bool IntersectionGenerator::CanMerge(const NodeID node_at_intersection,
 | 
			
		||||
        const bool becomes_narrower =
 | 
			
		||||
            angularDeviation(turn_angle, other_turn_angle) < NARROW_TURN_ANGLE &&
 | 
			
		||||
            angularDeviation(turn_angle, other_turn_angle) <=
 | 
			
		||||
                angularDeviation(intersection[index].turn.angle,
 | 
			
		||||
                                 intersection[other_index].turn.angle);
 | 
			
		||||
                angularDeviation(intersection[index].angle, intersection[other_index].angle);
 | 
			
		||||
 | 
			
		||||
        const bool has_same_deviation =
 | 
			
		||||
            std::abs(angularDeviation(intersection[index].turn.angle, STRAIGHT_ANGLE) -
 | 
			
		||||
                     angularDeviation(intersection[other_index].turn.angle, STRAIGHT_ANGLE)) <
 | 
			
		||||
            std::abs(angularDeviation(intersection[index].angle, STRAIGHT_ANGLE) -
 | 
			
		||||
                     angularDeviation(intersection[other_index].angle, STRAIGHT_ANGLE)) <
 | 
			
		||||
            MAXIMAL_ALLOWED_NO_TURN_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
 | 
			
		||||
    if (node_based_graph.GetEdgeData(intersection[third_index].turn.eid).name_id !=
 | 
			
		||||
        first_data.name_id)
 | 
			
		||||
    if (node_based_graph.GetEdgeData(intersection[third_index].eid).name_id != first_data.name_id)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // we only allow collapsing of a Y like fork. So the angle to the third index has to be
 | 
			
		||||
    // roughly equal:
 | 
			
		||||
    const auto y_angle_difference =
 | 
			
		||||
        angularDeviation(angularDeviation(intersection[third_index].turn.angle,
 | 
			
		||||
                                          intersection[first_index].turn.angle),
 | 
			
		||||
                         angularDeviation(intersection[third_index].turn.angle,
 | 
			
		||||
                                          intersection[second_index].turn.angle));
 | 
			
		||||
    const auto y_angle_difference = angularDeviation(
 | 
			
		||||
        angularDeviation(intersection[third_index].angle, intersection[first_index].angle),
 | 
			
		||||
        angularDeviation(intersection[third_index].angle, intersection[second_index].angle));
 | 
			
		||||
 | 
			
		||||
    // Allow larger angles if its three roads only of the same name
 | 
			
		||||
    // 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 ConnectedRoad &second) -> ConnectedRoad {
 | 
			
		||||
        ConnectedRoad result = first.entry_allowed ? first : second;
 | 
			
		||||
        result.turn.angle = combineAngles(first.turn.angle, second.turn.angle);
 | 
			
		||||
        result.turn.bearing = combineAngles(first.turn.bearing, second.turn.bearing);
 | 
			
		||||
        BOOST_ASSERT(0 <= result.turn.angle && result.turn.angle <= 360.0);
 | 
			
		||||
        BOOST_ASSERT(0 <= result.turn.bearing && result.turn.bearing <= 360.0);
 | 
			
		||||
        result.angle = combineAngles(first.angle, second.angle);
 | 
			
		||||
        result.bearing = combineAngles(first.bearing, second.bearing);
 | 
			
		||||
        BOOST_ASSERT(0 <= result.angle && result.angle <= 360.0);
 | 
			
		||||
        BOOST_ASSERT(0 <= result.bearing && result.bearing <= 360.0);
 | 
			
		||||
        return result;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -416,7 +411,7 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
 | 
			
		||||
    const bool is_connected_to_roundabout = [this, &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 false;
 | 
			
		||||
@ -459,26 +454,25 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
 | 
			
		||||
    {
 | 
			
		||||
        merged_first = true;
 | 
			
		||||
        // moving `a` to the left
 | 
			
		||||
        const double correction_factor =
 | 
			
		||||
            (360 - intersection[intersection.size() - 1].turn.angle) / 2;
 | 
			
		||||
        const double correction_factor = (360 - intersection[intersection.size() - 1].angle) / 2;
 | 
			
		||||
        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
 | 
			
		||||
        // below
 | 
			
		||||
        intersection[0] = merge(intersection.front(), intersection.back());
 | 
			
		||||
        intersection[0].turn.angle = 0;
 | 
			
		||||
        intersection[0].angle = 0;
 | 
			
		||||
        intersection.pop_back();
 | 
			
		||||
    }
 | 
			
		||||
    else if (CanMerge(intersection_node, intersection, 0, 1))
 | 
			
		||||
    {
 | 
			
		||||
        merged_first = true;
 | 
			
		||||
        // 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)
 | 
			
		||||
            intersection[i].turn.angle -= correction_factor;
 | 
			
		||||
            intersection[i].angle -= correction_factor;
 | 
			
		||||
        intersection[0] = merge(intersection[0], intersection[1]);
 | 
			
		||||
        intersection[0].turn.angle = 0;
 | 
			
		||||
        intersection[0].angle = 0;
 | 
			
		||||
        intersection.erase(intersection.begin() + 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -510,10 +504,9 @@ Intersection IntersectionGenerator::MergeSegregatedRoads(const NodeID intersecti
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second) {
 | 
			
		||||
        return first.turn.angle < second.turn.angle;
 | 
			
		||||
    };
 | 
			
		||||
    std::sort(std::begin(intersection), std::end(intersection), ByAngle);
 | 
			
		||||
    std::sort(std::begin(intersection),
 | 
			
		||||
              std::end(intersection),
 | 
			
		||||
              std::mem_fn(&ConnectedRoad::compareByAngle));
 | 
			
		||||
    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
 | 
			
		||||
        // the example). If the initial road can be merged to the left/right, we are about to adjust
 | 
			
		||||
        // the angle.
 | 
			
		||||
        const auto next_intersection_along_road =
 | 
			
		||||
            GetConnectedRoads(node_at_intersection, road.turn.eid);
 | 
			
		||||
        const auto next_intersection_along_road = GetConnectedRoads(node_at_intersection, road.eid);
 | 
			
		||||
 | 
			
		||||
        if (next_intersection_along_road.size() <= 1)
 | 
			
		||||
            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 =
 | 
			
		||||
            node_info_list[node_at_next_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
 | 
			
		||||
        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
 | 
			
		||||
@ -590,7 +582,7 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
 | 
			
		||||
                                             const ConnectedRoad &road,
 | 
			
		||||
                                             const ConnectedRoad &next_road_in_offset_direction) {
 | 
			
		||||
            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
 | 
			
		||||
            return (offset + MAXIMAL_ALLOWED_NO_TURN_DEVIATION > offset_limit) ? 0.5 * offset_limit
 | 
			
		||||
                                                                               : offset;
 | 
			
		||||
@ -608,8 +600,8 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
 | 
			
		||||
                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
 | 
			
		||||
            // angle to the left
 | 
			
		||||
            road.turn.angle = adjustAngle(road.turn.angle, corrected_offset);
 | 
			
		||||
            road.turn.bearing = adjustAngle(road.turn.bearing, corrected_offset);
 | 
			
		||||
            road.angle = adjustAngle(road.angle, corrected_offset);
 | 
			
		||||
            road.bearing = adjustAngle(road.bearing, corrected_offset);
 | 
			
		||||
        }
 | 
			
		||||
        else if (CanMerge(node_at_next_intersection,
 | 
			
		||||
                          next_intersection_along_road,
 | 
			
		||||
@ -624,8 +616,8 @@ Intersection IntersectionGenerator::AdjustForJoiningRoads(const NodeID node_at_i
 | 
			
		||||
                get_corrected_offset(offset, road, intersection[index - 1]);
 | 
			
		||||
            // at the target intersection, we merge to the left, so we need to shift the current
 | 
			
		||||
            // angle to the right
 | 
			
		||||
            road.turn.angle = adjustAngle(road.turn.angle, -corrected_offset);
 | 
			
		||||
            road.turn.bearing = adjustAngle(road.turn.bearing, -corrected_offset);
 | 
			
		||||
            road.angle = adjustAngle(road.angle, -corrected_offset);
 | 
			
		||||
            road.bearing = adjustAngle(road.bearing, -corrected_offset);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return intersection;
 | 
			
		||||
@ -653,11 +645,11 @@ IntersectionGenerator::GetActualNextIntersection(const NodeID starting_node,
 | 
			
		||||
    while (visited_nodes.count(node_at_intersection) == 0 &&
 | 
			
		||||
           (result.size() == 2 &&
 | 
			
		||||
            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);
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
        // When looping back to the original node, we obviously are in a loop. Stop there.
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID 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();
 | 
			
		||||
 | 
			
		||||
@ -75,20 +75,20 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
 | 
			
		||||
    const auto type = findBasicTurnType(via_edge, road);
 | 
			
		||||
    // handle travel modes:
 | 
			
		||||
    const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
 | 
			
		||||
    const auto out_mode = node_based_graph.GetEdgeData(road.turn.eid).travel_mode;
 | 
			
		||||
    const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
 | 
			
		||||
    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};
 | 
			
		||||
    }
 | 
			
		||||
    if (type == TurnType::Turn)
 | 
			
		||||
    {
 | 
			
		||||
        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 &&
 | 
			
		||||
            util::guidance::requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
 | 
			
		||||
                                                  name_table.GetRefForID(in_data.name_id),
 | 
			
		||||
@ -104,8 +104,8 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
 | 
			
		||||
                // that could potentially also offer different choices
 | 
			
		||||
                if (out_data.road_classification.IsMotorwayClass())
 | 
			
		||||
                    return {TurnType::Merge,
 | 
			
		||||
                            road.turn.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightRight
 | 
			
		||||
                                                             : DirectionModifier::SlightLeft};
 | 
			
		||||
                            road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightRight
 | 
			
		||||
                                                        : DirectionModifier::SlightLeft};
 | 
			
		||||
                else if (in_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
 | 
			
		||||
                    // could see toll-type at some point.
 | 
			
		||||
                    return {in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification,
 | 
			
		||||
                            getTurnDirection(road.turn.angle)};
 | 
			
		||||
                            getTurnDirection(road.angle)};
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
@ -129,40 +129,40 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
 | 
			
		||||
                    // precalculated distance value.
 | 
			
		||||
                    const auto distance = util::coordinate_calculation::haversineDistance(
 | 
			
		||||
                        node_info_list[node_based_graph.GetTarget(via_edge)],
 | 
			
		||||
                        node_info_list[node_based_graph.GetTarget(road.turn.eid)]);
 | 
			
		||||
                    return {TurnType::Turn,
 | 
			
		||||
                            (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
 | 
			
		||||
                                 FUZZY_ANGLE_DIFFERENCE ||
 | 
			
		||||
                             distance > 2 * MAX_COLLAPSE_DISTANCE)
 | 
			
		||||
                                ? DirectionModifier::Straight
 | 
			
		||||
                                : getTurnDirection(road.turn.angle)};
 | 
			
		||||
                        node_info_list[node_based_graph.GetTarget(road.eid)]);
 | 
			
		||||
                    return {
 | 
			
		||||
                        TurnType::Turn,
 | 
			
		||||
                        (angularDeviation(road.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE ||
 | 
			
		||||
                         distance > 2 * MAX_COLLAPSE_DISTANCE)
 | 
			
		||||
                            ? DirectionModifier::Straight
 | 
			
		||||
                            : getTurnDirection(road.angle)};
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                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
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return {in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification,
 | 
			
		||||
                    getTurnDirection(road.turn.angle)};
 | 
			
		||||
                    getTurnDirection(road.angle)};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    BOOST_ASSERT(type == TurnType::Continue);
 | 
			
		||||
    if (in_mode != out_mode)
 | 
			
		||||
    {
 | 
			
		||||
        return {TurnType::Notification, getTurnDirection(road.turn.angle)};
 | 
			
		||||
        return {TurnType::Notification, getTurnDirection(road.angle)};
 | 
			
		||||
    }
 | 
			
		||||
    if (num_roads > 2)
 | 
			
		||||
    {
 | 
			
		||||
        return {TurnType::Suppressed, getTurnDirection(road.turn.angle)};
 | 
			
		||||
        return {TurnType::Suppressed, getTurnDirection(road.angle)};
 | 
			
		||||
    }
 | 
			
		||||
    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 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 =
 | 
			
		||||
        node_based_graph.GetEdgeData(right.turn.eid).road_classification.IsLowPriorityRoadClass();
 | 
			
		||||
    if ((angularDeviation(left.turn.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
 | 
			
		||||
         angularDeviation(right.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
 | 
			
		||||
        node_based_graph.GetEdgeData(right.eid).road_classification.IsLowPriorityRoadClass();
 | 
			
		||||
    if ((angularDeviation(left.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
 | 
			
		||||
         angularDeviation(right.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
 | 
			
		||||
    {
 | 
			
		||||
        // 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 (low_priority_right && !low_priority_left)
 | 
			
		||||
            {
 | 
			
		||||
                left.turn.instruction = getInstructionForObvious(3, via_edge, false, left);
 | 
			
		||||
                right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                          DirectionModifier::SlightRight};
 | 
			
		||||
                left.instruction = getInstructionForObvious(3, via_edge, false, left);
 | 
			
		||||
                right.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                     DirectionModifier::SlightRight};
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (low_priority_left && !low_priority_right)
 | 
			
		||||
                {
 | 
			
		||||
                    left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                             DirectionModifier::SlightLeft};
 | 
			
		||||
                    right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                              DirectionModifier::SlightRight};
 | 
			
		||||
                    left.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                        DirectionModifier::SlightLeft};
 | 
			
		||||
                    right.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                         DirectionModifier::SlightRight};
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
                    right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
 | 
			
		||||
                    left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
                    right.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            left.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
 | 
			
		||||
            right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                      DirectionModifier::SlightRight};
 | 
			
		||||
            left.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
 | 
			
		||||
            right.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                 DirectionModifier::SlightRight};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
 | 
			
		||||
                 MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
 | 
			
		||||
             angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
    else if (angularDeviation(right.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
 | 
			
		||||
             angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
    {
 | 
			
		||||
        // right side is actually straight
 | 
			
		||||
        const auto &out_data = node_based_graph.GetEdgeData(right.turn.eid);
 | 
			
		||||
        if (angularDeviation(right.turn.angle, STRAIGHT_ANGLE) <
 | 
			
		||||
                MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
 | 
			
		||||
            angularDeviation(left.turn.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
        const auto &out_data = node_based_graph.GetEdgeData(right.eid);
 | 
			
		||||
        if (angularDeviation(right.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
 | 
			
		||||
            angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
        {
 | 
			
		||||
            if (detail::requiresAnnouncement(in_data, out_data))
 | 
			
		||||
            {
 | 
			
		||||
                if (low_priority_left && !low_priority_right)
 | 
			
		||||
                {
 | 
			
		||||
                    left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                             DirectionModifier::SlightLeft};
 | 
			
		||||
                    right.turn.instruction = getInstructionForObvious(3, via_edge, false, right);
 | 
			
		||||
                    left.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                        DirectionModifier::SlightLeft};
 | 
			
		||||
                    right.instruction = getInstructionForObvious(3, via_edge, false, right);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (low_priority_right && !low_priority_left)
 | 
			
		||||
                    {
 | 
			
		||||
                        left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                                 DirectionModifier::SlightLeft};
 | 
			
		||||
                        right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                                  DirectionModifier::SlightRight};
 | 
			
		||||
                        left.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                            DirectionModifier::SlightLeft};
 | 
			
		||||
                        right.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                             DirectionModifier::SlightRight};
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        right.turn.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
 | 
			
		||||
                        left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
                        right.instruction = {TurnType::Fork, DirectionModifier::SlightRight};
 | 
			
		||||
                        left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                right.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
 | 
			
		||||
                left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                         DirectionModifier::SlightLeft};
 | 
			
		||||
                right.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
 | 
			
		||||
                left.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                    DirectionModifier::SlightLeft};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // left side of fork
 | 
			
		||||
    if (low_priority_right && !low_priority_left)
 | 
			
		||||
        left.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
 | 
			
		||||
        left.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (low_priority_left && !low_priority_right)
 | 
			
		||||
            left.turn.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
 | 
			
		||||
            left.instruction = {TurnType::Turn, DirectionModifier::SlightLeft};
 | 
			
		||||
        else
 | 
			
		||||
            left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
            left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // right side of fork
 | 
			
		||||
    if (low_priority_left && !low_priority_right)
 | 
			
		||||
        right.turn.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
 | 
			
		||||
        right.instruction = {TurnType::Suppressed, DirectionModifier::SlightLeft};
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (low_priority_right && !low_priority_left)
 | 
			
		||||
            right.turn.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
 | 
			
		||||
            right.instruction = {TurnType::Turn, DirectionModifier::SlightRight};
 | 
			
		||||
        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
 | 
			
		||||
    if (left.entry_allowed && center.entry_allowed && right.entry_allowed)
 | 
			
		||||
    {
 | 
			
		||||
        left.turn.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
        if (angularDeviation(center.turn.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
 | 
			
		||||
        left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
 | 
			
		||||
        if (angularDeviation(center.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
 | 
			
		||||
        {
 | 
			
		||||
            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))
 | 
			
		||||
            {
 | 
			
		||||
                center.turn.instruction = {TurnType::Fork, DirectionModifier::Straight};
 | 
			
		||||
                center.instruction = {TurnType::Fork, DirectionModifier::Straight};
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                center.turn.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
 | 
			
		||||
                center.instruction = {TurnType::Suppressed, DirectionModifier::Straight};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        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)
 | 
			
		||||
    {
 | 
			
		||||
@ -311,22 +309,20 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
 | 
			
		||||
        else if (center.entry_allowed)
 | 
			
		||||
            assignFork(via_edge, left, center);
 | 
			
		||||
        else
 | 
			
		||||
            left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                     getTurnDirection(left.turn.angle)};
 | 
			
		||||
            left.instruction = {findBasicTurnType(via_edge, left), getTurnDirection(left.angle)};
 | 
			
		||||
    }
 | 
			
		||||
    else if (right.entry_allowed)
 | 
			
		||||
    {
 | 
			
		||||
        if (center.entry_allowed)
 | 
			
		||||
            assignFork(via_edge, center, right);
 | 
			
		||||
        else
 | 
			
		||||
            right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                      getTurnDirection(right.turn.angle)};
 | 
			
		||||
            right.instruction = {findBasicTurnType(via_edge, right), getTurnDirection(right.angle)};
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (center.entry_allowed)
 | 
			
		||||
            center.turn.instruction = {findBasicTurnType(via_edge, center),
 | 
			
		||||
                                       getTurnDirection(center.turn.angle)};
 | 
			
		||||
            center.instruction = {findBasicTurnType(via_edge, center),
 | 
			
		||||
                                  getTurnDirection(center.angle)};
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -337,18 +333,17 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid,
 | 
			
		||||
{
 | 
			
		||||
    for (std::size_t index = begin; index != end; ++index)
 | 
			
		||||
        if (intersection[index].entry_allowed)
 | 
			
		||||
            intersection[index].turn.instruction = {
 | 
			
		||||
                findBasicTurnType(via_eid, intersection[index]),
 | 
			
		||||
                getTurnDirection(intersection[index].turn.angle)};
 | 
			
		||||
            intersection[index].instruction = {findBasicTurnType(via_eid, intersection[index]),
 | 
			
		||||
                                               getTurnDirection(intersection[index].angle)};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool IntersectionHandler::isThroughStreet(const std::size_t index,
 | 
			
		||||
                                          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;
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    for (std::size_t road_index = 1; road_index < intersection.size(); ++road_index)
 | 
			
		||||
@ -357,12 +352,11 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index,
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
        const bool is_nearly_straight =
 | 
			
		||||
            angularDeviation(road.turn.angle, intersection[index].turn.angle) >
 | 
			
		||||
            (STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
 | 
			
		||||
        const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
 | 
			
		||||
                                        (STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE);
 | 
			
		||||
 | 
			
		||||
        const bool have_same_name = data_at_index.name_id == road_data.name_id;
 | 
			
		||||
        const bool have_same_category =
 | 
			
		||||
@ -397,13 +391,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
            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 =
 | 
			
		||||
            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 &&
 | 
			
		||||
            (best_continue == 0 ||
 | 
			
		||||
@ -419,7 +413,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
        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)
 | 
			
		||||
            {
 | 
			
		||||
                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;
 | 
			
		||||
                    if (road.entry_allowed)
 | 
			
		||||
@ -471,10 +465,10 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    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 &&
 | 
			
		||||
        node_based_graph.GetEdgeData(intersection[best_continue].turn.eid).road_classification ==
 | 
			
		||||
            node_based_graph.GetEdgeData(intersection[best].turn.eid).road_classification)
 | 
			
		||||
        node_based_graph.GetEdgeData(intersection[best_continue].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
 | 
			
		||||
        // obvious
 | 
			
		||||
@ -487,14 +481,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
 | 
			
		||||
        return std::count_if(
 | 
			
		||||
                   intersection.begin() + 1, intersection.end(), [&](const ConnectedRoad &road) {
 | 
			
		||||
                       return (in_data.name_id ==
 | 
			
		||||
                               node_based_graph.GetEdgeData(road.turn.eid).name_id) &&
 | 
			
		||||
                              angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
 | 
			
		||||
                       return (in_data.name_id == node_based_graph.GetEdgeData(road.eid).name_id) &&
 | 
			
		||||
                              angularDeviation(road.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
 | 
			
		||||
                   }) == num_continue_names.first;
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    // 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 = [&]() {
 | 
			
		||||
        // no continue road exists
 | 
			
		||||
@ -512,8 +505,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        // continue data now most certainly exists
 | 
			
		||||
        const auto &continue_data =
 | 
			
		||||
            node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
 | 
			
		||||
        const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
 | 
			
		||||
 | 
			
		||||
        if (obviousByRoadClass(in_data.road_classification,
 | 
			
		||||
                               continue_data.road_classification,
 | 
			
		||||
@ -550,7 +542,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
            if (index_candidate == 0)
 | 
			
		||||
                return index_candidate;
 | 
			
		||||
            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,
 | 
			
		||||
                                   best_data.road_classification,
 | 
			
		||||
                                   candidate_data.road_classification))
 | 
			
		||||
@ -565,7 +557,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
            if (index_candidate == 0)
 | 
			
		||||
                return index_candidate;
 | 
			
		||||
            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,
 | 
			
		||||
                                   best_data.road_classification,
 | 
			
		||||
                                   candidate_data.road_classification))
 | 
			
		||||
@ -575,16 +567,16 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        const double left_deviation =
 | 
			
		||||
            angularDeviation(intersection[left_index].turn.angle, STRAIGHT_ANGLE);
 | 
			
		||||
            angularDeviation(intersection[left_index].angle, STRAIGHT_ANGLE);
 | 
			
		||||
        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 &&
 | 
			
		||||
            std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
            return best;
 | 
			
		||||
 | 
			
		||||
        const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].turn.eid);
 | 
			
		||||
        const auto &right_data = node_based_graph.GetEdgeData(intersection[right_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].eid);
 | 
			
		||||
 | 
			
		||||
        const bool obvious_to_left =
 | 
			
		||||
            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
 | 
			
		||||
        // turn obvious
 | 
			
		||||
        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 &&
 | 
			
		||||
                   (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
 | 
			
		||||
                else if (in_data.road_classification == best_data.road_classification &&
 | 
			
		||||
                         best_data.road_classification.GetPriority() <
 | 
			
		||||
                             node_based_graph.GetEdgeData(intersection[index].turn.eid)
 | 
			
		||||
                             node_based_graph.GetEdgeData(intersection[index].eid)
 | 
			
		||||
                                 .road_classification.GetPriority())
 | 
			
		||||
                    return 0.8 * DISTINCTION_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
 | 
			
		||||
    {
 | 
			
		||||
        const double deviation =
 | 
			
		||||
            angularDeviation(intersection[best_continue].turn.angle, STRAIGHT_ANGLE);
 | 
			
		||||
        const auto &continue_data =
 | 
			
		||||
            node_based_graph.GetEdgeData(intersection[best_continue].turn.eid);
 | 
			
		||||
            angularDeviation(intersection[best_continue].angle, STRAIGHT_ANGLE);
 | 
			
		||||
        const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
 | 
			
		||||
        if (std::abs(deviation) < 1)
 | 
			
		||||
            return best_continue;
 | 
			
		||||
 | 
			
		||||
@ -656,7 +647,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
            if (i == best_continue || !intersection[i].entry_allowed)
 | 
			
		||||
                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 =
 | 
			
		||||
                obviousByRoadClass(in_data.road_classification,
 | 
			
		||||
                                   continue_data.road_classification,
 | 
			
		||||
@ -672,8 +663,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            // perfectly straight turns prevent obviousness
 | 
			
		||||
            const auto turn_deviation =
 | 
			
		||||
                angularDeviation(intersection[i].turn.angle, STRAIGHT_ANGLE);
 | 
			
		||||
            const auto turn_deviation = angularDeviation(intersection[i].angle, STRAIGHT_ANGLE);
 | 
			
		||||
            if (turn_deviation < FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
                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 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 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
 | 
			
		||||
            // turn, this should be alright.
 | 
			
		||||
            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];
 | 
			
		||||
            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
 | 
			
		||||
                // roads. So if there is a road that is enterable in the opposite direction just
 | 
			
		||||
                // prior, a turn is not obvious
 | 
			
		||||
                const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.turn.eid);
 | 
			
		||||
                if (angularDeviation(comparison_road.turn.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
 | 
			
		||||
                    angularDeviation(comparison_road.turn.angle, continue_road.turn.angle) <
 | 
			
		||||
                const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
 | 
			
		||||
                if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
 | 
			
		||||
                    angularDeviation(comparison_road.angle, continue_road.angle) <
 | 
			
		||||
                        FUZZY_ANGLE_DIFFERENCE &&
 | 
			
		||||
                    !turn_data.reversed && continue_data.CanCombineWith(turn_data))
 | 
			
		||||
                    return 0;
 | 
			
		||||
 | 
			
		||||
@ -17,9 +17,9 @@ bool isEndOfRoad(const ConnectedRoad &,
 | 
			
		||||
                 const ConnectedRoad &possible_right_turn,
 | 
			
		||||
                 const ConnectedRoad &possible_left_turn)
 | 
			
		||||
{
 | 
			
		||||
    return angularDeviation(possible_right_turn.turn.angle, 90) < NARROW_TURN_ANGLE &&
 | 
			
		||||
           angularDeviation(possible_left_turn.turn.angle, 270) < NARROW_TURN_ANGLE &&
 | 
			
		||||
           angularDeviation(possible_right_turn.turn.angle, possible_left_turn.turn.angle) >
 | 
			
		||||
    return angularDeviation(possible_right_turn.angle, 90) < NARROW_TURN_ANGLE &&
 | 
			
		||||
           angularDeviation(possible_left_turn.angle, 270) < NARROW_TURN_ANGLE &&
 | 
			
		||||
           angularDeviation(possible_right_turn.angle, possible_left_turn.angle) >
 | 
			
		||||
               2 * NARROW_TURN_ANGLE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_
 | 
			
		||||
inline RoadClassification roadClass(const ConnectedRoad &road,
 | 
			
		||||
                                    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)
 | 
			
		||||
@ -63,14 +63,14 @@ bool MotorwayHandler::canProcess(const NodeID,
 | 
			
		||||
    for (const auto &road : intersection)
 | 
			
		||||
    {
 | 
			
		||||
        // 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;
 | 
			
		||||
        else if (isMotorwayClass(road.turn.eid, node_based_graph))
 | 
			
		||||
        else if (isMotorwayClass(road.eid, node_based_graph))
 | 
			
		||||
        {
 | 
			
		||||
            if (road.entry_allowed)
 | 
			
		||||
                has_motorway = true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (!isRampClass(road.turn.eid, node_based_graph))
 | 
			
		||||
        else if (!isRampClass(road.eid, node_based_graph))
 | 
			
		||||
            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));
 | 
			
		||||
        std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
 | 
			
		||||
            if (road.turn.instruction.type == TurnType::OnRamp)
 | 
			
		||||
                road.turn.instruction.type = TurnType::OffRamp;
 | 
			
		||||
            if (road.instruction.type == TurnType::OnRamp)
 | 
			
		||||
                road.instruction.type = TurnType::OffRamp;
 | 
			
		||||
        });
 | 
			
		||||
        return intersection;
 | 
			
		||||
    }
 | 
			
		||||
@ -109,7 +109,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
        unsigned count = 0;
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        return count;
 | 
			
		||||
@ -119,24 +119,24 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
    const auto getContinueAngle = [this, in_data](const Intersection &intersection) {
 | 
			
		||||
        for (const auto &road : intersection)
 | 
			
		||||
        {
 | 
			
		||||
            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
 | 
			
		||||
            if (road.turn.angle != 0 && in_data.name_id == out_data.name_id &&
 | 
			
		||||
                in_data.name_id != EMPTY_NAMEID && isMotorwayClass(road.turn.eid, node_based_graph))
 | 
			
		||||
                return road.turn.angle;
 | 
			
		||||
            const auto &out_data = node_based_graph.GetEdgeData(road.eid);
 | 
			
		||||
            if (road.angle != 0 && in_data.name_id == out_data.name_id &&
 | 
			
		||||
                in_data.name_id != EMPTY_NAMEID && isMotorwayClass(road.eid, node_based_graph))
 | 
			
		||||
                return road.angle;
 | 
			
		||||
        }
 | 
			
		||||
        return intersection[0].turn.angle;
 | 
			
		||||
        return intersection[0].angle;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto getMostLikelyContinue = [this, in_data](const Intersection &intersection) {
 | 
			
		||||
        double angle = intersection[0].turn.angle;
 | 
			
		||||
        double angle = intersection[0].angle;
 | 
			
		||||
        double best = 180;
 | 
			
		||||
        for (const auto &road : intersection)
 | 
			
		||||
        {
 | 
			
		||||
            if (isMotorwayClass(road.turn.eid, node_based_graph) &&
 | 
			
		||||
                angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < best)
 | 
			
		||||
            if (isMotorwayClass(road.eid, node_based_graph) &&
 | 
			
		||||
                angularDeviation(road.angle, STRAIGHT_ANGLE) < best)
 | 
			
		||||
            {
 | 
			
		||||
                best = angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
 | 
			
		||||
                angle = road.turn.angle;
 | 
			
		||||
                best = angularDeviation(road.angle, STRAIGHT_ANGLE);
 | 
			
		||||
                angle = road.angle;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return angle;
 | 
			
		||||
@ -144,7 +144,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
 | 
			
		||||
    const auto findBestContinue = [&]() {
 | 
			
		||||
        const double continue_angle = getContinueAngle(intersection);
 | 
			
		||||
        if (continue_angle != intersection[0].turn.angle)
 | 
			
		||||
        if (continue_angle != intersection[0].angle)
 | 
			
		||||
            return continue_angle;
 | 
			
		||||
        else
 | 
			
		||||
            return getMostLikelyContinue(intersection);
 | 
			
		||||
@ -153,13 +153,13 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
    // find continue angle
 | 
			
		||||
    const double continue_angle = findBestContinue();
 | 
			
		||||
    // 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)
 | 
			
		||||
        {
 | 
			
		||||
            // do not announce ramps at the end of a highway
 | 
			
		||||
            intersection[1].turn.instruction = {TurnType::NoTurn,
 | 
			
		||||
                                                getTurnDirection(intersection[1].turn.angle)};
 | 
			
		||||
            intersection[1].instruction = {TurnType::NoTurn,
 | 
			
		||||
                                           getTurnDirection(intersection[1].angle)};
 | 
			
		||||
        }
 | 
			
		||||
        else if (intersection.size() == 3)
 | 
			
		||||
        {
 | 
			
		||||
@ -172,11 +172,11 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
            {
 | 
			
		||||
                // ending in a passing ramp
 | 
			
		||||
                if (intersection[1].entry_allowed)
 | 
			
		||||
                    intersection[1].turn.instruction = {
 | 
			
		||||
                        TurnType::NoTurn, getTurnDirection(intersection[1].turn.angle)};
 | 
			
		||||
                    intersection[1].instruction = {TurnType::NoTurn,
 | 
			
		||||
                                                   getTurnDirection(intersection[1].angle)};
 | 
			
		||||
                else
 | 
			
		||||
                    intersection[2].turn.instruction = {
 | 
			
		||||
                        TurnType::NoTurn, getTurnDirection(intersection[2].turn.angle)};
 | 
			
		||||
                    intersection[2].instruction = {TurnType::NoTurn,
 | 
			
		||||
                                                   getTurnDirection(intersection[2].angle)};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (intersection.size() == 4 &&
 | 
			
		||||
@ -209,9 +209,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
            {
 | 
			
		||||
                if (road.entry_allowed)
 | 
			
		||||
                {
 | 
			
		||||
                    BOOST_ASSERT(isRampClass(road.turn.eid, node_based_graph));
 | 
			
		||||
                    road.turn.instruction =
 | 
			
		||||
                        TurnInstruction::SUPPRESSED(getTurnDirection(road.turn.angle));
 | 
			
		||||
                    BOOST_ASSERT(isRampClass(road.eid, node_based_graph));
 | 
			
		||||
                    road.instruction = TurnInstruction::SUPPRESSED(getTurnDirection(road.angle));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -220,9 +219,9 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
            // normal motorway passing some ramps or mering onto another motorway
 | 
			
		||||
            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(),
 | 
			
		||||
                                             via_eid,
 | 
			
		||||
                                             isThroughStreet(1, intersection),
 | 
			
		||||
@ -237,26 +236,26 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
                    if (!road.entry_allowed)
 | 
			
		||||
                        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);
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (road.turn.angle < continue_angle)
 | 
			
		||||
                    else if (road.angle < continue_angle)
 | 
			
		||||
                    {
 | 
			
		||||
                        road.turn.instruction = {
 | 
			
		||||
                            isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp
 | 
			
		||||
                                                                         : TurnType::Turn,
 | 
			
		||||
                            (road.turn.angle < 145) ? DirectionModifier::Right
 | 
			
		||||
                                                    : DirectionModifier::SlightRight};
 | 
			
		||||
                        road.instruction = {isRampClass(road.eid, node_based_graph)
 | 
			
		||||
                                                ? TurnType::OffRamp
 | 
			
		||||
                                                : TurnType::Turn,
 | 
			
		||||
                                            (road.angle < 145) ? DirectionModifier::Right
 | 
			
		||||
                                                               : DirectionModifier::SlightRight};
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (road.turn.angle > continue_angle)
 | 
			
		||||
                    else if (road.angle > continue_angle)
 | 
			
		||||
                    {
 | 
			
		||||
                        road.turn.instruction = {
 | 
			
		||||
                            isRampClass(road.turn.eid, node_based_graph) ? TurnType::OffRamp
 | 
			
		||||
                                                                         : TurnType::Turn,
 | 
			
		||||
                            (road.turn.angle > 215) ? DirectionModifier::Left
 | 
			
		||||
                                                    : DirectionModifier::SlightLeft};
 | 
			
		||||
                        road.instruction = {isRampClass(road.eid, node_based_graph)
 | 
			
		||||
                                                ? TurnType::OffRamp
 | 
			
		||||
                                                : TurnType::Turn,
 | 
			
		||||
                                            (road.angle > 215) ? DirectionModifier::Left
 | 
			
		||||
                                                               : DirectionModifier::SlightLeft};
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -266,7 +265,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
        {
 | 
			
		||||
            if (exiting_motorways == 2 && intersection.size() == 2)
 | 
			
		||||
            {
 | 
			
		||||
                intersection[1].turn.instruction =
 | 
			
		||||
                intersection[1].instruction =
 | 
			
		||||
                    getInstructionForObvious(intersection.size(),
 | 
			
		||||
                                             via_eid,
 | 
			
		||||
                                             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)
 | 
			
		||||
                {
 | 
			
		||||
                    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())
 | 
			
		||||
                        {
 | 
			
		||||
@ -306,7 +305,7 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
 | 
			
		||||
                for (std::size_t i = 0; i < intersection.size(); ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    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())
 | 
			
		||||
                        {
 | 
			
		||||
@ -346,9 +345,9 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
 | 
			
		||||
    if (intersection.size() == 2 && num_valid_turns == 1)
 | 
			
		||||
    {
 | 
			
		||||
        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]);
 | 
			
		||||
    }
 | 
			
		||||
    else if (intersection.size() == 3)
 | 
			
		||||
@ -367,24 +366,23 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
 | 
			
		||||
            //          0
 | 
			
		||||
            if (intersection[1].entry_allowed)
 | 
			
		||||
            {
 | 
			
		||||
                if (isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id !=
 | 
			
		||||
                        EMPTY_NAMEID &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
 | 
			
		||||
                        node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
 | 
			
		||||
                if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[2].eid).name_id != EMPTY_NAMEID &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[2].eid).name_id ==
 | 
			
		||||
                        node_based_graph.GetEdgeData(intersection[1].eid).name_id)
 | 
			
		||||
                {
 | 
			
		||||
                    // 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)
 | 
			
		||||
                        intersection[1].turn.instruction = {TurnType::Merge,
 | 
			
		||||
                                                            DirectionModifier::SlightLeft};
 | 
			
		||||
                        intersection[1].instruction = {TurnType::Merge,
 | 
			
		||||
                                                       DirectionModifier::SlightLeft};
 | 
			
		||||
                    else // fallback
 | 
			
		||||
                        intersection[1].turn.instruction = {
 | 
			
		||||
                            TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
 | 
			
		||||
                        intersection[1].instruction = {TurnType::Merge,
 | 
			
		||||
                                                       getTurnDirection(intersection[1].angle)};
 | 
			
		||||
                }
 | 
			
		||||
                else // passing by the end of a motorway
 | 
			
		||||
                {
 | 
			
		||||
                    intersection[1].turn.instruction =
 | 
			
		||||
                    intersection[1].instruction =
 | 
			
		||||
                        getInstructionForObvious(intersection.size(),
 | 
			
		||||
                                                 via_eid,
 | 
			
		||||
                                                 isThroughStreet(1, intersection),
 | 
			
		||||
@ -394,24 +392,23 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                BOOST_ASSERT(intersection[2].entry_allowed);
 | 
			
		||||
                if (isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
 | 
			
		||||
                        EMPTY_NAMEID &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
 | 
			
		||||
                        node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
 | 
			
		||||
                if (isMotorwayClass(intersection[2].eid, node_based_graph) &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[1].eid).name_id != EMPTY_NAMEID &&
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[2].eid).name_id ==
 | 
			
		||||
                        node_based_graph.GetEdgeData(intersection[1].eid).name_id)
 | 
			
		||||
                {
 | 
			
		||||
                    // 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)
 | 
			
		||||
                        intersection[2].turn.instruction = {TurnType::Merge,
 | 
			
		||||
                                                            DirectionModifier::SlightRight};
 | 
			
		||||
                        intersection[2].instruction = {TurnType::Merge,
 | 
			
		||||
                                                       DirectionModifier::SlightRight};
 | 
			
		||||
                    else // fallback
 | 
			
		||||
                        intersection[2].turn.instruction = {
 | 
			
		||||
                            TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
 | 
			
		||||
                        intersection[2].instruction = {TurnType::Merge,
 | 
			
		||||
                                                       getTurnDirection(intersection[2].angle)};
 | 
			
		||||
                }
 | 
			
		||||
                else // passing the end of a highway
 | 
			
		||||
                {
 | 
			
		||||
                    intersection[2].turn.instruction =
 | 
			
		||||
                    intersection[2].instruction =
 | 
			
		||||
                        getInstructionForObvious(intersection.size(),
 | 
			
		||||
                                                 via_eid,
 | 
			
		||||
                                                 isThroughStreet(2, intersection),
 | 
			
		||||
@ -431,8 +428,8 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
 | 
			
		||||
            //    \   /
 | 
			
		||||
            //      |
 | 
			
		||||
            //      R
 | 
			
		||||
            if (isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
 | 
			
		||||
                isMotorwayClass(intersection[2].turn.eid, node_based_graph))
 | 
			
		||||
            if (isMotorwayClass(intersection[1].eid, node_based_graph) &&
 | 
			
		||||
                isMotorwayClass(intersection[2].eid, node_based_graph))
 | 
			
		||||
            {
 | 
			
		||||
                assignFork(via_eid, intersection[2], intersection[1]);
 | 
			
		||||
            }
 | 
			
		||||
@ -443,12 +440,11 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
 | 
			
		||||
                //      M  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,
 | 
			
		||||
                                                        DirectionModifier::SlightRight};
 | 
			
		||||
                    intersection[2].turn.instruction = {TurnType::Continue,
 | 
			
		||||
                                                        DirectionModifier::SlightLeft};
 | 
			
		||||
                    intersection[1].instruction = {TurnType::Turn, DirectionModifier::SlightRight};
 | 
			
		||||
                    intersection[2].instruction = {TurnType::Continue,
 | 
			
		||||
                                                   DirectionModifier::SlightLeft};
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
@ -463,20 +459,20 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
 | 
			
		||||
        bool passed_highway_entry = false;
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
            else if (isMotorwayClass(road.turn.eid, node_based_graph))
 | 
			
		||||
            else if (isMotorwayClass(road.eid, node_based_graph))
 | 
			
		||||
            {
 | 
			
		||||
                road.turn.instruction = {TurnType::Merge,
 | 
			
		||||
                                         passed_highway_entry ? DirectionModifier::SlightRight
 | 
			
		||||
                                                              : DirectionModifier::SlightLeft};
 | 
			
		||||
                road.instruction = {TurnType::Merge,
 | 
			
		||||
                                    passed_highway_entry ? DirectionModifier::SlightRight
 | 
			
		||||
                                                         : DirectionModifier::SlightLeft};
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                BOOST_ASSERT(isRampClass(road.turn.eid, node_based_graph));
 | 
			
		||||
                road.turn.instruction = {TurnType::OffRamp, getTurnDirection(road.turn.angle)};
 | 
			
		||||
                BOOST_ASSERT(isRampClass(road.eid, node_based_graph));
 | 
			
		||||
                road.instruction = {TurnType::OffRamp, getTurnDirection(road.angle)};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -498,26 +494,24 @@ Intersection MotorwayHandler::fallback(Intersection intersection) const
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        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 (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
                road.turn.instruction = {type, DirectionModifier::Straight};
 | 
			
		||||
            if (angularDeviation(road.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
 | 
			
		||||
                road.instruction = {type, DirectionModifier::Straight};
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                road.turn.instruction = {type,
 | 
			
		||||
                                         road.turn.angle > STRAIGHT_ANGLE
 | 
			
		||||
                                             ? DirectionModifier::SlightLeft
 | 
			
		||||
                                             : DirectionModifier::SlightRight};
 | 
			
		||||
                road.instruction = {type,
 | 
			
		||||
                                    road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
 | 
			
		||||
                                                                : DirectionModifier::SlightRight};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            road.turn.instruction = {type,
 | 
			
		||||
                                     road.turn.angle < STRAIGHT_ANGLE
 | 
			
		||||
                                         ? DirectionModifier::SlightLeft
 | 
			
		||||
                                         : DirectionModifier::SlightRight};
 | 
			
		||||
            road.instruction = {type,
 | 
			
		||||
                                road.angle < STRAIGHT_ANGLE ? DirectionModifier::SlightLeft
 | 
			
		||||
                                                            : DirectionModifier::SlightRight};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return intersection;
 | 
			
		||||
 | 
			
		||||
@ -29,13 +29,11 @@ bool LengthLimitedCoordinateAccumulator::terminate() { return accumulated_length
 | 
			
		||||
// update the accumulator
 | 
			
		||||
void LengthLimitedCoordinateAccumulator::update(const NodeID from_node,
 | 
			
		||||
                                                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(
 | 
			
		||||
        coordinates, util::coordinate_calculation::haversineDistance);
 | 
			
		||||
@ -77,10 +75,10 @@ operator()(const NodeID /*nid*/,
 | 
			
		||||
                result_score += 360.;
 | 
			
		||||
 | 
			
		||||
            // 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;
 | 
			
		||||
 | 
			
		||||
            return result_score + angularDeviation(road.turn.angle, STRAIGHT_ANGLE);
 | 
			
		||||
            return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return score(lhs) < score(rhs);
 | 
			
		||||
@ -92,7 +90,7 @@ operator()(const NodeID /*nid*/,
 | 
			
		||||
    if (min_element == intersection.end() || (requires_entry && !min_element->entry_allowed))
 | 
			
		||||
        return {};
 | 
			
		||||
    else
 | 
			
		||||
        return min_element->turn.eid;
 | 
			
		||||
        return (*min_element).eid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace guidance
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
 | 
			
		||||
         ++cnt, idx += step)
 | 
			
		||||
    {
 | 
			
		||||
        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
 | 
			
		||||
        if (edge_data.reversed || !road.entry_allowed)
 | 
			
		||||
            continue;
 | 
			
		||||
@ -93,7 +93,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
 | 
			
		||||
        // the roundabout.
 | 
			
		||||
        // The sorting of the angles represents a problem for left-sided driving, though.
 | 
			
		||||
        // 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;
 | 
			
		||||
        }
 | 
			
		||||
@ -116,7 +116,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
 | 
			
		||||
         ++cnt, idx += step)
 | 
			
		||||
    {
 | 
			
		||||
        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
 | 
			
		||||
        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
 | 
			
		||||
        // u-turn against the roundabout direction is invalidated.
 | 
			
		||||
        // 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)
 | 
			
		||||
        {
 | 
			
		||||
            road.entry_allowed = false;
 | 
			
		||||
@ -379,8 +379,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
 | 
			
		||||
             ++cnt, idx += step)
 | 
			
		||||
        {
 | 
			
		||||
            auto &road = intersection[idx];
 | 
			
		||||
            auto &turn = road.turn;
 | 
			
		||||
            const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
 | 
			
		||||
            auto &turn = road;
 | 
			
		||||
            const auto &out_data = node_based_graph.GetEdgeData(road.eid);
 | 
			
		||||
            if (out_data.roundabout)
 | 
			
		||||
            {
 | 
			
		||||
                // 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];
 | 
			
		||||
            if (!road.entry_allowed)
 | 
			
		||||
                continue;
 | 
			
		||||
            auto &turn = road.turn;
 | 
			
		||||
            auto &turn = road;
 | 
			
		||||
            const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
 | 
			
		||||
            if (out_data.roundabout)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -53,8 +53,8 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
 | 
			
		||||
 | 
			
		||||
    const auto findNextIntersectionForRoad =
 | 
			
		||||
        [&](const NodeID at_node, const ConnectedRoad &road, NodeID &output_node) {
 | 
			
		||||
            auto intersection = intersection_generator(at_node, road.turn.eid);
 | 
			
		||||
            auto in_edge = road.turn.eid;
 | 
			
		||||
            auto intersection = intersection_generator(at_node, road.eid);
 | 
			
		||||
            auto in_edge = road.eid;
 | 
			
		||||
            // skip over traffic lights
 | 
			
		||||
            // 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
 | 
			
		||||
@ -71,7 +71,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
 | 
			
		||||
                    intersection.clear();
 | 
			
		||||
                    return intersection;
 | 
			
		||||
                }
 | 
			
		||||
                in_edge = intersection[1].turn.eid;
 | 
			
		||||
                in_edge = intersection[1].eid;
 | 
			
		||||
                output_node = node_based_graph.GetTarget(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);
 | 
			
		||||
        if (index != 0)
 | 
			
		||||
            return index;
 | 
			
		||||
        else if (intersection.size() == 3 &&
 | 
			
		||||
                 intersection[1].turn.instruction.type == TurnType::Fork)
 | 
			
		||||
        else if (intersection.size() == 3 && intersection[1].instruction.type == TurnType::Fork)
 | 
			
		||||
        {
 | 
			
		||||
            // 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
 | 
			
		||||
@ -136,10 +135,10 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
 | 
			
		||||
    const auto &next_road = intersection[obvious_turn_index];
 | 
			
		||||
 | 
			
		||||
    const auto linkTest = [this, next_road](const ConnectedRoad &road) {
 | 
			
		||||
        return !node_based_graph.GetEdgeData(road.turn.eid).roundabout && road.entry_allowed &&
 | 
			
		||||
               angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE &&
 | 
			
		||||
               !hasRoundaboutType(road.turn.instruction) &&
 | 
			
		||||
               angularDeviation(next_road.turn.angle, road.turn.angle) >
 | 
			
		||||
        return !node_based_graph.GetEdgeData(road.eid).roundabout && road.entry_allowed &&
 | 
			
		||||
               angularDeviation(road.angle, STRAIGHT_ANGLE) <= 2 * NARROW_TURN_ANGLE &&
 | 
			
		||||
               !hasRoundaboutType(road.instruction) &&
 | 
			
		||||
               angularDeviation(next_road.angle, road.angle) >
 | 
			
		||||
                   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);
 | 
			
		||||
    // check whether the continue road is valid
 | 
			
		||||
    const auto check_valid = [this, source_edge_data](const ConnectedRoad &road) {
 | 
			
		||||
        const auto road_edge_data = node_based_graph.GetEdgeData(road.turn.eid);
 | 
			
		||||
        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
 | 
			
		||||
        return road_edge_data.road_classification == source_edge_data.road_classification &&
 | 
			
		||||
               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 next_road_length = util::coordinate_calculation::getLength(
 | 
			
		||||
        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);
 | 
			
		||||
    if (next_road_length > MAX_SLIPROAD_THRESHOLD)
 | 
			
		||||
    {
 | 
			
		||||
        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 =
 | 
			
		||||
        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)
 | 
			
		||||
    {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -195,20 +194,20 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
 | 
			
		||||
    {
 | 
			
		||||
        if (linkTest(road))
 | 
			
		||||
        {
 | 
			
		||||
            EdgeID candidate_in = road.turn.eid;
 | 
			
		||||
            EdgeID candidate_in = road.eid;
 | 
			
		||||
            const auto target_intersection = [&](NodeID node) {
 | 
			
		||||
                auto intersection = intersection_generator(node, candidate_in);
 | 
			
		||||
                // skip over traffic lights
 | 
			
		||||
                if (intersection.size() == 2)
 | 
			
		||||
                {
 | 
			
		||||
                    node = node_based_graph.GetTarget(candidate_in);
 | 
			
		||||
                    candidate_in = intersection[1].turn.eid;
 | 
			
		||||
                    candidate_in = intersection[1].eid;
 | 
			
		||||
                    intersection = intersection_generator(node, candidate_in);
 | 
			
		||||
                }
 | 
			
		||||
                return intersection;
 | 
			
		||||
            }(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
 | 
			
		||||
            const bool is_through_street =
 | 
			
		||||
                !target_intersection.empty() &&
 | 
			
		||||
@ -216,7 +215,7 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection intersection)
 | 
			
		||||
                    std::find_if(target_intersection.begin() + 1,
 | 
			
		||||
                                 target_intersection.end(),
 | 
			
		||||
                                 [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;
 | 
			
		||||
                                 });
 | 
			
		||||
 | 
			
		||||
@ -226,26 +225,24 @@ operator()(const NodeID, const EdgeID source_edge_id, Intersection 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 (node_based_graph.GetTarget(candidate_road.turn.eid) ==
 | 
			
		||||
                        next_intersection_node)
 | 
			
		||||
                    if (node_based_graph.GetTarget(candidate_road.eid) == next_intersection_node)
 | 
			
		||||
                    {
 | 
			
		||||
                        road.turn.instruction.type = TurnType::Sliproad;
 | 
			
		||||
                        road.instruction.type = TurnType::Sliproad;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        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 &&
 | 
			
		||||
                            node_based_graph.GetTarget(
 | 
			
		||||
                                skip_traffic_light_intersection[1].turn.eid) ==
 | 
			
		||||
                            node_based_graph.GetTarget(skip_traffic_light_intersection[1].eid) ==
 | 
			
		||||
                                next_intersection_node)
 | 
			
		||||
                        {
 | 
			
		||||
 | 
			
		||||
                            road.turn.instruction.type = TurnType::Sliproad;
 | 
			
		||||
                            road.instruction.type = TurnType::Sliproad;
 | 
			
		||||
                            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 (angularDeviation(next_road.turn.angle, STRAIGHT_ANGLE) < 5)
 | 
			
		||||
                intersection[obvious_turn_index].turn.instruction.type = TurnType::Suppressed;
 | 
			
		||||
            if (angularDeviation(next_road.angle, STRAIGHT_ANGLE) < 5)
 | 
			
		||||
                intersection[obvious_turn_index].instruction.type = TurnType::Suppressed;
 | 
			
		||||
            else
 | 
			
		||||
                intersection[obvious_turn_index].turn.instruction.type = TurnType::Continue;
 | 
			
		||||
            intersection[obvious_turn_index].turn.instruction.direction_modifier =
 | 
			
		||||
                getTurnDirection(intersection[obvious_turn_index].turn.angle);
 | 
			
		||||
                intersection[obvious_turn_index].instruction.type = TurnType::Continue;
 | 
			
		||||
            intersection[obvious_turn_index].instruction.direction_modifier =
 | 
			
		||||
                getTurnDirection(intersection[obvious_turn_index].angle);
 | 
			
		||||
        }
 | 
			
		||||
        else if (next_data.name_id != EMPTY_NAMEID)
 | 
			
		||||
        {
 | 
			
		||||
            intersection[obvious_turn_index].turn.instruction.type = TurnType::NewName;
 | 
			
		||||
            intersection[obvious_turn_index].turn.instruction.direction_modifier =
 | 
			
		||||
                getTurnDirection(intersection[obvious_turn_index].turn.angle);
 | 
			
		||||
            intersection[obvious_turn_index].instruction.type = TurnType::NewName;
 | 
			
		||||
            intersection[obvious_turn_index].instruction.direction_modifier =
 | 
			
		||||
                getTurnDirection(intersection[obvious_turn_index].angle);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            intersection[obvious_turn_index].turn.instruction.type = TurnType::Suppressed;
 | 
			
		||||
            intersection[obvious_turn_index].instruction.type = TurnType::Suppressed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -101,8 +101,8 @@ Intersection TurnAnalysis::assignTurnTypes(const NodeID from_nid,
 | 
			
		||||
    if (node_based_graph.GetEdgeData(via_eid).road_classification.IsMotorwayClass())
 | 
			
		||||
    {
 | 
			
		||||
        std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
 | 
			
		||||
            if (road.turn.instruction.type == TurnType::OnRamp)
 | 
			
		||||
                road.turn.instruction.type = TurnType::OffRamp;
 | 
			
		||||
            if (road.instruction.type == TurnType::OnRamp)
 | 
			
		||||
                road.instruction.type = TurnType::OffRamp;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    return intersection;
 | 
			
		||||
@ -114,7 +114,7 @@ TurnAnalysis::transformIntersectionIntoTurns(const Intersection &intersection) c
 | 
			
		||||
    std::vector<TurnOperation> turns;
 | 
			
		||||
    for (auto road : intersection)
 | 
			
		||||
        if (road.entry_allowed)
 | 
			
		||||
            turns.emplace_back(road.turn);
 | 
			
		||||
            turns.emplace_back(road);
 | 
			
		||||
 | 
			
		||||
    return turns;
 | 
			
		||||
}
 | 
			
		||||
@ -133,12 +133,12 @@ TurnAnalysis::setTurnTypes(const NodeID from_nid, const EdgeID, Intersection int
 | 
			
		||||
        if (!road.entry_allowed)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        const EdgeID onto_edge = road.turn.eid;
 | 
			
		||||
        const EdgeID onto_edge = road.eid;
 | 
			
		||||
        const NodeID to_nid = node_based_graph.GetTarget(onto_edge);
 | 
			
		||||
 | 
			
		||||
        road.turn.instruction = {TurnType::Turn,
 | 
			
		||||
                                 (from_nid == to_nid) ? DirectionModifier::UTurn
 | 
			
		||||
                                                      : getTurnDirection(road.turn.angle)};
 | 
			
		||||
        road.instruction = {TurnType::Turn,
 | 
			
		||||
                            (from_nid == to_nid) ? DirectionModifier::UTurn
 | 
			
		||||
                                                 : getTurnDirection(road.angle)};
 | 
			
		||||
    }
 | 
			
		||||
    return intersection;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@ classifyIntersection(Intersection intersection)
 | 
			
		||||
    std::sort(intersection.begin(),
 | 
			
		||||
              intersection.end(),
 | 
			
		||||
              [](const ConnectedRoad &left, const ConnectedRoad &right) {
 | 
			
		||||
                  return left.turn.bearing < right.turn.bearing;
 | 
			
		||||
                  return left.bearing < right.bearing;
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
    util::guidance::EntryClass entry_class;
 | 
			
		||||
@ -46,11 +46,11 @@ classifyIntersection(Intersection intersection)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        DiscreteBearing last_discrete_bearing = util::guidance::BearingClass::getDiscreteBearing(
 | 
			
		||||
            std::round(intersection.back().turn.bearing));
 | 
			
		||||
            std::round(intersection.back().bearing));
 | 
			
		||||
        for (const auto road : intersection)
 | 
			
		||||
        {
 | 
			
		||||
            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)
 | 
			
		||||
                return false;
 | 
			
		||||
            last_discrete_bearing = discrete_bearing;
 | 
			
		||||
@ -62,8 +62,8 @@ classifyIntersection(Intersection intersection)
 | 
			
		||||
    std::size_t number = 0;
 | 
			
		||||
    if (canBeDiscretized)
 | 
			
		||||
    {
 | 
			
		||||
        if (util::guidance::BearingClass::getDiscreteBearing(intersection.back().turn.bearing) <
 | 
			
		||||
            util::guidance::BearingClass::getDiscreteBearing(intersection.front().turn.bearing))
 | 
			
		||||
        if (util::guidance::BearingClass::getDiscreteBearing(intersection.back().bearing) <
 | 
			
		||||
            util::guidance::BearingClass::getDiscreteBearing(intersection.front().bearing))
 | 
			
		||||
        {
 | 
			
		||||
            intersection.insert(intersection.begin(), intersection.back());
 | 
			
		||||
            intersection.pop_back();
 | 
			
		||||
@ -73,7 +73,7 @@ classifyIntersection(Intersection intersection)
 | 
			
		||||
            if (road.entry_allowed)
 | 
			
		||||
                entry_class.activate(number);
 | 
			
		||||
            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 *
 | 
			
		||||
                                         util::guidance::BearingClass::discrete_step_size));
 | 
			
		||||
            ++number;
 | 
			
		||||
@ -85,7 +85,7 @@ classifyIntersection(Intersection intersection)
 | 
			
		||||
        {
 | 
			
		||||
            if (road.entry_allowed)
 | 
			
		||||
                entry_class.activate(number);
 | 
			
		||||
            bearing_class.add(std::round(road.turn.bearing));
 | 
			
		||||
            bearing_class.add(std::round(road.bearing));
 | 
			
		||||
            ++number;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -48,28 +48,28 @@ bool findPreviousIntersection(const NodeID node_v,
 | 
			
		||||
    // Node -> Via_Edge -> Intersection[0 == UTURN] -> reverse_of(via_edge) -> Intersection at node
 | 
			
		||||
    // (looking at the reverse direction).
 | 
			
		||||
    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 =
 | 
			
		||||
        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
 | 
			
		||||
    // previous intersection.
 | 
			
		||||
    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
 | 
			
		||||
    // 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;
 | 
			
		||||
 | 
			
		||||
    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 =
 | 
			
		||||
        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
 | 
			
		||||
    // The u-turn at the now found intersection should, hopefully, represent the previous edge.
 | 
			
		||||
    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
 | 
			
		||||
    // find it.
 | 
			
		||||
@ -85,7 +85,7 @@ bool findPreviousIntersection(const NodeID node_v,
 | 
			
		||||
        result_intersection.end() !=
 | 
			
		||||
        std::find_if(result_intersection.begin(),
 | 
			
		||||
                     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)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -47,8 +47,8 @@ operator()(const NodeID, const EdgeID via_edge, Intersection intersection) const
 | 
			
		||||
 | 
			
		||||
    if (intersection[0].entry_allowed)
 | 
			
		||||
    {
 | 
			
		||||
        intersection[0].turn.instruction = {findBasicTurnType(via_edge, intersection[0]),
 | 
			
		||||
                                            DirectionModifier::UTurn};
 | 
			
		||||
        intersection[0].instruction = {findBasicTurnType(via_edge, intersection[0]),
 | 
			
		||||
                                       DirectionModifier::UTurn};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (intersection.size() == 2)
 | 
			
		||||
@ -62,14 +62,14 @@ operator()(const NodeID, const EdgeID via_edge, 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Intersection TurnHandler::handleTwoWayTurn(const EdgeID via_edge, Intersection intersection) const
 | 
			
		||||
{
 | 
			
		||||
    BOOST_ASSERT(intersection[0].turn.angle < 0.001);
 | 
			
		||||
    intersection[1].turn.instruction =
 | 
			
		||||
    BOOST_ASSERT(intersection[0].angle < 0.001);
 | 
			
		||||
    intersection[1].instruction =
 | 
			
		||||
        getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
 | 
			
		||||
 | 
			
		||||
    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 &first_data = node_based_graph.GetEdgeData(road.turn.eid);
 | 
			
		||||
    const auto &second_data = node_based_graph.GetEdgeData(other.turn.eid);
 | 
			
		||||
    const auto &first_data = node_based_graph.GetEdgeData(road.eid);
 | 
			
		||||
    const auto &second_data = node_based_graph.GetEdgeData(other.eid);
 | 
			
		||||
    const auto &first_classification = first_data.road_classification;
 | 
			
		||||
    const auto &second_classification = second_data.road_classification;
 | 
			
		||||
    const bool is_ramp = first_classification.IsRampClass();
 | 
			
		||||
@ -107,19 +107,18 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    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 &&
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
    const bool is_much_narrower_than_other =
 | 
			
		||||
        angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
 | 
			
		||||
                angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
 | 
			
		||||
        angularDeviation(other.angle, STRAIGHT_ANGLE) /
 | 
			
		||||
                angularDeviation(road.angle, STRAIGHT_ANGLE) >
 | 
			
		||||
            INCREASES_BY_FOURTY_PERCENT &&
 | 
			
		||||
        angularDeviation(angularDeviation(other.turn.angle, STRAIGHT_ANGLE),
 | 
			
		||||
                         angularDeviation(road.turn.angle, STRAIGHT_ANGLE)) >
 | 
			
		||||
            FUZZY_ANGLE_DIFFERENCE;
 | 
			
		||||
        angularDeviation(angularDeviation(other.angle, STRAIGHT_ANGLE),
 | 
			
		||||
                         angularDeviation(road.angle, STRAIGHT_ANGLE)) > FUZZY_ANGLE_DIFFERENCE;
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
{
 | 
			
		||||
    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
 | 
			
		||||
               OOOOOOO
 | 
			
		||||
             /
 | 
			
		||||
@ -151,26 +150,26 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
 | 
			
		||||
        if (intersection[1].entry_allowed)
 | 
			
		||||
        {
 | 
			
		||||
            if (TurnType::OnRamp != findBasicTurnType(via_edge, intersection[1]))
 | 
			
		||||
                intersection[1].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
 | 
			
		||||
                intersection[1].instruction = {TurnType::EndOfRoad, DirectionModifier::Right};
 | 
			
		||||
            else
 | 
			
		||||
                intersection[1].turn.instruction = {TurnType::OnRamp, DirectionModifier::Right};
 | 
			
		||||
                intersection[1].instruction = {TurnType::OnRamp, DirectionModifier::Right};
 | 
			
		||||
        }
 | 
			
		||||
        if (intersection[2].entry_allowed)
 | 
			
		||||
        {
 | 
			
		||||
            if (TurnType::OnRamp != findBasicTurnType(via_edge, intersection[2]))
 | 
			
		||||
 | 
			
		||||
                intersection[2].turn.instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
 | 
			
		||||
                intersection[2].instruction = {TurnType::EndOfRoad, DirectionModifier::Left};
 | 
			
		||||
            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
 | 
			
		||||
    {
 | 
			
		||||
        const auto direction_at_one = getTurnDirection(intersection[1].turn.angle);
 | 
			
		||||
        const auto direction_at_two = getTurnDirection(intersection[2].turn.angle);
 | 
			
		||||
        const auto direction_at_one = getTurnDirection(intersection[1].angle);
 | 
			
		||||
        const auto direction_at_two = getTurnDirection(intersection[2].angle);
 | 
			
		||||
        if (obvious_index == 1)
 | 
			
		||||
        {
 | 
			
		||||
            intersection[1].turn.instruction = getInstructionForObvious(
 | 
			
		||||
            intersection[1].instruction = getInstructionForObvious(
 | 
			
		||||
                3, via_edge, isThroughStreet(1, intersection), intersection[1]);
 | 
			
		||||
 | 
			
		||||
            const auto second_direction = (direction_at_one == direction_at_two &&
 | 
			
		||||
@ -178,13 +177,13 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
 | 
			
		||||
                                              ? DirectionModifier::SlightLeft
 | 
			
		||||
                                              : direction_at_two;
 | 
			
		||||
 | 
			
		||||
            intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
 | 
			
		||||
                                                second_direction};
 | 
			
		||||
            intersection[2].instruction = {findBasicTurnType(via_edge, intersection[2]),
 | 
			
		||||
                                           second_direction};
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(obvious_index == 2);
 | 
			
		||||
            intersection[2].turn.instruction = getInstructionForObvious(
 | 
			
		||||
            intersection[2].instruction = getInstructionForObvious(
 | 
			
		||||
                3, via_edge, isThroughStreet(2, intersection), intersection[2]);
 | 
			
		||||
 | 
			
		||||
            const auto first_direction = (direction_at_one == direction_at_two &&
 | 
			
		||||
@ -192,16 +191,16 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
 | 
			
		||||
                                             ? DirectionModifier::SlightRight
 | 
			
		||||
                                             : direction_at_one;
 | 
			
		||||
 | 
			
		||||
            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                                first_direction};
 | 
			
		||||
            intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                           first_direction};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else // basic turn assignment
 | 
			
		||||
    {
 | 
			
		||||
        intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                            getTurnDirection(intersection[1].turn.angle)};
 | 
			
		||||
        intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
 | 
			
		||||
                                            getTurnDirection(intersection[2].turn.angle)};
 | 
			
		||||
        intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                       getTurnDirection(intersection[1].angle)};
 | 
			
		||||
        intersection[2].instruction = {findBasicTurnType(via_edge, intersection[2]),
 | 
			
		||||
                                       getTurnDirection(intersection[2].angle)};
 | 
			
		||||
    }
 | 
			
		||||
    return intersection;
 | 
			
		||||
}
 | 
			
		||||
@ -214,7 +213,7 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
 | 
			
		||||
    double straightmost_deviation = 180;
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
            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
 | 
			
		||||
    if (obvious_index != 0)
 | 
			
		||||
    {
 | 
			
		||||
        intersection[obvious_index].turn.instruction =
 | 
			
		||||
        intersection[obvious_index].instruction =
 | 
			
		||||
            getInstructionForObvious(intersection.size(),
 | 
			
		||||
                                     via_edge,
 | 
			
		||||
                                     isThroughStreet(obvious_index, intersection),
 | 
			
		||||
@ -242,24 +241,24 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
 | 
			
		||||
            auto &left = intersection[fork_range.second];
 | 
			
		||||
            auto &right = intersection[fork_range.first];
 | 
			
		||||
            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 =
 | 
			
		||||
                node_based_graph.GetEdgeData(right.turn.eid).road_classification;
 | 
			
		||||
                node_based_graph.GetEdgeData(right.eid).road_classification;
 | 
			
		||||
            if (canBeSeenAsFork(left_classification, right_classification))
 | 
			
		||||
                assignFork(via_edge, left, right);
 | 
			
		||||
            else if (left_classification.GetPriority() > right_classification.GetPriority())
 | 
			
		||||
            {
 | 
			
		||||
                right.turn.instruction =
 | 
			
		||||
                right.instruction =
 | 
			
		||||
                    getInstructionForObvious(intersection.size(), via_edge, false, right);
 | 
			
		||||
                left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                         DirectionModifier::SlightLeft};
 | 
			
		||||
                left.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                    DirectionModifier::SlightLeft};
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                left.turn.instruction =
 | 
			
		||||
                left.instruction =
 | 
			
		||||
                    getInstructionForObvious(intersection.size(), via_edge, false, left);
 | 
			
		||||
                right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                          DirectionModifier::SlightRight};
 | 
			
		||||
                right.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                     DirectionModifier::SlightRight};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (fork_range.second - fork_range.first == 2)
 | 
			
		||||
@ -281,13 +280,13 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
 | 
			
		||||
        intersection = assignRightTurns(via_edge, std::move(intersection), straightmost_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
 | 
			
		||||
        intersection = assignLeftTurns(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 = assignRightTurns(via_edge, std::move(intersection), straightmost_turn + 1);
 | 
			
		||||
@ -312,7 +311,7 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
 | 
			
		||||
        BOOST_ASSERT(!intersection.empty());
 | 
			
		||||
 | 
			
		||||
        for (auto &road : intersection)
 | 
			
		||||
            road = mirror(std::move(road));
 | 
			
		||||
            road.mirror();
 | 
			
		||||
 | 
			
		||||
        std::reverse(intersection.begin() + 1, intersection.end());
 | 
			
		||||
    };
 | 
			
		||||
@ -349,8 +348,8 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
 | 
			
		||||
    // Handle Turns 1-3
 | 
			
		||||
    else if (up_to == 3)
 | 
			
		||||
    {
 | 
			
		||||
        const auto first_direction = getTurnDirection(intersection[1].turn.angle);
 | 
			
		||||
        const auto second_direction = getTurnDirection(intersection[2].turn.angle);
 | 
			
		||||
        const auto first_direction = getTurnDirection(intersection[1].angle);
 | 
			
		||||
        const auto second_direction = getTurnDirection(intersection[2].angle);
 | 
			
		||||
        if (first_direction == second_direction)
 | 
			
		||||
        {
 | 
			
		||||
            // conflict
 | 
			
		||||
@ -364,9 +363,9 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
 | 
			
		||||
    // Handle Turns 1-4
 | 
			
		||||
    else if (up_to == 4)
 | 
			
		||||
    {
 | 
			
		||||
        const auto first_direction = getTurnDirection(intersection[1].turn.angle);
 | 
			
		||||
        const auto second_direction = getTurnDirection(intersection[2].turn.angle);
 | 
			
		||||
        const auto third_direction = getTurnDirection(intersection[3].turn.angle);
 | 
			
		||||
        const auto first_direction = getTurnDirection(intersection[1].angle);
 | 
			
		||||
        const auto second_direction = getTurnDirection(intersection[2].angle);
 | 
			
		||||
        const auto third_direction = getTurnDirection(intersection[3].angle);
 | 
			
		||||
        if (first_direction != second_direction && second_direction != third_direction)
 | 
			
		||||
        {
 | 
			
		||||
            // due to the circular order, the turn directions are unique
 | 
			
		||||
@ -395,28 +394,26 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
 | 
			
		||||
        // triggered 2>= ...)
 | 
			
		||||
        //
 | 
			
		||||
        // 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 &&
 | 
			
		||||
                 angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
 | 
			
		||||
                 angularDeviation(intersection[2].angle, intersection[3].angle) >=
 | 
			
		||||
                     NARROW_TURN_ANGLE)
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed &&
 | 
			
		||||
                         intersection[3].entry_allowed);
 | 
			
		||||
 | 
			
		||||
            intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                                DirectionModifier::SharpRight};
 | 
			
		||||
            intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
 | 
			
		||||
                                                DirectionModifier::Right};
 | 
			
		||||
            intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
 | 
			
		||||
                                                DirectionModifier::SlightRight};
 | 
			
		||||
            intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                           DirectionModifier::SharpRight};
 | 
			
		||||
            intersection[2].instruction = {findBasicTurnType(via_edge, intersection[2]),
 | 
			
		||||
                                           DirectionModifier::Right};
 | 
			
		||||
            intersection[3].instruction = {findBasicTurnType(via_edge, intersection[3]),
 | 
			
		||||
                                           DirectionModifier::SlightRight};
 | 
			
		||||
        }
 | 
			
		||||
        else if (((first_direction == second_direction && second_direction == third_direction) ||
 | 
			
		||||
                  (first_direction == second_direction &&
 | 
			
		||||
                   angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) <
 | 
			
		||||
                       GROUP_ANGLE) ||
 | 
			
		||||
                   angularDeviation(intersection[2].angle, intersection[3].angle) < GROUP_ANGLE) ||
 | 
			
		||||
                  (second_direction == third_direction &&
 | 
			
		||||
                   angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) <
 | 
			
		||||
                       GROUP_ANGLE)))
 | 
			
		||||
                   angularDeviation(intersection[1].angle, intersection[2].angle) < GROUP_ANGLE)))
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed &&
 | 
			
		||||
                         intersection[3].entry_allowed);
 | 
			
		||||
@ -424,26 +421,23 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge,
 | 
			
		||||
            assignTrivialTurns(via_edge, intersection, 1, up_to);
 | 
			
		||||
        }
 | 
			
		||||
        else if (((first_direction == second_direction &&
 | 
			
		||||
                   angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
 | 
			
		||||
                       GROUP_ANGLE) ||
 | 
			
		||||
                   angularDeviation(intersection[2].angle, intersection[3].angle) >= GROUP_ANGLE) ||
 | 
			
		||||
                  (second_direction == third_direction &&
 | 
			
		||||
                   angularDeviation(intersection[1].turn.angle, intersection[2].turn.angle) >=
 | 
			
		||||
                       GROUP_ANGLE)))
 | 
			
		||||
                   angularDeviation(intersection[1].angle, intersection[2].angle) >= GROUP_ANGLE)))
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(intersection[1].entry_allowed && intersection[2].entry_allowed &&
 | 
			
		||||
                         intersection[3].entry_allowed);
 | 
			
		||||
 | 
			
		||||
            if (angularDeviation(intersection[2].turn.angle, intersection[3].turn.angle) >=
 | 
			
		||||
                GROUP_ANGLE)
 | 
			
		||||
            if (angularDeviation(intersection[2].angle, intersection[3].angle) >= GROUP_ANGLE)
 | 
			
		||||
            {
 | 
			
		||||
                handleDistinctConflict(via_edge, intersection[2], intersection[1]);
 | 
			
		||||
                intersection[3].turn.instruction = {findBasicTurnType(via_edge, intersection[3]),
 | 
			
		||||
                                                    third_direction};
 | 
			
		||||
                intersection[3].instruction = {findBasicTurnType(via_edge, intersection[3]),
 | 
			
		||||
                                               third_direction};
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                                    first_direction};
 | 
			
		||||
                intersection[1].instruction = {findBasicTurnType(via_edge, intersection[1]),
 | 
			
		||||
                                               first_direction};
 | 
			
		||||
                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
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
            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)
 | 
			
		||||
    {
 | 
			
		||||
        std::size_t left = best, right = best;
 | 
			
		||||
        while (left + 1 < intersection.size() &&
 | 
			
		||||
               (angularDeviation(intersection[left + 1].turn.angle, STRAIGHT_ANGLE) <=
 | 
			
		||||
                    NARROW_TURN_ANGLE ||
 | 
			
		||||
                (angularDeviation(intersection[left].turn.angle,
 | 
			
		||||
                                  intersection[left + 1].turn.angle) <= NARROW_TURN_ANGLE &&
 | 
			
		||||
                 angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
 | 
			
		||||
        while (
 | 
			
		||||
            left + 1 < intersection.size() &&
 | 
			
		||||
            (angularDeviation(intersection[left + 1].angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE ||
 | 
			
		||||
             (angularDeviation(intersection[left].angle, intersection[left + 1].angle) <=
 | 
			
		||||
                  NARROW_TURN_ANGLE &&
 | 
			
		||||
              angularDeviation(intersection[left].angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
 | 
			
		||||
            ++left;
 | 
			
		||||
        while (
 | 
			
		||||
            right > 1 &&
 | 
			
		||||
            (angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <=
 | 
			
		||||
                 NARROW_TURN_ANGLE ||
 | 
			
		||||
             (angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) <
 | 
			
		||||
            (angularDeviation(intersection[right - 1].angle, STRAIGHT_ANGLE) <= NARROW_TURN_ANGLE ||
 | 
			
		||||
             (angularDeviation(intersection[right].angle, intersection[right - 1].angle) <
 | 
			
		||||
                  NARROW_TURN_ANGLE &&
 | 
			
		||||
              angularDeviation(intersection[right - 1].turn.angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
 | 
			
		||||
              angularDeviation(intersection[right - 1].angle, STRAIGHT_ANGLE) <= GROUP_ANGLE)))
 | 
			
		||||
            --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 separated_at_left_side =
 | 
			
		||||
            angularDeviation(intersection[left].turn.angle,
 | 
			
		||||
                             intersection[(left + 1) % intersection.size()].turn.angle) >=
 | 
			
		||||
            GROUP_ANGLE;
 | 
			
		||||
            angularDeviation(intersection[left].angle,
 | 
			
		||||
                             intersection[(left + 1) % intersection.size()].angle) >= GROUP_ANGLE;
 | 
			
		||||
        const bool separated_at_right_side =
 | 
			
		||||
            right > 0 &&
 | 
			
		||||
            angularDeviation(intersection[right].turn.angle, intersection[right - 1].turn.angle) >=
 | 
			
		||||
            angularDeviation(intersection[right].angle, intersection[right - 1].angle) >=
 | 
			
		||||
                GROUP_ANGLE;
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
        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();
 | 
			
		||||
            for (std::size_t index = right + 1; index <= left; ++index)
 | 
			
		||||
                if (ramp_class !=
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[index].turn.eid)
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[index].eid)
 | 
			
		||||
                        .road_classification.IsLinkClass())
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
            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)
 | 
			
		||||
            {
 | 
			
		||||
                const auto base_classification =
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[base_index].turn.eid)
 | 
			
		||||
                        .road_classification;
 | 
			
		||||
                    node_based_graph.GetEdgeData(intersection[base_index].eid).road_classification;
 | 
			
		||||
                for (std::size_t compare_index = right; compare_index <= left; ++compare_index)
 | 
			
		||||
                {
 | 
			
		||||
                    if (base_index == compare_index)
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
                    const auto compare_classification =
 | 
			
		||||
                        node_based_graph.GetEdgeData(intersection[compare_index].turn.eid)
 | 
			
		||||
                        node_based_graph.GetEdgeData(intersection[compare_index].eid)
 | 
			
		||||
                            .road_classification;
 | 
			
		||||
                    if (obviousByRoadClass(
 | 
			
		||||
                            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)
 | 
			
		||||
    // 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)
 | 
			
		||||
            left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                     getTurnDirection(left.turn.angle)};
 | 
			
		||||
            left.instruction = {findBasicTurnType(via_edge, left), getTurnDirection(left.angle)};
 | 
			
		||||
        if (right.entry_allowed)
 | 
			
		||||
            right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                      getTurnDirection(right.turn.angle)};
 | 
			
		||||
            right.instruction = {findBasicTurnType(via_edge, right), getTurnDirection(right.angle)};
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (getTurnDirection(left.turn.angle) == DirectionModifier::Straight ||
 | 
			
		||||
        getTurnDirection(left.turn.angle) == DirectionModifier::SlightLeft ||
 | 
			
		||||
        getTurnDirection(right.turn.angle) == DirectionModifier::SlightRight)
 | 
			
		||||
    if (getTurnDirection(left.angle) == DirectionModifier::Straight ||
 | 
			
		||||
        getTurnDirection(left.angle) == DirectionModifier::SlightLeft ||
 | 
			
		||||
        getTurnDirection(right.angle) == DirectionModifier::SlightRight)
 | 
			
		||||
    {
 | 
			
		||||
        const auto left_classification =
 | 
			
		||||
            node_based_graph.GetEdgeData(left.turn.eid).road_classification;
 | 
			
		||||
        const auto left_classification = node_based_graph.GetEdgeData(left.eid).road_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))
 | 
			
		||||
            assignFork(via_edge, left, right);
 | 
			
		||||
        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,
 | 
			
		||||
            // we declare it
 | 
			
		||||
            // as complex (at least size 4)
 | 
			
		||||
            right.turn.instruction = getInstructionForObvious(4, via_edge, false, right);
 | 
			
		||||
            left.turn.instruction = {findBasicTurnType(via_edge, left),
 | 
			
		||||
                                     DirectionModifier::SlightLeft};
 | 
			
		||||
            right.instruction = getInstructionForObvious(4, via_edge, false, right);
 | 
			
		||||
            left.instruction = {findBasicTurnType(via_edge, left), DirectionModifier::SlightLeft};
 | 
			
		||||
        }
 | 
			
		||||
        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,
 | 
			
		||||
            // we declare it
 | 
			
		||||
            // as complex (at least size 4)
 | 
			
		||||
            left.turn.instruction = getInstructionForObvious(4, via_edge, false, left);
 | 
			
		||||
            right.turn.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                      DirectionModifier::SlightRight};
 | 
			
		||||
            left.instruction = getInstructionForObvious(4, via_edge, false, left);
 | 
			
		||||
            right.instruction = {findBasicTurnType(via_edge, right),
 | 
			
		||||
                                 DirectionModifier::SlightRight};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    const auto left_type = findBasicTurnType(via_edge, left);
 | 
			
		||||
    const auto right_type = findBasicTurnType(via_edge, right);
 | 
			
		||||
    // 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
 | 
			
		||||
        left.turn.instruction = {left_type, DirectionModifier::Right};
 | 
			
		||||
        right.turn.instruction = {right_type, DirectionModifier::SharpRight};
 | 
			
		||||
        left.instruction = {left_type, DirectionModifier::Right};
 | 
			
		||||
        right.instruction = {right_type, DirectionModifier::SharpRight};
 | 
			
		||||
        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
 | 
			
		||||
        left.turn.instruction = {left_type, DirectionModifier::SlightRight};
 | 
			
		||||
        right.turn.instruction = {right_type, DirectionModifier::Right};
 | 
			
		||||
        left.instruction = {left_type, DirectionModifier::SlightRight};
 | 
			
		||||
        right.instruction = {right_type, DirectionModifier::Right};
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    // 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
 | 
			
		||||
        left.turn.instruction = {left_type, DirectionModifier::Left};
 | 
			
		||||
        right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
 | 
			
		||||
        left.instruction = {left_type, DirectionModifier::Left};
 | 
			
		||||
        right.instruction = {right_type, DirectionModifier::SlightLeft};
 | 
			
		||||
        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
 | 
			
		||||
        left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
 | 
			
		||||
        right.turn.instruction = {right_type, DirectionModifier::Left};
 | 
			
		||||
        left.instruction = {left_type, DirectionModifier::SharpLeft};
 | 
			
		||||
        right.instruction = {right_type, DirectionModifier::Left};
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    // Shift the lesser penalty
 | 
			
		||||
    if (getTurnDirection(left.turn.angle) == DirectionModifier::SharpLeft)
 | 
			
		||||
    if (getTurnDirection(left.angle) == DirectionModifier::SharpLeft)
 | 
			
		||||
    {
 | 
			
		||||
        left.turn.instruction = {left_type, DirectionModifier::SharpLeft};
 | 
			
		||||
        right.turn.instruction = {right_type, DirectionModifier::Left};
 | 
			
		||||
        left.instruction = {left_type, DirectionModifier::SharpLeft};
 | 
			
		||||
        right.instruction = {right_type, DirectionModifier::Left};
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (getTurnDirection(right.turn.angle) == DirectionModifier::SharpRight)
 | 
			
		||||
    if (getTurnDirection(right.angle) == DirectionModifier::SharpRight)
 | 
			
		||||
    {
 | 
			
		||||
        left.turn.instruction = {left_type, DirectionModifier::Right};
 | 
			
		||||
        right.turn.instruction = {right_type, DirectionModifier::SharpRight};
 | 
			
		||||
        left.instruction = {left_type, DirectionModifier::Right};
 | 
			
		||||
        right.instruction = {right_type, DirectionModifier::SharpRight};
 | 
			
		||||
        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};
 | 
			
		||||
            right.turn.instruction = {right_type, DirectionModifier::SharpRight};
 | 
			
		||||
            left.instruction = {left_type, DirectionModifier::Right};
 | 
			
		||||
            right.instruction = {right_type, DirectionModifier::SharpRight};
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            left.turn.instruction = {left_type, DirectionModifier::SlightRight};
 | 
			
		||||
            right.turn.instruction = {right_type, DirectionModifier::Right};
 | 
			
		||||
            left.instruction = {left_type, DirectionModifier::SlightRight};
 | 
			
		||||
            right.instruction = {right_type, DirectionModifier::Right};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    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};
 | 
			
		||||
            right.turn.instruction = {right_type, DirectionModifier::Left};
 | 
			
		||||
            left.instruction = {left_type, DirectionModifier::SharpLeft};
 | 
			
		||||
            right.instruction = {right_type, DirectionModifier::Left};
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            left.turn.instruction = {left_type, DirectionModifier::Left};
 | 
			
		||||
            right.turn.instruction = {right_type, DirectionModifier::SlightLeft};
 | 
			
		||||
            left.instruction = {left_type, DirectionModifier::Left};
 | 
			
		||||
            right.instruction = {right_type, DirectionModifier::SlightLeft};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -113,11 +113,11 @@ LaneDataVector augmentMultiple(const std::size_t none_index,
 | 
			
		||||
        if (intersection[intersection_index].entry_allowed)
 | 
			
		||||
        {
 | 
			
		||||
            // FIXME this probably can be only a subset of these turns here?
 | 
			
		||||
            lane_data.push_back({tag_by_modifier[intersection[intersection_index]
 | 
			
		||||
                                                     .turn.instruction.direction_modifier],
 | 
			
		||||
                                 lane_data[none_index].from,
 | 
			
		||||
                                 lane_data[none_index].to,
 | 
			
		||||
                                 false});
 | 
			
		||||
            lane_data.push_back(
 | 
			
		||||
                {tag_by_modifier[intersection[intersection_index].instruction.direction_modifier],
 | 
			
		||||
                 lane_data[none_index].from,
 | 
			
		||||
                 lane_data[none_index].to,
 | 
			
		||||
                 false});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    lane_data.erase(lane_data.begin() + none_index);
 | 
			
		||||
@ -162,7 +162,7 @@ LaneDataVector handleRenamingSituations(const std::size_t none_index,
 | 
			
		||||
        if (!road.entry_allowed)
 | 
			
		||||
            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::SlightRight;
 | 
			
		||||
        has_right |= modifier == DirectionModifier::SharpRight;
 | 
			
		||||
 | 
			
		||||
@ -167,8 +167,8 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
 | 
			
		||||
        (intersection.size() == 2 &&
 | 
			
		||||
         ((lane_description_id != INVALID_LANE_DESCRIPTIONID &&
 | 
			
		||||
           lane_description_id ==
 | 
			
		||||
               node_based_graph.GetEdgeData(intersection[1].turn.eid).lane_description_id) ||
 | 
			
		||||
          angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE));
 | 
			
		||||
               node_based_graph.GetEdgeData(intersection[1].eid).lane_description_id) ||
 | 
			
		||||
          angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE));
 | 
			
		||||
 | 
			
		||||
    if (is_going_straight_and_turns_continue)
 | 
			
		||||
        return TurnLaneScenario::NONE;
 | 
			
		||||
@ -201,9 +201,9 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
 | 
			
		||||
            const auto &road = previous_intersection[road_index];
 | 
			
		||||
            // in case of a sliproad that is connected to road of simlar angle, we handle the
 | 
			
		||||
            // 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;
 | 
			
		||||
 | 
			
		||||
                const auto &closest_road = [&]() {
 | 
			
		||||
@ -217,16 +217,16 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
 | 
			
		||||
                        BOOST_ASSERT(road_index + 1 < previous_intersection.size());
 | 
			
		||||
                        return previous_intersection[road_index + 1];
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (angularDeviation(road.turn.angle,
 | 
			
		||||
                                              previous_intersection.at(road_index - 1).turn.angle) <
 | 
			
		||||
                             angularDeviation(road.turn.angle,
 | 
			
		||||
                                              previous_intersection.at(road_index + 1).turn.angle))
 | 
			
		||||
                    else if (angularDeviation(road.angle,
 | 
			
		||||
                                              previous_intersection.at(road_index - 1).angle) <
 | 
			
		||||
                             angularDeviation(road.angle,
 | 
			
		||||
                                              previous_intersection.at(road_index + 1).angle))
 | 
			
		||||
                        return previous_intersection[road_index - 1];
 | 
			
		||||
                    else
 | 
			
		||||
                        return previous_intersection[road_index + 1];
 | 
			
		||||
                }();
 | 
			
		||||
 | 
			
		||||
                if (via_edge == closest_road.turn.eid)
 | 
			
		||||
                if (via_edge == closest_road.eid)
 | 
			
		||||
                    return TurnLaneScenario::SLIPROAD;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -482,8 +482,8 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data,
 | 
			
		||||
        all_simple &= (best_match->entry_allowed ||
 | 
			
		||||
                       // check for possible u-turn match on non-reversed edge
 | 
			
		||||
                       ((match_index == 0 || match_index + 1 == intersection.size()) &&
 | 
			
		||||
                        !node_based_graph.GetEdgeData(best_match->turn.eid).reversed));
 | 
			
		||||
        all_simple &= isValidMatch(data.tag, best_match->turn.instruction);
 | 
			
		||||
                        !node_based_graph.GetEdgeData(best_match->eid).reversed));
 | 
			
		||||
        all_simple &= isValidMatch(data.tag, best_match->instruction);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
    // 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());
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    // types
 | 
			
		||||
    auto next_intersection = turn_analysis.getIntersection(at, straightmost->turn.eid);
 | 
			
		||||
    auto next_intersection = turn_analysis.getIntersection(at, straightmost->eid);
 | 
			
		||||
    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
 | 
			
		||||
    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);
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
@ -565,8 +565,7 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
 | 
			
		||||
        const auto best_match_at_next_intersection =
 | 
			
		||||
            findBestMatch(turn_lane_data[lane].tag, next_intersection);
 | 
			
		||||
        if (best_match_at_next_intersection->entry_allowed &&
 | 
			
		||||
            isValidMatch(turn_lane_data[lane].tag,
 | 
			
		||||
                         best_match_at_next_intersection->turn.instruction))
 | 
			
		||||
            isValidMatch(turn_lane_data[lane].tag, best_match_at_next_intersection->instruction))
 | 
			
		||||
        {
 | 
			
		||||
            if (!matched_at_first[lane] || turn_lane_data[lane].tag == TurnLaneType::straight ||
 | 
			
		||||
                getMatchingQuality(turn_lane_data[lane].tag, *best_match) >
 | 
			
		||||
@ -679,7 +678,7 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
 | 
			
		||||
                      std::find_if(previous_intersection.begin(),
 | 
			
		||||
                                   previous_intersection.end(),
 | 
			
		||||
                                   [](const ConnectedRoad &road) {
 | 
			
		||||
                                       return road.turn.instruction.type == TurnType::Sliproad;
 | 
			
		||||
                                       return road.instruction.type == TurnType::Sliproad;
 | 
			
		||||
                                   }));
 | 
			
		||||
 | 
			
		||||
    BOOST_ASSERT(sliproad_index <= previous_intersection.size());
 | 
			
		||||
@ -697,18 +696,18 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
 | 
			
		||||
            BOOST_ASSERT(sliproad_index + 1 < previous_intersection.size());
 | 
			
		||||
            return previous_intersection[sliproad_index + 1];
 | 
			
		||||
        }
 | 
			
		||||
        else if (angularDeviation(sliproad.turn.angle,
 | 
			
		||||
                                  previous_intersection.at(sliproad_index - 1).turn.angle) <
 | 
			
		||||
                 angularDeviation(sliproad.turn.angle,
 | 
			
		||||
                                  previous_intersection.at(sliproad_index + 1).turn.angle))
 | 
			
		||||
        else if (angularDeviation(sliproad.angle,
 | 
			
		||||
                                  previous_intersection.at(sliproad_index - 1).angle) <
 | 
			
		||||
                 angularDeviation(sliproad.angle,
 | 
			
		||||
                                  previous_intersection.at(sliproad_index + 1).angle))
 | 
			
		||||
            return previous_intersection[sliproad_index - 1];
 | 
			
		||||
        else
 | 
			
		||||
            return previous_intersection[sliproad_index + 1];
 | 
			
		||||
    }();
 | 
			
		||||
    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 =
 | 
			
		||||
        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 ||
 | 
			
		||||
        sliproad_description_id == INVALID_LANE_DESCRIPTIONID)
 | 
			
		||||
@ -716,7 +715,7 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
 | 
			
		||||
 | 
			
		||||
    TurnLaneDescription combined_description;
 | 
			
		||||
    // 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.end(),
 | 
			
		||||
 | 
			
		||||
@ -109,7 +109,7 @@ double getMatchingQuality(const TurnLaneType::Mask tag, const ConnectedRoad &roa
 | 
			
		||||
    BOOST_ASSERT(static_cast<std::size_t>(modifier) <
 | 
			
		||||
                 sizeof(idealized_turn_angles) / sizeof(*idealized_turn_angles));
 | 
			
		||||
    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
 | 
			
		||||
@ -123,9 +123,9 @@ typename Intersection::const_iterator findBestMatch(const TurnLaneType::Mask tag
 | 
			
		||||
                            intersection.end(),
 | 
			
		||||
                            [tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
 | 
			
		||||
                                // prefer valid matches
 | 
			
		||||
                                if (isValidMatch(tag, lhs.turn.instruction) !=
 | 
			
		||||
                                    isValidMatch(tag, rhs.turn.instruction))
 | 
			
		||||
                                    return isValidMatch(tag, lhs.turn.instruction);
 | 
			
		||||
                                if (isValidMatch(tag, lhs.instruction) !=
 | 
			
		||||
                                    isValidMatch(tag, rhs.instruction))
 | 
			
		||||
                                    return isValidMatch(tag, lhs.instruction);
 | 
			
		||||
 | 
			
		||||
                                // if the entry allowed flags don't match, we select the one with
 | 
			
		||||
                                // entry allowed set to true
 | 
			
		||||
@ -154,8 +154,8 @@ typename Intersection::const_iterator findBestMatchForReverse(const TurnLaneType
 | 
			
		||||
        intersection.end(),
 | 
			
		||||
        [tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
 | 
			
		||||
            // prefer valid matches
 | 
			
		||||
            if (isValidMatch(tag, lhs.turn.instruction) != isValidMatch(tag, rhs.turn.instruction))
 | 
			
		||||
                return isValidMatch(tag, lhs.turn.instruction);
 | 
			
		||||
            if (isValidMatch(tag, lhs.instruction) != isValidMatch(tag, rhs.instruction))
 | 
			
		||||
                return isValidMatch(tag, lhs.instruction);
 | 
			
		||||
 | 
			
		||||
            // if the entry allowed flags don't match, we select the one with
 | 
			
		||||
            // entry allowed set to true
 | 
			
		||||
@ -182,7 +182,7 @@ bool canMatchTrivially(const Intersection &intersection, const LaneDataVector &l
 | 
			
		||||
        if (intersection[road_index].entry_allowed)
 | 
			
		||||
        {
 | 
			
		||||
            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;
 | 
			
		||||
 | 
			
		||||
            if (findBestMatch(lane_data[lane].tag, intersection) !=
 | 
			
		||||
@ -216,7 +216,7 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
 | 
			
		||||
            lane_data_id = it->second;
 | 
			
		||||
 | 
			
		||||
        // 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)
 | 
			
		||||
@ -225,11 +225,10 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
 | 
			
		||||
        if (intersection[0].entry_allowed)
 | 
			
		||||
        {
 | 
			
		||||
            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 ||
 | 
			
		||||
                    intersection[1].turn.instruction.direction_modifier !=
 | 
			
		||||
                        DirectionModifier::SharpRight)
 | 
			
		||||
                    intersection[1].instruction.direction_modifier != DirectionModifier::SharpRight)
 | 
			
		||||
                {
 | 
			
		||||
                    // cannot match u-turn in a valid way
 | 
			
		||||
                    return intersection;
 | 
			
		||||
@ -238,8 +237,8 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
 | 
			
		||||
                road_index = 2;
 | 
			
		||||
            }
 | 
			
		||||
            intersection[u_turn].entry_allowed = true;
 | 
			
		||||
            intersection[u_turn].turn.instruction.type = TurnType::Turn;
 | 
			
		||||
            intersection[u_turn].turn.instruction.direction_modifier = DirectionModifier::UTurn;
 | 
			
		||||
            intersection[u_turn].instruction.type = TurnType::Turn;
 | 
			
		||||
            intersection[u_turn].instruction.direction_modifier = DirectionModifier::UTurn;
 | 
			
		||||
 | 
			
		||||
            matchRoad(intersection[u_turn], lane_data.back());
 | 
			
		||||
            // continue with the first lane
 | 
			
		||||
@ -254,14 +253,13 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
 | 
			
		||||
        if (intersection[road_index].entry_allowed)
 | 
			
		||||
        {
 | 
			
		||||
            BOOST_ASSERT(lane_data[lane].from != INVALID_LANEID);
 | 
			
		||||
            BOOST_ASSERT(
 | 
			
		||||
                isValidMatch(lane_data[lane].tag, intersection[road_index].turn.instruction));
 | 
			
		||||
            BOOST_ASSERT(isValidMatch(lane_data[lane].tag, intersection[road_index].instruction));
 | 
			
		||||
            BOOST_ASSERT(findBestMatch(lane_data[lane].tag, intersection) ==
 | 
			
		||||
                         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)
 | 
			
		||||
                intersection[road_index].turn.instruction.type = TurnType::UseLane;
 | 
			
		||||
                intersection[road_index].instruction.type = TurnType::UseLane;
 | 
			
		||||
 | 
			
		||||
            matchRoad(intersection[road_index], lane_data[lane]);
 | 
			
		||||
            ++lane;
 | 
			
		||||
@ -272,11 +270,10 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
 | 
			
		||||
    if (lane + 1 == lane_data.size() && lane_data.back().tag == TurnLaneType::uturn)
 | 
			
		||||
    {
 | 
			
		||||
        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 ||
 | 
			
		||||
                intersection.back().turn.instruction.direction_modifier !=
 | 
			
		||||
                    DirectionModifier::SharpLeft)
 | 
			
		||||
                intersection.back().instruction.direction_modifier != DirectionModifier::SharpLeft)
 | 
			
		||||
            {
 | 
			
		||||
                // cannot match u-turn in a valid way
 | 
			
		||||
                return intersection;
 | 
			
		||||
@ -284,8 +281,8 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
 | 
			
		||||
            u_turn = intersection.size() - 1;
 | 
			
		||||
        }
 | 
			
		||||
        intersection[u_turn].entry_allowed = true;
 | 
			
		||||
        intersection[u_turn].turn.instruction.type = TurnType::Turn;
 | 
			
		||||
        intersection[u_turn].turn.instruction.direction_modifier = DirectionModifier::UTurn;
 | 
			
		||||
        intersection[u_turn].instruction.type = TurnType::Turn;
 | 
			
		||||
        intersection[u_turn].instruction.direction_modifier = DirectionModifier::UTurn;
 | 
			
		||||
 | 
			
		||||
        matchRoad(intersection[u_turn], lane_data.back());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,8 @@ namespace osrm
 | 
			
		||||
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_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user