adding tests for guidance
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
#include "engine/guidance/post_processing.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
#include "engine/guidance/assemble_steps.hpp"
|
||||
#include "engine/guidance/toolkit.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
@@ -55,8 +55,8 @@ void fixFinalRoundabout(std::vector<RouteStep> &steps)
|
||||
propagation_step.maneuver.exit = 0;
|
||||
propagation_step.geometry_end = steps.back().geometry_begin;
|
||||
|
||||
if( propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
||||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit )
|
||||
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
||||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
|
||||
propagation_step.rotary_name = propagation_step.name;
|
||||
|
||||
break;
|
||||
@@ -130,7 +130,7 @@ void closeOffRoundabout(const bool on_roundabout,
|
||||
steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary
|
||||
? TurnType::EnterRotary
|
||||
: TurnType::EnterRoundabout;
|
||||
if( steps[1].maneuver.instruction.type == TurnType::EnterRotary )
|
||||
if (steps[1].maneuver.instruction.type == TurnType::EnterRotary)
|
||||
steps[1].rotary_name = steps[0].name;
|
||||
}
|
||||
|
||||
@@ -154,8 +154,8 @@ void closeOffRoundabout(const bool on_roundabout,
|
||||
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 )
|
||||
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
|
||||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
|
||||
propagation_step.rotary_name = propagation_step.name;
|
||||
|
||||
propagation_step.name = step.name;
|
||||
@@ -219,9 +219,8 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
||||
// adds an intersection to the initial route step
|
||||
// It includes the length of the last step, until the intersection
|
||||
// Also updates the length of the respective segment
|
||||
auto addIntersection =
|
||||
[](RouteStep into, const RouteStep &last_step, const RouteStep &intersection)
|
||||
{
|
||||
auto addIntersection = [](RouteStep into, const RouteStep &last_step,
|
||||
const RouteStep &intersection) {
|
||||
into.maneuver.intersections.push_back(
|
||||
{last_step.duration, last_step.distance, intersection.maneuver.location});
|
||||
|
||||
@@ -294,8 +293,7 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
|
||||
// Two valid NO_TURNs exist in each leg in the form of Depart/Arrive
|
||||
|
||||
// keep valid instructions
|
||||
const auto not_is_valid = [](const RouteStep &step)
|
||||
{
|
||||
const auto not_is_valid = [](const RouteStep &step) {
|
||||
return step.maneuver.instruction == TurnInstruction::NO_TURN() &&
|
||||
step.maneuver.waypoint_type == WaypointType::None;
|
||||
};
|
||||
@@ -352,10 +350,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||
// geometry offsets have to be adjusted. Move all offsets to the front and reduce by
|
||||
// one. (This is an inplace forward one and reduce by one)
|
||||
std::transform(geometry.segment_offsets.begin() + 1, geometry.segment_offsets.end(),
|
||||
geometry.segment_offsets.begin(), [](const std::size_t val)
|
||||
{
|
||||
return val - 1;
|
||||
});
|
||||
geometry.segment_offsets.begin(),
|
||||
[](const std::size_t val) { return val - 1; });
|
||||
|
||||
geometry.segment_offsets.pop_back();
|
||||
const auto ¤t_depart = steps.front();
|
||||
@@ -378,21 +374,18 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||
steps.front().geometry_begin = 1;
|
||||
// reduce all offsets by one (inplace)
|
||||
std::transform(geometry.segment_offsets.begin(), geometry.segment_offsets.end(),
|
||||
geometry.segment_offsets.begin(), [](const std::size_t val)
|
||||
{
|
||||
return val - 1;
|
||||
});
|
||||
geometry.segment_offsets.begin(),
|
||||
[](const std::size_t val) { return val - 1; });
|
||||
|
||||
steps.front().maneuver = detail::stepManeuverFromGeometry(
|
||||
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
|
||||
}
|
||||
|
||||
// and update the leg geometry indices for the removed entry
|
||||
std::for_each(steps.begin(), steps.end(), [](RouteStep &step)
|
||||
{
|
||||
--step.geometry_begin;
|
||||
--step.geometry_end;
|
||||
});
|
||||
std::for_each(steps.begin(), steps.end(), [](RouteStep &step) {
|
||||
--step.geometry_begin;
|
||||
--step.geometry_end;
|
||||
});
|
||||
}
|
||||
|
||||
// make sure we still have enough segments
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "extractor/guidance/constants.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
@@ -16,20 +17,6 @@ namespace extractor
|
||||
{
|
||||
namespace guidance
|
||||
{
|
||||
// configuration of turn classification
|
||||
const bool constexpr INVERT = true;
|
||||
|
||||
// what angle is interpreted as going straight
|
||||
const double constexpr STRAIGHT_ANGLE = 180.;
|
||||
// if a turn deviates this much from going straight, it will be kept straight
|
||||
const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
|
||||
// angle that lies between two nearly indistinguishable roads
|
||||
const double constexpr NARROW_TURN_ANGLE = 30.;
|
||||
const double constexpr GROUP_ANGLE = 90;
|
||||
// angle difference that can be classified as straight, if its the only narrow turn
|
||||
const double constexpr FUZZY_ANGLE_DIFFERENCE = 15.;
|
||||
const double constexpr DISTINCTION_RATIO = 2;
|
||||
const unsigned constexpr INVALID_NAME_ID = 0;
|
||||
|
||||
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
@@ -101,17 +88,15 @@ inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_base
|
||||
bool TurnAnalysis::isRotary(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)
|
||||
{
|
||||
const auto getCoordinate = [this](const NodeID node) {
|
||||
return util::Coordinate(node_info_list[node].lon, node_info_list[node].lat);
|
||||
};
|
||||
|
||||
unsigned roundabout_name_id = 0;
|
||||
std::unordered_set<unsigned> connected_names;
|
||||
|
||||
const auto getNextOnRoundabout =
|
||||
[this, &roundabout_name_id, &connected_names](const NodeID node)
|
||||
{
|
||||
const auto getNextOnRoundabout = [this, &roundabout_name_id,
|
||||
&connected_names](const NodeID node) {
|
||||
EdgeID continue_edge = SPECIAL_EDGEID;
|
||||
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
@@ -183,15 +168,20 @@ bool TurnAnalysis::isRotary(const NodeID nid) const
|
||||
// circle
|
||||
// with both vertices right at the other side (so half their distance in meters).
|
||||
// Otherwise, we construct a circle through the first tree vertices.
|
||||
auto node_itr = roundabout_nodes.begin();
|
||||
const double radius = roundabout_nodes.size() >= 3
|
||||
? util::coordinate_calculation::circleRadius(
|
||||
getCoordinate(*node_itr++),
|
||||
getCoordinate(*node_itr++),
|
||||
getCoordinate(*node_itr))
|
||||
: 0.5 * util::coordinate_calculation::haversineDistance(
|
||||
getCoordinate(*node_itr++),
|
||||
getCoordinate(*node_itr));
|
||||
const auto getRadius = [&roundabout_nodes,&getCoordinate](){
|
||||
auto node_itr = roundabout_nodes.begin();
|
||||
if( roundabout_nodes.size() == 2 )
|
||||
{
|
||||
const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++);
|
||||
return 0.5 * util::coordinate_calculation::haversineDistance( first, second );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto first = getCoordinate(*node_itr++), second = getCoordinate(*node_itr++), third = getCoordinate(*node_itr++);
|
||||
return util::coordinate_calculation::circleRadius(first,second,third);
|
||||
}
|
||||
};
|
||||
const double radius = getRadius();
|
||||
|
||||
// check whether the circle computation has gone wrong
|
||||
// The radius computation can result in infinity, if the three coordinates are non-distinct.
|
||||
@@ -199,7 +189,6 @@ bool TurnAnalysis::isRotary(const NodeID nid) const
|
||||
if (std::isinf(radius))
|
||||
return false;
|
||||
|
||||
const double constexpr MAX_ROUNDABOUT_RADIUS = 15; // 30 m diameter as final distinction
|
||||
return radius > MAX_ROUNDABOUT_RADIUS;
|
||||
}
|
||||
|
||||
@@ -240,10 +229,10 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
|
||||
}
|
||||
if (on_roundabout || can_enter_roundabout)
|
||||
{
|
||||
bool is_rotary = isRotary(node_based_graph.GetTarget(via_edge));
|
||||
const bool is_rotary = isRotary(node_based_graph.GetTarget(via_edge));
|
||||
// find the radius of the roundabout
|
||||
intersection = handleRoundabouts(is_rotary, via_edge, on_roundabout, can_exit_roundabout_separately,
|
||||
std::move(intersection));
|
||||
intersection = handleRoundabouts(is_rotary, via_edge, on_roundabout,
|
||||
can_exit_roundabout_separately, std::move(intersection));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -283,10 +272,8 @@ std::vector<TurnOperation> TurnAnalysis::getTurns(const NodeID from, const EdgeI
|
||||
|
||||
inline std::size_t countValid(const std::vector<ConnectedRoad> &intersection)
|
||||
{
|
||||
return std::count_if(intersection.begin(), intersection.end(), [](const ConnectedRoad &road)
|
||||
{
|
||||
return road.entry_allowed;
|
||||
});
|
||||
return std::count_if(intersection.begin(), intersection.end(),
|
||||
[](const ConnectedRoad &road) { return road.entry_allowed; });
|
||||
}
|
||||
|
||||
std::vector<ConnectedRoad>
|
||||
@@ -377,14 +364,23 @@ TurnAnalysis::fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersec
|
||||
const auto type = detail::isMotorwayClass(out_data.road_classification.road_class)
|
||||
? TurnType::Merge
|
||||
: TurnType::Turn;
|
||||
if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
|
||||
road.turn.instruction = {type, DirectionModifier::Straight};
|
||||
|
||||
if (type == TurnType::Turn)
|
||||
{
|
||||
if (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE)
|
||||
road.turn.instruction = {type, DirectionModifier::Straight};
|
||||
else
|
||||
{
|
||||
road.turn.instruction = {type, road.turn.angle > STRAIGHT_ANGLE
|
||||
? DirectionModifier::SlightLeft
|
||||
: DirectionModifier::SlightRight};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
road.turn.instruction = {type,
|
||||
road.turn.angle > STRAIGHT_ANGLE
|
||||
? DirectionModifier::SlightLeft
|
||||
: DirectionModifier::SlightRight};
|
||||
road.turn.instruction = {type, road.turn.angle < STRAIGHT_ANGLE
|
||||
? DirectionModifier::SlightLeft
|
||||
: DirectionModifier::SlightRight};
|
||||
}
|
||||
}
|
||||
return intersection;
|
||||
@@ -397,8 +393,7 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||
BOOST_ASSERT(detail::isMotorwayClass(in_data.road_classification.road_class));
|
||||
|
||||
const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection)
|
||||
{
|
||||
const auto countExitingMotorways = [this](const std::vector<ConnectedRoad> &intersection) {
|
||||
unsigned count = 0;
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
@@ -409,22 +404,20 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
};
|
||||
|
||||
// find the angle that continues on our current highway
|
||||
const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &intersection)
|
||||
{
|
||||
const auto getContinueAngle = [this, in_data](const std::vector<ConnectedRoad> &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 != 0 &&
|
||||
in_data.name_id != INVALID_NAME_ID &&
|
||||
detail::isMotorwayClass(out_data.road_classification.road_class))
|
||||
return road.turn.angle;
|
||||
}
|
||||
return intersection[0].turn.angle;
|
||||
};
|
||||
|
||||
const auto getMostLikelyContinue =
|
||||
[this, in_data](const std::vector<ConnectedRoad> &intersection)
|
||||
{
|
||||
const auto getMostLikelyContinue = [this,
|
||||
in_data](const std::vector<ConnectedRoad> &intersection) {
|
||||
double angle = intersection[0].turn.angle;
|
||||
double best = 180;
|
||||
for (const auto &road : intersection)
|
||||
@@ -440,18 +433,33 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
return angle;
|
||||
};
|
||||
|
||||
const auto findBestContinue = [&]()
|
||||
{
|
||||
const auto findBestContinue = [&]() {
|
||||
const double continue_angle = getContinueAngle(intersection);
|
||||
if (continue_angle != intersection[0].turn.angle)
|
||||
return continue_angle;
|
||||
else
|
||||
return getMostLikelyContinue(intersection);
|
||||
};
|
||||
// check whether the obvious choice is actually a through street
|
||||
const auto isThroughStreet = [&intersection, this](const ConnectedRoad &connection) {
|
||||
if (node_based_graph.GetEdgeData(connection.turn.eid).name_id == INVALID_NAME_ID)
|
||||
return false;
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
// a through street cannot start at our own position
|
||||
if (road.turn.angle < std::numeric_limits<double>::epsilon())
|
||||
continue;
|
||||
if (angularDeviation(road.turn.angle, connection.turn.angle) >
|
||||
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
|
||||
node_based_graph.GetEdgeData(road.turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(connection.turn.eid).name_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// find continue angle
|
||||
const double continue_angle = findBestContinue();
|
||||
|
||||
// highway does not continue and has no obvious choice
|
||||
if (continue_angle == intersection[0].turn.angle)
|
||||
{
|
||||
@@ -524,12 +532,11 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
BOOST_ASSERT(!detail::isRampClass(intersection[1].turn.eid, node_based_graph));
|
||||
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge,
|
||||
isThroughStreet(intersection[1]), intersection[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// continue on the same highway
|
||||
bool continues = (getContinueAngle(intersection) != intersection[0].turn.angle);
|
||||
// Normal Highway exit or merge
|
||||
for (auto &road : intersection)
|
||||
{
|
||||
@@ -539,11 +546,8 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
|
||||
if (road.turn.angle == continue_angle)
|
||||
{
|
||||
if (continues)
|
||||
road.turn.instruction =
|
||||
TurnInstruction::SUPPRESSED(DirectionModifier::Straight);
|
||||
else // TODO handle turn direction correctly
|
||||
road.turn.instruction = {TurnType::Merge, DirectionModifier::Straight};
|
||||
road.turn.instruction = getInstructionForObvious(
|
||||
intersection.size(), via_edge, isThroughStreet(road), road);
|
||||
}
|
||||
else if (road.turn.angle < continue_angle)
|
||||
{
|
||||
@@ -570,7 +574,8 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
if (exiting_motorways == 2 && intersection.size() == 2)
|
||||
{
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge,
|
||||
isThroughStreet(intersection[1]), intersection[1]);
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "Disabled U-Turn on a freeway at "
|
||||
<< localizer(node_based_graph.GetTarget(via_edge));
|
||||
@@ -633,8 +638,9 @@ TurnAnalysis::handleFromMotorway(const EdgeID via_edge,
|
||||
auto coord = localizer(node_based_graph.GetTarget(via_edge));
|
||||
util::SimpleLogger().Write(logWARNING)
|
||||
<< "Found motorway junction with more than "
|
||||
"2 exiting motorways or additional ramps at " << std::setprecision(12)
|
||||
<< toFloating(coord.lat) << " " << toFloating(coord.lon);
|
||||
"2 exiting motorways or additional ramps at "
|
||||
<< std::setprecision(12) << toFloating(coord.lat) << " "
|
||||
<< toFloating(coord.lon);
|
||||
fallbackTurnAssignmentMotorway(intersection);
|
||||
}
|
||||
} // done for more than one highway exit
|
||||
@@ -647,14 +653,30 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
||||
std::vector<ConnectedRoad> intersection) const
|
||||
{
|
||||
auto num_valid_turns = countValid(intersection);
|
||||
const auto isThroughStreet = [&intersection, this](const ConnectedRoad &connection) {
|
||||
if (node_based_graph.GetEdgeData(connection.turn.eid).name_id == INVALID_NAME_ID)
|
||||
return false;
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
// a through street cannot start at our own position
|
||||
if (road.turn.angle < std::numeric_limits<double>::epsilon())
|
||||
continue;
|
||||
if (angularDeviation(road.turn.angle, connection.turn.angle) >
|
||||
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
|
||||
node_based_graph.GetEdgeData(road.turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(connection.turn.eid).name_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// ramp straight into a motorway/ramp
|
||||
if (intersection.size() == 2 && num_valid_turns == 1)
|
||||
{
|
||||
BOOST_ASSERT(!intersection[0].entry_allowed);
|
||||
BOOST_ASSERT(detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph));
|
||||
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
intersection[1].turn.instruction = getInstructionForObvious(
|
||||
intersection.size(), via_edge, isThroughStreet(intersection[1]), intersection[1]);
|
||||
}
|
||||
else if (intersection.size() == 3)
|
||||
{
|
||||
@@ -672,7 +694,11 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
||||
// 0
|
||||
if (intersection[1].entry_allowed)
|
||||
{
|
||||
if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph))
|
||||
if (detail::isMotorwayClass(intersection[1].turn.eid, node_based_graph) &&
|
||||
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id !=
|
||||
INVALID_NAME_ID &&
|
||||
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id)
|
||||
{
|
||||
// circular order indicates a merge to the left (0-3 onto 4
|
||||
if (angularDeviation(intersection[1].turn.angle, STRAIGHT_ANGLE) <
|
||||
@@ -684,13 +710,20 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
||||
TurnType::Merge, getTurnDirection(intersection[1].turn.angle)};
|
||||
}
|
||||
else // passing by the end of a motorway
|
||||
{
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge,
|
||||
isThroughStreet(intersection[1]), intersection[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(intersection[2].entry_allowed);
|
||||
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph))
|
||||
if (detail::isMotorwayClass(intersection[2].turn.eid, node_based_graph) &&
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id !=
|
||||
INVALID_NAME_ID &&
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(intersection[0].turn.eid).name_id)
|
||||
{
|
||||
// circular order (5-0) onto 4
|
||||
if (angularDeviation(intersection[2].turn.angle, STRAIGHT_ANGLE) <
|
||||
@@ -702,8 +735,11 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
||||
TurnType::Merge, getTurnDirection(intersection[2].turn.angle)};
|
||||
}
|
||||
else // passing the end of a highway
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
{
|
||||
intersection[2].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge,
|
||||
isThroughStreet(intersection[2]), intersection[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -733,17 +769,14 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
||||
if (detail::isMotorwayClass(node_based_graph.GetEdgeData(intersection[1].turn.eid)
|
||||
.road_classification.road_class))
|
||||
{
|
||||
intersection[1].turn.instruction = {TurnType::Merge,
|
||||
intersection[1].turn.instruction = {TurnType::Turn,
|
||||
DirectionModifier::SlightRight};
|
||||
intersection[2].turn.instruction = {TurnType::Fork,
|
||||
intersection[2].turn.instruction = {TurnType::Continue,
|
||||
DirectionModifier::SlightLeft};
|
||||
}
|
||||
else
|
||||
{
|
||||
intersection[1].turn.instruction = {TurnType::Fork,
|
||||
DirectionModifier::SlightRight};
|
||||
intersection[2].turn.instruction = {TurnType::Merge,
|
||||
DirectionModifier::SlightLeft};
|
||||
assignFork(via_edge, intersection[2], intersection[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -762,8 +795,8 @@ TurnAnalysis::handleMotorwayRamp(const EdgeID via_edge,
|
||||
}
|
||||
else if (detail::isMotorwayClass(edge_data.road_classification.road_class))
|
||||
{
|
||||
road.turn.instruction = {TurnType::Merge,
|
||||
passed_highway_entry ? DirectionModifier::SlightRight
|
||||
road.turn.instruction = {TurnType::Merge, passed_highway_entry
|
||||
? DirectionModifier::SlightRight
|
||||
: DirectionModifier::SlightLeft};
|
||||
}
|
||||
else
|
||||
@@ -814,9 +847,7 @@ bool TurnAnalysis::isMotorwayJunction(const EdgeID via_edge,
|
||||
{
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.turn.eid);
|
||||
// not merging or forking?
|
||||
if ((angularDeviation(road.turn.angle, 0) > 35 &&
|
||||
angularDeviation(road.turn.angle, 180) > 35) ||
|
||||
(road.entry_allowed && angularDeviation(road.turn.angle, 0) < 35))
|
||||
if (road.entry_allowed && angularDeviation(road.turn.angle, STRAIGHT_ANGLE) > 60)
|
||||
return false;
|
||||
else if (out_data.road_classification.road_class == FunctionalRoadClass::MOTORWAY ||
|
||||
out_data.road_classification.road_class == FunctionalRoadClass::TRUNK)
|
||||
@@ -860,6 +891,7 @@ TurnType TurnAnalysis::findBasicTurnType(const EdgeID via_edge, const ConnectedR
|
||||
|
||||
TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roads,
|
||||
const EdgeID via_edge,
|
||||
const bool through_street,
|
||||
const ConnectedRoad &road) const
|
||||
{
|
||||
const auto type = findBasicTurnType(via_edge, road);
|
||||
@@ -882,7 +914,19 @@ TurnInstruction TurnAnalysis::getInstructionForObvious(const std::size_t num_roa
|
||||
if (in_data.name_id != out_data.name_id &&
|
||||
requiresNameAnnounced(name_table.GetNameForID(in_data.name_id),
|
||||
name_table.GetNameForID(out_data.name_id)))
|
||||
return {TurnType::NewName, getTurnDirection(road.turn.angle)};
|
||||
{
|
||||
// obvious turn onto a through street is a merge
|
||||
if (through_street)
|
||||
{
|
||||
return {TurnType::Merge, road.turn.angle > STRAIGHT_ANGLE
|
||||
? DirectionModifier::SlightRight
|
||||
: DirectionModifier::SlightLeft};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {TurnType::NewName, getTurnDirection(road.turn.angle)};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in_mode == out_mode)
|
||||
@@ -918,7 +962,7 @@ TurnAnalysis::handleTwoWayTurn(const EdgeID via_edge, std::vector<ConnectedRoad>
|
||||
{
|
||||
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
|
||||
|
||||
if (intersection[1].turn.instruction.type == TurnType::Suppressed)
|
||||
intersection[1].turn.instruction.type = TurnType::NoTurn;
|
||||
@@ -931,15 +975,28 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
std::vector<ConnectedRoad> intersection) const
|
||||
{
|
||||
BOOST_ASSERT(intersection[0].turn.angle < 0.001);
|
||||
const auto isObviousOfTwo = [](const ConnectedRoad road, const ConnectedRoad other)
|
||||
{
|
||||
return (angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
|
||||
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85) ||
|
||||
(angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
|
||||
std::numeric_limits<double>::epsilon()) ||
|
||||
(angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
|
||||
1.4);
|
||||
const auto isObviousOfTwo = [this](const ConnectedRoad road, const ConnectedRoad other) {
|
||||
const auto first_class =
|
||||
node_based_graph.GetEdgeData(road.turn.eid).road_classification.road_class;
|
||||
const bool is_ramp = isRampClass(first_class);
|
||||
const auto second_class =
|
||||
node_based_graph.GetEdgeData(other.turn.eid).road_classification.road_class;
|
||||
const bool is_narrow_turn =
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE;
|
||||
const bool other_turn_is_at_least_orthogonal =
|
||||
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) > 85;
|
||||
const bool turn_is_perfectly_straight = angularDeviation(road.turn.angle, STRAIGHT_ANGLE) <
|
||||
std::numeric_limits<double>::epsilon();
|
||||
const bool is_obvious_by_road_class =
|
||||
(!is_ramp && (2 * getPriority(first_class) < getPriority(second_class))) ||
|
||||
(!isLowPriorityRoadClass(first_class) && isLowPriorityRoadClass(second_class));
|
||||
const bool is_much_narrower_than_other =
|
||||
angularDeviation(other.turn.angle, STRAIGHT_ANGLE) /
|
||||
angularDeviation(road.turn.angle, STRAIGHT_ANGLE) >
|
||||
INCREASES_BY_FOURTY_PERCENT;
|
||||
return (is_narrow_turn && other_turn_is_at_least_orthogonal) ||
|
||||
turn_is_perfectly_straight || is_much_narrower_than_other ||
|
||||
is_obvious_by_road_class;
|
||||
};
|
||||
|
||||
/* Two nearly straight turns -> FORK
|
||||
@@ -959,30 +1016,39 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
const auto right_class = node_based_graph.GetEdgeData(intersection[1].turn.eid)
|
||||
.road_classification.road_class;
|
||||
if (canBeSeenAsFork(left_class, right_class))
|
||||
{
|
||||
assignFork(via_edge, intersection[2], intersection[1]);
|
||||
else if (getPriority(left_class) > getPriority(right_class))
|
||||
}
|
||||
else if (isObviousOfTwo(intersection[1], intersection[2]))
|
||||
{
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
|
||||
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
||||
DirectionModifier::SlightLeft};
|
||||
}
|
||||
else
|
||||
else if (isObviousOfTwo(intersection[2], intersection[1]))
|
||||
{
|
||||
intersection[2].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
|
||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
||||
DirectionModifier::SlightRight};
|
||||
}
|
||||
else
|
||||
{
|
||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
||||
DirectionModifier::SlightRight};
|
||||
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
||||
DirectionModifier::SlightLeft};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (intersection[1].entry_allowed)
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
|
||||
if (intersection[2].entry_allowed)
|
||||
intersection[2].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
|
||||
}
|
||||
}
|
||||
/* T Intersection
|
||||
@@ -1028,7 +1094,7 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
{
|
||||
if (TurnType::Ramp != findBasicTurnType(via_edge, intersection[1]))
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[1]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[1]);
|
||||
else
|
||||
intersection[1].turn.instruction = {TurnType::Ramp, DirectionModifier::Straight};
|
||||
}
|
||||
@@ -1052,7 +1118,7 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
{
|
||||
if (intersection[2].entry_allowed)
|
||||
intersection[2].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[2]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, intersection[2]);
|
||||
if (intersection[1].entry_allowed)
|
||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
||||
DirectionModifier::Right};
|
||||
@@ -1062,11 +1128,18 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
node_based_graph.GetEdgeData(intersection[1].turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(intersection[2].turn.eid).name_id)
|
||||
{
|
||||
const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn, const ConnectedRoad other)
|
||||
-> TurnInstruction
|
||||
{
|
||||
return {isObviousOfTwo(turn, other) ? TurnType::Merge : TurnType::Turn,
|
||||
getTurnDirection(turn.turn.angle)};
|
||||
const auto findTurn = [isObviousOfTwo](const ConnectedRoad turn,
|
||||
const ConnectedRoad other) -> TurnInstruction {
|
||||
if (isObviousOfTwo(turn, other))
|
||||
{
|
||||
return {TurnType::Merge, turn.turn.angle < STRAIGHT_ANGLE
|
||||
? DirectionModifier::SlightLeft
|
||||
: DirectionModifier::SlightRight};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {TurnType::Turn, getTurnDirection(turn.turn.angle)};
|
||||
}
|
||||
};
|
||||
intersection[1].turn.instruction = findTurn(intersection[1], intersection[2]);
|
||||
intersection[2].turn.instruction = findTurn(intersection[2], intersection[1]);
|
||||
@@ -1087,7 +1160,7 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
intersection[1].turn.instruction = {TurnType::Continue,
|
||||
getTurnDirection(intersection[1].turn.angle)};
|
||||
}
|
||||
intersection[2].turn.instruction = {TurnType::Turn,
|
||||
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
||||
getTurnDirection(intersection[2].turn.angle)};
|
||||
}
|
||||
// other street merges from the right
|
||||
@@ -1105,28 +1178,30 @@ TurnAnalysis::handleThreeWayTurn(const EdgeID via_edge,
|
||||
intersection[2].turn.instruction = {TurnType::Continue,
|
||||
getTurnDirection(intersection[2].turn.angle)};
|
||||
}
|
||||
intersection[1].turn.instruction = {TurnType::Turn,
|
||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
||||
getTurnDirection(intersection[1].turn.angle)};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isObviousOfTwo(intersection[1], intersection[2]))
|
||||
{
|
||||
intersection[1].turn.instruction = getInstructionForObvious(3,via_edge,intersection[1]);
|
||||
intersection[1].turn.instruction =
|
||||
getInstructionForObvious(3, via_edge, false, intersection[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersection[1].turn.instruction = {TurnType::Turn,
|
||||
intersection[1].turn.instruction = {findBasicTurnType(via_edge, intersection[1]),
|
||||
getTurnDirection(intersection[1].turn.angle)};
|
||||
}
|
||||
|
||||
if (isObviousOfTwo(intersection[2], intersection[1]))
|
||||
{
|
||||
intersection[2].turn.instruction = getInstructionForObvious(3,via_edge,intersection[2]);
|
||||
intersection[2].turn.instruction =
|
||||
getInstructionForObvious(3, via_edge, false, intersection[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersection[2].turn.instruction = {TurnType::Turn,
|
||||
intersection[2].turn.instruction = {findBasicTurnType(via_edge, intersection[2]),
|
||||
getTurnDirection(intersection[2].turn.angle)};
|
||||
}
|
||||
}
|
||||
@@ -1167,14 +1242,18 @@ void TurnAnalysis::handleDistinctConflict(const EdgeID via_edge,
|
||||
else if (getPriority(left_class) > getPriority(right_class))
|
||||
{
|
||||
// FIXME this should possibly know about the actual roads?
|
||||
right.turn.instruction = getInstructionForObvious(4, via_edge, right);
|
||||
// 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};
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME this should possibly know aboat the actual roads?
|
||||
left.turn.instruction = getInstructionForObvious(4, via_edge, left);
|
||||
// FIXME this should possibly know about the actual roads?
|
||||
// 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};
|
||||
}
|
||||
@@ -1288,10 +1367,29 @@ TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
|
||||
}
|
||||
}
|
||||
|
||||
// check whether the obvious choice is actually a through street
|
||||
const auto isThroughStreet = [&intersection, this](const std::size_t index) {
|
||||
if (node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id == INVALID_NAME_ID)
|
||||
return false;
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
// a through street cannot start at our own position
|
||||
if (road.turn.angle < std::numeric_limits<double>::epsilon())
|
||||
continue;
|
||||
if (angularDeviation(road.turn.angle, intersection[index].turn.angle) >
|
||||
(STRAIGHT_ANGLE - NARROW_TURN_ANGLE) &&
|
||||
node_based_graph.GetEdgeData(road.turn.eid).name_id ==
|
||||
node_based_graph.GetEdgeData(intersection[index].turn.eid).name_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (obvious_index != 0)
|
||||
{
|
||||
intersection[obvious_index].turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, intersection[obvious_index]);
|
||||
getInstructionForObvious(intersection.size(), via_edge, isThroughStreet(obvious_index),
|
||||
intersection[obvious_index]);
|
||||
|
||||
// assign left/right turns
|
||||
intersection = assignLeftTurns(via_edge, std::move(intersection), obvious_index + 1);
|
||||
@@ -1312,14 +1410,14 @@ TurnAnalysis::handleComplexTurn(const EdgeID via_edge,
|
||||
else if (getPriority(left_class) > getPriority(right_class))
|
||||
{
|
||||
right.turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, right);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, right);
|
||||
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
||||
DirectionModifier::SlightLeft};
|
||||
}
|
||||
else
|
||||
{
|
||||
left.turn.instruction =
|
||||
getInstructionForObvious(intersection.size(), via_edge, left);
|
||||
getInstructionForObvious(intersection.size(), via_edge, false, left);
|
||||
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
||||
DirectionModifier::SlightRight};
|
||||
}
|
||||
@@ -1489,8 +1587,7 @@ std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_nod
|
||||
{TurnOperation{via_eid, 0., {TurnType::Invalid, DirectionModifier::UTurn}}, false});
|
||||
}
|
||||
|
||||
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
|
||||
{
|
||||
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);
|
||||
@@ -1527,13 +1624,11 @@ std::vector<ConnectedRoad> TurnAnalysis::getConnectedRoads(const NodeID from_nod
|
||||
std::vector<ConnectedRoad>
|
||||
TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const
|
||||
{
|
||||
const auto getRight = [&](std::size_t index)
|
||||
{
|
||||
const auto getRight = [&](std::size_t index) {
|
||||
return (index + intersection.size() - 1) % intersection.size();
|
||||
};
|
||||
|
||||
const auto mergable = [&](std::size_t first, std::size_t second) -> bool
|
||||
{
|
||||
const auto mergable = [&](std::size_t first, std::size_t second) -> bool {
|
||||
const auto &first_data = node_based_graph.GetEdgeData(intersection[first].turn.eid);
|
||||
const auto &second_data = node_based_graph.GetEdgeData(intersection[second].turn.eid);
|
||||
|
||||
@@ -1547,8 +1642,8 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
|
||||
first_data.reversed != second_data.reversed;
|
||||
};
|
||||
|
||||
const auto merge = [](const ConnectedRoad &first, const ConnectedRoad &second) -> ConnectedRoad
|
||||
{
|
||||
const auto merge = [](const ConnectedRoad &first,
|
||||
const ConnectedRoad &second) -> ConnectedRoad {
|
||||
if (!first.entry_allowed)
|
||||
{
|
||||
ConnectedRoad result = second;
|
||||
@@ -1581,7 +1676,6 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
|
||||
// these result in an adjustment of all other angles
|
||||
if (mergable(0, intersection.size() - 1))
|
||||
{
|
||||
// std::cout << "First merge" << std::endl;
|
||||
const double correction_factor =
|
||||
(360 - intersection[intersection.size() - 1].turn.angle) / 2;
|
||||
for (std::size_t i = 1; i + 1 < intersection.size(); ++i)
|
||||
@@ -1592,7 +1686,6 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
|
||||
}
|
||||
else if (mergable(0, 1))
|
||||
{
|
||||
// std::cout << "First merge" << std::endl;
|
||||
const double correction_factor = (intersection[1].turn.angle) / 2;
|
||||
for (std::size_t i = 2; i < intersection.size(); ++i)
|
||||
intersection[i].turn.angle += correction_factor;
|
||||
@@ -1614,8 +1707,7 @@ TurnAnalysis::mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) cons
|
||||
}
|
||||
}
|
||||
|
||||
const auto ByAngle = [](const ConnectedRoad &first, const ConnectedRoad second)
|
||||
{
|
||||
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);
|
||||
@@ -1640,7 +1732,7 @@ void TurnAnalysis::assignFork(const EdgeID via_edge,
|
||||
{
|
||||
if (low_priority_right && !low_priority_left)
|
||||
{
|
||||
left.turn.instruction = getInstructionForObvious(3, via_edge, left);
|
||||
left.turn.instruction = getInstructionForObvious(3, via_edge, false, left);
|
||||
right.turn.instruction = {findBasicTurnType(via_edge, right),
|
||||
DirectionModifier::SlightRight};
|
||||
}
|
||||
@@ -1683,7 +1775,7 @@ void TurnAnalysis::assignFork(const EdgeID via_edge,
|
||||
{
|
||||
left.turn.instruction = {findBasicTurnType(via_edge, left),
|
||||
DirectionModifier::SlightLeft};
|
||||
right.turn.instruction = getInstructionForObvious(3, via_edge, right);
|
||||
right.turn.instruction = getInstructionForObvious(3, via_edge, false, right);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1887,10 +1979,24 @@ TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_deviation <= NARROW_TURN_ANGLE)
|
||||
{
|
||||
std::size_t left = best, right = best;
|
||||
if (intersection[left].turn.angle >= 180)
|
||||
{
|
||||
// due to best > 1, we can safely decrement right
|
||||
--right;
|
||||
if (angularDeviation(intersection[right].turn.angle, STRAIGHT_ANGLE) >
|
||||
NARROW_TURN_ANGLE)
|
||||
return std::make_pair(std::size_t{0}, std::size_t{0});
|
||||
}
|
||||
else
|
||||
{
|
||||
++left;
|
||||
if (left >= intersection.size() ||
|
||||
angularDeviation(intersection[left].turn.angle, STRAIGHT_ANGLE) > NARROW_TURN_ANGLE)
|
||||
return std::make_pair(std::size_t{0}, std::size_t{0});
|
||||
}
|
||||
while (left + 1 < intersection.size() &&
|
||||
angularDeviation(intersection[left].turn.angle, intersection[left + 1].turn.angle) <
|
||||
NARROW_TURN_ANGLE)
|
||||
@@ -1909,7 +2015,7 @@ TurnAnalysis::findFork(const std::vector<ConnectedRoad> &intersection) const
|
||||
2 * NARROW_TURN_ANGLE)
|
||||
return std::make_pair(right, left);
|
||||
}
|
||||
return std::make_pair(0llu, 0llu);
|
||||
return std::make_pair(std::size_t{0}, std::size_t{0});
|
||||
}
|
||||
|
||||
// Can only assign three turns
|
||||
@@ -1917,8 +2023,7 @@ std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
|
||||
std::vector<ConnectedRoad> intersection,
|
||||
const std::size_t starting_at) const
|
||||
{
|
||||
const auto count_valid = [&intersection, starting_at]()
|
||||
{
|
||||
const auto count_valid = [&intersection, starting_at]() {
|
||||
std::size_t count = 0;
|
||||
for (std::size_t i = starting_at; i < intersection.size(); ++i)
|
||||
if (intersection[i].entry_allowed)
|
||||
@@ -1990,7 +2095,7 @@ std::vector<ConnectedRoad> TurnAnalysis::assignLeftTurns(const EdgeID via_edge,
|
||||
findBasicTurnType(via_edge, intersection[starting_at + 1]), second_direction};
|
||||
if (intersection[starting_at + 2].entry_allowed)
|
||||
intersection[starting_at + 2].turn.instruction = {
|
||||
findBasicTurnType(via_edge, intersection[starting_at + 2]), second_direction};
|
||||
findBasicTurnType(via_edge, intersection[starting_at + 2]), third_direction};
|
||||
}
|
||||
else if (2 >= (intersection[starting_at].entry_allowed +
|
||||
intersection[starting_at + 1].entry_allowed +
|
||||
@@ -2187,8 +2292,7 @@ std::vector<ConnectedRoad> TurnAnalysis::assignRightTurns(const EdgeID via_edge,
|
||||
const std::size_t up_to) const
|
||||
{
|
||||
BOOST_ASSERT(up_to <= intersection.size());
|
||||
const auto count_valid = [&intersection, up_to]()
|
||||
{
|
||||
const auto count_valid = [&intersection, up_to]() {
|
||||
std::size_t count = 0;
|
||||
for (std::size_t i = 1; i < up_to; ++i)
|
||||
if (intersection[i].entry_allowed)
|
||||
|
||||
@@ -122,8 +122,9 @@ double perpendicularDistance(const Coordinate segment_source,
|
||||
BOOST_ASSERT(query_location.IsValid());
|
||||
|
||||
FloatCoordinate projected_nearest;
|
||||
std::tie(ratio, projected_nearest) =
|
||||
projectPointOnSegment(mercator::fromWGS84(segment_source), mercator::fromWGS84(segment_target), mercator::fromWGS84(query_location));
|
||||
std::tie(ratio, projected_nearest) = projectPointOnSegment(mercator::fromWGS84(segment_source),
|
||||
mercator::fromWGS84(segment_target),
|
||||
mercator::fromWGS84(query_location));
|
||||
nearest_location = mercator::toWGS84(projected_nearest);
|
||||
|
||||
const double approximate_distance = greatCircleDistance(query_location, nearest_location);
|
||||
@@ -215,7 +216,9 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3)
|
||||
// free after http://paulbourke.net/geometry/circlesphere/
|
||||
// require three distinct points
|
||||
if (C1 == C2 || C2 == C3 || C1 == C3)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
// define line through c1, c2 and c2,c3
|
||||
const double C2C1_lat = static_cast<double>(toFloating(C2.lat - C1.lat)); // yDelta_a
|
||||
@@ -255,7 +258,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3)
|
||||
const double C2C1_slope = C2C1_lat / C2C1_lon;
|
||||
const double C3C2_slope = C3C2_lat / C3C2_lon;
|
||||
|
||||
//can this ever happen?
|
||||
// can this ever happen?
|
||||
if (std::abs(C2C1_slope - C3C2_slope) < std::numeric_limits<double>::epsilon())
|
||||
return boost::none;
|
||||
|
||||
@@ -356,12 +359,14 @@ double degreeToPixel(FloatLatitude lat, unsigned zoom)
|
||||
|
||||
FloatCoordinate fromWGS84(const FloatCoordinate &wgs84_coordinate)
|
||||
{
|
||||
return {wgs84_coordinate.lon, FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}};
|
||||
return {wgs84_coordinate.lon,
|
||||
FloatLatitude{coordinate_calculation::mercator::latToY(wgs84_coordinate.lat)}};
|
||||
}
|
||||
|
||||
FloatCoordinate toWGS84(const FloatCoordinate &mercator_coordinate)
|
||||
{
|
||||
return {mercator_coordinate.lon, coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))};
|
||||
return {mercator_coordinate.lon,
|
||||
coordinate_calculation::mercator::yToLat(static_cast<double>(mercator_coordinate.lat))};
|
||||
}
|
||||
|
||||
// Converts a WMS tile coordinate (z,x,y) into a wgs bounding box
|
||||
|
||||
+14
-11
@@ -1,10 +1,10 @@
|
||||
#include "util/exception.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/simple_logger.hpp"
|
||||
#include "util/exception.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
@@ -17,27 +17,30 @@ NameTable::NameTable(const std::string &filename)
|
||||
{
|
||||
boost::filesystem::ifstream name_stream(filename, std::ios::binary);
|
||||
|
||||
if( !name_stream )
|
||||
if (!name_stream)
|
||||
throw exception("Failed to open " + filename + " for reading.");
|
||||
|
||||
name_stream >> m_name_table;
|
||||
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read(reinterpret_cast<char *>(&number_of_chars), sizeof(number_of_chars));
|
||||
if( !name_stream )
|
||||
if (!name_stream)
|
||||
throw exception("Encountered invalid file, failed to read number of contained chars");
|
||||
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
|
||||
name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
|
||||
number_of_chars * sizeof(m_names_char_list[0]));
|
||||
if( !name_stream )
|
||||
throw exception("Failed to read " + std::to_string(number_of_chars) + " characters from file.");
|
||||
|
||||
if (0 == m_names_char_list.size())
|
||||
m_names_char_list.back() = 0;
|
||||
if (number_of_chars > 0)
|
||||
{
|
||||
name_stream.read(reinterpret_cast<char *>(&m_names_char_list[0]),
|
||||
number_of_chars * sizeof(m_names_char_list[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
util::SimpleLogger().Write(logWARNING) << "list of street names is empty";
|
||||
}
|
||||
if (!name_stream)
|
||||
throw exception("Failed to read " + std::to_string(number_of_chars) +
|
||||
" characters from file.");
|
||||
}
|
||||
|
||||
std::string NameTable::GetNameForID(const unsigned name_id) const
|
||||
|
||||
Reference in New Issue
Block a user