introduce roundabout-turns into instruction set

This commit is contained in:
Moritz Kobitzsch
2016-04-18 13:41:19 +02:00
parent 8d68d4c050
commit 1544a08ea2
19 changed files with 791 additions and 141 deletions
+5 -3
View File
@@ -34,9 +34,11 @@ const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "s
// translations of TurnTypes. Not all types are exposed to the outside world.
// invalid types should never be returned as part of the API
const constexpr char *turn_type_names[] = {
"invalid", "no turn", "invalid", "new name", "continue", "turn", "merge",
"ramp", "fork", "end of road", "roundabout", "invalid", "roundabout", "invalid",
"rotary", "invalid", "rotary", "invalid", "invalid", "notification"};
"invalid", "new name", "continue", "turn", "merge", "ramp",
"fork", "end of road", "notification", "roundabout", "roundabout", "rotary",
"rotary", "roundabout_turn", "roundabout_turn", "invalid", "invalid", "invalid",
"invalid", "invalid", "invalid", "invalid", "invalid", "invalid"};
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
// Check whether to include a modifier in the result of the API
+99 -31
View File
@@ -4,6 +4,8 @@
#include "engine/guidance/assemble_steps.hpp"
#include "engine/guidance/toolkit.hpp"
#include "util/guidance/toolkit.hpp"
#include <boost/assert.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
@@ -17,6 +19,8 @@
using TurnInstruction = osrm::extractor::guidance::TurnInstruction;
using TurnType = osrm::extractor::guidance::TurnType;
using DirectionModifier = osrm::extractor::guidance::DirectionModifier;
using osrm::util::guidance::angularDeviation;
using osrm::util::guidance::getTurnDirection;
namespace osrm
{
@@ -43,7 +47,9 @@ void print(const std::vector<RouteStep> &steps)
for (const auto &intersection : step.maneuver.intersections)
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
std::cout << "] name[" << step.name_id << "]: " << step.name
<< " Bearings: " << step.maneuver.bearing_before << " "
<< step.maneuver.bearing_after << std::endl;
}
}
@@ -79,17 +85,25 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
--propagation_index)
{
auto &propagation_step = steps[propagation_index];
if (propagation_index == 0 || entersRoundabout(propagation_step.maneuver.instruction))
if (entersRoundabout(propagation_step.maneuver.instruction))
{
propagation_step.maneuver.exit = 0;
propagation_step.geometry_end = steps.back().geometry_begin;
// remember the current name as rotary name in tha case we end in a rotary
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
propagation_step.rotary_name = propagation_step.name;
break;
else if (propagation_step.maneuver.instruction.type ==
TurnType::EnterRoundaboutIntersection ||
propagation_step.maneuver.instruction.type ==
TurnType::EnterRoundaboutIntersectionAtExit)
propagation_step.maneuver.instruction.type = TurnType::EnterRoundabout;
return;
}
// accumulate turn data into the enter instructions
else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout)
{
// TODO this operates on the data that is in the instructions.
@@ -109,14 +123,17 @@ bool setUpRoundabout(RouteStep &step)
// Special case handling, if an entry is directly tied to an exit
const auto instruction = step.maneuver.instruction;
if (instruction.type == TurnType::EnterRotaryAtExit ||
instruction.type == TurnType::EnterRoundaboutAtExit)
instruction.type == TurnType::EnterRoundaboutAtExit ||
instruction.type == TurnType::EnterRoundaboutIntersectionAtExit)
{
step.maneuver.exit = 1;
// prevent futher special case handling of these two.
if (instruction.type == TurnType::EnterRotaryAtExit)
step.maneuver.instruction.type = TurnType::EnterRotary;
else
else if (instruction.type == TurnType::EnterRoundaboutAtExit)
step.maneuver.instruction.type = TurnType::EnterRoundabout;
else
step.maneuver.instruction.type = TurnType::EnterRoundaboutIntersection;
}
if (leavesRoundabout(instruction))
@@ -126,8 +143,10 @@ bool setUpRoundabout(RouteStep &step)
// prevent futher special case handling of these two.
if (instruction.type == TurnType::EnterAndExitRotary)
step.maneuver.instruction.type = TurnType::EnterRotary;
else
else if (instruction.type == TurnType::EnterAndExitRoundabout)
step.maneuver.instruction.type = TurnType::EnterRoundabout;
else
step.maneuver.instruction.type = TurnType::EnterRoundaboutIntersection;
return false;
}
else
@@ -145,28 +164,35 @@ void closeOffRoundabout(const bool on_roundabout,
if (!on_roundabout)
{
// We reached a special case that requires the addition of a special route step in
// the beginning.
// We started in a roundabout, so to announce the exit, we move use the exit
// instruction and
// move it right to the beginning to make sure to immediately announce the exit.
// We reached a special case that requires the addition of a special route step in the
// beginning. We started in a roundabout, so to announce the exit, we move use the exit
// instruction and move it right to the beginning to make sure to immediately announce the
// exit.
BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) ||
steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout);
steps[0].geometry_end = 1;
steps[1] = detail::forwardInto(steps[1], steps[0]);
steps[0].duration = 0;
steps[0].distance = 0;
steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
? TurnType::EnterRotary
: TurnType::EnterRoundabout;
const auto exitToEnter = [](const TurnType type) {
if (TurnType::ExitRotary == type)
return TurnType::EnterRotary;
// if we do not enter the roundabout Intersection, we cannot treat the full traversal as
// a turn. So we switch it up to the roundabout type
else if (type == TurnType::ExitRoundaboutIntersection)
return TurnType::EnterRoundabout;
else
return TurnType::EnterRoundabout;
};
steps[1].maneuver.instruction.type = exitToEnter(step.maneuver.instruction.type);
if (steps[1].maneuver.instruction.type == TurnType::EnterRotary)
steps[1].rotary_name = steps[0].name;
}
// Normal exit from the roundabout, or exit from a previously fixed roundabout.
// Propagate the index back to the entering
// location and
// prepare the current silent set of instructions for removal.
// Normal exit from the roundabout, or exit from a previously fixed roundabout. Propagate the
// index back to the entering location and prepare the current silent set of instructions for
// removal.
const auto exit_bearing = steps[step_index].maneuver.bearing_after;
if (step_index > 1)
{
// The very first route-step is head, so we cannot iterate past that one
@@ -177,15 +203,55 @@ void closeOffRoundabout(const bool on_roundabout,
propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]);
if (entersRoundabout(propagation_step.maneuver.instruction))
{
// TODO at this point, we can remember the additional name for a rotary
// This requires some initial thought on the data format, though
propagation_step.maneuver.exit = step.maneuver.exit;
propagation_step.geometry_end = step.geometry_end;
// remember rotary name
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
{
propagation_step.rotary_name = propagation_step.name;
}
else if (propagation_step.maneuver.instruction.type ==
TurnType::EnterRoundaboutIntersection ||
propagation_step.maneuver.instruction.type ==
TurnType::EnterRoundaboutIntersectionAtExit)
{
// Compute the angle between two bearings on a normal turn circle
//
// Bearings Angles
//
// 0 180
// 315 45 225 135
//
// 270 x 90 270 x 90
//
// 225 135 315 45
// 180 0
//
// A turn from north to north-east offerst bearing 0 and 45 has to be translated
// into a turn of 135 degrees. The same holdes for 90 - 135 (east to south
// east).
// For north, the transformation works by angle = 540 (360 + 180) - exit_bearing
// % 360;
// All other cases are handled by first rotating both bearings to an
// entry_bearing of 0.
const double angle = [](const double entry_bearing, const double exit_bearing) {
const double offset = 360 - entry_bearing;
const double rotated_exit = [](double bearing, const double offset) {
bearing += offset;
return bearing > 360 ? bearing - 360 : bearing;
}(exit_bearing, offset);
const auto angle = 540 - rotated_exit;
return angle > 360 ? angle - 360 : angle;
}(propagation_step.maneuver.bearing_before, exit_bearing);
std::cout << "Step: " << propagation_step.maneuver.bearing_before << " "
<< exit_bearing << " result: " << angle << std::endl;
propagation_step.maneuver.instruction.direction_modifier =
::osrm::util::guidance::getTurnDirection(angle);
}
propagation_step.name = step.name;
propagation_step.name_id = step.name_id;
@@ -508,8 +574,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
{
// Doing this step in post-processing provides a few challenges we cannot overcome.
// The removal of an initial step imposes some copy overhead in the steps, moving all later
// steps to the front.
// In addition, we cannot reduce the travel time that is accumulated at a different location.
// steps to the front. In addition, we cannot reduce the travel time that is accumulated at a
// different location.
// As a direct implication, we have to keep the time of the initial/final turns (which adds a
// few seconds of inaccuracy at both ends. This is acceptable, however, since the turn should
// usually not be as relevant.
@@ -517,14 +583,16 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
if (steps.size() < 2 || geometry.locations.size() <= 2)
return;
// if phantom node is located at the connection of two segments, either one can be selected as
// if phantom node is located at the connection of two segments, either one can be selected
// as
// turn
//
// a --- b
// |
// c
//
// If a route from b to c is requested, both a--b and b--c could be selected as start segment.
// If a route from b to c is requested, both a--b and b--c could be selected as start
// segment.
// In case of a--b, we end up with an unwanted turn saying turn-right onto b-c.
// These cases start off with an initial segment which is of zero length.
// We have to be careful though, since routing that starts in a roundabout has a valid.
@@ -558,12 +626,12 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
const auto &current_depart = steps.front();
auto &designated_depart = *(steps.begin() + 1);
// FIXME this is required to be consistent with the route durations. The initial turn is
// not actually part of the route, though
// FIXME this is required to be consistent with the route durations. The initial
// turn is not actually part of the route, though
designated_depart.duration += current_depart.duration;
// update initial turn direction/bearings. Due to the duplicated first coordinate, the
// initial bearing is invalid
// update initial turn direction/bearings. Due to the duplicated first coordinate,
// the initial bearing is invalid
designated_depart.maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
@@ -595,8 +663,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
BOOST_ASSERT(geometry.locations.size() >= steps.size());
auto &next_to_last_step = *(steps.end() - 2);
// in the end, the situation with the roundabout cannot occur. As a result, we can remove all
// zero-length instructions
// in the end, the situation with the roundabout cannot occur. As a result, we can remove
// all zero-length instructions
if (next_to_last_step.distance <= 1)
{
geometry.locations.pop_back();
@@ -205,7 +205,7 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
return result;
}
};
if (intersection.size() == 1)
if (intersection.size() <= 1)
return intersection;
const bool is_connected_to_roundabout = [this,&intersection]() {
@@ -245,7 +245,6 @@ Intersection IntersectionGenerator::mergeSegregatedRoads(Intersection intersecti
intersection.pop_back();
}
else if (mergable(0, 1))
{
const double correction_factor = (intersection[1].turn.angle) / 2;
@@ -2,11 +2,13 @@
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/simple_logger.hpp"
#include <algorithm>
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
using osrm::util::guidance::getTurnDirection;
namespace osrm
{
@@ -2,6 +2,10 @@
#include "extractor/guidance/intersection_scenario_three_way.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "util/guidance/toolkit.hpp"
using osrm::util::guidance::angularDeviation;
namespace osrm
{
namespace extractor
@@ -3,12 +3,16 @@
#include "extractor/guidance/toolkit.hpp"
#include "util/simple_logger.hpp"
#include "util/guidance/toolkit.hpp"
#include <limits>
#include <utility>
#include <boost/assert.hpp>
using osrm::util::guidance::angularDeviation;
using osrm::util::guidance::getTurnDirection;
namespace osrm
{
namespace extractor
+144 -38
View File
@@ -2,14 +2,18 @@
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/simple_logger.hpp"
#include <algorithm>
#include <cmath>
#include <set>
#include <unordered_set>
#include <boost/assert.hpp>
using osrm::util::guidance::getTurnDirection;
namespace osrm
{
namespace extractor
@@ -19,8 +23,10 @@ namespace guidance
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table)
: IntersectionHandler(node_based_graph, node_info_list, name_table)
const util::NameTable &name_table,
const CompressedEdgeContainer &compressed_edge_container)
: IntersectionHandler(node_based_graph, node_info_list, name_table),
compressed_edge_container(compressed_edge_container)
{
}
@@ -31,7 +37,11 @@ bool RoundaboutHandler::canProcess(const NodeID from_nid,
const Intersection &intersection) const
{
const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
return flags.on_roundabout || flags.can_enter;
if (!flags.on_roundabout && !flags.can_enter)
return false;
const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid));
return roundabout_type != RoundaboutType::None;
}
Intersection RoundaboutHandler::
@@ -39,10 +49,10 @@ operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersectio
{
invalidateExitAgainstDirection(from_nid, via_eid, intersection);
const auto flags = getRoundaboutFlags(from_nid, via_eid, intersection);
const bool is_rotary = isRotary(node_based_graph.GetTarget(via_eid));
const auto roundabout_type = getRoundaboutType(node_based_graph.GetTarget(via_eid));
// find the radius of the roundabout
return handleRoundabouts(is_rotary, via_eid, flags.on_roundabout, flags.can_exit_separately,
std::move(intersection));
return handleRoundabouts(roundabout_type, via_eid, flags.on_roundabout,
flags.can_exit_separately, std::move(intersection));
}
detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
@@ -56,7 +66,7 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
{
const auto &edge_data = node_based_graph.GetEdgeData(road.turn.eid);
// only check actual outgoing edges
if (edge_data.reversed || !road.entry_allowed )
if (edge_data.reversed || !road.entry_allowed)
continue;
if (edge_data.roundabout)
@@ -85,7 +95,7 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
Intersection &intersection) const
{
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
if( in_edge_data.roundabout )
if (in_edge_data.roundabout)
return;
bool past_roundabout_angle = false;
@@ -116,7 +126,74 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
}
}
bool RoundaboutHandler::isRotary(const NodeID nid) const
// If we want to see a roundabout as a turn, the exits have to be distinct enough to be seen a
// dedicated turns. We are limiting it to four-way intersections with well distinct bearings.
// All entry/roads and exit roads have to be simple. Not segregated roads.
// Processing segregated roads would technically require an angle of the turn to be available
// in postprocessing since we correct the turn-angle in turn-generaion.
bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
const std::set<NodeID> &roundabout_nodes) const
{
// translate a node ID into its respective coordinate stored in the node_info_list
const auto getCoordinate = [this](const NodeID node) {
return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat);
};
const bool has_limited_size = roundabout_nodes.size() <= 4;
if (!has_limited_size)
return false;
const bool simple_exits = !std::find_if( roundabout_nodes.begin(), roundabout_nodes.end(), [this]( const NodeID node ){
return (node_based_graph.GetOutDegree(node) > 3);
});
if (!simple_exits)
return false;
// Find all exit bearings. Only if they are well distinct (at least 60 degrees between
// them), we allow a roundabout turn
const auto exit_bearings = [this, &roundabout_nodes, getCoordinate]() {
std::vector<double> result;
for (const auto node : roundabout_nodes)
{
// given the reverse edge and the forward edge on a roundabout, a simple entry/exit
// can only contain a single further road
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
{
const auto edge_data = node_based_graph.GetEdgeData(edge);
if (edge_data.roundabout)
continue;
// there is a single non-roundabout edge
const auto src_coordinate = getCoordinate(node);
const auto next_coordinate = getRepresentativeCoordinate(
node, node_based_graph.GetTarget(edge), edge, edge_data.reversed,
compressed_edge_container, node_info_list);
result.push_back(
util::coordinate_calculation::bearing(src_coordinate, next_coordinate));
break;
}
}
std::sort(result.begin(), result.end());
return result;
}();
const bool well_distinct_bearings = [](const std::vector<double> &bearings) {
for (std::size_t bearing_index = 0; bearing_index < bearings.size(); ++bearing_index)
{
const double difference =
std::abs(bearings[(bearing_index + 1) % bearings.size()] - bearings[bearing_index]);
// we assume non-narrow turns as well distinct
if (difference <= NARROW_TURN_ANGLE)
return false;
}
return true;
}(exit_bearings);
return well_distinct_bearings;
}
RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
{
// translate a node ID into its respective coordinate stored in the node_info_list
const auto getCoordinate = [this](const NodeID node) {
@@ -168,31 +245,33 @@ bool RoundaboutHandler::isRotary(const NodeID nid) const
NodeID last_node = nid;
while (0 == roundabout_nodes.count(last_node))
{
roundabout_nodes.insert(last_node);
// only count exits/entry locations
if (node_based_graph.GetOutDegree(last_node) > 2)
roundabout_nodes.insert(last_node);
const auto eid = getNextOnRoundabout(last_node);
if (eid == SPECIAL_EDGEID)
{
util::SimpleLogger().Write(logDEBUG) << "Non-Loop Roundabout found.";
return false;
return RoundaboutType::None;
}
last_node = node_based_graph.GetTarget(eid);
if (last_node == nid)
break;
}
// do we have a dedicated name for the rotary, if not its a roundabout
// This function can theoretically fail if the roundabout name is partly
// used with a reference and without. This will be fixed automatically
// when we handle references separately or if the useage is more consistent
if (roundabout_name_id == 0 || connected_names.count(roundabout_name_id))
// a roundabout that cannot be entered or exited should not get here
if (roundabout_nodes.size() == 0)
return RoundaboutType::None;
// More a traffic loop than anything else, currently treated as roundabout turn
if (roundabout_nodes.size() == 1)
{
return false;
return RoundaboutType::RoundaboutIntersection;
}
if (roundabout_nodes.size() <= 1)
{
return false;
}
// calculate the radius of the roundabout/rotary. For two coordinates, we assume a minimal
// circle
// with both vertices right at the other side (so half their distance in meters).
@@ -217,12 +296,42 @@ bool RoundaboutHandler::isRotary(const NodeID nid) const
// The radius computation can result in infinity, if the three coordinates are non-distinct.
// To stay on the safe side, we say its not a rotary
if (std::isinf(radius))
return false;
return RoundaboutType::Roundabout;
return radius > MAX_ROUNDABOUT_RADIUS;
// not within the dedicated radii for special roundabouts
if (radius > MAX_ROUNDABOUT_INTERSECTION_RADIUS && radius <= MAX_ROUNDABOUT_RADIUS)
return RoundaboutType::Roundabout;
if (radius > MAX_ROUNDABOUT_RADIUS)
{
// do we have a dedicated name for the rotary, if not its a roundabout
// This function can theoretically fail if the roundabout name is partly
// used with a reference and without. This will be fixed automatically
// when we handle references separately or if the useage is more consistent
if (0 != roundabout_name_id && 0 == connected_names.count(roundabout_name_id))
return RoundaboutType::Rotary;
else
return RoundaboutType::Roundabout;
}
if (radius <= MAX_ROUNDABOUT_INTERSECTION_RADIUS)
{
const bool qualifies_as_roundabout_nitersection =
qualifiesAsRoundaboutIntersection(roundabout_nodes);
if (qualifies_as_roundabout_nitersection)
{
return RoundaboutType::RoundaboutIntersection;
}
else
{
return RoundaboutType::Roundabout;
}
}
return RoundaboutType::Roundabout;
}
Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabout_type,
const EdgeID via_eid,
const bool on_roundabout,
const bool can_exit_roundabout_separately,
@@ -248,14 +357,14 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
}
else
{
turn.instruction =
TurnInstruction::REMAIN_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
turn.instruction = TurnInstruction::REMAIN_ROUNDABOUT(
roundabout_type, getTurnDirection(turn.angle));
}
}
else
{
turn.instruction =
TurnInstruction::EXIT_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
TurnInstruction::EXIT_ROUNDABOUT(roundabout_type, getTurnDirection(turn.angle));
}
}
return intersection;
@@ -269,20 +378,17 @@ Intersection RoundaboutHandler::handleRoundabouts(const bool is_rotary,
const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
if (out_data.roundabout)
{
turn.instruction =
TurnInstruction::ENTER_ROUNDABOUT(is_rotary, getTurnDirection(turn.angle));
if (can_exit_roundabout_separately)
{
if (turn.instruction.type == TurnType::EnterRotary)
turn.instruction.type = TurnType::EnterRotaryAtExit;
if (turn.instruction.type == TurnType::EnterRoundabout)
turn.instruction.type = TurnType::EnterRoundaboutAtExit;
}
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT_AT_EXIT(
roundabout_type, getTurnDirection(turn.angle));
else
turn.instruction = TurnInstruction::ENTER_ROUNDABOUT(
roundabout_type, getTurnDirection(turn.angle));
}
else
{
turn.instruction = TurnInstruction::ENTER_AND_EXIT_ROUNDABOUT(
is_rotary, getTurnDirection(turn.angle));
roundabout_type, getTurnDirection(turn.angle));
}
}
return intersection;
+4 -1
View File
@@ -3,6 +3,7 @@
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/simple_logger.hpp"
#include <cstddef>
@@ -11,6 +12,8 @@
#include <set>
#include <unordered_set>
using osrm::util::guidance::getTurnDirection;
namespace osrm
{
namespace extractor
@@ -36,7 +39,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
barrier_nodes,
node_info_list,
compressed_edge_container),
roundabout_handler(node_based_graph, node_info_list, name_table),
roundabout_handler(node_based_graph, node_info_list, name_table, compressed_edge_container),
motorway_handler(node_based_graph, node_info_list, name_table),
turn_handler(node_based_graph, node_info_list, name_table)
{
+3
View File
@@ -4,6 +4,7 @@
#include "extractor/guidance/turn_handler.hpp"
#include "util/simple_logger.hpp"
#include "util/guidance/toolkit.hpp"
#include <limits>
#include <utility>
@@ -11,6 +12,8 @@
#include <boost/assert.hpp>
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
using osrm::util::guidance::getTurnDirection;
using osrm::util::guidance::angularDeviation;
namespace osrm
{