Upgrade clang-format to version 15 (#6859)
This commit is contained in:
@@ -65,12 +65,12 @@ void benchmark(BenchStaticRTree &rtree, unsigned num_queries)
|
||||
util::FixedLatitude{lat_udist(mt_rand)});
|
||||
}
|
||||
|
||||
benchmarkQuery(queries, "raw RTree queries (1 result)", [&rtree](const util::Coordinate &q) {
|
||||
return rtree.Nearest(q, 1);
|
||||
});
|
||||
benchmarkQuery(queries, "raw RTree queries (10 results)", [&rtree](const util::Coordinate &q) {
|
||||
return rtree.Nearest(q, 10);
|
||||
});
|
||||
benchmarkQuery(queries,
|
||||
"raw RTree queries (1 result)",
|
||||
[&rtree](const util::Coordinate &q) { return rtree.Nearest(q, 1); });
|
||||
benchmarkQuery(queries,
|
||||
"raw RTree queries (10 results)",
|
||||
[&rtree](const util::Coordinate &q) { return rtree.Nearest(q, 10); });
|
||||
}
|
||||
} // namespace osrm::benchmarks
|
||||
|
||||
|
||||
@@ -619,7 +619,8 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
util::UnbufferedLog log;
|
||||
log << "initializing node priorities...";
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, remaining_nodes.size(), PQGrainSize),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.GetThreadData();
|
||||
for (auto x = range.begin(), end = range.end(); x != end; ++x)
|
||||
{
|
||||
@@ -656,7 +657,8 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<NodeID>(0, remaining_nodes.size(), IndependentGrainSize),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.GetThreadData();
|
||||
// determine independent node set
|
||||
for (auto i = range.begin(), end = range.end(); i != end; ++i)
|
||||
@@ -669,9 +671,9 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
|
||||
// sort all remaining nodes to the beginning of the sequence
|
||||
const auto begin_independent_nodes = std::stable_partition(
|
||||
remaining_nodes.begin(), remaining_nodes.end(), [](RemainingNodeData node_data) {
|
||||
return !node_data.is_independent;
|
||||
});
|
||||
remaining_nodes.begin(),
|
||||
remaining_nodes.end(),
|
||||
[](RemainingNodeData node_data) { return !node_data.is_independent; });
|
||||
auto begin_independent_nodes_idx =
|
||||
std::distance(remaining_nodes.begin(), begin_independent_nodes);
|
||||
auto end_independent_nodes_idx = remaining_nodes.size();
|
||||
@@ -680,7 +682,8 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<NodeID>(
|
||||
begin_independent_nodes_idx, end_independent_nodes_idx, ContractGrainSize),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.GetThreadData();
|
||||
for (auto position = range.begin(), end = range.end(); position != end; ++position)
|
||||
{
|
||||
@@ -699,7 +702,8 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<NodeID>(
|
||||
begin_independent_nodes_idx, end_independent_nodes_idx, DeleteGrainSize),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.GetThreadData();
|
||||
for (auto position = range.begin(), end = range.end(); position != end; ++position)
|
||||
{
|
||||
@@ -709,10 +713,13 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
});
|
||||
|
||||
// make sure we really sort each block
|
||||
tbb::parallel_for(thread_data_list.data.range(), [&](const auto &range) {
|
||||
for (auto &data : range)
|
||||
tbb::parallel_sort(data->inserted_edges.begin(), data->inserted_edges.end());
|
||||
});
|
||||
tbb::parallel_for(thread_data_list.data.range(),
|
||||
[&](const auto &range)
|
||||
{
|
||||
for (auto &data : range)
|
||||
tbb::parallel_sort(data->inserted_edges.begin(),
|
||||
data->inserted_edges.end());
|
||||
});
|
||||
|
||||
// insert new edges
|
||||
for (auto &data : thread_data_list.data)
|
||||
@@ -743,7 +750,8 @@ std::vector<bool> contractGraph(ContractorGraph &graph,
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<NodeID>(
|
||||
begin_independent_nodes_idx, end_independent_nodes_idx, NeighboursGrainSize),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.GetThreadData();
|
||||
for (auto position = range.begin(), end = range.end(); position != end; ++position)
|
||||
{
|
||||
|
||||
@@ -47,17 +47,18 @@ void printUnreachableStatistics(const Partition &partition,
|
||||
for (auto node : cell.GetSourceNodes())
|
||||
{
|
||||
const auto &weights = cell.GetOutWeight(node);
|
||||
invalid_sources += std::all_of(weights.begin(), weights.end(), [](auto weight) {
|
||||
return weight == INVALID_EDGE_WEIGHT;
|
||||
});
|
||||
invalid_sources +=
|
||||
std::all_of(weights.begin(),
|
||||
weights.end(),
|
||||
[](auto weight) { return weight == INVALID_EDGE_WEIGHT; });
|
||||
}
|
||||
for (auto node : cell.GetDestinationNodes())
|
||||
{
|
||||
const auto &weights = cell.GetInWeight(node);
|
||||
invalid_destinations +=
|
||||
std::all_of(weights.begin(), weights.end(), [](auto weight) {
|
||||
return weight == INVALID_EDGE_WEIGHT;
|
||||
});
|
||||
std::all_of(weights.begin(),
|
||||
weights.end(),
|
||||
[](auto weight) { return weight == INVALID_EDGE_WEIGHT; });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,8 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
|
||||
std::transform(intersection.entry.begin(),
|
||||
intersection.entry.end(),
|
||||
std::back_inserter(entry.values),
|
||||
[](const bool has_entry) -> util::json::Value {
|
||||
[](const bool has_entry) -> util::json::Value
|
||||
{
|
||||
if (has_entry)
|
||||
return util::json::True();
|
||||
else
|
||||
@@ -151,11 +152,11 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
|
||||
{
|
||||
util::json::Array classes;
|
||||
classes.values.reserve(intersection.classes.size());
|
||||
std::transform(
|
||||
intersection.classes.begin(),
|
||||
intersection.classes.end(),
|
||||
std::back_inserter(classes.values),
|
||||
[](const std::string &class_name) { return util::json::String{class_name}; });
|
||||
std::transform(intersection.classes.begin(),
|
||||
intersection.classes.end(),
|
||||
std::back_inserter(classes.values),
|
||||
[](const std::string &class_name)
|
||||
{ return util::json::String{class_name}; });
|
||||
result.values["classes"] = std::move(classes);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,9 +43,11 @@ std::vector<util::Coordinate> douglasPeucker(std::vector<util::Coordinate>::cons
|
||||
}
|
||||
|
||||
std::vector<util::FloatCoordinate> projected_coordinates(size);
|
||||
std::transform(begin, end, projected_coordinates.begin(), [](const util::Coordinate coord) {
|
||||
return util::web_mercator::fromWGS84(coord);
|
||||
});
|
||||
std::transform(begin,
|
||||
end,
|
||||
projected_coordinates.begin(),
|
||||
[](const util::Coordinate coord)
|
||||
{ return util::web_mercator::fromWGS84(coord); });
|
||||
|
||||
std::vector<bool> is_necessary(size, false);
|
||||
BOOST_ASSERT(is_necessary.size() >= 2);
|
||||
|
||||
@@ -9,9 +9,8 @@ bool EngineConfig::IsValid() const
|
||||
// leads to an empty path
|
||||
const bool all_path_are_empty = storage_config.GetPath("").empty();
|
||||
|
||||
const auto unlimited_or_more_than = [](const auto v, const auto limit) {
|
||||
return v == -1 || v > limit;
|
||||
};
|
||||
const auto unlimited_or_more_than = [](const auto v, const auto limit)
|
||||
{ return v == -1 || v > limit; };
|
||||
|
||||
const bool limits_valid =
|
||||
unlimited_or_more_than(max_locations_distance_table, 2) &&
|
||||
|
||||
@@ -40,22 +40,21 @@ unsigned calculateOverviewZoomLevel(const std::vector<LegGeometry> &leg_geometri
|
||||
std::vector<util::Coordinate> assembleOverview(const std::vector<LegGeometry> &leg_geometries,
|
||||
const bool use_simplification)
|
||||
{
|
||||
auto overview_size =
|
||||
std::accumulate(leg_geometries.begin(),
|
||||
leg_geometries.end(),
|
||||
0,
|
||||
[](const std::size_t sum, const LegGeometry &leg_geometry) {
|
||||
return sum + leg_geometry.locations.size();
|
||||
}) -
|
||||
leg_geometries.size() + 1;
|
||||
auto overview_size = std::accumulate(leg_geometries.begin(),
|
||||
leg_geometries.end(),
|
||||
0,
|
||||
[](const std::size_t sum, const LegGeometry &leg_geometry)
|
||||
{ return sum + leg_geometry.locations.size(); }) -
|
||||
leg_geometries.size() + 1;
|
||||
std::vector<util::Coordinate> overview_geometry;
|
||||
overview_geometry.reserve(overview_size);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -7,18 +7,21 @@ namespace osrm::engine::guidance
|
||||
|
||||
Route assembleRoute(const std::vector<RouteLeg> &route_legs)
|
||||
{
|
||||
auto distance = std::accumulate(
|
||||
route_legs.begin(), route_legs.end(), 0., [](const double sum, const RouteLeg &leg) {
|
||||
return sum + leg.distance;
|
||||
});
|
||||
auto duration = std::accumulate(
|
||||
route_legs.begin(), route_legs.end(), 0., [](const double sum, const RouteLeg &leg) {
|
||||
return sum + leg.duration;
|
||||
});
|
||||
auto weight = std::accumulate(
|
||||
route_legs.begin(), route_legs.end(), 0., [](const double sum, const RouteLeg &leg) {
|
||||
return sum + leg.weight;
|
||||
});
|
||||
auto distance =
|
||||
std::accumulate(route_legs.begin(),
|
||||
route_legs.end(),
|
||||
0.,
|
||||
[](const double sum, const RouteLeg &leg) { return sum + leg.distance; });
|
||||
auto duration =
|
||||
std::accumulate(route_legs.begin(),
|
||||
route_legs.end(),
|
||||
0.,
|
||||
[](const double sum, const RouteLeg &leg) { return sum + leg.duration; });
|
||||
auto weight =
|
||||
std::accumulate(route_legs.begin(),
|
||||
route_legs.end(),
|
||||
0.,
|
||||
[](const double sum, const RouteLeg &leg) { return sum + leg.weight; });
|
||||
|
||||
return Route{distance, duration, weight};
|
||||
}
|
||||
|
||||
@@ -102,7 +102,8 @@ bool isStaggeredIntersection(const RouteStepIterator step_prior_to_intersection,
|
||||
// If adjusted, make sure to check validity of the is_right/is_left classification below
|
||||
const constexpr auto MAX_STAGGERED_DISTANCE = 3; // debatable, but keep short to be on safe side
|
||||
|
||||
const auto angle = [](const RouteStep &step) {
|
||||
const auto angle = [](const RouteStep &step)
|
||||
{
|
||||
const auto &intersection = step.intersections.front();
|
||||
const auto entry_bearing = util::bearing::reverse(intersection.bearings[intersection.in]);
|
||||
const auto exit_bearing = intersection.bearings[intersection.out];
|
||||
|
||||
@@ -59,7 +59,8 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste
|
||||
// c
|
||||
// |
|
||||
// d
|
||||
const auto use_total_angle = [&]() {
|
||||
const auto use_total_angle = [&]()
|
||||
{
|
||||
// only consider actual turns in combination:
|
||||
if (angularDeviation(total_angle, 180) < 0.5 * NARROW_TURN_ANGLE)
|
||||
return false;
|
||||
@@ -99,7 +100,8 @@ inline void handleSliproad(RouteStepIterator sliproad_step)
|
||||
{
|
||||
// find the next step after the sliproad step itself (this is not necessarily the next step,
|
||||
// since we might have to skip over traffic lights/node penalties)
|
||||
auto next_step = [&sliproad_step]() {
|
||||
auto next_step = [&sliproad_step]()
|
||||
{
|
||||
auto next_step = findNextTurn(sliproad_step);
|
||||
while (isTrafficLightStep(*next_step))
|
||||
{
|
||||
@@ -196,7 +198,8 @@ void AdjustToCombinedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
: getTurnDirection(angle);
|
||||
|
||||
// a turn that is a new name or straight (turn/continue)
|
||||
const auto is_non_turn = [](const RouteStep &step) {
|
||||
const auto is_non_turn = [](const RouteStep &step)
|
||||
{
|
||||
return hasTurnType(step, TurnType::NewName) ||
|
||||
(hasTurnType(step, TurnType::Turn) &&
|
||||
hasModifier(step, DirectionModifier::Straight)) ||
|
||||
@@ -307,7 +310,8 @@ void SegregatedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
// Used to control updating of the modifier based on turn direction
|
||||
bool update_modifier_for_turn_direction = true;
|
||||
|
||||
const auto calculate_turn_angle = [](const RouteStep &entry_step, const RouteStep &exit_step) {
|
||||
const auto calculate_turn_angle = [](const RouteStep &entry_step, const RouteStep &exit_step)
|
||||
{
|
||||
return util::bearing::angleBetween(entry_step.maneuver.bearing_before,
|
||||
exit_step.maneuver.bearing_after);
|
||||
};
|
||||
@@ -316,7 +320,8 @@ void SegregatedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
const auto turn_angle = calculate_turn_angle(step_at_turn_location, transfer_from_step);
|
||||
const auto turn_direction = getTurnDirection(turn_angle);
|
||||
|
||||
const auto is_straight_step = [](const RouteStep &step) {
|
||||
const auto is_straight_step = [](const RouteStep &step)
|
||||
{
|
||||
return ((hasTurnType(step, TurnType::NewName) || hasTurnType(step, TurnType::Continue) ||
|
||||
hasTurnType(step, TurnType::Suppressed) || hasTurnType(step, TurnType::Turn)) &&
|
||||
(hasModifier(step, DirectionModifier::Straight) ||
|
||||
@@ -324,7 +329,8 @@ void SegregatedTurnStrategy::operator()(RouteStep &step_at_turn_location,
|
||||
hasModifier(step, DirectionModifier::SlightRight)));
|
||||
};
|
||||
|
||||
const auto is_turn_step = [](const RouteStep &step) {
|
||||
const auto is_turn_step = [](const RouteStep &step)
|
||||
{
|
||||
return (hasTurnType(step, TurnType::Turn) || hasTurnType(step, TurnType::Continue) ||
|
||||
hasTurnType(step, TurnType::NewName) || hasTurnType(step, TurnType::Suppressed));
|
||||
};
|
||||
|
||||
@@ -17,7 +17,8 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
|
||||
const double min_distance_needed_for_lane_change)
|
||||
{
|
||||
// Lane anticipation works on contiguous ranges of short steps that have lane information
|
||||
const auto is_short_has_lanes = [&](const RouteStep &step) {
|
||||
const auto is_short_has_lanes = [&](const RouteStep &step)
|
||||
{
|
||||
const auto has_lanes = step.intersections.front().lanes.lanes_in_turn > 0;
|
||||
|
||||
if (!has_lanes)
|
||||
@@ -45,7 +46,8 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
|
||||
|
||||
std::vector<StepIterRange> quick_lanes_ranges;
|
||||
|
||||
const auto range_back_inserter = [&](StepIterRange range) {
|
||||
const auto range_back_inserter = [&](StepIterRange range)
|
||||
{
|
||||
if (std::distance(range.first, range.second) > 1)
|
||||
quick_lanes_ranges.push_back(std::move(range));
|
||||
};
|
||||
@@ -58,7 +60,8 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
|
||||
|
||||
// Walk backwards over all turns, constraining possible turn lanes.
|
||||
// Later turn lanes constrain earlier ones: we have to anticipate lane changes.
|
||||
const auto constrain_lanes = [&](const StepIterRange &turns) {
|
||||
const auto constrain_lanes = [&](const StepIterRange &turns)
|
||||
{
|
||||
const std::reverse_iterator<StepIter> rev_first{turns.second};
|
||||
const std::reverse_iterator<StepIter> rev_last{turns.first};
|
||||
|
||||
@@ -74,127 +77,135 @@ std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
|
||||
// segment for a lane switch, but the total distance shouldn't be unlimited.
|
||||
double distance_to_constrained = 0.0;
|
||||
|
||||
util::for_each_pair(rev_first, rev_last, [&](RouteStep ¤t, RouteStep &previous) {
|
||||
const auto current_inst = current.maneuver.instruction;
|
||||
const auto current_lanes = current.intersections.front().lanes;
|
||||
|
||||
// Constrain the previous turn's lanes
|
||||
auto &previous_lanes = previous.intersections.front().lanes;
|
||||
const auto previous_inst = previous.maneuver.instruction;
|
||||
|
||||
// Lane mapping (N:M) from previous lanes (N) to current lanes (M), with:
|
||||
// N > M, N > 1 fan-in situation, constrain N lanes to min(N,M) shared lanes
|
||||
// otherwise nothing to constrain
|
||||
const bool lanes_to_constrain = previous_lanes.lanes_in_turn > 1;
|
||||
const bool lanes_fan_in = previous_lanes.lanes_in_turn > current_lanes.lanes_in_turn;
|
||||
|
||||
// only prevent use lanes due to making all turns. don't make turns during curvy
|
||||
// segments
|
||||
if (previous_inst.type == TurnType::Suppressed)
|
||||
distance_to_constrained += previous.distance;
|
||||
else
|
||||
distance_to_constrained = 0.;
|
||||
|
||||
const auto lane_delta = previous_lanes.lanes_in_turn - current_lanes.lanes_in_turn;
|
||||
const auto can_make_all_turns =
|
||||
distance_to_constrained > lane_delta * min_distance_needed_for_lane_change;
|
||||
|
||||
if (!lanes_to_constrain || !lanes_fan_in || can_make_all_turns)
|
||||
return;
|
||||
|
||||
// We do not have a mapping from lanes to lanes. All we have is the lanes in the turn
|
||||
// and all the lanes at that situation. To perfectly handle lane anticipation in cases
|
||||
// where lanes in the turn fan in but for example the overall lanes at that location
|
||||
// fan out, we would have to know the asymmetric mapping of lanes. This is currently
|
||||
// not possible at the moment. In the following we implement a heuristic instead.
|
||||
const LaneID current_num_lanes_right_of_turn = current.NumLanesToTheRight();
|
||||
const LaneID current_num_lanes_left_of_turn = current.NumLanesToTheLeft();
|
||||
|
||||
// 0/ Tag keep straight with the next turn's direction if available
|
||||
const auto previous_is_straight =
|
||||
!isLeftTurn(previous_inst) && !isRightTurn(previous_inst);
|
||||
|
||||
if (previous_is_straight)
|
||||
util::for_each_pair(
|
||||
rev_first,
|
||||
rev_last,
|
||||
[&](RouteStep ¤t, RouteStep &previous)
|
||||
{
|
||||
if (isLeftTurn(current_inst) || is_straight_left.count(¤t) > 0)
|
||||
is_straight_left.insert(&previous);
|
||||
else if (isRightTurn(current_inst) || is_straight_right.count(¤t) > 0)
|
||||
is_straight_right.insert(&previous);
|
||||
}
|
||||
const auto current_inst = current.maneuver.instruction;
|
||||
const auto current_lanes = current.intersections.front().lanes;
|
||||
|
||||
// 1/ How to anticipate left, right:
|
||||
const auto anticipate_for_left_turn = [&] {
|
||||
// Current turn is left turn, already keep left during previous turn.
|
||||
// This implies constraining the rightmost lanes in previous step.
|
||||
LaneID new_first_lane_from_the_right =
|
||||
previous_lanes.first_lane_from_the_right // start from rightmost lane
|
||||
+ previous_lanes.lanes_in_turn // one past leftmost lane
|
||||
- current_lanes.lanes_in_turn; // back number of new lanes
|
||||
// Constrain the previous turn's lanes
|
||||
auto &previous_lanes = previous.intersections.front().lanes;
|
||||
const auto previous_inst = previous.maneuver.instruction;
|
||||
|
||||
// The leftmost target lanes might not be involved in the turn. Figure out
|
||||
// how many lanes are to the left and not in the turn.
|
||||
new_first_lane_from_the_right -=
|
||||
std::min(current_num_lanes_left_of_turn, current_lanes.lanes_in_turn);
|
||||
// Lane mapping (N:M) from previous lanes (N) to current lanes (M), with:
|
||||
// N > M, N > 1 fan-in situation, constrain N lanes to min(N,M) shared lanes
|
||||
// otherwise nothing to constrain
|
||||
const bool lanes_to_constrain = previous_lanes.lanes_in_turn > 1;
|
||||
const bool lanes_fan_in =
|
||||
previous_lanes.lanes_in_turn > current_lanes.lanes_in_turn;
|
||||
|
||||
previous_lanes = {current_lanes.lanes_in_turn, new_first_lane_from_the_right};
|
||||
};
|
||||
// only prevent use lanes due to making all turns. don't make turns during curvy
|
||||
// segments
|
||||
if (previous_inst.type == TurnType::Suppressed)
|
||||
distance_to_constrained += previous.distance;
|
||||
else
|
||||
distance_to_constrained = 0.;
|
||||
|
||||
const auto anticipate_for_right_turn = [&] {
|
||||
// Current turn is right turn, already keep right during the previous turn.
|
||||
// This implies constraining the leftmost lanes in the previous turn step.
|
||||
LaneID new_first_lane_from_the_right = previous_lanes.first_lane_from_the_right;
|
||||
const auto lane_delta = previous_lanes.lanes_in_turn - current_lanes.lanes_in_turn;
|
||||
const auto can_make_all_turns =
|
||||
distance_to_constrained > lane_delta * min_distance_needed_for_lane_change;
|
||||
|
||||
// The rightmost target lanes might not be involved in the turn. Figure out
|
||||
// how many lanes are to the right and not in the turn.
|
||||
new_first_lane_from_the_right +=
|
||||
std::min(current_num_lanes_right_of_turn, current_lanes.lanes_in_turn);
|
||||
if (!lanes_to_constrain || !lanes_fan_in || can_make_all_turns)
|
||||
return;
|
||||
|
||||
previous_lanes = {current_lanes.lanes_in_turn, new_first_lane_from_the_right};
|
||||
};
|
||||
// We do not have a mapping from lanes to lanes. All we have is the lanes in the
|
||||
// turn and all the lanes at that situation. To perfectly handle lane anticipation
|
||||
// in cases where lanes in the turn fan in but for example the overall lanes at that
|
||||
// location fan out, we would have to know the asymmetric mapping of lanes. This is
|
||||
// currently not possible at the moment. In the following we implement a heuristic
|
||||
// instead.
|
||||
const LaneID current_num_lanes_right_of_turn = current.NumLanesToTheRight();
|
||||
const LaneID current_num_lanes_left_of_turn = current.NumLanesToTheLeft();
|
||||
|
||||
// 2/ When to anticipate a left, right turn
|
||||
if (isLeftTurn(current_inst))
|
||||
anticipate_for_left_turn();
|
||||
else if (isRightTurn(current_inst))
|
||||
anticipate_for_right_turn();
|
||||
else // keepStraight
|
||||
{
|
||||
// Heuristic: we do not have a from-lanes -> to-lanes mapping. What we use
|
||||
// here instead in addition is the number of all lanes (not only the lanes
|
||||
// in a turn):
|
||||
//
|
||||
// -v-v v-v- straight follows
|
||||
// | | | |
|
||||
// <- v v -> keep straight here
|
||||
// | |
|
||||
// <-| |->
|
||||
//
|
||||
// A route from the top left to the bottom right here goes over a keep
|
||||
// straight. If we handle all keep straights as right turns (in right-sided
|
||||
// driving), we wrongly guide the user to the rightmost lanes in the first turn.
|
||||
// Not only is this wrong but the opposite of what we expect.
|
||||
//
|
||||
// The following implements a heuristic to determine a keep straight's
|
||||
// direction in relation to the next step. In the above example we would get:
|
||||
//
|
||||
// coming from right, going to left (in direction of way) -> handle as left turn
|
||||
// 0/ Tag keep straight with the next turn's direction if available
|
||||
const auto previous_is_straight =
|
||||
!isLeftTurn(previous_inst) && !isRightTurn(previous_inst);
|
||||
|
||||
if (is_straight_left.count(¤t) > 0)
|
||||
if (previous_is_straight)
|
||||
{
|
||||
if (isLeftTurn(current_inst) || is_straight_left.count(¤t) > 0)
|
||||
is_straight_left.insert(&previous);
|
||||
else if (isRightTurn(current_inst) || is_straight_right.count(¤t) > 0)
|
||||
is_straight_right.insert(&previous);
|
||||
}
|
||||
|
||||
// 1/ How to anticipate left, right:
|
||||
const auto anticipate_for_left_turn = [&]
|
||||
{
|
||||
// Current turn is left turn, already keep left during previous turn.
|
||||
// This implies constraining the rightmost lanes in previous step.
|
||||
LaneID new_first_lane_from_the_right =
|
||||
previous_lanes.first_lane_from_the_right // start from rightmost lane
|
||||
+ previous_lanes.lanes_in_turn // one past leftmost lane
|
||||
- current_lanes.lanes_in_turn; // back number of new lanes
|
||||
|
||||
// The leftmost target lanes might not be involved in the turn. Figure out
|
||||
// how many lanes are to the left and not in the turn.
|
||||
new_first_lane_from_the_right -=
|
||||
std::min(current_num_lanes_left_of_turn, current_lanes.lanes_in_turn);
|
||||
|
||||
previous_lanes = {current_lanes.lanes_in_turn, new_first_lane_from_the_right};
|
||||
};
|
||||
|
||||
const auto anticipate_for_right_turn = [&]
|
||||
{
|
||||
// Current turn is right turn, already keep right during the previous turn.
|
||||
// This implies constraining the leftmost lanes in the previous turn step.
|
||||
LaneID new_first_lane_from_the_right = previous_lanes.first_lane_from_the_right;
|
||||
|
||||
// The rightmost target lanes might not be involved in the turn. Figure out
|
||||
// how many lanes are to the right and not in the turn.
|
||||
new_first_lane_from_the_right +=
|
||||
std::min(current_num_lanes_right_of_turn, current_lanes.lanes_in_turn);
|
||||
|
||||
previous_lanes = {current_lanes.lanes_in_turn, new_first_lane_from_the_right};
|
||||
};
|
||||
|
||||
// 2/ When to anticipate a left, right turn
|
||||
if (isLeftTurn(current_inst))
|
||||
anticipate_for_left_turn();
|
||||
else if (is_straight_right.count(¤t) > 0)
|
||||
else if (isRightTurn(current_inst))
|
||||
anticipate_for_right_turn();
|
||||
else // FIXME: right-sided driving
|
||||
anticipate_for_right_turn();
|
||||
}
|
||||
else // keepStraight
|
||||
{
|
||||
// Heuristic: we do not have a from-lanes -> to-lanes mapping. What we use
|
||||
// here instead in addition is the number of all lanes (not only the lanes
|
||||
// in a turn):
|
||||
//
|
||||
// -v-v v-v- straight follows
|
||||
// | | | |
|
||||
// <- v v -> keep straight here
|
||||
// | |
|
||||
// <-| |->
|
||||
//
|
||||
// A route from the top left to the bottom right here goes over a keep
|
||||
// straight. If we handle all keep straights as right turns (in right-sided
|
||||
// driving), we wrongly guide the user to the rightmost lanes in the first turn.
|
||||
// Not only is this wrong but the opposite of what we expect.
|
||||
//
|
||||
// The following implements a heuristic to determine a keep straight's
|
||||
// direction in relation to the next step. In the above example we would get:
|
||||
//
|
||||
// coming from right, going to left (in direction of way) -> handle as left turn
|
||||
|
||||
if (previous_inst.type == TurnType::Suppressed &&
|
||||
current_inst.type == TurnType::Suppressed && previous.mode == current.mode &&
|
||||
previous_lanes == current_lanes)
|
||||
{
|
||||
previous.ElongateBy(current);
|
||||
current.Invalidate();
|
||||
}
|
||||
});
|
||||
if (is_straight_left.count(¤t) > 0)
|
||||
anticipate_for_left_turn();
|
||||
else if (is_straight_right.count(¤t) > 0)
|
||||
anticipate_for_right_turn();
|
||||
else // FIXME: right-sided driving
|
||||
anticipate_for_right_turn();
|
||||
}
|
||||
|
||||
if (previous_inst.type == TurnType::Suppressed &&
|
||||
current_inst.type == TurnType::Suppressed && previous.mode == current.mode &&
|
||||
previous_lanes == current_lanes)
|
||||
{
|
||||
previous.ElongateBy(current);
|
||||
current.Invalidate();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
std::for_each(begin(quick_lanes_ranges), end(quick_lanes_ranges), constrain_lanes);
|
||||
|
||||
@@ -77,7 +77,8 @@ void processRoundaboutExits(const RouteStepIterator begin, const RouteStepIterat
|
||||
return;
|
||||
}
|
||||
|
||||
const auto passes_exit_or_leaves_roundabout = [](auto const &step) {
|
||||
const auto passes_exit_or_leaves_roundabout = [](auto const &step)
|
||||
{
|
||||
return staysOnRoundabout(step.maneuver.instruction) ||
|
||||
leavesRoundabout(step.maneuver.instruction);
|
||||
};
|
||||
@@ -142,9 +143,8 @@ void processRoundaboutExits(const RouteStepIterator begin, const RouteStepIterat
|
||||
// instructions in between
|
||||
void processRoundaboutGroups(const std::pair<RouteStepIterator, RouteStepIterator> &range)
|
||||
{
|
||||
const auto leaves_roundabout = [](auto const &step) {
|
||||
return leavesRoundabout(step.maneuver.instruction);
|
||||
};
|
||||
const auto leaves_roundabout = [](auto const &step)
|
||||
{ return leavesRoundabout(step.maneuver.instruction); };
|
||||
|
||||
auto itr = range.first;
|
||||
while (itr != range.second)
|
||||
@@ -174,9 +174,8 @@ void processRoundaboutGroups(const std::pair<RouteStepIterator, RouteStepIterato
|
||||
std::vector<RouteStep> handleRoundabouts(std::vector<RouteStep> steps)
|
||||
{
|
||||
// check if a step has roundabout type
|
||||
const auto has_roundabout_type = [](auto const &step) {
|
||||
return hasRoundaboutType(step.maneuver.instruction);
|
||||
};
|
||||
const auto has_roundabout_type = [](auto const &step)
|
||||
{ return hasRoundaboutType(step.maneuver.instruction); };
|
||||
const auto first_roundabout_type =
|
||||
std::find_if(steps.begin(), steps.end(), has_roundabout_type);
|
||||
|
||||
@@ -193,7 +192,8 @@ std::vector<RouteStep> handleRoundabouts(std::vector<RouteStep> steps)
|
||||
// this group by paradigm does might contain intermediate roundabout instructions, when they are
|
||||
// directly connected. Otherwise it will be a sequence containing everything from enter to exit.
|
||||
// If we already start on the roundabout, the first valid place will be steps.begin().
|
||||
const auto is_on_roundabout = [¤tly_on_roundabout](const auto &step) {
|
||||
const auto is_on_roundabout = [¤tly_on_roundabout](const auto &step)
|
||||
{
|
||||
if (currently_on_roundabout)
|
||||
{
|
||||
if (leavesRoundabout(step.maneuver.instruction))
|
||||
@@ -327,10 +327,13 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
||||
}
|
||||
|
||||
// and update the leg geometry indices for the removed entry
|
||||
std::for_each(steps.begin(), steps.end(), [offset](RouteStep &step) {
|
||||
step.geometry_begin -= offset;
|
||||
step.geometry_end -= offset;
|
||||
});
|
||||
std::for_each(steps.begin(),
|
||||
steps.end(),
|
||||
[offset](RouteStep &step)
|
||||
{
|
||||
step.geometry_begin -= offset;
|
||||
step.geometry_end -= offset;
|
||||
});
|
||||
|
||||
auto &first_step = steps.front();
|
||||
auto bearing = first_bearing;
|
||||
@@ -645,16 +648,18 @@ void applyOverrides(const datafacade::BaseDataFacade &facade,
|
||||
auto step_to_update = std::find_if(
|
||||
current_step_it,
|
||||
route_iter,
|
||||
[&leg_geometry, &via_node_coords](const auto &step) {
|
||||
[&leg_geometry, &via_node_coords](const auto &step)
|
||||
{
|
||||
util::Log(logDEBUG) << "Leg geom from " << step.geometry_begin << " to "
|
||||
<< step.geometry_end << std::endl;
|
||||
|
||||
// iterators over geometry of current step
|
||||
auto begin = leg_geometry.locations.begin() + step.geometry_begin;
|
||||
auto end = leg_geometry.locations.begin() + step.geometry_end;
|
||||
auto via_match = std::find_if(begin, end, [&](const auto &location) {
|
||||
return location == via_node_coords;
|
||||
});
|
||||
auto via_match = std::find_if(begin,
|
||||
end,
|
||||
[&](const auto &location)
|
||||
{ return location == via_node_coords; });
|
||||
if (via_match != end)
|
||||
{
|
||||
util::Log(logDEBUG)
|
||||
|
||||
@@ -15,19 +15,20 @@ std::vector<RouteStep> suppressShortNameSegments(std::vector<RouteStep> steps)
|
||||
return steps;
|
||||
|
||||
// we remove only name changes that don't offer additional information
|
||||
const auto name_change_without_lanes = [](const RouteStep &step) {
|
||||
return hasTurnType(step, TurnType::NewName) && !hasLanes(step);
|
||||
};
|
||||
const auto name_change_without_lanes = [](const RouteStep &step)
|
||||
{ return hasTurnType(step, TurnType::NewName) && !hasLanes(step); };
|
||||
|
||||
// check if the next step is not important enough to announce
|
||||
const auto can_be_extended_to = [](const RouteStep &step) {
|
||||
const auto can_be_extended_to = [](const RouteStep &step)
|
||||
{
|
||||
const auto is_not_arrive = !hasWaypointType(step);
|
||||
const auto is_silent = !hasTurnType(step) || hasTurnType(step, TurnType::Suppressed);
|
||||
|
||||
return is_not_arrive && is_silent;
|
||||
};
|
||||
|
||||
const auto suppress = [](RouteStep &from_step, RouteStep &onto_step) {
|
||||
const auto suppress = [](RouteStep &from_step, RouteStep &onto_step)
|
||||
{
|
||||
from_step.ElongateBy(onto_step);
|
||||
onto_step.Invalidate();
|
||||
};
|
||||
@@ -36,28 +37,29 @@ std::vector<RouteStep> suppressShortNameSegments(std::vector<RouteStep> steps)
|
||||
// only available for a very short time
|
||||
const auto reduce_verbosity_if_possible =
|
||||
[suppress, can_be_extended_to](RouteStepIterator ¤t_turn_itr,
|
||||
RouteStepIterator &previous_turn_itr) {
|
||||
if (haveSameName(*previous_turn_itr, *current_turn_itr))
|
||||
RouteStepIterator &previous_turn_itr)
|
||||
{
|
||||
if (haveSameName(*previous_turn_itr, *current_turn_itr))
|
||||
suppress(*previous_turn_itr, *current_turn_itr);
|
||||
else
|
||||
{
|
||||
// remember the location of the name change so we can advance the previous turn
|
||||
const auto location_of_name_change = current_turn_itr;
|
||||
auto distance = current_turn_itr->distance;
|
||||
// sum up all distances that can be relevant to the name change
|
||||
while (can_be_extended_to(*(current_turn_itr + 1)) &&
|
||||
distance < NAME_SEGMENT_CUTOFF_LENGTH)
|
||||
{
|
||||
++current_turn_itr;
|
||||
distance += current_turn_itr->distance;
|
||||
}
|
||||
|
||||
if (distance < NAME_SEGMENT_CUTOFF_LENGTH)
|
||||
suppress(*previous_turn_itr, *current_turn_itr);
|
||||
else
|
||||
{
|
||||
// remember the location of the name change so we can advance the previous turn
|
||||
const auto location_of_name_change = current_turn_itr;
|
||||
auto distance = current_turn_itr->distance;
|
||||
// sum up all distances that can be relevant to the name change
|
||||
while (can_be_extended_to(*(current_turn_itr + 1)) &&
|
||||
distance < NAME_SEGMENT_CUTOFF_LENGTH)
|
||||
{
|
||||
++current_turn_itr;
|
||||
distance += current_turn_itr->distance;
|
||||
}
|
||||
|
||||
if (distance < NAME_SEGMENT_CUTOFF_LENGTH)
|
||||
suppress(*previous_turn_itr, *current_turn_itr);
|
||||
else
|
||||
previous_turn_itr = location_of_name_change;
|
||||
}
|
||||
};
|
||||
previous_turn_itr = location_of_name_change;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_ASSERT(!hasTurnType(steps.back()) && hasWaypointType(steps.back()));
|
||||
for (auto previous_turn_itr = steps.begin(), current_turn_itr = std::next(previous_turn_itr);
|
||||
|
||||
+4
-4
@@ -93,10 +93,10 @@ Hint Hint::FromBase64(const std::string &base64Hint)
|
||||
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
const datafacade::BaseDataFacade &facade) const
|
||||
{
|
||||
const auto all_valid =
|
||||
std::all_of(segment_hints.begin(), segment_hints.end(), [&](const auto &seg_hint) {
|
||||
return seg_hint.IsValid(new_input_coordinates, facade);
|
||||
});
|
||||
const auto all_valid = std::all_of(segment_hints.begin(),
|
||||
segment_hints.end(),
|
||||
[&](const auto &seg_hint)
|
||||
{ return seg_hint.IsValid(new_input_coordinates, facade); });
|
||||
if (!all_valid)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -50,7 +50,8 @@ void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
||||
// sort by forward id, then by reverse id and then by distance
|
||||
std::sort(candidates.begin(),
|
||||
candidates.end(),
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs) {
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
|
||||
{
|
||||
return lhs.phantom_node.forward_segment_id.id <
|
||||
rhs.phantom_node.forward_segment_id.id ||
|
||||
(lhs.phantom_node.forward_segment_id.id ==
|
||||
@@ -65,7 +66,8 @@ void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
||||
auto new_end =
|
||||
std::unique(candidates.begin(),
|
||||
candidates.end(),
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs) {
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
|
||||
{
|
||||
return lhs.phantom_node.forward_segment_id.id ==
|
||||
rhs.phantom_node.forward_segment_id.id &&
|
||||
lhs.phantom_node.reverse_segment_id.id ==
|
||||
@@ -95,9 +97,8 @@ void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
||||
// sort by distance to make pruning effective
|
||||
std::sort(candidates.begin(),
|
||||
candidates.end(),
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs) {
|
||||
return lhs.distance < rhs.distance;
|
||||
});
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
|
||||
{ return lhs.distance < rhs.distance; });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +134,8 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
if (max_radius_map_matching > 0 && std::any_of(parameters.radiuses.begin(),
|
||||
parameters.radiuses.end(),
|
||||
[&](const auto &radius) {
|
||||
[&](const auto &radius)
|
||||
{
|
||||
if (!radius)
|
||||
return false;
|
||||
return *radius > max_radius_map_matching;
|
||||
@@ -192,7 +194,8 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
tidied.parameters.radiuses.begin(),
|
||||
tidied.parameters.radiuses.end(),
|
||||
search_radiuses.begin(),
|
||||
[default_radius = this->default_radius](const boost::optional<double> &maybe_radius) {
|
||||
[default_radius = this->default_radius](const boost::optional<double> &maybe_radius)
|
||||
{
|
||||
if (maybe_radius)
|
||||
{
|
||||
return *maybe_radius * RADIUS_MULTIPLIER;
|
||||
@@ -212,9 +215,8 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
filterCandidates(tidied.parameters.coordinates, candidates_lists);
|
||||
if (std::all_of(candidates_lists.begin(),
|
||||
candidates_lists.end(),
|
||||
[](const std::vector<PhantomNodeWithDistance> &candidates) {
|
||||
return candidates.empty();
|
||||
}))
|
||||
[](const std::vector<PhantomNodeWithDistance> &candidates)
|
||||
{ return candidates.empty(); }))
|
||||
{
|
||||
return Error("NoSegment",
|
||||
std::string("Could not find a matching segment for any coordinate."),
|
||||
|
||||
@@ -251,7 +251,8 @@ std::vector<std::size_t> getEdgeIndex(const std::vector<RTreeLeaf> &edges)
|
||||
// as the sort condition
|
||||
std::sort(sorted_edge_indexes.begin(),
|
||||
sorted_edge_indexes.end(),
|
||||
[&edges](const std::size_t &left, const std::size_t &right) -> bool {
|
||||
[&edges](const std::size_t &left, const std::size_t &right) -> bool
|
||||
{
|
||||
return (edges[left].u != edges[right].u) ? edges[left].u < edges[right].u
|
||||
: edges[left].v < edges[right].v;
|
||||
});
|
||||
@@ -430,9 +431,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
||||
{
|
||||
vtzero::tile_builder tile;
|
||||
|
||||
const auto get_geometry_id = [&facade](auto edge) {
|
||||
return facade.GetGeometryIndex(edge.forward_segment_id.id).id;
|
||||
};
|
||||
const auto get_geometry_id = [&facade](auto edge)
|
||||
{ return facade.GetGeometryIndex(edge.forward_segment_id.id).id; };
|
||||
|
||||
// Convert tile coordinates into mercator coordinates
|
||||
double min_mercator_lon, min_mercator_lat, max_mercator_lon, max_mercator_lat;
|
||||
|
||||
@@ -137,7 +137,8 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
std::vector<bool> waypoint_legs(route_parameters.coordinates.size(), false);
|
||||
std::for_each(route_parameters.waypoints.begin(),
|
||||
route_parameters.waypoints.end(),
|
||||
[&](const std::size_t waypoint_index) {
|
||||
[&](const std::size_t waypoint_index)
|
||||
{
|
||||
BOOST_ASSERT(waypoint_index < waypoint_legs.size());
|
||||
waypoint_legs[waypoint_index] = true;
|
||||
});
|
||||
@@ -156,22 +157,23 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
else
|
||||
{
|
||||
const auto all_in_same_component =
|
||||
[](const std::vector<PhantomNodeCandidates> &waypoint_candidates) {
|
||||
return std::any_of(waypoint_candidates.front().begin(),
|
||||
waypoint_candidates.front().end(),
|
||||
// For each of the first possible phantoms, check if all other
|
||||
// positions in the list have a phantom from the same component.
|
||||
[&](const PhantomNode &phantom) {
|
||||
const auto component_id = phantom.component.id;
|
||||
return std::all_of(
|
||||
std::next(waypoint_candidates.begin()),
|
||||
std::end(waypoint_candidates),
|
||||
[component_id](const PhantomNodeCandidates &candidates) {
|
||||
return candidatesHaveComponent(candidates,
|
||||
component_id);
|
||||
});
|
||||
});
|
||||
};
|
||||
[](const std::vector<PhantomNodeCandidates> &waypoint_candidates)
|
||||
{
|
||||
return std::any_of(waypoint_candidates.front().begin(),
|
||||
waypoint_candidates.front().end(),
|
||||
// For each of the first possible phantoms, check if all other
|
||||
// positions in the list have a phantom from the same component.
|
||||
[&](const PhantomNode &phantom)
|
||||
{
|
||||
const auto component_id = phantom.component.id;
|
||||
return std::all_of(
|
||||
std::next(waypoint_candidates.begin()),
|
||||
std::end(waypoint_candidates),
|
||||
[component_id](const PhantomNodeCandidates &candidates) {
|
||||
return candidatesHaveComponent(candidates, component_id);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (!all_in_same_component(snapped_phantoms))
|
||||
{
|
||||
|
||||
@@ -223,9 +223,8 @@ RandIt filterViaCandidatesByStretch(RandIt first,
|
||||
const auto stretch_weight_limit =
|
||||
(1. + parameters.kAtMostLongerBy) * from_alias<double>(weight);
|
||||
|
||||
const auto over_weight_limit = [=](const auto via) {
|
||||
return from_alias<double>(via.weight) > stretch_weight_limit;
|
||||
};
|
||||
const auto over_weight_limit = [=](const auto via)
|
||||
{ return from_alias<double>(via.weight) > stretch_weight_limit; };
|
||||
|
||||
return std::remove_if(first, last, over_weight_limit);
|
||||
}
|
||||
@@ -298,13 +297,15 @@ RandIt filterPackedPathsByCellSharing(RandIt first,
|
||||
for (const auto &edge : shortest_path.path)
|
||||
cells.insert(get_cell(std::get<1>(edge)));
|
||||
|
||||
const auto over_sharing_limit = [&](const auto &packed) {
|
||||
const auto over_sharing_limit = [&](const auto &packed)
|
||||
{
|
||||
if (packed.path.empty())
|
||||
{ // don't remove routes with single-node (empty) path
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto not_seen = [&](const PackedEdge edge) {
|
||||
const auto not_seen = [&](const PackedEdge edge)
|
||||
{
|
||||
const auto source_cell = get_cell(std::get<0>(edge));
|
||||
const auto target_cell = get_cell(std::get<1>(edge));
|
||||
return cells.count(source_cell) < 1 && cells.count(target_cell) < 1;
|
||||
@@ -364,7 +365,8 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
||||
BOOST_ASSERT(path.via.weight != INVALID_EDGE_WEIGHT);
|
||||
|
||||
// node == parent_in_main_heap(parent_in_side_heap(v)) -> plateaux at `node`
|
||||
const auto has_plateaux_at_node = [&](const NodeID node, const Heap &fst, const Heap &snd) {
|
||||
const auto has_plateaux_at_node = [&](const NodeID node, const Heap &fst, const Heap &snd)
|
||||
{
|
||||
BOOST_ASSERT(fst.WasInserted(node));
|
||||
auto const parent = fst.GetData(node).parent;
|
||||
return snd.WasInserted(parent) && snd.GetData(parent).parent == node;
|
||||
@@ -374,7 +376,8 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
||||
// tree from t overlap. An edge is part of such a plateaux around `v` if:
|
||||
// v == parent_in_reverse_search(parent_in_forward_search(v)).
|
||||
// Here we calculate the last node on the plateaux in either direction.
|
||||
const auto plateaux_end = [&](NodeID node, const Heap &fst, const Heap &snd) {
|
||||
const auto plateaux_end = [&](NodeID node, const Heap &fst, const Heap &snd)
|
||||
{
|
||||
BOOST_ASSERT(node != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(fst.WasInserted(node));
|
||||
BOOST_ASSERT(snd.WasInserted(node));
|
||||
@@ -388,7 +391,8 @@ RandIt filterPackedPathsByLocalOptimality(const WeightedViaNodePackedPath &path,
|
||||
return node;
|
||||
};
|
||||
|
||||
const auto is_not_locally_optimal = [&](const auto &packed) {
|
||||
const auto is_not_locally_optimal = [&](const auto &packed)
|
||||
{
|
||||
BOOST_ASSERT(packed.via.node != path.via.node);
|
||||
BOOST_ASSERT(packed.via.weight != INVALID_EDGE_WEIGHT);
|
||||
BOOST_ASSERT(packed.via.node != SPECIAL_NODEID);
|
||||
@@ -475,14 +479,16 @@ RandIt filterUnpackedPathsBySharing(RandIt first,
|
||||
|
||||
nodes.insert(begin(shortest_path.nodes), end(shortest_path.nodes));
|
||||
|
||||
const auto over_sharing_limit = [&](auto &unpacked) {
|
||||
const auto over_sharing_limit = [&](auto &unpacked)
|
||||
{
|
||||
if (unpacked.edges.empty())
|
||||
{ // don't remove routes with single-node (empty) path
|
||||
return false;
|
||||
}
|
||||
|
||||
EdgeDuration total_duration = {0};
|
||||
const auto add_if_seen = [&](const EdgeDuration duration, const NodeID node) {
|
||||
const auto add_if_seen = [&](const EdgeDuration duration, const NodeID node)
|
||||
{
|
||||
auto node_duration = facade.GetNodeDuration(node);
|
||||
total_duration += node_duration;
|
||||
if (nodes.count(node) > 0)
|
||||
@@ -533,9 +539,8 @@ RandIt filterAnnotatedRoutesByStretch(RandIt first,
|
||||
const auto stretch_duration_limit =
|
||||
(1. + parameters.kAtMostLongerBy) * from_alias<double>(shortest_route_duration);
|
||||
|
||||
const auto over_duration_limit = [=](const auto &route) {
|
||||
return from_alias<double>(route.duration()) > stretch_duration_limit;
|
||||
};
|
||||
const auto over_duration_limit = [=](const auto &route)
|
||||
{ return from_alias<double>(route.duration()) > stretch_duration_limit; };
|
||||
|
||||
return std::remove_if(first, last, over_duration_limit);
|
||||
}
|
||||
@@ -837,9 +842,9 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
it = filterViaCandidatesByStretch(begin(candidate_vias), it, shortest_path_weight, parameters);
|
||||
|
||||
// Pre-rank by weight; sharing filtering below then discards by similarity.
|
||||
std::sort(begin(candidate_vias), it, [](const auto lhs, const auto rhs) {
|
||||
return lhs.weight < rhs.weight;
|
||||
});
|
||||
std::sort(begin(candidate_vias),
|
||||
it,
|
||||
[](const auto lhs, const auto rhs) { return lhs.weight < rhs.weight; });
|
||||
|
||||
// Filtered and ranked candidate range
|
||||
const auto candidate_vias_first = begin(candidate_vias);
|
||||
@@ -850,7 +855,8 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
// The recursive path unpacking below destructs heaps.
|
||||
// We need to save all packed paths from the heaps upfront.
|
||||
|
||||
const auto extract_packed_path_from_heaps = [&](WeightedViaNode via) {
|
||||
const auto extract_packed_path_from_heaps = [&](WeightedViaNode via)
|
||||
{
|
||||
auto packed_path = retrievePackedPathFromHeap(forward_heap, reverse_heap, via.node);
|
||||
|
||||
return WeightedViaNodePackedPath{via, std::move(packed_path)};
|
||||
@@ -928,9 +934,8 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
std::vector<InternalRouteResult> routes;
|
||||
routes.reserve(number_of_unpacked_paths);
|
||||
|
||||
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) {
|
||||
return extractRoute(facade, path.via.weight, endpoint_candidates, path.nodes, path.edges);
|
||||
};
|
||||
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path)
|
||||
{ return extractRoute(facade, path.via.weight, endpoint_candidates, path.nodes, path.edges); };
|
||||
|
||||
std::transform(unpacked_paths_first,
|
||||
unpacked_paths_last,
|
||||
|
||||
@@ -45,15 +45,16 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
||||
unpacked_nodes.reserve(packed_leg.size());
|
||||
unpacked_edges.reserve(packed_leg.size());
|
||||
unpacked_nodes.push_back(packed_leg.front());
|
||||
ch::unpackPath(facade,
|
||||
packed_leg.begin(),
|
||||
packed_leg.end(),
|
||||
[&unpacked_nodes, &unpacked_edges](std::pair<NodeID, NodeID> &edge,
|
||||
const auto &edge_id) {
|
||||
BOOST_ASSERT(edge.first == unpacked_nodes.back());
|
||||
unpacked_nodes.push_back(edge.second);
|
||||
unpacked_edges.push_back(edge_id);
|
||||
});
|
||||
ch::unpackPath(
|
||||
facade,
|
||||
packed_leg.begin(),
|
||||
packed_leg.end(),
|
||||
[&unpacked_nodes, &unpacked_edges](std::pair<NodeID, NodeID> &edge, const auto &edge_id)
|
||||
{
|
||||
BOOST_ASSERT(edge.first == unpacked_nodes.back());
|
||||
unpacked_nodes.push_back(edge.second);
|
||||
unpacked_edges.push_back(edge_id);
|
||||
});
|
||||
}
|
||||
|
||||
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
|
||||
|
||||
@@ -95,7 +95,7 @@ void relaxOutgoingEdges(
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const Args &... args)
|
||||
const Args &...args)
|
||||
{
|
||||
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
|
||||
|
||||
@@ -280,49 +280,51 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
// Check if node is in the destinations list and update weights/durations
|
||||
auto update_values =
|
||||
[&](NodeID node, EdgeWeight weight, EdgeDuration duration, EdgeDistance distance) {
|
||||
auto candidates = target_nodes_index.equal_range(node);
|
||||
for (auto it = candidates.first; it != candidates.second;)
|
||||
[&](NodeID node, EdgeWeight weight, EdgeDuration duration, EdgeDistance distance)
|
||||
{
|
||||
auto candidates = target_nodes_index.equal_range(node);
|
||||
for (auto it = candidates.first; it != candidates.second;)
|
||||
{
|
||||
std::size_t index;
|
||||
EdgeWeight target_weight;
|
||||
EdgeDuration target_duration;
|
||||
EdgeDistance target_distance;
|
||||
std::tie(index, target_weight, target_duration, target_distance) = it->second;
|
||||
|
||||
const auto path_weight = weight + target_weight;
|
||||
if (path_weight >= EdgeWeight{0})
|
||||
{
|
||||
std::size_t index;
|
||||
EdgeWeight target_weight;
|
||||
EdgeDuration target_duration;
|
||||
EdgeDistance target_distance;
|
||||
std::tie(index, target_weight, target_duration, target_distance) = it->second;
|
||||
const auto path_duration = duration + target_duration;
|
||||
const auto path_distance = distance + target_distance;
|
||||
|
||||
const auto path_weight = weight + target_weight;
|
||||
if (path_weight >= EdgeWeight{0})
|
||||
EdgeDistance nulldistance = {0};
|
||||
auto ¤t_distance =
|
||||
distances_table.empty() ? nulldistance : distances_table[index];
|
||||
|
||||
if (std::tie(path_weight, path_duration, path_distance) <
|
||||
std::tie(weights_table[index], durations_table[index], current_distance))
|
||||
{
|
||||
const auto path_duration = duration + target_duration;
|
||||
const auto path_distance = distance + target_distance;
|
||||
|
||||
EdgeDistance nulldistance = {0};
|
||||
auto ¤t_distance =
|
||||
distances_table.empty() ? nulldistance : distances_table[index];
|
||||
|
||||
if (std::tie(path_weight, path_duration, path_distance) <
|
||||
std::tie(weights_table[index], durations_table[index], current_distance))
|
||||
{
|
||||
weights_table[index] = path_weight;
|
||||
durations_table[index] = path_duration;
|
||||
current_distance = path_distance;
|
||||
middle_nodes_table[index] = node;
|
||||
}
|
||||
|
||||
// Remove node from destinations list
|
||||
it = target_nodes_index.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
weights_table[index] = path_weight;
|
||||
durations_table[index] = path_duration;
|
||||
current_distance = path_distance;
|
||||
middle_nodes_table[index] = node;
|
||||
}
|
||||
|
||||
// Remove node from destinations list
|
||||
it = target_nodes_index.erase(it);
|
||||
}
|
||||
};
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto insert_node = [&](NodeID node,
|
||||
EdgeWeight initial_weight,
|
||||
EdgeDuration initial_duration,
|
||||
EdgeDistance initial_distance) {
|
||||
EdgeDistance initial_distance)
|
||||
{
|
||||
if (target_nodes_index.count(node))
|
||||
{
|
||||
// Source and target on the same edge node. If target is not reachable directly via
|
||||
|
||||
@@ -83,7 +83,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
const bool use_timestamps = trace_timestamps.size() > 1;
|
||||
|
||||
const auto median_sample_time = [&] {
|
||||
const auto median_sample_time = [&]
|
||||
{
|
||||
if (use_timestamps)
|
||||
{
|
||||
return std::max(1u, getMedianSampleTime(trace_timestamps));
|
||||
@@ -104,9 +105,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
std::transform(candidates_list[t].begin(),
|
||||
candidates_list[t].end(),
|
||||
emission_log_probabilities[t].begin(),
|
||||
[&](const PhantomNodeWithDistance &candidate) {
|
||||
return default_emission_log_probability(candidate.distance);
|
||||
});
|
||||
[&](const PhantomNodeWithDistance &candidate)
|
||||
{ return default_emission_log_probability(candidate.distance); });
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -118,22 +118,19 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
{
|
||||
map_matching::EmissionLogProbability emission_log_probability(
|
||||
*trace_gps_precision[t]);
|
||||
std::transform(
|
||||
candidates_list[t].begin(),
|
||||
candidates_list[t].end(),
|
||||
emission_log_probabilities[t].begin(),
|
||||
[&emission_log_probability](const PhantomNodeWithDistance &candidate) {
|
||||
return emission_log_probability(candidate.distance);
|
||||
});
|
||||
std::transform(candidates_list[t].begin(),
|
||||
candidates_list[t].end(),
|
||||
emission_log_probabilities[t].begin(),
|
||||
[&emission_log_probability](const PhantomNodeWithDistance &candidate)
|
||||
{ return emission_log_probability(candidate.distance); });
|
||||
}
|
||||
else
|
||||
{
|
||||
std::transform(candidates_list[t].begin(),
|
||||
candidates_list[t].end(),
|
||||
emission_log_probabilities[t].begin(),
|
||||
[&](const PhantomNodeWithDistance &candidate) {
|
||||
return default_emission_log_probability(candidate.distance);
|
||||
});
|
||||
[&](const PhantomNodeWithDistance &candidate)
|
||||
{ return default_emission_log_probability(candidate.distance); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,7 +155,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
||||
{
|
||||
|
||||
const auto step_time = [&] {
|
||||
const auto step_time = [&]
|
||||
{
|
||||
if (use_timestamps)
|
||||
{
|
||||
return trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()];
|
||||
@@ -169,7 +167,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
}
|
||||
}();
|
||||
|
||||
const auto max_distance_delta = [&] {
|
||||
const auto max_distance_delta = [&]
|
||||
{
|
||||
if (use_timestamps)
|
||||
{
|
||||
return step_time * facade.GetMapMatchingMaxSpeed();
|
||||
@@ -180,7 +179,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
}
|
||||
}();
|
||||
|
||||
const bool gap_in_trace = [&]() {
|
||||
const bool gap_in_trace = [&]()
|
||||
{
|
||||
// use temporal information if available to determine a split
|
||||
// but do not determine split by timestamps if wasn't asked about it
|
||||
if (use_timestamps && allow_splitting)
|
||||
@@ -419,7 +419,8 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
|
||||
util::for_each_pair(
|
||||
reconstructed_indices,
|
||||
[&trace_distance, &trace_coordinates](const std::pair<std::size_t, std::size_t> &prev,
|
||||
const std::pair<std::size_t, std::size_t> &curr) {
|
||||
const std::pair<std::size_t, std::size_t> &curr)
|
||||
{
|
||||
trace_distance += util::coordinate_calculation::greatCircleDistance(
|
||||
trace_coordinates[prev.first], trace_coordinates[curr.first]);
|
||||
});
|
||||
|
||||
@@ -25,9 +25,8 @@ std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &endpoin
|
||||
auto requires_loop =
|
||||
std::any_of(endpoint_candidates.target_phantoms.begin(),
|
||||
endpoint_candidates.target_phantoms.end(),
|
||||
[&](const auto &target_phantom) {
|
||||
return requiresForwardLoop(source_phantom, target_phantom);
|
||||
});
|
||||
[&](const auto &target_phantom)
|
||||
{ return requiresForwardLoop(source_phantom, target_phantom); });
|
||||
if (requires_loop)
|
||||
{
|
||||
res.push_back(source_phantom.forward_segment_id.id);
|
||||
@@ -57,9 +56,8 @@ std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &endpoi
|
||||
auto requires_loop =
|
||||
std::any_of(endpoint_candidates.target_phantoms.begin(),
|
||||
endpoint_candidates.target_phantoms.end(),
|
||||
[&](const auto &target_phantom) {
|
||||
return requiresBackwardLoop(source_phantom, target_phantom);
|
||||
});
|
||||
[&](const auto &target_phantom)
|
||||
{ return requiresBackwardLoop(source_phantom, target_phantom); });
|
||||
if (requires_loop)
|
||||
{
|
||||
res.push_back(source_phantom.reverse_segment_id.id);
|
||||
@@ -86,7 +84,8 @@ PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candid
|
||||
{
|
||||
auto source_it = std::find_if(candidates.source_phantoms.begin(),
|
||||
candidates.source_phantoms.end(),
|
||||
[&path](const auto &source_phantom) {
|
||||
[&path](const auto &source_phantom)
|
||||
{
|
||||
return path.front() == source_phantom.forward_segment_id.id ||
|
||||
path.front() == source_phantom.reverse_segment_id.id;
|
||||
});
|
||||
@@ -94,7 +93,8 @@ PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candid
|
||||
|
||||
auto target_it = std::find_if(candidates.target_phantoms.begin(),
|
||||
candidates.target_phantoms.end(),
|
||||
[&path](const auto &target_phantom) {
|
||||
[&path](const auto &target_phantom)
|
||||
{
|
||||
return path.back() == target_phantom.forward_segment_id.id ||
|
||||
path.back() == target_phantom.reverse_segment_id.id;
|
||||
});
|
||||
|
||||
@@ -19,9 +19,8 @@ void unpackEdge(const DataFacade<Algorithm> &facade,
|
||||
unpackPath(facade,
|
||||
path.begin(),
|
||||
path.end(),
|
||||
[&unpacked_path](const std::pair<NodeID, NodeID> &edge, const auto & /* data */) {
|
||||
unpacked_path.emplace_back(edge.first);
|
||||
});
|
||||
[&unpacked_path](const std::pair<NodeID, NodeID> &edge, const auto & /* data */)
|
||||
{ unpacked_path.emplace_back(edge.first); });
|
||||
unpacked_path.emplace_back(to);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,8 @@ std::vector<TurnData> generateTurns(const datafacade &facade,
|
||||
// it saves us a bunch of re-allocations during iteration.
|
||||
directed_graph.reserve(edges.size() * 2);
|
||||
|
||||
const auto get_geometry_id = [&facade](auto edge) {
|
||||
return facade.GetGeometryIndex(edge.forward_segment_id.id).id;
|
||||
};
|
||||
const auto get_geometry_id = [&facade](auto edge)
|
||||
{ return facade.GetGeometryIndex(edge.forward_segment_id.id).id; };
|
||||
|
||||
// To build a tile, we can only rely on the r-tree to quickly find all data visible within the
|
||||
// tile itself. The Rtree returns a series of segments that may or may not offer turns
|
||||
@@ -215,10 +214,10 @@ std::vector<TurnData> getTileTurns(const DataFacade<ch::Algorithm> &facade,
|
||||
//
|
||||
// would offer a backward edge at `b` to `a` (due to the oneway from a to b)
|
||||
// but could also offer a shortcut (b-c-a) from `b` to `a` which is longer.
|
||||
EdgeID edge_id = facade.FindSmallestEdge(
|
||||
approach_node, exit_node, [](const contractor::QueryEdge::EdgeData &data) {
|
||||
return data.forward && !data.shortcut;
|
||||
});
|
||||
EdgeID edge_id = facade.FindSmallestEdge(approach_node,
|
||||
exit_node,
|
||||
[](const contractor::QueryEdge::EdgeData &data)
|
||||
{ return data.forward && !data.shortcut; });
|
||||
|
||||
// Depending on how the graph is constructed, we might have to look for
|
||||
// a backwards edge instead. They're equivalent, just one is available for
|
||||
@@ -227,10 +226,10 @@ std::vector<TurnData> getTileTurns(const DataFacade<ch::Algorithm> &facade,
|
||||
// If we didn't find a forward edge, try for a backward one
|
||||
if (SPECIAL_EDGEID == edge_id)
|
||||
{
|
||||
edge_id = facade.FindSmallestEdge(
|
||||
exit_node, approach_node, [](const contractor::QueryEdge::EdgeData &data) {
|
||||
return data.backward && !data.shortcut;
|
||||
});
|
||||
edge_id = facade.FindSmallestEdge(exit_node,
|
||||
approach_node,
|
||||
[](const contractor::QueryEdge::EdgeData &data)
|
||||
{ return data.backward && !data.shortcut; });
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(edge_id == SPECIAL_EDGEID || !facade.GetEdgeData(edge_id).shortcut,
|
||||
|
||||
@@ -151,7 +151,8 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
|
||||
NodeID current_edge_source_coordinate_id = node_u;
|
||||
|
||||
const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id) {
|
||||
const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id)
|
||||
{
|
||||
if (edge_based_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
return SegmentID{SPECIAL_SEGMENTID, false};
|
||||
@@ -409,7 +410,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
||||
NodeID current_edge_source_coordinate_id = node_u;
|
||||
const EdgeData &forward_data = m_node_based_graph.GetEdgeData(eid);
|
||||
|
||||
const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id) {
|
||||
const auto edge_id_to_segment_id = [](const NodeID edge_based_node_id)
|
||||
{
|
||||
if (edge_based_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
return SegmentID{SPECIAL_SEGMENTID, false};
|
||||
@@ -532,7 +534,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
TurnPenalty turn_duration_penalty;
|
||||
};
|
||||
|
||||
auto const transfer_data = [&](const EdgeWithData &edge_with_data) {
|
||||
auto const transfer_data = [&](const EdgeWithData &edge_with_data)
|
||||
{
|
||||
m_edge_based_edge_list.push_back(edge_with_data.edge);
|
||||
turn_weight_penalties.push_back(edge_with_data.turn_weight_penalty);
|
||||
turn_duration_penalties.push_back(edge_with_data.turn_duration_penalty);
|
||||
@@ -568,7 +571,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
// First part of the pipeline generates iterator ranges of IDs in sets of GRAINSIZE
|
||||
tbb::filter<void, tbb::blocked_range<NodeID>> generator_stage(
|
||||
tbb::filter_mode::serial_in_order, [&](tbb::flow_control &fc) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&](tbb::flow_control &fc)
|
||||
{
|
||||
if (current_node < node_count)
|
||||
{
|
||||
auto next_node = std::min(current_node + GRAINSIZE, node_count);
|
||||
@@ -599,7 +604,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto &turn_angle,
|
||||
const auto &road_legs_on_the_right,
|
||||
const auto &road_legs_on_the_left,
|
||||
const auto &edge_geometries) {
|
||||
const auto &edge_geometries)
|
||||
{
|
||||
const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from);
|
||||
const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to);
|
||||
|
||||
@@ -710,7 +716,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
//
|
||||
tbb::filter<tbb::blocked_range<NodeID>, EdgesPipelineBufferPtr> processor_stage(
|
||||
tbb::filter_mode::parallel,
|
||||
[&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
||||
[&](const tbb::blocked_range<NodeID> &intersection_node_range)
|
||||
{
|
||||
auto buffer = std::make_shared<EdgesPipelineBuffer>();
|
||||
buffer->nodes_processed = intersection_node_range.size();
|
||||
|
||||
@@ -795,16 +802,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
const auto turn =
|
||||
std::find_if(connected_roads.begin(),
|
||||
connected_roads.end(),
|
||||
[edge = outgoing_edge.edge](const auto &road) {
|
||||
return road.eid == edge;
|
||||
});
|
||||
[edge = outgoing_edge.edge](const auto &road)
|
||||
{ return road.eid == edge; });
|
||||
OSRM_ASSERT(turn != connected_roads.end(),
|
||||
m_coordinates[intersection_node]);
|
||||
|
||||
std::vector<ExtractionTurnLeg> road_legs_on_the_right;
|
||||
std::vector<ExtractionTurnLeg> road_legs_on_the_left;
|
||||
|
||||
auto get_connected_road_info = [&](const auto &connected_edge) {
|
||||
auto get_connected_road_info = [&](const auto &connected_edge)
|
||||
{
|
||||
const auto &edge_data =
|
||||
m_node_based_graph.GetEdgeData(connected_edge.eid);
|
||||
|
||||
@@ -1012,9 +1019,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
auto const has_unconditional =
|
||||
std::any_of(restrictions.begin(),
|
||||
restrictions.end(),
|
||||
[](const auto &restriction) {
|
||||
return restriction->IsUnconditional();
|
||||
});
|
||||
[](const auto &restriction)
|
||||
{ return restriction->IsUnconditional(); });
|
||||
if (has_unconditional)
|
||||
continue;
|
||||
|
||||
@@ -1120,7 +1126,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
util::Percent routing_progress(log, node_count);
|
||||
std::vector<EdgeWithData> delayed_data;
|
||||
tbb::filter<EdgesPipelineBufferPtr, void> output_stage(
|
||||
tbb::filter_mode::serial_in_order, [&](auto buffer) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&](auto buffer)
|
||||
{
|
||||
routing_progress.PrintAddition(buffer->nodes_processed);
|
||||
|
||||
m_connectivity_checksum = buffer->checksum.update_checksum(m_connectivity_checksum);
|
||||
@@ -1140,7 +1148,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
std::for_each(buffer->turn_to_ebn_map.begin(),
|
||||
buffer->turn_to_ebn_map.end(),
|
||||
[&global_turn_to_ebn_map](const auto &p) {
|
||||
[&global_turn_to_ebn_map](const auto &p)
|
||||
{
|
||||
// TODO: log conflicts here
|
||||
global_turn_to_ebn_map.insert(p);
|
||||
});
|
||||
@@ -1178,26 +1187,32 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
return std::vector<NodeID>{turn_edges.second.first, turn_edges.second.second};
|
||||
});
|
||||
|
||||
std::for_each(std::next(turns.begin()), turns.end(), [&](const auto &turn) {
|
||||
std::vector<std::vector<NodeID>> next_node_sequences;
|
||||
const auto next_turn_edges = global_turn_to_ebn_map.equal_range(turn);
|
||||
for (auto &node_sequence : node_sequences)
|
||||
{
|
||||
const auto found_it = std::find_if(
|
||||
next_turn_edges.first, next_turn_edges.second, [&](const auto &turn_edges) {
|
||||
const auto pre_turn_edge = turn_edges.second.first;
|
||||
return (node_sequence.back() == pre_turn_edge);
|
||||
});
|
||||
std::for_each(std::next(turns.begin()),
|
||||
turns.end(),
|
||||
[&](const auto &turn)
|
||||
{
|
||||
std::vector<std::vector<NodeID>> next_node_sequences;
|
||||
const auto next_turn_edges = global_turn_to_ebn_map.equal_range(turn);
|
||||
for (auto &node_sequence : node_sequences)
|
||||
{
|
||||
const auto found_it = std::find_if(
|
||||
next_turn_edges.first,
|
||||
next_turn_edges.second,
|
||||
[&](const auto &turn_edges)
|
||||
{
|
||||
const auto pre_turn_edge = turn_edges.second.first;
|
||||
return (node_sequence.back() == pre_turn_edge);
|
||||
});
|
||||
|
||||
if (found_it != next_turn_edges.second)
|
||||
{
|
||||
const auto post_turn_edge = found_it->second.second;
|
||||
node_sequence.push_back(post_turn_edge);
|
||||
next_node_sequences.push_back(std::move(node_sequence));
|
||||
}
|
||||
}
|
||||
node_sequences = std::move(next_node_sequences);
|
||||
});
|
||||
if (found_it != next_turn_edges.second)
|
||||
{
|
||||
const auto post_turn_edge = found_it->second.second;
|
||||
node_sequence.push_back(post_turn_edge);
|
||||
next_node_sequences.push_back(std::move(node_sequence));
|
||||
}
|
||||
}
|
||||
node_sequences = std::move(next_node_sequences);
|
||||
});
|
||||
|
||||
for (const auto &node_sequence : node_sequences)
|
||||
{
|
||||
@@ -1237,7 +1252,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// Now, update the turn_id property on every EdgeBasedEdge - it will equal the position in the
|
||||
// m_edge_based_edge_list array for each object.
|
||||
tbb::parallel_for(tbb::blocked_range<NodeID>(0, m_edge_based_edge_list.size()),
|
||||
[this](const tbb::blocked_range<NodeID> &range) {
|
||||
[this](const tbb::blocked_range<NodeID> &range)
|
||||
{
|
||||
for (auto x = range.begin(), end = range.end(); x != end; ++x)
|
||||
{
|
||||
m_edge_based_edge_list[x].data.turn_id = x;
|
||||
|
||||
@@ -460,10 +460,10 @@ void ExtractionContainers::PrepareNodes()
|
||||
util::UnbufferedLog log;
|
||||
log << "Sorting all nodes ... " << std::flush;
|
||||
TIMER_START(sorting_nodes);
|
||||
tbb::parallel_sort(
|
||||
all_nodes_list.begin(), all_nodes_list.end(), [](const auto &left, const auto &right) {
|
||||
return left.node_id < right.node_id;
|
||||
});
|
||||
tbb::parallel_sort(all_nodes_list.begin(),
|
||||
all_nodes_list.end(),
|
||||
[](const auto &left, const auto &right)
|
||||
{ return left.node_id < right.node_id; });
|
||||
TIMER_STOP(sorting_nodes);
|
||||
log << "ok, after " << TIMER_SEC(sorting_nodes) << "s";
|
||||
}
|
||||
@@ -629,7 +629,8 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
|
||||
// Remove all remaining edges. They are invalid because there are no corresponding nodes for
|
||||
// them. This happens when using osmosis with bbox or polygon to extract smaller areas.
|
||||
auto markSourcesInvalid = [](InternalExtractorEdge &edge) {
|
||||
auto markSourcesInvalid = [](InternalExtractorEdge &edge)
|
||||
{
|
||||
util::Log(logDEBUG) << "Found invalid node reference " << edge.result.source;
|
||||
edge.result.source = SPECIAL_NODEID;
|
||||
edge.result.osm_source_id = SPECIAL_OSM_NODEID;
|
||||
@@ -743,7 +744,8 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
|
||||
// Remove all remaining edges. They are invalid because there are no corresponding nodes for
|
||||
// them. This happens when using osmosis with bbox or polygon to extract smaller areas.
|
||||
auto markTargetsInvalid = [](InternalExtractorEdge &edge) {
|
||||
auto markTargetsInvalid = [](InternalExtractorEdge &edge)
|
||||
{
|
||||
util::Log(logDEBUG) << "Found invalid node reference " << edge.result.target;
|
||||
edge.result.target = SPECIAL_NODEID;
|
||||
};
|
||||
@@ -898,7 +900,8 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverr
|
||||
<< " maneuver overrides...";
|
||||
TIMER_START(identify_maneuver_override_ways);
|
||||
|
||||
const auto mark_ids = [&](auto const &external_maneuver_override) {
|
||||
const auto mark_ids = [&](auto const &external_maneuver_override)
|
||||
{
|
||||
NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
|
||||
const auto &turn_path = external_maneuver_override.turn_path;
|
||||
maneuver_override_ways[turn_path.From()] = dummy_segment;
|
||||
@@ -918,7 +921,8 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverr
|
||||
std::for_each(
|
||||
external_maneuver_overrides_list.begin(), external_maneuver_overrides_list.end(), mark_ids);
|
||||
|
||||
const auto set_ids = [&](size_t way_list_idx, auto const &way_id) {
|
||||
const auto set_ids = [&](size_t way_list_idx, auto const &way_id)
|
||||
{
|
||||
auto itr = maneuver_override_ways.find(way_id);
|
||||
if (itr != maneuver_override_ways.end())
|
||||
{
|
||||
@@ -984,7 +988,8 @@ void ExtractionContainers::PrepareTrafficSignals(
|
||||
|
||||
void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways)
|
||||
{
|
||||
auto const osm_node_to_internal_nbn = [&](auto const osm_node) {
|
||||
auto const osm_node_to_internal_nbn = [&](auto const osm_node)
|
||||
{
|
||||
auto internal = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), osm_node);
|
||||
if (internal == SPECIAL_NODEID)
|
||||
@@ -994,8 +999,9 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
return internal;
|
||||
};
|
||||
|
||||
const auto strings_to_turn_type_and_direction = [](const std::string &turn_string,
|
||||
const std::string &direction_string) {
|
||||
const auto strings_to_turn_type_and_direction =
|
||||
[](const std::string &turn_string, const std::string &direction_string)
|
||||
{
|
||||
auto result = std::make_pair(guidance::TurnType::MaxTurnType,
|
||||
guidance::DirectionModifier::MaxDirectionModifier);
|
||||
|
||||
@@ -1059,7 +1065,8 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
// Returns true on successful transformation, false in case of invalid references.
|
||||
// Later, the UnresolvedManeuverOverride will be converted into a final ManeuverOverride
|
||||
// once the edge-based-node IDs are generated by the edge-based-graph-factory
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type)
|
||||
{
|
||||
if (external_type.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
auto const &external = external_type.turn_path.AsViaWayPath();
|
||||
@@ -1092,11 +1099,12 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
};
|
||||
|
||||
const auto transform_into_internal_types =
|
||||
[&](const InputManeuverOverride &external_maneuver_override) {
|
||||
UnresolvedManeuverOverride internal_maneuver_override;
|
||||
if (transform(external_maneuver_override, internal_maneuver_override))
|
||||
internal_maneuver_overrides.push_back(std::move(internal_maneuver_override));
|
||||
};
|
||||
[&](const InputManeuverOverride &external_maneuver_override)
|
||||
{
|
||||
UnresolvedManeuverOverride internal_maneuver_override;
|
||||
if (transform(external_maneuver_override, internal_maneuver_override))
|
||||
internal_maneuver_overrides.push_back(std::move(internal_maneuver_override));
|
||||
};
|
||||
|
||||
// Transforming the overrides into the dedicated internal types
|
||||
{
|
||||
@@ -1124,7 +1132,8 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa
|
||||
|
||||
// Enter invalid IDs into the map to indicate that we want to find out about
|
||||
// nodes of these ways.
|
||||
const auto mark_ids = [&](auto const &turn_restriction) {
|
||||
const auto mark_ids = [&](auto const &turn_restriction)
|
||||
{
|
||||
NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
|
||||
const auto &turn_path = turn_restriction.turn_path;
|
||||
restriction_ways[turn_path.From()] = dummy_segment;
|
||||
@@ -1142,7 +1151,8 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa
|
||||
std::for_each(restrictions_list.begin(), restrictions_list.end(), mark_ids);
|
||||
|
||||
// Update the values for all ways already sporting SPECIAL_NODEID
|
||||
const auto set_ids = [&](const size_t way_list_idx, auto const &way_id) {
|
||||
const auto set_ids = [&](const size_t way_list_idx, auto const &way_id)
|
||||
{
|
||||
auto itr = restriction_ways.find(way_id);
|
||||
if (itr != restriction_ways.end())
|
||||
{
|
||||
@@ -1178,7 +1188,8 @@ ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTra
|
||||
|
||||
std::unordered_set<OSMNodeID> bidirectional_signals;
|
||||
|
||||
const auto mark_signals = [&](auto const &traffic_signal) {
|
||||
const auto mark_signals = [&](auto const &traffic_signal)
|
||||
{
|
||||
if (traffic_signal.second == TrafficLightClass::DIRECTION_FORWARD ||
|
||||
traffic_signal.second == TrafficLightClass::DIRECTION_REVERSE)
|
||||
{
|
||||
@@ -1193,7 +1204,8 @@ ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTra
|
||||
std::for_each(external_traffic_signals.begin(), external_traffic_signals.end(), mark_signals);
|
||||
|
||||
// Extract all the segments that lead up to unidirectional traffic signals.
|
||||
const auto set_segments = [&](const size_t way_list_idx, auto const & /*unused*/) {
|
||||
const auto set_segments = [&](const size_t way_list_idx, auto const & /*unused*/)
|
||||
{
|
||||
const auto node_start_offset =
|
||||
used_node_id_list.begin() + way_node_id_offsets[way_list_idx];
|
||||
const auto node_end_offset =
|
||||
@@ -1227,7 +1239,9 @@ ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTra
|
||||
util::for_each_indexed(ways_list.cbegin(), ways_list.cend(), set_segments);
|
||||
|
||||
util::for_each_pair(
|
||||
signal_segments, [](const auto pair_a, const auto pair_b) {
|
||||
signal_segments,
|
||||
[](const auto pair_a, const auto pair_b)
|
||||
{
|
||||
if (pair_a.first == pair_b.first)
|
||||
{
|
||||
// If a node is appearing multiple times in this map, then it's ambiguous.
|
||||
@@ -1252,7 +1266,8 @@ ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTra
|
||||
void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction_ways)
|
||||
{
|
||||
|
||||
auto const to_internal = [&](auto const osm_node) {
|
||||
auto const to_internal = [&](auto const osm_node)
|
||||
{
|
||||
auto internal = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), osm_node);
|
||||
if (internal == SPECIAL_NODEID)
|
||||
@@ -1264,7 +1279,8 @@ void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction
|
||||
|
||||
// Transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs).
|
||||
// Returns true on successful transformation, false in case of invalid references.
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type)
|
||||
{
|
||||
if (external_type.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
auto const &external = external_type.turn_path.AsViaWayPath();
|
||||
@@ -1293,7 +1309,8 @@ void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction
|
||||
return internal_type.Valid();
|
||||
};
|
||||
|
||||
const auto transform_into_internal_types = [&](InputTurnRestriction &external_restriction) {
|
||||
const auto transform_into_internal_types = [&](InputTurnRestriction &external_restriction)
|
||||
{
|
||||
TurnRestriction restriction;
|
||||
if (transform(external_restriction, restriction))
|
||||
{
|
||||
|
||||
+21
-11
@@ -442,9 +442,12 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting
|
||||
|
||||
ExtractionRelationContainer relations;
|
||||
|
||||
const auto buffer_reader = [](osmium::io::Reader &reader) {
|
||||
const auto buffer_reader = [](osmium::io::Reader &reader)
|
||||
{
|
||||
return tbb::filter<void, SharedBuffer>(
|
||||
tbb::filter_mode::serial_in_order, [&reader](tbb::flow_control &fc) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&reader](tbb::flow_control &fc)
|
||||
{
|
||||
if (auto buffer = reader.read())
|
||||
{
|
||||
return std::make_shared<osmium::memory::Buffer>(std::move(buffer));
|
||||
@@ -466,7 +469,9 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting
|
||||
osmium_location_handler_type location_handler(location_cache);
|
||||
|
||||
tbb::filter<SharedBuffer, SharedBuffer> location_cacher(
|
||||
tbb::filter_mode::serial_in_order, [&location_handler](SharedBuffer buffer) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&location_handler](SharedBuffer buffer)
|
||||
{
|
||||
osmium::apply(buffer->begin(), buffer->end(), location_handler);
|
||||
return buffer;
|
||||
});
|
||||
@@ -475,7 +480,8 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting
|
||||
tbb::filter<SharedBuffer, ParsedBuffer> buffer_transformer(
|
||||
tbb::filter_mode::parallel,
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
[&](const SharedBuffer buffer) {
|
||||
[&](const SharedBuffer buffer)
|
||||
{
|
||||
ParsedBuffer parsed_buffer;
|
||||
parsed_buffer.buffer = buffer;
|
||||
scripting_environment.ProcessElements(*buffer,
|
||||
@@ -495,7 +501,9 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting
|
||||
unsigned number_of_restrictions = 0;
|
||||
unsigned number_of_maneuver_overrides = 0;
|
||||
tbb::filter<ParsedBuffer, void> buffer_storage(
|
||||
tbb::filter_mode::serial_in_order, [&](const ParsedBuffer &parsed_buffer) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&](const ParsedBuffer &parsed_buffer)
|
||||
{
|
||||
number_of_nodes += parsed_buffer.resulting_nodes.size();
|
||||
// put parsed objects thru extractor callbacks
|
||||
for (const auto &result : parsed_buffer.resulting_nodes)
|
||||
@@ -524,7 +532,8 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting
|
||||
tbb::filter<SharedBuffer, std::shared_ptr<ExtractionRelationContainer>> buffer_relation_cache(
|
||||
tbb::filter_mode::parallel,
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
[&](const SharedBuffer buffer) {
|
||||
[&](const SharedBuffer buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return std::shared_ptr<ExtractionRelationContainer>{};
|
||||
|
||||
@@ -562,7 +571,8 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting
|
||||
tbb::filter<std::shared_ptr<ExtractionRelationContainer>, void> buffer_storage_relation(
|
||||
tbb::filter_mode::serial_in_order,
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
[&](const std::shared_ptr<ExtractionRelationContainer> parsed_relations) {
|
||||
[&](const std::shared_ptr<ExtractionRelationContainer> parsed_relations)
|
||||
{
|
||||
number_of_relations += parsed_relations->GetRelationsNum();
|
||||
relations.Merge(std::move(*parsed_relations));
|
||||
});
|
||||
@@ -749,7 +759,8 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
segregated_edges,
|
||||
turn_lane_map);
|
||||
|
||||
const auto create_edge_based_edges = [&]() {
|
||||
const auto create_edge_based_edges = [&]()
|
||||
{
|
||||
// scoped to release intermediate data structures right after the call
|
||||
RestrictionMap unconditional_node_restriction_map(restriction_graph);
|
||||
ConditionalRestrictionMap conditional_node_restriction_map(restriction_graph);
|
||||
@@ -795,9 +806,8 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNodeSegment> edge_based_node_seg
|
||||
auto start_point_count = std::accumulate(edge_based_node_segments.begin(),
|
||||
edge_based_node_segments.end(),
|
||||
0,
|
||||
[](const size_t so_far, const auto &segment) {
|
||||
return so_far + (segment.is_startpoint ? 1 : 0);
|
||||
});
|
||||
[](const size_t so_far, const auto &segment)
|
||||
{ return so_far + (segment.is_startpoint ? 1 : 0); });
|
||||
if (start_point_count == 0)
|
||||
{
|
||||
throw util::exception("There are no snappable edges left after processing. Are you "
|
||||
|
||||
@@ -140,7 +140,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
InternalExtractorEdge::WeightData forward_weight_data;
|
||||
InternalExtractorEdge::WeightData backward_weight_data;
|
||||
|
||||
const auto toValueByEdgeOrByMeter = [&nodes](const double by_way, const double by_meter) {
|
||||
const auto toValueByEdgeOrByMeter = [&nodes](const double by_way, const double by_meter)
|
||||
{
|
||||
using Value = detail::ByEdgeOrByMeterValue;
|
||||
// get value by weight per edge
|
||||
if (by_way >= 0)
|
||||
@@ -194,7 +195,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
}
|
||||
}
|
||||
|
||||
const auto classStringToMask = [this](const std::string &class_name) {
|
||||
const auto classStringToMask = [this](const std::string &class_name)
|
||||
{
|
||||
auto iter = classes_map.find(class_name);
|
||||
if (iter == classes_map.end())
|
||||
{
|
||||
@@ -212,7 +214,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
return iter->second;
|
||||
}
|
||||
};
|
||||
const auto classesToMask = [&](const auto &classes) {
|
||||
const auto classesToMask = [&](const auto &classes)
|
||||
{
|
||||
ClassData mask = 0;
|
||||
for (const auto &name_and_flag : classes)
|
||||
{
|
||||
@@ -232,7 +235,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
const ClassData forward_classes = classesToMask(parsed_way.forward_classes);
|
||||
const ClassData backward_classes = classesToMask(parsed_way.backward_classes);
|
||||
|
||||
const auto laneStringToDescription = [](const std::string &lane_string) -> TurnLaneDescription {
|
||||
const auto laneStringToDescription = [](const std::string &lane_string) -> TurnLaneDescription
|
||||
{
|
||||
if (lane_string.empty())
|
||||
return {};
|
||||
|
||||
@@ -332,7 +336,8 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
road_classification.SetNumberOfLanes(std::max(road_deduced_num_lanes, // len(turn:lanes)
|
||||
road_classification.GetNumberOfLanes()));
|
||||
|
||||
const auto GetNameID = [this, &parsed_way](bool is_forward) -> NameID {
|
||||
const auto GetNameID = [this, &parsed_way](bool is_forward) -> NameID
|
||||
{
|
||||
const std::string &ref = is_forward ? parsed_way.forward_ref : parsed_way.backward_ref;
|
||||
// Get the unique identifier for the street name, destination, and ref
|
||||
const auto name_iterator = string_map.find(MapKey(parsed_way.name,
|
||||
@@ -418,30 +423,31 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
forward_classes,
|
||||
parsed_way.forward_travel_mode,
|
||||
parsed_way.is_left_hand_driving});
|
||||
util::for_each_pair(
|
||||
nodes, [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
NodeBasedEdgeWithOSM edge = {
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
{0}, // weight
|
||||
{0}, // duration
|
||||
{0}, // distance
|
||||
{}, // geometry id
|
||||
static_cast<AnnotationID>(annotation_data_id),
|
||||
{true,
|
||||
in_backward_direction && !split_edge,
|
||||
split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.forward_restricted,
|
||||
road_classification,
|
||||
parsed_way.highway_turn_classification,
|
||||
parsed_way.access_turn_classification}};
|
||||
util::for_each_pair(nodes,
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
|
||||
{
|
||||
NodeBasedEdgeWithOSM edge = {
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
{0}, // weight
|
||||
{0}, // duration
|
||||
{0}, // distance
|
||||
{}, // geometry id
|
||||
static_cast<AnnotationID>(annotation_data_id),
|
||||
{true,
|
||||
in_backward_direction && !split_edge,
|
||||
split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.forward_restricted,
|
||||
road_classification,
|
||||
parsed_way.highway_turn_classification,
|
||||
parsed_way.access_turn_classification}};
|
||||
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(edge, forward_weight_data, forward_duration_data, {}));
|
||||
});
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
edge, forward_weight_data, forward_duration_data, {}));
|
||||
});
|
||||
}
|
||||
|
||||
if (in_backward_direction && (!in_forward_direction || split_edge))
|
||||
@@ -452,38 +458,38 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
backward_classes,
|
||||
parsed_way.backward_travel_mode,
|
||||
parsed_way.is_left_hand_driving});
|
||||
util::for_each_pair(
|
||||
nodes, [&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
NodeBasedEdgeWithOSM edge = {
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
{0}, // weight
|
||||
{0}, // duration
|
||||
{0}, // distance
|
||||
{}, // geometry id
|
||||
static_cast<AnnotationID>(annotation_data_id),
|
||||
{false,
|
||||
true,
|
||||
split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_restricted,
|
||||
road_classification,
|
||||
parsed_way.highway_turn_classification,
|
||||
parsed_way.access_turn_classification}};
|
||||
util::for_each_pair(nodes,
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
|
||||
{
|
||||
NodeBasedEdgeWithOSM edge = {
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
{0}, // weight
|
||||
{0}, // duration
|
||||
{0}, // distance
|
||||
{}, // geometry id
|
||||
static_cast<AnnotationID>(annotation_data_id),
|
||||
{false,
|
||||
true,
|
||||
split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_restricted,
|
||||
road_classification,
|
||||
parsed_way.highway_turn_classification,
|
||||
parsed_way.access_turn_classification}};
|
||||
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(edge, backward_weight_data, backward_duration_data, {}));
|
||||
});
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
edge, backward_weight_data, backward_duration_data, {}));
|
||||
});
|
||||
}
|
||||
|
||||
std::transform(nodes.begin(),
|
||||
nodes.end(),
|
||||
std::back_inserter(external_memory.used_node_id_list),
|
||||
[](const osmium::NodeRef &ref) {
|
||||
return OSMNodeID{static_cast<std::uint64_t>(ref.ref())};
|
||||
});
|
||||
[](const osmium::NodeRef &ref)
|
||||
{ return OSMNodeID{static_cast<std::uint64_t>(ref.ref())}; });
|
||||
|
||||
auto way_id = OSMWayID{static_cast<std::uint64_t>(input_way.id())};
|
||||
external_memory.ways_list.push_back(way_id);
|
||||
|
||||
@@ -37,7 +37,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
// restriction path.
|
||||
std::unordered_set<NodeID> incompressible_via_nodes;
|
||||
|
||||
const auto remember_via_nodes = [&](const auto &restriction) {
|
||||
const auto remember_via_nodes = [&](const auto &restriction)
|
||||
{
|
||||
if (restriction.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
incompressible_via_nodes.insert(restriction.turn_path.AsViaNodePath().via);
|
||||
@@ -186,16 +187,17 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
*/
|
||||
const auto selectAnnotation =
|
||||
[&node_data_container](const AnnotationID front_annotation,
|
||||
const AnnotationID back_annotation) {
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer
|
||||
// to the intersection is preferred. If its empty, however, we keep the
|
||||
// non-empty one
|
||||
if (node_data_container[back_annotation].lane_description_id ==
|
||||
INVALID_LANE_DESCRIPTIONID)
|
||||
return front_annotation;
|
||||
return back_annotation;
|
||||
};
|
||||
const AnnotationID back_annotation)
|
||||
{
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer
|
||||
// to the intersection is preferred. If its empty, however, we keep the
|
||||
// non-empty one
|
||||
if (node_data_container[back_annotation].lane_description_id ==
|
||||
INVALID_LANE_DESCRIPTIONID)
|
||||
return front_annotation;
|
||||
return back_annotation;
|
||||
};
|
||||
|
||||
graph.GetEdgeData(forward_e1).annotation_data = selectAnnotation(
|
||||
fwd_edge_data1.annotation_data, fwd_edge_data2.annotation_data);
|
||||
@@ -250,10 +252,10 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
roads_on_the_left);
|
||||
scripting_environment.ProcessTurn(extraction_turn);
|
||||
|
||||
auto update_direction_penalty = [&extraction_turn, weight_multiplier](
|
||||
bool signal,
|
||||
EdgeDuration &duration_penalty,
|
||||
EdgeWeight &weight_penalty) {
|
||||
auto update_direction_penalty =
|
||||
[&extraction_turn, weight_multiplier](
|
||||
bool signal, EdgeDuration &duration_penalty, EdgeWeight &weight_penalty)
|
||||
{
|
||||
if (signal)
|
||||
{
|
||||
duration_penalty = to_alias<EdgeDuration>(extraction_turn.duration *
|
||||
@@ -303,7 +305,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
auto apply_e2_to_e1 = [&graph](EdgeID edge1,
|
||||
EdgeID edge2,
|
||||
EdgeWeight &weight_penalty,
|
||||
EdgeDuration &duration_penalty) {
|
||||
EdgeDuration &duration_penalty)
|
||||
{
|
||||
auto &edge1_data = graph.GetEdgeData(edge1);
|
||||
const auto &edge2_data = graph.GetEdgeData(edge2);
|
||||
edge1_data.weight += edge2_data.weight;
|
||||
@@ -345,7 +348,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
// Set a dummy empty penalty weight if opposite value exists.
|
||||
auto set_dummy_penalty = [](EdgeWeight &weight_penalty,
|
||||
EdgeDuration &duration_penalty,
|
||||
EdgeWeight &other_weight_penalty) {
|
||||
EdgeWeight &other_weight_penalty)
|
||||
{
|
||||
if (weight_penalty == INVALID_EDGE_WEIGHT &&
|
||||
other_weight_penalty != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
|
||||
@@ -88,9 +88,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
std::vector<util::Coordinate> coordinates) const
|
||||
{
|
||||
// check if the coordinate is equal to the interseciton coordinate
|
||||
const auto not_same_as_start = [&](const util::Coordinate coordinate) {
|
||||
return node_coordinates[traversed_in_reverse ? to_node : intersection_node] != coordinate;
|
||||
};
|
||||
const auto not_same_as_start = [&](const util::Coordinate coordinate)
|
||||
{ return node_coordinates[traversed_in_reverse ? to_node : intersection_node] != coordinate; };
|
||||
// this is only used for debug purposes in assertions. We don't want warnings about it
|
||||
(void)not_same_as_start;
|
||||
|
||||
@@ -176,7 +175,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
* information on the very first turn angle (requires knowledge about previous road) and the
|
||||
* respective lane widths.
|
||||
*/
|
||||
const bool first_coordinate_is_far_away = [&first_distance, considered_lanes]() {
|
||||
const bool first_coordinate_is_far_away = [&first_distance, considered_lanes]()
|
||||
{
|
||||
const auto required_distance =
|
||||
considered_lanes * ASSUMED_LANE_WIDTH + LOOKAHEAD_DISTANCE_WITHOUT_LANES;
|
||||
return first_distance > required_distance;
|
||||
@@ -256,7 +256,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
* possible negative:
|
||||
* http://www.openstreetmap.org/search?query=52.514503%2013.32252#map=19/52.51450/13.32252
|
||||
*/
|
||||
const auto straight_distance_and_index = [&]() {
|
||||
const auto straight_distance_and_index = [&]()
|
||||
{
|
||||
auto straight_distance = segment_distances[1];
|
||||
|
||||
std::size_t index;
|
||||
@@ -276,7 +277,8 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
const auto straight_distance = straight_distance_and_index.second;
|
||||
const auto straight_index = straight_distance_and_index.first;
|
||||
|
||||
const bool starts_of_without_turn = [&]() {
|
||||
const bool starts_of_without_turn = [&]()
|
||||
{
|
||||
return straight_distance >=
|
||||
considered_lanes * ASSUMED_LANE_WIDTH + LOOKAHEAD_DISTANCE_WITHOUT_LANES;
|
||||
}();
|
||||
@@ -435,7 +437,8 @@ CoordinateExtractor::ExtractCoordinateAtLength(const double distance,
|
||||
auto length_cache_itr = length_cache.begin() + 1;
|
||||
// find the end of the segment containing the coordinate which is at least distance away
|
||||
const auto find_coordinate_at_distance = [distance, &accumulated_distance, &length_cache_itr](
|
||||
const util::Coordinate /*coordinate*/) mutable {
|
||||
const util::Coordinate /*coordinate*/) mutable
|
||||
{
|
||||
const auto result = (accumulated_distance + *length_cache_itr) >= distance;
|
||||
if (!result)
|
||||
{
|
||||
@@ -468,18 +471,19 @@ util::Coordinate CoordinateExtractor::ExtractCoordinateAtLength(
|
||||
// checks (via its state) for an accumulated distance
|
||||
const auto coordinate_at_distance =
|
||||
[distance, &accumulated_distance, last_coordinate = coordinates.front()](
|
||||
const util::Coordinate coordinate) mutable {
|
||||
const double segment_distance =
|
||||
util::coordinate_calculation::greatCircleDistance(last_coordinate, coordinate);
|
||||
const auto result = (accumulated_distance + segment_distance) >= distance;
|
||||
if (!result)
|
||||
{
|
||||
accumulated_distance += segment_distance;
|
||||
last_coordinate = coordinate;
|
||||
}
|
||||
const util::Coordinate coordinate) mutable
|
||||
{
|
||||
const double segment_distance =
|
||||
util::coordinate_calculation::greatCircleDistance(last_coordinate, coordinate);
|
||||
const auto result = (accumulated_distance + segment_distance) >= distance;
|
||||
if (!result)
|
||||
{
|
||||
accumulated_distance += segment_distance;
|
||||
last_coordinate = coordinate;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
return result;
|
||||
};
|
||||
|
||||
// find the begin of the segment containing the coordinate
|
||||
const auto coordinate_after =
|
||||
@@ -514,9 +518,8 @@ util::Coordinate CoordinateExtractor::GetCoordinateCloseToTurn(const NodeID from
|
||||
// the compressed edges contain node ids, we transfer them to coordinates accessing the
|
||||
// node_coordinates array
|
||||
const auto compressedGeometryToCoordinate =
|
||||
[this](const CompressedEdgeContainer::OnewayCompressedEdge &compressed_edge) {
|
||||
return node_coordinates[compressed_edge.node_id];
|
||||
};
|
||||
[this](const CompressedEdgeContainer::OnewayCompressedEdge &compressed_edge)
|
||||
{ return node_coordinates[compressed_edge.node_id]; };
|
||||
|
||||
// return the first coordinate that is reasonably far away from the start node
|
||||
const util::Coordinate start_coordinate = node_coordinates[start_node];
|
||||
@@ -526,10 +529,11 @@ util::Coordinate CoordinateExtractor::GetCoordinateCloseToTurn(const NodeID from
|
||||
// away from the first entry
|
||||
const auto far_enough_away =
|
||||
[start_coordinate, compressedGeometryToCoordinate](
|
||||
const CompressedEdgeContainer::OnewayCompressedEdge &compressed_edge) {
|
||||
return util::coordinate_calculation::greatCircleDistance(
|
||||
compressedGeometryToCoordinate(compressed_edge), start_coordinate) > 1;
|
||||
};
|
||||
const CompressedEdgeContainer::OnewayCompressedEdge &compressed_edge)
|
||||
{
|
||||
return util::coordinate_calculation::greatCircleDistance(
|
||||
compressedGeometryToCoordinate(compressed_edge), start_coordinate) > 1;
|
||||
};
|
||||
|
||||
// find the first coordinate, that is at least unequal to the begin of the edge
|
||||
if (traversed_in_reverse)
|
||||
@@ -614,7 +618,8 @@ CoordinateExtractor::GetMaxDeviation(std::vector<util::Coordinate>::const_iterat
|
||||
const util::Coordinate straight_end) const
|
||||
{
|
||||
// compute the deviation of a single coordinate from a straight line
|
||||
auto get_single_deviation = [&](const util::Coordinate coordinate) {
|
||||
auto get_single_deviation = [&](const util::Coordinate coordinate)
|
||||
{
|
||||
// find the projected coordinate
|
||||
auto coord_between = util::coordinate_calculation::projectPointOnSegment(
|
||||
straight_begin, straight_end, coordinate)
|
||||
@@ -626,10 +631,11 @@ CoordinateExtractor::GetMaxDeviation(std::vector<util::Coordinate>::const_iterat
|
||||
|
||||
// note: we don't accumulate here but rather compute the maximum. The functor passed here is not
|
||||
// summing up anything.
|
||||
return std::accumulate(
|
||||
range_begin, range_end, 0.0, [&](const double current, const util::Coordinate coordinate) {
|
||||
return std::max(current, get_single_deviation(coordinate));
|
||||
});
|
||||
return std::accumulate(range_begin,
|
||||
range_end,
|
||||
0.0,
|
||||
[&](const double current, const util::Coordinate coordinate)
|
||||
{ return std::max(current, get_single_deviation(coordinate)); });
|
||||
}
|
||||
|
||||
bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinates,
|
||||
@@ -645,7 +651,8 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
return true;
|
||||
|
||||
// TODO we might have to fix this to better compensate for errors due to repeated coordinates
|
||||
const bool takes_an_actual_turn = [&coordinates]() {
|
||||
const bool takes_an_actual_turn = [&coordinates]()
|
||||
{
|
||||
const auto begin_bearing =
|
||||
util::coordinate_calculation::bearing(coordinates[0], coordinates[1]);
|
||||
const auto end_bearing = util::coordinate_calculation::bearing(
|
||||
@@ -660,7 +667,8 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
|
||||
const auto get_deviation = [](const util::Coordinate line_start,
|
||||
const util::Coordinate line_end,
|
||||
const util::Coordinate point) {
|
||||
const util::Coordinate point)
|
||||
{
|
||||
// find the projected coordinate
|
||||
auto coord_between =
|
||||
util::coordinate_calculation::projectPointOnSegment(line_start, line_end, point).second;
|
||||
@@ -669,19 +677,22 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
};
|
||||
|
||||
// a curve needs to be on one side of the coordinate array
|
||||
const bool all_same_side = [&]() {
|
||||
const bool all_same_side = [&]()
|
||||
{
|
||||
if (coordinates.size() <= 3)
|
||||
return true;
|
||||
|
||||
const bool ccw = util::coordinate_calculation::isCCW(
|
||||
coordinates.front(), coordinates.back(), coordinates[1]);
|
||||
|
||||
return std::all_of(
|
||||
coordinates.begin() + 2, coordinates.end() - 1, [&](const util::Coordinate coordinate) {
|
||||
const bool compare_ccw = util::coordinate_calculation::isCCW(
|
||||
coordinates.front(), coordinates.back(), coordinate);
|
||||
return ccw == compare_ccw;
|
||||
});
|
||||
return std::all_of(coordinates.begin() + 2,
|
||||
coordinates.end() - 1,
|
||||
[&](const util::Coordinate coordinate)
|
||||
{
|
||||
const bool compare_ccw = util::coordinate_calculation::isCCW(
|
||||
coordinates.front(), coordinates.back(), coordinate);
|
||||
return ccw == compare_ccw;
|
||||
});
|
||||
}();
|
||||
|
||||
if (!all_same_side)
|
||||
@@ -694,13 +705,16 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
double maximum_deviation = 0;
|
||||
|
||||
std::tie(has_up_down_deviation, maximum_deviation_index, maximum_deviation) =
|
||||
[&coordinates, get_deviation]() -> std::tuple<bool, std::size_t, double> {
|
||||
const auto increasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) {
|
||||
[&coordinates, get_deviation]() -> std::tuple<bool, std::size_t, double>
|
||||
{
|
||||
const auto increasing = [&](const util::Coordinate lhs, const util::Coordinate rhs)
|
||||
{
|
||||
return get_deviation(coordinates.front(), coordinates.back(), lhs) <
|
||||
get_deviation(coordinates.front(), coordinates.back(), rhs);
|
||||
};
|
||||
|
||||
const auto decreasing = [&](const util::Coordinate lhs, const util::Coordinate rhs) {
|
||||
const auto decreasing = [&](const util::Coordinate lhs, const util::Coordinate rhs)
|
||||
{
|
||||
return get_deviation(coordinates.front(), coordinates.back(), lhs) >
|
||||
get_deviation(coordinates.front(), coordinates.back(), rhs);
|
||||
};
|
||||
@@ -744,7 +758,8 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
|
||||
BOOST_ASSERT(coordinates.size() >= 3);
|
||||
// Compute all turn angles along the road
|
||||
const auto turn_angles = [coordinates]() {
|
||||
const auto turn_angles = [coordinates]()
|
||||
{
|
||||
std::vector<double> turn_angles;
|
||||
turn_angles.reserve(coordinates.size() - 2);
|
||||
for (std::size_t index = 0; index + 2 < coordinates.size(); ++index)
|
||||
@@ -755,10 +770,9 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
return turn_angles;
|
||||
}();
|
||||
|
||||
const bool curve_is_valid = [&turn_angles,
|
||||
&segment_distances,
|
||||
&segment_length,
|
||||
&considered_lane_width]() {
|
||||
const bool curve_is_valid =
|
||||
[&turn_angles, &segment_distances, &segment_length, &considered_lane_width]()
|
||||
{
|
||||
// internal state for our lamdae
|
||||
bool last_was_straight = false;
|
||||
// a turn angle represents two segments between three coordinates. We initialize the
|
||||
@@ -769,8 +783,9 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
// every call to the lamda requires a call to the distances. They need to be aligned
|
||||
BOOST_ASSERT(segment_distances.size() == turn_angles.size() + 2);
|
||||
|
||||
const auto detect_invalid_curve = [&](const double previous_angle,
|
||||
const double current_angle) {
|
||||
const auto detect_invalid_curve =
|
||||
[&](const double previous_angle, const double current_angle)
|
||||
{
|
||||
const auto both_actually_turn =
|
||||
(util::angularDeviation(previous_angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE) &&
|
||||
(util::angularDeviation(current_angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE);
|
||||
@@ -822,7 +837,8 @@ bool CoordinateExtractor::IsDirectOffset(const std::vector<util::Coordinate> &co
|
||||
const std::uint8_t considered_lanes) const
|
||||
{
|
||||
// check if a given length is with half a lane of the assumed lane offset
|
||||
const auto IsCloseToLaneDistance = [considered_lanes](const double width) {
|
||||
const auto IsCloseToLaneDistance = [considered_lanes](const double width)
|
||||
{
|
||||
// a road usually is connected to the middle of the lanes. So the lane-offset has to
|
||||
// consider half to road
|
||||
const auto lane_offset = 0.5 * considered_lanes * ASSUMED_LANE_WIDTH;
|
||||
@@ -856,7 +872,8 @@ bool CoordinateExtractor::IsDirectOffset(const std::vector<util::Coordinate> &co
|
||||
const auto segment_offset_past_thirty_meters =
|
||||
std::find_if(segment_distances.begin() + offset_index,
|
||||
segment_distances.end(),
|
||||
[accumulated_distance = 0.](const auto value) mutable {
|
||||
[accumulated_distance = 0.](const auto value) mutable
|
||||
{
|
||||
accumulated_distance += value;
|
||||
return value >= 30;
|
||||
});
|
||||
@@ -888,20 +905,21 @@ CoordinateExtractor::PrepareLengthCache(const std::vector<util::Coordinate> &coo
|
||||
// sentinel
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
// We're only interested in the side effect of the lambda, not the return value
|
||||
[[maybe_unused]] auto _ = std::find_if(
|
||||
std::next(std::begin(coordinates)),
|
||||
std::end(coordinates),
|
||||
[last_coordinate = coordinates.front(),
|
||||
limit,
|
||||
&segment_distances,
|
||||
accumulated_distance = 0.](const util::Coordinate current_coordinate) mutable {
|
||||
const auto distance = util::coordinate_calculation::greatCircleDistance(
|
||||
last_coordinate, current_coordinate);
|
||||
accumulated_distance += distance;
|
||||
last_coordinate = current_coordinate;
|
||||
segment_distances.push_back(distance);
|
||||
return accumulated_distance >= limit;
|
||||
});
|
||||
[[maybe_unused]] auto _ =
|
||||
std::find_if(std::next(std::begin(coordinates)),
|
||||
std::end(coordinates),
|
||||
[last_coordinate = coordinates.front(),
|
||||
limit,
|
||||
&segment_distances,
|
||||
accumulated_distance = 0.](const util::Coordinate current_coordinate) mutable
|
||||
{
|
||||
const auto distance = util::coordinate_calculation::greatCircleDistance(
|
||||
last_coordinate, current_coordinate);
|
||||
accumulated_distance += distance;
|
||||
last_coordinate = current_coordinate;
|
||||
segment_distances.push_back(distance);
|
||||
return accumulated_distance >= limit;
|
||||
});
|
||||
return segment_distances;
|
||||
}
|
||||
|
||||
@@ -916,19 +934,18 @@ CoordinateExtractor::TrimCoordinatesToLength(std::vector<util::Coordinate> coord
|
||||
double distance_to_current_coordinate = 0;
|
||||
std::size_t coordinate_index = 0;
|
||||
|
||||
const auto compute_length =
|
||||
[&coordinate_index, &distance_to_current_coordinate, &coordinates]() {
|
||||
const auto new_distance =
|
||||
distance_to_current_coordinate +
|
||||
util::coordinate_calculation::greatCircleDistance(coordinates[coordinate_index - 1],
|
||||
coordinates[coordinate_index]);
|
||||
return new_distance;
|
||||
};
|
||||
|
||||
const auto read_length_from_cache = [&length_cache, &coordinate_index]() {
|
||||
return length_cache[coordinate_index];
|
||||
const auto compute_length = [&coordinate_index, &distance_to_current_coordinate, &coordinates]()
|
||||
{
|
||||
const auto new_distance =
|
||||
distance_to_current_coordinate +
|
||||
util::coordinate_calculation::greatCircleDistance(coordinates[coordinate_index - 1],
|
||||
coordinates[coordinate_index]);
|
||||
return new_distance;
|
||||
};
|
||||
|
||||
const auto read_length_from_cache = [&length_cache, &coordinate_index]()
|
||||
{ return length_cache[coordinate_index]; };
|
||||
|
||||
bool use_cache = !length_cache.empty();
|
||||
|
||||
if (use_cache && length_cache.back() < desired_length && coordinates.size() >= 2)
|
||||
@@ -1044,8 +1061,9 @@ CoordinateExtractor::SampleCoordinates(const std::vector<util::Coordinate> &coor
|
||||
|
||||
double carry_length = 0., total_length = 0.;
|
||||
// interpolate coordinates as long as we are not past the desired length
|
||||
const auto add_samples_until_length_limit = [&](const util::Coordinate previous_coordinate,
|
||||
const util::Coordinate current_coordinate) {
|
||||
const auto add_samples_until_length_limit =
|
||||
[&](const util::Coordinate previous_coordinate, const util::Coordinate current_coordinate)
|
||||
{
|
||||
// pretend to have found an element and stop the sampling
|
||||
if (total_length > max_sample_length)
|
||||
return true;
|
||||
|
||||
@@ -67,9 +67,8 @@ getEdgeCoordinates(const extractor::CompressedEdgeContainer &compressed_geometri
|
||||
std::transform(geometry.begin(),
|
||||
geometry.end(),
|
||||
std::back_inserter(result),
|
||||
[&node_coordinates](const auto &compressed_edge) {
|
||||
return node_coordinates[compressed_edge.node_id];
|
||||
});
|
||||
[&node_coordinates](const auto &compressed_edge)
|
||||
{ return node_coordinates[compressed_edge.node_id]; });
|
||||
|
||||
// filter duplicated coordinates
|
||||
result.erase(std::unique(result.begin(), result.end()), result.end());
|
||||
@@ -95,7 +94,8 @@ double findClosestOppositeBearing(const IntersectionEdgeGeometries &edge_geometr
|
||||
const auto min = std::min_element(
|
||||
edge_geometries.begin(),
|
||||
edge_geometries.end(),
|
||||
[bearing = util::bearing::reverse(bearing)](const auto &lhs, const auto &rhs) {
|
||||
[bearing = util::bearing::reverse(bearing)](const auto &lhs, const auto &rhs)
|
||||
{
|
||||
return util::angularDeviation(lhs.perceived_bearing, bearing) <
|
||||
util::angularDeviation(rhs.perceived_bearing, bearing);
|
||||
});
|
||||
@@ -128,7 +128,7 @@ std::pair<bool, double> findMergedBearing(const util::NodeBasedDynamicGraph &gra
|
||||
{
|
||||
// In some intersections, turning roads can introduce artificial turns if we merge here.
|
||||
// Consider a scenario like:
|
||||
//
|
||||
//
|
||||
// a . g - f
|
||||
// | .
|
||||
// | .
|
||||
@@ -136,7 +136,7 @@ std::pair<bool, double> findMergedBearing(const util::NodeBasedDynamicGraph &gra
|
||||
// d-b--------e
|
||||
// |
|
||||
// c
|
||||
//
|
||||
//
|
||||
// Merging `bgf` and `be` would introduce an angle, even though d-b-e is perfectly straight
|
||||
// We don't change the angle, if such an opposite road exists
|
||||
return {false, entry.perceived_bearing};
|
||||
@@ -239,9 +239,10 @@ getIntersectionOutgoingGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||
}
|
||||
|
||||
// Sort edges in the clockwise bearings order
|
||||
std::sort(edge_geometries.begin(), edge_geometries.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.perceived_bearing < rhs.perceived_bearing;
|
||||
});
|
||||
std::sort(edge_geometries.begin(),
|
||||
edge_geometries.end(),
|
||||
[](const auto &lhs, const auto &rhs)
|
||||
{ return lhs.perceived_bearing < rhs.perceived_bearing; });
|
||||
return edge_geometries;
|
||||
}
|
||||
} // namespace
|
||||
@@ -317,9 +318,8 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||
neighbor_geometries.begin(),
|
||||
std::find_if(neighbor_geometries.begin(),
|
||||
neighbor_geometries.end(),
|
||||
[&graph, &intersection_node](const auto &road) {
|
||||
return graph.GetTarget(road.eid) == intersection_node;
|
||||
}));
|
||||
[&graph, &intersection_node](const auto &road)
|
||||
{ return graph.GetTarget(road.eid) == intersection_node; }));
|
||||
BOOST_ASSERT(static_cast<std::size_t>(neighbor_curr) != neighbor_geometries.size());
|
||||
const auto neighbor_prev = (neighbor_curr + neighbor_edges - 1) % neighbor_edges;
|
||||
const auto neighbor_next = (neighbor_curr + 1) % neighbor_edges;
|
||||
@@ -403,10 +403,11 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||
|
||||
inline auto findEdge(const IntersectionEdgeGeometries &geometries, const EdgeID &edge)
|
||||
{
|
||||
const auto it = std::lower_bound(
|
||||
geometries.begin(), geometries.end(), edge, [](const auto &geometry, const auto edge) {
|
||||
return geometry.eid < edge;
|
||||
});
|
||||
const auto it =
|
||||
std::lower_bound(geometries.begin(),
|
||||
geometries.end(),
|
||||
edge,
|
||||
[](const auto &geometry, const auto edge) { return geometry.eid < edge; });
|
||||
BOOST_ASSERT(it != geometries.end() && it->eid == edge);
|
||||
return it;
|
||||
}
|
||||
@@ -425,9 +426,10 @@ template <typename RestrictionsRange>
|
||||
bool isTurnRestricted(const RestrictionsRange &restrictions, const NodeID to)
|
||||
{
|
||||
// Check if any of the restrictions would prevent a turn to 'to'
|
||||
return std::any_of(restrictions.begin(), restrictions.end(), [&to](const auto &restriction) {
|
||||
return restriction->IsTurnRestricted(to);
|
||||
});
|
||||
return std::any_of(restrictions.begin(),
|
||||
restrictions.end(),
|
||||
[&to](const auto &restriction)
|
||||
{ return restriction->IsTurnRestricted(to); });
|
||||
}
|
||||
|
||||
bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
|
||||
@@ -614,9 +616,8 @@ IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &gr
|
||||
IntersectionViewData uturn{{SPECIAL_EDGEID, 0., 0., 0.}, false, 0.};
|
||||
std::size_t allowed_uturns_number = 0;
|
||||
|
||||
const auto is_uturn = [](const auto angle) {
|
||||
return std::fabs(angle) < std::numeric_limits<double>::epsilon();
|
||||
};
|
||||
const auto is_uturn = [](const auto angle)
|
||||
{ return std::fabs(angle) < std::numeric_limits<double>::epsilon(); };
|
||||
|
||||
for (const auto &outgoing_edge : outgoing_edges)
|
||||
{
|
||||
@@ -665,9 +666,9 @@ IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &gr
|
||||
// 2) use turn angle if the smallest arc between turn and initial angles passes 0°
|
||||
const auto use_turn_angle = (turn_angle > 270 && initial_angle < 90) ||
|
||||
(turn_angle < 90 && initial_angle > 270);
|
||||
const auto adjusted_angle = is_uturn(initial_angle)
|
||||
? (turn_angle > 180. ? 360. : 0.)
|
||||
: use_turn_angle ? turn_angle : initial_angle;
|
||||
const auto adjusted_angle = is_uturn(initial_angle) ? (turn_angle > 180. ? 360. : 0.)
|
||||
: use_turn_angle ? turn_angle
|
||||
: initial_angle;
|
||||
pre_intersection_view.push_back({road, adjusted_angle});
|
||||
}
|
||||
}
|
||||
@@ -680,12 +681,11 @@ IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &gr
|
||||
}
|
||||
|
||||
// Order roads in counter-clockwise order starting from the U-turn edge in the OSM order
|
||||
std::stable_sort(pre_intersection_view.begin(),
|
||||
pre_intersection_view.end(),
|
||||
[](const auto &lhs, const auto &rhs) {
|
||||
return std::tie(lhs.second, lhs.first.angle) <
|
||||
std::tie(rhs.second, rhs.first.angle);
|
||||
});
|
||||
std::stable_sort(
|
||||
pre_intersection_view.begin(),
|
||||
pre_intersection_view.end(),
|
||||
[](const auto &lhs, const auto &rhs)
|
||||
{ return std::tie(lhs.second, lhs.first.angle) < std::tie(rhs.second, rhs.first.angle); });
|
||||
|
||||
// Adjust perceived bearings to keep the initial OSM order with respect to the first edge
|
||||
for (auto curr = pre_intersection_view.begin(), next = std::next(curr);
|
||||
@@ -706,9 +706,8 @@ IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &gr
|
||||
|
||||
auto no_uturn = std::none_of(pre_intersection_view.begin(),
|
||||
pre_intersection_view.end(),
|
||||
[&is_uturn](const IntersectionViewDataWithAngle &road) {
|
||||
return is_uturn(road.first.angle);
|
||||
});
|
||||
[&is_uturn](const IntersectionViewDataWithAngle &road)
|
||||
{ return is_uturn(road.first.angle); });
|
||||
// After all of this, if we now don't have a u-turn, let's add one to the intersection.
|
||||
// This is a hack to fix the triggered assertion ( see:
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/6218 ). Ideally we would fix this more
|
||||
|
||||
@@ -27,7 +27,8 @@ inline auto makeCheckRoadForName(const NameID name_id,
|
||||
const SuffixTable &suffix_table)
|
||||
{
|
||||
return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table](
|
||||
const MergableRoadDetector::MergableRoadData &road) {
|
||||
const MergableRoadDetector::MergableRoadData &road)
|
||||
{
|
||||
// since we filter here, we don't want any other name than the one we are looking for
|
||||
const auto road_name_id =
|
||||
node_data_container
|
||||
@@ -89,9 +90,8 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
|
||||
* / -- \
|
||||
* a ---- b - - /
|
||||
*/
|
||||
const auto road_target = [this](const MergableRoadData &road) {
|
||||
return node_based_graph.GetTarget(road.eid);
|
||||
};
|
||||
const auto road_target = [this](const MergableRoadData &road)
|
||||
{ return node_based_graph.GetTarget(road.eid); };
|
||||
|
||||
// TODO might have to skip over trivial intersections
|
||||
if (road_target(lhs) == intersection_node || road_target(rhs) == intersection_node)
|
||||
@@ -262,7 +262,8 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||
if (angularDeviation(connector_turn->angle, ORTHOGONAL_ANGLE) > NARROW_TURN_ANGLE)
|
||||
return false;
|
||||
|
||||
const auto num_lanes = [this](const MergableRoadData &road) {
|
||||
const auto num_lanes = [this](const MergableRoadData &road)
|
||||
{
|
||||
return std::max<std::uint8_t>(
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification.GetNumberOfLanes(), 1);
|
||||
};
|
||||
@@ -308,7 +309,8 @@ bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length)
|
||||
{
|
||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
@@ -380,7 +382,8 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length)
|
||||
{
|
||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
@@ -424,7 +427,8 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
/* extract the number of lanes for a road
|
||||
* restricts a vector to the last two thirds of the length
|
||||
*/
|
||||
const auto prune = [](auto &data_vector) {
|
||||
const auto prune = [](auto &data_vector)
|
||||
{
|
||||
BOOST_ASSERT(data_vector.size() >= 3);
|
||||
// erase the first third of the vector
|
||||
data_vector.erase(data_vector.begin(), data_vector.begin() + data_vector.size() / 3);
|
||||
@@ -493,7 +497,8 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
|
||||
return false;
|
||||
|
||||
// check if all entries at the destination or at the source are the same
|
||||
const auto all_same_name_and_degree_three = [this](const NodeID nid) {
|
||||
const auto all_same_name_and_degree_three = [this](const NodeID nid)
|
||||
{
|
||||
// check if the intersection found has degree three
|
||||
if (node_based_graph.GetOutDegree(nid) != 3)
|
||||
return false;
|
||||
@@ -505,7 +510,8 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(range.front()).annotation_data)
|
||||
.name_id;
|
||||
|
||||
const auto has_required_name = [this, required_name_id](const auto edge_id) {
|
||||
const auto has_required_name = [this, required_name_id](const auto edge_id)
|
||||
{
|
||||
const auto road_name_id =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
@@ -562,7 +568,8 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
|
||||
barrier_nodes,
|
||||
turn_lanes_data,
|
||||
next_intersection_parameters);
|
||||
const auto extract_name_id = [this](const MergableRoadData &road) {
|
||||
const auto extract_name_id = [this](const MergableRoadData &road)
|
||||
{
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id;
|
||||
|
||||
@@ -74,10 +74,12 @@ boost::optional<EdgeID> SelectRoadByNameOnlyChoiceAndStraightness::operator()(
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const
|
||||
{
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs)
|
||||
{
|
||||
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
||||
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
||||
const auto score = [&](const IntersectionViewData &road) {
|
||||
const auto score = [&](const IntersectionViewData &road)
|
||||
{
|
||||
double result_score = 0;
|
||||
// since angular deviation is limited by 0-180, we add 360 for invalid
|
||||
if (requires_entry && !road.entry_allowed)
|
||||
@@ -127,10 +129,12 @@ boost::optional<EdgeID> SelectStraightmostRoadByNameAndOnlyChoice::operator()(
|
||||
if (intersection.size() == 1)
|
||||
return {};
|
||||
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs)
|
||||
{
|
||||
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
||||
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
||||
const auto score = [&](const IntersectionViewData &road) {
|
||||
const auto score = [&](const IntersectionViewData &road)
|
||||
{
|
||||
double result_score = 0;
|
||||
// since angular deviation is limited by 0-180, we add 360 for invalid
|
||||
if (requires_entry && !road.entry_allowed)
|
||||
@@ -149,8 +153,11 @@ boost::optional<EdgeID> SelectStraightmostRoadByNameAndOnlyChoice::operator()(
|
||||
return score(lhs) < score(rhs);
|
||||
};
|
||||
|
||||
const auto count_desired_name =
|
||||
std::count_if(std::begin(intersection), std::end(intersection), [&](const auto &road) {
|
||||
const auto count_desired_name = std::count_if(
|
||||
std::begin(intersection),
|
||||
std::end(intersection),
|
||||
[&](const auto &road)
|
||||
{
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id == desired_name_id;
|
||||
|
||||
@@ -65,7 +65,8 @@ void LocationDependentData::loadLocationDependentData(
|
||||
|
||||
const auto &features_array = geojson["features"].GetArray();
|
||||
|
||||
auto convert_value = [](const auto &property) -> property_t {
|
||||
auto convert_value = [](const auto &property) -> property_t
|
||||
{
|
||||
if (property.IsString())
|
||||
return std::string(property.GetString());
|
||||
if (property.IsNumber())
|
||||
@@ -75,7 +76,8 @@ void LocationDependentData::loadLocationDependentData(
|
||||
return {};
|
||||
};
|
||||
|
||||
auto collect_properties = [this, &convert_value](const auto &object) -> std::size_t {
|
||||
auto collect_properties = [this, &convert_value](const auto &object) -> std::size_t
|
||||
{
|
||||
properties_t object_properties;
|
||||
for (const auto &property : object)
|
||||
{
|
||||
@@ -86,18 +88,21 @@ void LocationDependentData::loadLocationDependentData(
|
||||
return index;
|
||||
};
|
||||
|
||||
auto index_polygon = [this, &bounding_boxes](const auto &rings, auto properties_index) {
|
||||
auto index_polygon = [this, &bounding_boxes](const auto &rings, auto properties_index)
|
||||
{
|
||||
// At least an outer ring in polygon https://tools.ietf.org/html/rfc7946#section-3.1.6
|
||||
BOOST_ASSERT(rings.Size() > 0);
|
||||
|
||||
auto to_point = [](const auto &json) -> point_t {
|
||||
auto to_point = [](const auto &json) -> point_t
|
||||
{
|
||||
util::validateCoordinate(json);
|
||||
const auto &coords = json.GetArray();
|
||||
return {coords[0].GetDouble(), coords[1].GetDouble()};
|
||||
};
|
||||
|
||||
std::vector<segment_t> segments;
|
||||
auto append_ring_segments = [&segments, &to_point](const auto &coordinates_array) -> box_t {
|
||||
auto append_ring_segments = [&segments, &to_point](const auto &coordinates_array) -> box_t
|
||||
{
|
||||
using coord_t = boost::geometry::traits::coordinate_type<point_t>::type;
|
||||
auto x_min = std::numeric_limits<coord_t>::max();
|
||||
auto y_min = std::numeric_limits<coord_t>::max();
|
||||
@@ -208,68 +213,72 @@ LocationDependentData::FindByKey(const std::vector<std::size_t> &property_indexe
|
||||
std::vector<std::size_t> LocationDependentData::GetPropertyIndexes(const point_t &point) const
|
||||
{
|
||||
std::vector<std::size_t> result;
|
||||
auto inserter = [this, &result](const rtree_t::value_type &rtree_entry) {
|
||||
auto inserter = [this, &result](const rtree_t::value_type &rtree_entry)
|
||||
{
|
||||
const auto properties_index = polygons[rtree_entry.second].second;
|
||||
result.push_back(properties_index);
|
||||
};
|
||||
|
||||
// Search the R-tree and collect a Lua table of tags that correspond to the location
|
||||
rtree.query(boost::geometry::index::intersects(point) &&
|
||||
boost::geometry::index::satisfies([this, &point](const rtree_t::value_type &v) {
|
||||
// Simple point-in-polygon algorithm adapted from
|
||||
// https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
rtree.query(
|
||||
boost::geometry::index::intersects(point) &&
|
||||
boost::geometry::index::satisfies(
|
||||
[this, &point](const rtree_t::value_type &v)
|
||||
{
|
||||
// Simple point-in-polygon algorithm adapted from
|
||||
// https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
|
||||
const auto &envelop = v.first;
|
||||
const auto &bands = polygons[v.second].first;
|
||||
const auto &envelop = v.first;
|
||||
const auto &bands = polygons[v.second].first;
|
||||
|
||||
const auto y_min = envelop.min_corner().y();
|
||||
const auto y_max = envelop.max_corner().y();
|
||||
const auto dy = (y_max - y_min) / bands.size();
|
||||
const auto y_min = envelop.min_corner().y();
|
||||
const auto y_max = envelop.max_corner().y();
|
||||
const auto dy = (y_max - y_min) / bands.size();
|
||||
|
||||
std::size_t band = (point.y() - y_min) / dy;
|
||||
if (band >= bands.size())
|
||||
{
|
||||
band = bands.size() - 1;
|
||||
std::size_t band = (point.y() - y_min) / dy;
|
||||
if (band >= bands.size())
|
||||
{
|
||||
band = bands.size() - 1;
|
||||
}
|
||||
|
||||
bool inside = false;
|
||||
|
||||
for (const auto &segment : bands[band])
|
||||
{
|
||||
const auto point_x = point.x(), point_y = point.y();
|
||||
const auto from_x = segment.first.x(), from_y = segment.first.y();
|
||||
const auto to_x = segment.second.x(), to_y = segment.second.y();
|
||||
|
||||
if (to_y == from_y)
|
||||
{ // handle horizontal segments: check if on boundary or skip
|
||||
if ((to_y == point_y) &&
|
||||
(from_x == point_x || (to_x > point_x) != (from_x > point_x)))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool inside = false;
|
||||
|
||||
for (const auto &segment : bands[band])
|
||||
if ((to_y > point_y) != (from_y > point_y))
|
||||
{
|
||||
const auto point_x = point.x(), point_y = point.y();
|
||||
const auto from_x = segment.first.x(), from_y = segment.first.y();
|
||||
const auto to_x = segment.second.x(), to_y = segment.second.y();
|
||||
const auto ax = to_x - from_x;
|
||||
const auto ay = to_y - from_y;
|
||||
const auto tx = point_x - from_x;
|
||||
const auto ty = point_y - from_y;
|
||||
|
||||
if (to_y == from_y)
|
||||
{ // handle horizontal segments: check if on boundary or skip
|
||||
if ((to_y == point_y) &&
|
||||
(from_x == point_x || (to_x > point_x) != (from_x > point_x)))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
const auto cross_product = tx * ay - ax * ty;
|
||||
|
||||
if ((to_y > point_y) != (from_y > point_y))
|
||||
if (cross_product == 0)
|
||||
return true;
|
||||
|
||||
if ((ay > 0) == (cross_product > 0))
|
||||
{
|
||||
const auto ax = to_x - from_x;
|
||||
const auto ay = to_y - from_y;
|
||||
const auto tx = point_x - from_x;
|
||||
const auto ty = point_y - from_y;
|
||||
|
||||
const auto cross_product = tx * ay - ax * ty;
|
||||
|
||||
if (cross_product == 0)
|
||||
return true;
|
||||
|
||||
if ((ay > 0) == (cross_product > 0))
|
||||
{
|
||||
inside = !inside;
|
||||
}
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inside;
|
||||
}),
|
||||
boost::make_function_output_iterator(std::ref(inserter)));
|
||||
return inside;
|
||||
}),
|
||||
boost::make_function_output_iterator(std::ref(inserter)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -46,27 +46,31 @@ void NodeBasedGraphFactory::BuildCompressedOutputGraph(const std::vector<NodeBas
|
||||
util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
||||
|
||||
// check whether the graph is sane
|
||||
BOOST_ASSERT([this]() {
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
BOOST_ASSERT(
|
||||
[this]()
|
||||
{
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
for (const auto nbg_node_u :
|
||||
util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
{
|
||||
// we cannot have invalid edge-ids in the graph
|
||||
if (nbg_edge_id == SPECIAL_EDGEID)
|
||||
return false;
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
// we cannot have invalid edge-ids in the graph
|
||||
if (nbg_edge_id == SPECIAL_EDGEID)
|
||||
return false;
|
||||
|
||||
const auto nbg_node_v = compressed_output_graph.GetTarget(nbg_edge_id);
|
||||
const auto nbg_node_v = compressed_output_graph.GetTarget(nbg_edge_id);
|
||||
|
||||
auto reverse = compressed_output_graph.FindEdge(nbg_node_v, nbg_node_u);
|
||||
auto reverse = compressed_output_graph.FindEdge(nbg_node_v, nbg_node_u);
|
||||
|
||||
// found an edge that is reversed in both directions, should be two distinct edges
|
||||
if (compressed_output_graph.GetEdgeData(nbg_edge_id).reversed &&
|
||||
compressed_output_graph.GetEdgeData(reverse).reversed)
|
||||
return false;
|
||||
// found an edge that is reversed in both directions, should be two distinct
|
||||
// edges
|
||||
if (compressed_output_graph.GetEdgeData(nbg_edge_id).reversed &&
|
||||
compressed_output_graph.GetEdgeData(reverse).reversed)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
|
||||
void NodeBasedGraphFactory::Compress(ScriptingEnvironment &scripting_environment,
|
||||
@@ -208,13 +212,15 @@ void NodeBasedGraphFactory::CompressAnnotationData()
|
||||
}
|
||||
|
||||
// remove unreferenced entries, shifting other entries to the front
|
||||
const auto new_end =
|
||||
std::remove_if(annotation_data.begin(), annotation_data.end(), [&](auto const &data) {
|
||||
// both elements are considered equal (to remove the second
|
||||
// one) if the annotation mapping of the second one is
|
||||
// invalid
|
||||
return data.name_id == INVALID_NAMEID;
|
||||
});
|
||||
const auto new_end = std::remove_if(annotation_data.begin(),
|
||||
annotation_data.end(),
|
||||
[&](auto const &data)
|
||||
{
|
||||
// both elements are considered equal (to remove the
|
||||
// second one) if the annotation mapping of the second
|
||||
// one is invalid
|
||||
return data.name_id == INVALID_NAMEID;
|
||||
});
|
||||
|
||||
const auto old_size = annotation_data.size();
|
||||
// remove all remaining elements
|
||||
|
||||
@@ -123,9 +123,10 @@ struct transferBuilder
|
||||
for (const auto &suffix_node : suffix_nodes)
|
||||
{
|
||||
const auto &edges = rg.GetEdges(suffix_node);
|
||||
const auto edge_it = std::find_if(edges.begin(), edges.end(), [&to](const auto &edge) {
|
||||
return edge.node_based_to == to && !edge.is_transfer;
|
||||
});
|
||||
const auto edge_it = std::find_if(
|
||||
edges.begin(),
|
||||
edges.end(),
|
||||
[&to](const auto &edge) { return edge.node_based_to == to && !edge.is_transfer; });
|
||||
if (edge_it != edges.end())
|
||||
{
|
||||
*(new_suffix_it++) = edge_it->target;
|
||||
@@ -154,18 +155,22 @@ struct transferBuilder
|
||||
// the transfer
|
||||
const auto &restrictions = rg.GetRestrictions(cur_node);
|
||||
const auto is_restricted =
|
||||
std::any_of(restrictions.begin(), restrictions.end(), [&](const auto &restriction) {
|
||||
return restriction->IsTurnRestricted(suffix_edge.node_based_to) &&
|
||||
restriction->IsUnconditional();
|
||||
});
|
||||
std::any_of(restrictions.begin(),
|
||||
restrictions.end(),
|
||||
[&](const auto &restriction)
|
||||
{
|
||||
return restriction->IsTurnRestricted(suffix_edge.node_based_to) &&
|
||||
restriction->IsUnconditional();
|
||||
});
|
||||
if (is_restricted)
|
||||
continue;
|
||||
|
||||
const auto &edges = rg.GetEdges(cur_node);
|
||||
// Check that the suffix edge is not a next edge along the current path.
|
||||
const auto can_transfer = std::none_of(edges.begin(), edges.end(), [&](auto &edge) {
|
||||
return edge.node_based_to == suffix_edge.node_based_to;
|
||||
});
|
||||
const auto can_transfer = std::none_of(
|
||||
edges.begin(),
|
||||
edges.end(),
|
||||
[&](auto &edge) { return edge.node_based_to == suffix_edge.node_based_to; });
|
||||
if (can_transfer)
|
||||
{
|
||||
insertEdge(rg,
|
||||
@@ -186,9 +191,9 @@ struct transferBuilder
|
||||
|
||||
this->next_suffixes(from, to);
|
||||
|
||||
std::for_each(suffix_nodes.begin(), suffix_nodes.end(), [&](const auto &suffix_node) {
|
||||
this->add_suffix_transfer(suffix_node);
|
||||
});
|
||||
std::for_each(suffix_nodes.begin(),
|
||||
suffix_nodes.end(),
|
||||
[&](const auto &suffix_node) { this->add_suffix_transfer(suffix_node); });
|
||||
|
||||
for (const auto &suffix_node : suffix_nodes)
|
||||
{
|
||||
@@ -207,7 +212,8 @@ struct transferBuilder
|
||||
template <typename builder_type>
|
||||
void buildGraph(RestrictionGraph &rg, const std::vector<TurnRestriction> &restrictions)
|
||||
{
|
||||
const auto run_builder = [&](const auto &restriction) {
|
||||
const auto run_builder = [&](const auto &restriction)
|
||||
{
|
||||
builder_type builder(rg);
|
||||
|
||||
builder.start(restriction.turn_path.From(), restriction.turn_path.FirstVia());
|
||||
@@ -248,9 +254,9 @@ RestrictionGraph constructRestrictionGraph(const std::vector<TurnRestriction> &t
|
||||
// Start renumbering
|
||||
const auto permutation = util::orderingToPermutation(ordering);
|
||||
util::inplacePermutation(rg.nodes.begin(), rg.nodes.end(), permutation);
|
||||
std::for_each(rg.edges.begin(), rg.edges.end(), [&](auto &edge) {
|
||||
edge.target = permutation[edge.target];
|
||||
});
|
||||
std::for_each(rg.edges.begin(),
|
||||
rg.edges.end(),
|
||||
[&](auto &edge) { edge.target = permutation[edge.target]; });
|
||||
rg.num_via_nodes = std::count(is_via_node.begin(), is_via_node.end(), true);
|
||||
for (auto &entry : rg.via_edge_to_node)
|
||||
{
|
||||
|
||||
@@ -245,7 +245,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"valid",
|
||||
&osmium::Location::valid);
|
||||
|
||||
auto get_location_tag = [](auto &context, const auto &location, const char *key) {
|
||||
auto get_location_tag = [](auto &context, const auto &location, const char *key)
|
||||
{
|
||||
if (context.location_dependent_data.empty())
|
||||
return sol::object(context.state);
|
||||
|
||||
@@ -272,7 +273,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"get_nodes",
|
||||
[](const osmium::Way &way) { return sol::as_table(&way.nodes()); },
|
||||
"get_location_tag",
|
||||
[&context, &get_location_tag](const osmium::Way &way, const char *key) {
|
||||
[&context, &get_location_tag](const osmium::Way &way, const char *key)
|
||||
{
|
||||
// HEURISTIC: use a single node (last) of the way to localize the way
|
||||
// For more complicated scenarios a proper merging of multiple tags
|
||||
// at one or many locations must be provided
|
||||
@@ -292,9 +294,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"version",
|
||||
&osmium::Node::version,
|
||||
"get_location_tag",
|
||||
[&context, &get_location_tag](const osmium::Node &node, const char *key) {
|
||||
return get_location_tag(context, node.location(), key);
|
||||
});
|
||||
[&context, &get_location_tag](const osmium::Node &node, const char *key)
|
||||
{ return get_location_tag(context, node.location(), key); });
|
||||
|
||||
context.state.new_enum("traffic_lights",
|
||||
"none",
|
||||
@@ -310,7 +311,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"ResultNode",
|
||||
"traffic_lights",
|
||||
sol::property([](const ExtractionNode &node) { return node.traffic_lights; },
|
||||
[](ExtractionNode &node, const sol::object &obj) {
|
||||
[](ExtractionNode &node, const sol::object &obj)
|
||||
{
|
||||
if (obj.is<bool>())
|
||||
{
|
||||
// The old approach of assigning a boolean traffic light
|
||||
@@ -361,7 +363,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
sol::property(&ExtractionWay::GetName, &ExtractionWay::SetName),
|
||||
"ref", // backward compatibility
|
||||
sol::property(&ExtractionWay::GetForwardRef,
|
||||
[](ExtractionWay &way, const char *ref) {
|
||||
[](ExtractionWay &way, const char *ref)
|
||||
{
|
||||
way.SetForwardRef(ref);
|
||||
way.SetBackwardRef(ref);
|
||||
}),
|
||||
@@ -420,7 +423,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
sol::property([](const ExtractionWay &way) { return way.access_turn_classification; },
|
||||
[](ExtractionWay &way, int flag) { way.access_turn_classification = flag; }));
|
||||
|
||||
auto getTypedRefBySol = [](const sol::object &obj) -> ExtractionRelation::OsmIDTyped {
|
||||
auto getTypedRefBySol = [](const sol::object &obj) -> ExtractionRelation::OsmIDTyped
|
||||
{
|
||||
if (obj.is<osmium::Way>())
|
||||
{
|
||||
osmium::Way *way = obj.as<osmium::Way *>();
|
||||
@@ -456,20 +460,19 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"get_value_by_key",
|
||||
[](ExtractionRelation &rel, const char *key) -> const char * { return rel.GetAttr(key); },
|
||||
"get_role",
|
||||
[&getTypedRefBySol](ExtractionRelation &rel, const sol::object &obj) -> const char * {
|
||||
return rel.GetRole(getTypedRefBySol(obj));
|
||||
});
|
||||
[&getTypedRefBySol](ExtractionRelation &rel, const sol::object &obj) -> const char *
|
||||
{ return rel.GetRole(getTypedRefBySol(obj)); });
|
||||
|
||||
context.state.new_usertype<ExtractionRelationContainer>(
|
||||
"ExtractionRelationContainer",
|
||||
"get_relations",
|
||||
[&getTypedRefBySol](ExtractionRelationContainer &cont, const sol::object &obj)
|
||||
-> const ExtractionRelationContainer::RelationIDList & {
|
||||
return cont.GetRelations(getTypedRefBySol(obj));
|
||||
},
|
||||
-> const ExtractionRelationContainer::RelationIDList &
|
||||
{ return cont.GetRelations(getTypedRefBySol(obj)); },
|
||||
"relation",
|
||||
[](ExtractionRelationContainer &cont, const ExtractionRelation::OsmIDTyped &rel_id)
|
||||
-> const ExtractionRelation & { return cont.GetRelationData(rel_id); });
|
||||
[](ExtractionRelationContainer &cont,
|
||||
const ExtractionRelation::OsmIDTyped &rel_id) -> const ExtractionRelation &
|
||||
{ return cont.GetRelationData(rel_id); });
|
||||
|
||||
context.state.new_usertype<NodeBasedEdgeClassification>(
|
||||
"NodeBasedEdgeClassification",
|
||||
@@ -489,17 +492,14 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
"restricted",
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> bool { return c.restricted; }),
|
||||
"road_classification",
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> RoadClassification {
|
||||
return c.road_classification;
|
||||
}),
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> RoadClassification
|
||||
{ return c.road_classification; }),
|
||||
"highway_turn_classification",
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> uint8_t {
|
||||
return c.highway_turn_classification;
|
||||
}),
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> uint8_t
|
||||
{ return c.highway_turn_classification; }),
|
||||
"access_turn_classification",
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> uint8_t {
|
||||
return c.access_turn_classification;
|
||||
}));
|
||||
sol::property([](NodeBasedEdgeClassification &c) -> uint8_t
|
||||
{ return c.access_turn_classification; }));
|
||||
|
||||
context.state.new_usertype<ExtractionSegment>("ExtractionSegment",
|
||||
"source",
|
||||
@@ -517,10 +517,12 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
|
||||
// Keep in mind .location is available only if .pbf is preprocessed to set the location with the
|
||||
// ref using osmium command "osmium add-locations-to-ways"
|
||||
context.state.new_usertype<osmium::NodeRef>(
|
||||
"NodeRef", "id", &osmium::NodeRef::ref, "location", [](const osmium::NodeRef &nref) {
|
||||
return nref.location();
|
||||
});
|
||||
context.state.new_usertype<osmium::NodeRef>("NodeRef",
|
||||
"id",
|
||||
&osmium::NodeRef::ref,
|
||||
"location",
|
||||
[](const osmium::NodeRef &nref)
|
||||
{ return nref.location(); });
|
||||
|
||||
context.state.new_usertype<InternalExtractorEdge>("EdgeSource",
|
||||
"source_coordinate",
|
||||
@@ -576,7 +578,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
util::Log() << "Using profile api version " << context.api_version;
|
||||
|
||||
// version-dependent parts of the api
|
||||
auto initV2Context = [&]() {
|
||||
auto initV2Context = [&]()
|
||||
{
|
||||
// clear global not used in v2
|
||||
context.state["properties"] = sol::nullopt;
|
||||
|
||||
@@ -667,26 +670,31 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
}
|
||||
};
|
||||
|
||||
auto initialize_V3_extraction_turn = [&]() {
|
||||
auto initialize_V3_extraction_turn = [&]()
|
||||
{
|
||||
context.state.new_usertype<ExtractionTurn>(
|
||||
"ExtractionTurn",
|
||||
"angle",
|
||||
&ExtractionTurn::angle,
|
||||
"turn_type",
|
||||
sol::property([](const ExtractionTurn &turn) {
|
||||
if (turn.number_of_roads > 2 || turn.source_mode != turn.target_mode ||
|
||||
turn.is_u_turn)
|
||||
return osrm::guidance::TurnType::Turn;
|
||||
else
|
||||
return osrm::guidance::TurnType::NoTurn;
|
||||
}),
|
||||
sol::property(
|
||||
[](const ExtractionTurn &turn)
|
||||
{
|
||||
if (turn.number_of_roads > 2 || turn.source_mode != turn.target_mode ||
|
||||
turn.is_u_turn)
|
||||
return osrm::guidance::TurnType::Turn;
|
||||
else
|
||||
return osrm::guidance::TurnType::NoTurn;
|
||||
}),
|
||||
"direction_modifier",
|
||||
sol::property([](const ExtractionTurn &turn) {
|
||||
if (turn.is_u_turn)
|
||||
return osrm::guidance::DirectionModifier::UTurn;
|
||||
else
|
||||
return osrm::guidance::DirectionModifier::Straight;
|
||||
}),
|
||||
sol::property(
|
||||
[](const ExtractionTurn &turn)
|
||||
{
|
||||
if (turn.is_u_turn)
|
||||
return osrm::guidance::DirectionModifier::UTurn;
|
||||
else
|
||||
return osrm::guidance::DirectionModifier::Straight;
|
||||
}),
|
||||
"has_traffic_light",
|
||||
&ExtractionTurn::has_traffic_light,
|
||||
"weight",
|
||||
|
||||
@@ -12,7 +12,8 @@ TurnPathCompressor::TurnPathCompressor(std::vector<TurnRestriction> &restriction
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
{
|
||||
// Track all turn paths by their respective start/via/end nodes.
|
||||
auto index = [&](auto &element) {
|
||||
auto index = [&](auto &element)
|
||||
{
|
||||
starts.insert({element.From(), &element});
|
||||
ends.insert({element.To(), &element});
|
||||
if (element.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
@@ -44,7 +45,8 @@ void TurnPathCompressor::Compress(const NodeID from, const NodeID via, const Nod
|
||||
std::back_inserter(start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_start = [&](auto ptr) {
|
||||
const auto update_start = [&](auto ptr)
|
||||
{
|
||||
if (ptr->Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
|
||||
@@ -97,7 +99,8 @@ void TurnPathCompressor::Compress(const NodeID from, const NodeID via, const Nod
|
||||
std::back_inserter(end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end = [&](auto ptr) {
|
||||
const auto update_end = [&](auto ptr)
|
||||
{
|
||||
if (ptr->Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
auto &node_ptr = ptr->AsViaNodePath();
|
||||
@@ -145,7 +148,8 @@ void TurnPathCompressor::Compress(const NodeID from, const NodeID via, const Nod
|
||||
// remove compressed node from all via paths
|
||||
auto all_vias_range = vias.equal_range(via);
|
||||
|
||||
const auto update_via = [&](auto restriction_pair) {
|
||||
const auto update_via = [&](auto restriction_pair)
|
||||
{
|
||||
BOOST_ASSERT(restriction_pair.second->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = restriction_pair.second->AsViaWayPath();
|
||||
BOOST_ASSERT(std::find(way_ptr.via.begin(), way_ptr.via.end(), via) != way_ptr.via.end());
|
||||
|
||||
@@ -18,7 +18,8 @@ std::vector<T> removeInvalidTurnPaths(std::vector<T> turn_relations,
|
||||
log << "Removing invalid " << T::Name() << "s...";
|
||||
TIMER_START(remove_invalid_turn_paths);
|
||||
|
||||
const auto is_valid_edge = [&node_based_graph](const auto from, const auto to) {
|
||||
const auto is_valid_edge = [&node_based_graph](const auto from, const auto to)
|
||||
{
|
||||
const auto eid = node_based_graph.FindEdge(from, to);
|
||||
if (eid == SPECIAL_EDGEID)
|
||||
{
|
||||
@@ -35,26 +36,29 @@ std::vector<T> removeInvalidTurnPaths(std::vector<T> turn_relations,
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto is_valid_node = [is_valid_edge](const auto &via_node_path) {
|
||||
const auto is_valid_node = [is_valid_edge](const auto &via_node_path)
|
||||
{
|
||||
return is_valid_edge(via_node_path.from, via_node_path.via) &&
|
||||
is_valid_edge(via_node_path.via, via_node_path.to);
|
||||
};
|
||||
|
||||
const auto is_valid_way = [is_valid_edge](const auto &via_way_path) {
|
||||
const auto is_valid_way = [is_valid_edge](const auto &via_way_path)
|
||||
{
|
||||
if (!is_valid_edge(via_way_path.from, via_way_path.via.front()))
|
||||
return false;
|
||||
|
||||
const auto invalid_it = std::adjacent_find(
|
||||
via_way_path.via.begin(), via_way_path.via.end(), [&](auto via_from, auto via_to) {
|
||||
return !is_valid_edge(via_from, via_to);
|
||||
});
|
||||
const auto invalid_it = std::adjacent_find(via_way_path.via.begin(),
|
||||
via_way_path.via.end(),
|
||||
[&](auto via_from, auto via_to)
|
||||
{ return !is_valid_edge(via_from, via_to); });
|
||||
if (invalid_it != via_way_path.via.end())
|
||||
return false;
|
||||
|
||||
return is_valid_edge(via_way_path.via.back(), via_way_path.to);
|
||||
};
|
||||
|
||||
const auto is_invalid = [is_valid_way, is_valid_node](const auto &turn_relation) {
|
||||
const auto is_invalid = [is_valid_way, is_valid_node](const auto &turn_relation)
|
||||
{
|
||||
if (turn_relation.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
return !is_valid_node(turn_relation.turn_path.AsViaNodePath());
|
||||
|
||||
@@ -38,9 +38,10 @@ bool WayRestrictionMap::IsRestricted(DuplicatedNodeID duplicated_node, const Nod
|
||||
// Checks if a turn to 'to' is restricted
|
||||
BOOST_ASSERT(duplicated_node < restriction_graph.num_via_nodes);
|
||||
const auto &restrictions = restriction_graph.GetRestrictions(duplicated_node);
|
||||
return std::any_of(restrictions.begin(), restrictions.end(), [&to](const auto &restriction) {
|
||||
return restriction->IsTurnRestricted(to);
|
||||
});
|
||||
return std::any_of(restrictions.begin(),
|
||||
restrictions.end(),
|
||||
[&to](const auto &restriction)
|
||||
{ return restriction->IsTurnRestricted(to); });
|
||||
}
|
||||
|
||||
std::vector<const TurnRestriction *>
|
||||
|
||||
@@ -43,10 +43,13 @@ bool DrivewayHandler::canProcess(const NodeID /*nid*/,
|
||||
return false;
|
||||
|
||||
auto low_priority_count =
|
||||
std::count_if(intersection.begin(), intersection.end(), [this](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid)
|
||||
.flags.road_classification.IsLowPriorityRoadClass();
|
||||
});
|
||||
std::count_if(intersection.begin(),
|
||||
intersection.end(),
|
||||
[this](const auto &road)
|
||||
{
|
||||
return node_based_graph.GetEdgeData(road.eid)
|
||||
.flags.road_classification.IsLowPriorityRoadClass();
|
||||
});
|
||||
|
||||
// Process intersection if it has two edges with normal priority and one is the entry edge,
|
||||
// and also has at least one edge with lower priority
|
||||
@@ -57,11 +60,13 @@ Intersection DrivewayHandler::operator()(const NodeID nid,
|
||||
const EdgeID source_edge_id,
|
||||
Intersection intersection) const
|
||||
{
|
||||
auto road =
|
||||
std::find_if(intersection.begin() + 1, intersection.end(), [this](const auto &road) {
|
||||
return !node_based_graph.GetEdgeData(road.eid)
|
||||
.flags.road_classification.IsLowPriorityRoadClass();
|
||||
});
|
||||
auto road = std::find_if(intersection.begin() + 1,
|
||||
intersection.end(),
|
||||
[this](const auto &road)
|
||||
{
|
||||
return !node_based_graph.GetEdgeData(road.eid)
|
||||
.flags.road_classification.IsLowPriorityRoadClass();
|
||||
});
|
||||
|
||||
(void)nid;
|
||||
OSRM_ASSERT(road != intersection.end(), node_coordinates[nid]);
|
||||
@@ -76,14 +81,22 @@ Intersection DrivewayHandler::operator()(const NodeID nid,
|
||||
|
||||
if (road->instruction.direction_modifier == DirectionModifier::Straight)
|
||||
{
|
||||
std::for_each(intersection.begin() + 1, road, [](auto &side_road) {
|
||||
if (side_road.instruction.direction_modifier == DirectionModifier::Straight)
|
||||
side_road.instruction.direction_modifier = DirectionModifier::SlightRight;
|
||||
});
|
||||
std::for_each(road + 1, intersection.end(), [](auto &side_road) {
|
||||
if (side_road.instruction.direction_modifier == DirectionModifier::Straight)
|
||||
side_road.instruction.direction_modifier = DirectionModifier::SlightLeft;
|
||||
});
|
||||
std::for_each(
|
||||
intersection.begin() + 1,
|
||||
road,
|
||||
[](auto &side_road)
|
||||
{
|
||||
if (side_road.instruction.direction_modifier == DirectionModifier::Straight)
|
||||
side_road.instruction.direction_modifier = DirectionModifier::SlightRight;
|
||||
});
|
||||
std::for_each(
|
||||
road + 1,
|
||||
intersection.end(),
|
||||
[](auto &side_road)
|
||||
{
|
||||
if (side_road.instruction.direction_modifier == DirectionModifier::Straight)
|
||||
side_road.instruction.direction_modifier = DirectionModifier::SlightLeft;
|
||||
});
|
||||
}
|
||||
|
||||
return intersection;
|
||||
|
||||
@@ -96,7 +96,9 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
|
||||
// First part of the pipeline generates iterator ranges of IDs in sets of GRAINSIZE
|
||||
tbb::filter<void, tbb::blocked_range<NodeID>> generator_stage(
|
||||
tbb::filter_mode::serial_in_order, [&](tbb::flow_control &fc) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&](tbb::flow_control &fc)
|
||||
{
|
||||
if (current_node < node_count)
|
||||
{
|
||||
auto next_node = std::min(current_node + GRAINSIZE, node_count);
|
||||
@@ -116,7 +118,8 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
//
|
||||
tbb::filter<tbb::blocked_range<NodeID>, TurnsPipelineBufferPtr> guidance_stage(
|
||||
tbb::filter_mode::parallel,
|
||||
[&](const tbb::blocked_range<NodeID> &intersection_node_range) {
|
||||
[&](const tbb::blocked_range<NodeID> &intersection_node_range)
|
||||
{
|
||||
auto buffer = std::make_shared<TurnsPipelineBuffer>();
|
||||
buffer->nodes_processed = intersection_node_range.size();
|
||||
|
||||
@@ -224,9 +227,8 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const auto turn =
|
||||
std::find_if(intersection.begin(),
|
||||
intersection.end(),
|
||||
[edge = outgoing_edge.edge](const auto &road) {
|
||||
return road.eid == edge;
|
||||
});
|
||||
[edge = outgoing_edge.edge](const auto &road)
|
||||
{ return road.eid == edge; });
|
||||
|
||||
OSRM_ASSERT(turn != intersection.end(),
|
||||
node_coordinates[intersection_node]);
|
||||
@@ -267,9 +269,8 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
auto has_unconditional =
|
||||
std::any_of(restrictions.begin(),
|
||||
restrictions.end(),
|
||||
[](const auto &restriction) {
|
||||
return restriction->IsUnconditional();
|
||||
});
|
||||
[](const auto &restriction)
|
||||
{ return restriction->IsUnconditional(); });
|
||||
|
||||
if (has_unconditional)
|
||||
continue;
|
||||
@@ -307,7 +308,9 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
std::vector<guidance::TurnData> delayed_turn_data;
|
||||
|
||||
tbb::filter<TurnsPipelineBufferPtr, void> guidance_output_stage(
|
||||
tbb::filter_mode::serial_in_order, [&](auto buffer) {
|
||||
tbb::filter_mode::serial_in_order,
|
||||
[&](auto buffer)
|
||||
{
|
||||
guidance_progress.PrintAddition(buffer->nodes_processed);
|
||||
|
||||
connectivity_checksum = buffer->checksum.update_checksum(connectivity_checksum);
|
||||
@@ -315,9 +318,8 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
// Guidance data
|
||||
std::for_each(buffer->continuous_turn_data.begin(),
|
||||
buffer->continuous_turn_data.end(),
|
||||
[&turn_data_container](const auto &turn_data) {
|
||||
turn_data_container.push_back(turn_data);
|
||||
});
|
||||
[&turn_data_container](const auto &turn_data)
|
||||
{ turn_data_container.push_back(turn_data); });
|
||||
|
||||
// Copy via-way restrictions delayed data
|
||||
delayed_turn_data.insert(delayed_turn_data.end(),
|
||||
@@ -336,9 +338,8 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
// NOTE: EBG edges delayed_data and turns delayed_turn_data have the same index
|
||||
std::for_each(delayed_turn_data.begin(),
|
||||
delayed_turn_data.end(),
|
||||
[&turn_data_container](const auto &turn_data) {
|
||||
turn_data_container.push_back(turn_data);
|
||||
});
|
||||
[&turn_data_container](const auto &turn_data)
|
||||
{ turn_data_container.push_back(turn_data); });
|
||||
}
|
||||
|
||||
util::Log() << "done.";
|
||||
|
||||
@@ -356,7 +356,8 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
|
||||
ConnectedRoad &right) const
|
||||
{
|
||||
// TODO handle low priority road classes in a reasonable way
|
||||
const auto suppressed_type = [&](const ConnectedRoad &road) {
|
||||
const auto suppressed_type = [&](const ConnectedRoad &road)
|
||||
{
|
||||
const auto in_mode =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||
|
||||
@@ -96,10 +96,13 @@ MotorwayHandler::operator()(const NodeID, const EdgeID via_eid, Intersection int
|
||||
if (isMotorwayClass(via_eid, node_based_graph))
|
||||
{
|
||||
intersection = fromMotorway(via_eid, std::move(intersection));
|
||||
std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
|
||||
if (road.instruction.type == TurnType::OnRamp)
|
||||
road.instruction.type = TurnType::OffRamp;
|
||||
});
|
||||
std::for_each(intersection.begin(),
|
||||
intersection.end(),
|
||||
[](ConnectedRoad &road)
|
||||
{
|
||||
if (road.instruction.type == TurnType::OnRamp)
|
||||
road.instruction.type = TurnType::OffRamp;
|
||||
});
|
||||
return intersection;
|
||||
}
|
||||
else // coming from a ramp
|
||||
@@ -116,7 +119,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
||||
BOOST_ASSERT(isMotorwayClass(via_eid, node_based_graph));
|
||||
|
||||
// find the angle that continues on our current highway
|
||||
const auto getContinueAngle = [this, in_data](const Intersection &intersection) {
|
||||
const auto getContinueAngle = [this, in_data](const Intersection &intersection)
|
||||
{
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
if (!road.entry_allowed)
|
||||
@@ -136,7 +140,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
||||
return intersection[0].angle;
|
||||
};
|
||||
|
||||
const auto getMostLikelyContinue = [this](const Intersection &intersection) {
|
||||
const auto getMostLikelyContinue = [this](const Intersection &intersection)
|
||||
{
|
||||
double angle = intersection[0].angle;
|
||||
double best = 180;
|
||||
for (const auto &road : intersection)
|
||||
@@ -151,7 +156,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
||||
return angle;
|
||||
};
|
||||
|
||||
const auto findBestContinue = [&]() {
|
||||
const auto findBestContinue = [&]()
|
||||
{
|
||||
const double continue_angle = getContinueAngle(intersection);
|
||||
if (continue_angle != intersection[0].angle)
|
||||
return continue_angle;
|
||||
@@ -209,10 +215,11 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
||||
const auto valid_exits = std::count_if(intersection.begin(),
|
||||
intersection.end(),
|
||||
[](const auto &road) { return road.entry_allowed; });
|
||||
const auto exiting_motorways =
|
||||
std::count_if(intersection.begin(), intersection.end(), [this](const auto &road) {
|
||||
return road.entry_allowed && isMotorwayClass(road.eid, node_based_graph);
|
||||
});
|
||||
const auto exiting_motorways = std::count_if(
|
||||
intersection.begin(),
|
||||
intersection.end(),
|
||||
[this](const auto &road)
|
||||
{ return road.entry_allowed && isMotorwayClass(road.eid, node_based_graph); });
|
||||
|
||||
if (exiting_motorways == 0)
|
||||
{
|
||||
|
||||
@@ -119,11 +119,11 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
||||
if (!has_limited_size)
|
||||
return false;
|
||||
|
||||
const bool simple_exits =
|
||||
roundabout_nodes.end() ==
|
||||
std::find_if(roundabout_nodes.begin(), roundabout_nodes.end(), [this](const NodeID node) {
|
||||
return (node_based_graph.GetOutDegree(node) > 3);
|
||||
});
|
||||
const bool simple_exits = roundabout_nodes.end() ==
|
||||
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;
|
||||
@@ -131,7 +131,8 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
||||
// 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]() {
|
||||
const auto exit_bearings = [this, &roundabout_nodes]()
|
||||
{
|
||||
std::vector<double> result;
|
||||
for (const auto node : roundabout_nodes)
|
||||
{
|
||||
@@ -151,7 +152,8 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
||||
edge_range.begin(),
|
||||
edge_range.end(),
|
||||
std::uint8_t{0},
|
||||
[this](const auto current_max, const auto current_eid) {
|
||||
[this](const auto current_max, const auto current_eid)
|
||||
{
|
||||
return std::max(current_max,
|
||||
node_based_graph.GetEdgeData(current_eid)
|
||||
.flags.road_classification.GetNumberOfLanes());
|
||||
@@ -187,7 +189,8 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
||||
return result;
|
||||
}();
|
||||
|
||||
const bool well_distinct_bearings = [](const std::vector<double> &bearings) {
|
||||
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 =
|
||||
@@ -207,10 +210,10 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
std::unordered_set<unsigned> roundabout_name_ids;
|
||||
std::unordered_set<unsigned> connected_names;
|
||||
|
||||
const auto getNextOnRoundabout = [this, &roundabout_name_ids, &connected_names](
|
||||
const NodeID node,
|
||||
const bool roundabout,
|
||||
const bool circular) {
|
||||
const auto getNextOnRoundabout =
|
||||
[this, &roundabout_name_ids, &connected_names](
|
||||
const NodeID node, const bool roundabout, const bool circular)
|
||||
{
|
||||
BOOST_ASSERT(roundabout != circular);
|
||||
EdgeID continue_edge = SPECIAL_EDGEID;
|
||||
for (const auto edge_id : node_based_graph.GetAdjacentEdgeRange(node))
|
||||
@@ -230,7 +233,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
if (!edge_name_empty)
|
||||
{
|
||||
|
||||
const auto announce = [&](unsigned id) {
|
||||
const auto announce = [&](unsigned id)
|
||||
{
|
||||
return util::guidance::requiresNameAnnounced(
|
||||
id, edge_data.name_id, name_table, street_name_suffix_table);
|
||||
};
|
||||
@@ -250,7 +254,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
};
|
||||
|
||||
// this value is a hard abort to deal with potential self-loops
|
||||
const auto countRoundaboutFlags = [&](const NodeID at_node) {
|
||||
const auto countRoundaboutFlags = [&](const NodeID at_node)
|
||||
{
|
||||
// FIXME: this would be nicer as boost::count_if, but our integer range does not support
|
||||
// these range based handlers
|
||||
std::size_t count = 0;
|
||||
@@ -263,7 +268,8 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
return count;
|
||||
};
|
||||
|
||||
const auto getEdgeLength = [&](const NodeID source_node, EdgeID eid) {
|
||||
const auto getEdgeLength = [&](const NodeID source_node, EdgeID eid)
|
||||
{
|
||||
double length = 0.;
|
||||
auto last_coord = node_coordinates[source_node];
|
||||
const auto &edge_bucket = compressed_geometries.GetBucketReference(eid);
|
||||
@@ -404,7 +410,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
|
||||
else
|
||||
{
|
||||
// Check if there is a non-service exit
|
||||
const auto has_non_ignorable_exit = [&]() {
|
||||
const auto has_non_ignorable_exit = [&]()
|
||||
{
|
||||
for (const auto eid :
|
||||
node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
{
|
||||
|
||||
@@ -46,7 +46,8 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
extractor::intersection::CoordinateExtractor coordExtractor(
|
||||
graph, factory.GetCompressedEdges(), coordinates);
|
||||
|
||||
auto const get_edge_length = [&](NodeID from_node, EdgeID edge_id, NodeID to_node) {
|
||||
auto const get_edge_length = [&](NodeID from_node, EdgeID edge_id, NodeID to_node)
|
||||
{
|
||||
auto const geom =
|
||||
coordExtractor.GetCoordinatesAlongRoad(from_node, edge_id, false, to_node);
|
||||
double length = 0.0;
|
||||
@@ -58,7 +59,8 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
};
|
||||
|
||||
// Returns an angle between edges from from_edge_id to to_edge_id
|
||||
auto const get_angle = [&](NodeID from_node, EdgeID from_edge_id, EdgeID to_edge_id) {
|
||||
auto const get_angle = [&](NodeID from_node, EdgeID from_edge_id, EdgeID to_edge_id)
|
||||
{
|
||||
auto intersection_node = graph.GetTarget(from_edge_id);
|
||||
auto from_edge_id_outgoing = graph.FindEdge(intersection_node, from_node);
|
||||
auto to_node = graph.GetTarget(to_edge_id);
|
||||
@@ -70,7 +72,8 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
node_from, coordinates[intersection_node], node_to);
|
||||
};
|
||||
|
||||
auto const get_edge_info = [&](EdgeID edge_id, NodeID node, auto const &edge_data) -> EdgeInfo {
|
||||
auto const get_edge_info = [&](EdgeID edge_id, NodeID node, auto const &edge_data) -> EdgeInfo
|
||||
{
|
||||
/// @todo Make string normalization/lowercase/trim for comparison ...
|
||||
|
||||
auto const id = annotation[edge_data.annotation_data].name_id;
|
||||
@@ -84,22 +87,24 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
edge_data.flags};
|
||||
};
|
||||
|
||||
auto is_bidirectional = [](auto flags) {
|
||||
return flags.is_split || (!flags.is_split && flags.forward && flags.backward);
|
||||
};
|
||||
auto is_bidirectional = [](auto flags)
|
||||
{ return flags.is_split || (!flags.is_split && flags.forward && flags.backward); };
|
||||
|
||||
auto is_internal_straight = [](auto const turn_degree) {
|
||||
auto is_internal_straight = [](auto const turn_degree)
|
||||
{
|
||||
return (turn_degree > INTERNAL_STRAIGHT_LOWER_BOUND &&
|
||||
turn_degree < INTERNAL_STRAIGHT_UPPER_BOUND);
|
||||
};
|
||||
|
||||
// Lambda to check if the turn set includes a right turn type
|
||||
const auto has_turn_right = [](std::set<guidance::DirectionModifier::Enum> &turn_types) {
|
||||
const auto has_turn_right = [](std::set<guidance::DirectionModifier::Enum> &turn_types)
|
||||
{
|
||||
return turn_types.find(guidance::DirectionModifier::Right) != turn_types.end() ||
|
||||
turn_types.find(guidance::DirectionModifier::SharpRight) != turn_types.end();
|
||||
};
|
||||
// Lambda to check if the turn set includes a left turn type
|
||||
const auto has_turn_left = [](std::set<guidance::DirectionModifier::Enum> &turn_types) {
|
||||
const auto has_turn_left = [](std::set<guidance::DirectionModifier::Enum> &turn_types)
|
||||
{
|
||||
return turn_types.find(guidance::DirectionModifier::Left) != turn_types.end() ||
|
||||
turn_types.find(guidance::DirectionModifier::SharpLeft) != turn_types.end();
|
||||
};
|
||||
@@ -108,7 +113,8 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
const std::vector<EdgeInfo> &v1,
|
||||
const std::vector<EdgeInfo> &v2,
|
||||
EdgeInfo const ¤t,
|
||||
double edge_length) {
|
||||
double edge_length)
|
||||
{
|
||||
// Internal intersection edges must be short and cannot be a roundabout.
|
||||
// Also they must be a road use (not footway, cycleway, etc.)
|
||||
// TODO - consider whether alleys, cul-de-sacs, and other road uses
|
||||
@@ -219,7 +225,8 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
return true;
|
||||
};
|
||||
|
||||
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2) {
|
||||
auto const collect_edge_info_fn = [&](auto const &edges1, NodeID node2)
|
||||
{
|
||||
std::vector<EdgeInfo> info;
|
||||
|
||||
for (auto e : edges1)
|
||||
@@ -234,15 +241,15 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
if (info.empty())
|
||||
return info;
|
||||
|
||||
std::sort(info.begin(), info.end(), [](EdgeInfo const &e1, EdgeInfo const &e2) {
|
||||
return e1.node < e2.node;
|
||||
});
|
||||
std::sort(info.begin(),
|
||||
info.end(),
|
||||
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node < e2.node; });
|
||||
|
||||
info.erase(
|
||||
std::unique(info.begin(),
|
||||
info.end(),
|
||||
[](EdgeInfo const &e1, EdgeInfo const &e2) { return e1.node == e2.node; }),
|
||||
info.end());
|
||||
info.erase(std::unique(info.begin(),
|
||||
info.end(),
|
||||
[](EdgeInfo const &e1, EdgeInfo const &e2)
|
||||
{ return e1.node == e2.node; }),
|
||||
info.end());
|
||||
|
||||
return info;
|
||||
};
|
||||
@@ -253,7 +260,8 @@ std::unordered_set<EdgeID> findSegregatedNodes(const extractor::NodeBasedGraphFa
|
||||
NodeID node1,
|
||||
auto const &edges2,
|
||||
NodeID node2,
|
||||
double edge_length) {
|
||||
double edge_length)
|
||||
{
|
||||
return isSegregated(node1,
|
||||
collect_edge_info_fn(edges1, node2),
|
||||
collect_edge_info_fn(edges2, node1),
|
||||
|
||||
@@ -91,7 +91,8 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/,
|
||||
}
|
||||
|
||||
// Link-check for (bc) and later on (cd) which both are getting shortcutted by Sliproad
|
||||
const auto is_potential_link = [this, main_road](const ConnectedRoad &road) {
|
||||
const auto is_potential_link = [this, main_road](const ConnectedRoad &road)
|
||||
{
|
||||
if (!road.entry_allowed)
|
||||
{
|
||||
return false;
|
||||
@@ -188,7 +189,8 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/,
|
||||
const auto is_left_sliproad_turn = road_index > *obvious;
|
||||
|
||||
// Road at the intersection the main road leads onto which the sliproad arrives onto
|
||||
const auto crossing_road = [&] {
|
||||
const auto crossing_road = [&]
|
||||
{
|
||||
if (is_left_sliproad_turn)
|
||||
return main_road_intersection->intersection.getLeftmostRoad();
|
||||
|
||||
@@ -266,7 +268,8 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/,
|
||||
if (target_intersection.isDeadEnd())
|
||||
continue;
|
||||
|
||||
const auto find_valid = [](const extractor::intersection::IntersectionView &view) {
|
||||
const auto find_valid = [](const extractor::intersection::IntersectionView &view)
|
||||
{
|
||||
// according to our current sliproad idea, there should only be one valid turn
|
||||
auto itr = std::find_if(
|
||||
view.begin(), view.end(), [](const auto &road) { return road.entry_allowed; });
|
||||
@@ -326,16 +329,19 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/,
|
||||
is_left_sliproad_turn ? main_road_intersection->intersection.size() - 2 : 2;
|
||||
auto next_to_crossing_road = main_road_intersection->intersection[next_to_crossing_idx];
|
||||
auto next_to_crossing_node = node_based_graph.GetTarget(next_to_crossing_road.eid);
|
||||
auto found_common_node = std::find_if(
|
||||
begin(target_intersection), end(target_intersection), [&](const auto &road) {
|
||||
if (next_to_crossing_node == node_based_graph.GetTarget(road.eid))
|
||||
{
|
||||
auto direction = getTurnDirection(road.angle);
|
||||
return direction == DirectionModifier::SharpRight ||
|
||||
direction == DirectionModifier::SharpLeft;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
auto found_common_node =
|
||||
std::find_if(begin(target_intersection),
|
||||
end(target_intersection),
|
||||
[&](const auto &road)
|
||||
{
|
||||
if (next_to_crossing_node == node_based_graph.GetTarget(road.eid))
|
||||
{
|
||||
auto direction = getTurnDirection(road.angle);
|
||||
return direction == DirectionModifier::SharpRight ||
|
||||
direction == DirectionModifier::SharpLeft;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (found_common_node == target_intersection.end())
|
||||
continue;
|
||||
}
|
||||
@@ -499,7 +505,8 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/,
|
||||
node_based_graph.GetEdgeData(candidate_road.eid).annotation_data);
|
||||
|
||||
// Name mismatch: check roads at `c` and `d` for same name
|
||||
const auto name_mismatch = [&](const NameID road_name_id) {
|
||||
const auto name_mismatch = [&](const NameID road_name_id)
|
||||
{
|
||||
return util::guidance::requiresNameAnnounced(road_name_id, //
|
||||
candidate_data.name_id, //
|
||||
name_table, //
|
||||
|
||||
@@ -50,11 +50,15 @@ bool SuppressModeHandler::canProcess(const NodeID,
|
||||
const auto first = begin(intersection);
|
||||
const auto last = end(intersection);
|
||||
|
||||
const auto all_share_mode = std::all_of(first, last, [this, &in_mode](const auto &road) {
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode == in_mode;
|
||||
});
|
||||
const auto all_share_mode = std::all_of(
|
||||
first,
|
||||
last,
|
||||
[this, &in_mode](const auto &road)
|
||||
{
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode == in_mode;
|
||||
});
|
||||
|
||||
return (suppress_in_mode != end(suppressed)) && all_share_mode;
|
||||
}
|
||||
@@ -65,13 +69,16 @@ SuppressModeHandler::operator()(const NodeID, const EdgeID, Intersection interse
|
||||
const auto first = begin(intersection);
|
||||
const auto last = end(intersection);
|
||||
|
||||
std::for_each(first, last, [&](auto &road) {
|
||||
const auto modifier = road.instruction.direction_modifier;
|
||||
// use NoTurn, to not even have it as an IntermediateIntersection
|
||||
const auto type = TurnType::NoTurn;
|
||||
std::for_each(first,
|
||||
last,
|
||||
[&](auto &road)
|
||||
{
|
||||
const auto modifier = road.instruction.direction_modifier;
|
||||
// use NoTurn, to not even have it as an IntermediateIntersection
|
||||
const auto type = TurnType::NoTurn;
|
||||
|
||||
road.instruction = {type, modifier};
|
||||
});
|
||||
road.instruction = {type, modifier};
|
||||
});
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,8 @@ Intersection TurnAnalysis::AssignTurnTypes(
|
||||
std::transform(intersection_view.begin(),
|
||||
intersection_view.end(),
|
||||
std::back_inserter(intersection),
|
||||
[&](const extractor::intersection::IntersectionViewData &data) {
|
||||
[&](const extractor::intersection::IntersectionViewData &data)
|
||||
{
|
||||
return ConnectedRoad(data,
|
||||
{TurnType::Invalid, DirectionModifier::UTurn},
|
||||
INVALID_LANE_DATAID);
|
||||
@@ -161,10 +162,13 @@ Intersection TurnAnalysis::AssignTurnTypes(
|
||||
// Turn On Ramps Into Off Ramps, if we come from a motorway-like road
|
||||
if (node_based_graph.GetEdgeData(entering_via_edge).flags.road_classification.IsMotorwayClass())
|
||||
{
|
||||
std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
|
||||
if (road.instruction.type == TurnType::OnRamp)
|
||||
road.instruction.type = TurnType::OffRamp;
|
||||
});
|
||||
std::for_each(intersection.begin(),
|
||||
intersection.end(),
|
||||
[](ConnectedRoad &road)
|
||||
{
|
||||
if (road.instruction.type == TurnType::OnRamp)
|
||||
road.instruction.type = TurnType::OffRamp;
|
||||
});
|
||||
}
|
||||
|
||||
// After we ran all handlers and determined instruction type
|
||||
|
||||
@@ -17,14 +17,14 @@ classifyIntersection(Intersection intersection, const osrm::util::Coordinate &lo
|
||||
|
||||
std::sort(intersection.begin(),
|
||||
intersection.end(),
|
||||
[](const ConnectedRoad &left, const ConnectedRoad &right) {
|
||||
return left.perceived_bearing < right.perceived_bearing;
|
||||
});
|
||||
[](const ConnectedRoad &left, const ConnectedRoad &right)
|
||||
{ return left.perceived_bearing < right.perceived_bearing; });
|
||||
|
||||
util::guidance::EntryClass entry_class;
|
||||
util::guidance::BearingClass bearing_class;
|
||||
|
||||
const bool canBeDiscretized = [&]() {
|
||||
const bool canBeDiscretized = [&]()
|
||||
{
|
||||
if (intersection.size() <= 1)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -127,9 +127,8 @@ bool findPreviousIntersection(const NodeID node_v,
|
||||
result_intersection.end() !=
|
||||
std::find_if(result_intersection.begin(),
|
||||
result_intersection.end(),
|
||||
[via_edge](const extractor::intersection::IntersectionViewData &road) {
|
||||
return road.eid == via_edge;
|
||||
});
|
||||
[via_edge](const extractor::intersection::IntersectionViewData &road)
|
||||
{ return road.eid == via_edge; });
|
||||
|
||||
if (!check_via_edge)
|
||||
{
|
||||
|
||||
@@ -223,10 +223,12 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
|
||||
|
||||
bool TurnHandler::hasObvious(const EdgeID &via_edge, const Fork &fork) const
|
||||
{
|
||||
auto obvious_road =
|
||||
std::adjacent_find(fork.begin, fork.end, [&, this](const auto &a, const auto &b) {
|
||||
return this->isObviousOfTwo(via_edge, a, b) || this->isObviousOfTwo(via_edge, b, a);
|
||||
});
|
||||
auto obvious_road = std::adjacent_find(fork.begin,
|
||||
fork.end,
|
||||
[&, this](const auto &a, const auto &b) {
|
||||
return this->isObviousOfTwo(via_edge, a, b) ||
|
||||
this->isObviousOfTwo(via_edge, b, a);
|
||||
});
|
||||
// return whether an obvious road was found
|
||||
return obvious_road != fork.end;
|
||||
}
|
||||
@@ -246,10 +248,11 @@ Intersection TurnHandler::handleThreeWayTurn(const EdgeID via_edge, Intersection
|
||||
OOOOOOO
|
||||
*/
|
||||
|
||||
const auto all_links =
|
||||
std::all_of(intersection.begin(), intersection.end(), [this](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsLinkClass();
|
||||
});
|
||||
const auto all_links = std::all_of(
|
||||
intersection.begin(),
|
||||
intersection.end(),
|
||||
[this](const auto &road)
|
||||
{ return node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsLinkClass(); });
|
||||
|
||||
auto fork = findFork(via_edge, intersection);
|
||||
if (fork && (all_links || obvious_index == 0))
|
||||
@@ -438,7 +441,8 @@ Intersection TurnHandler::assignLeftTurns(const EdgeID via_edge,
|
||||
const std::size_t starting_at) const
|
||||
{
|
||||
BOOST_ASSERT(starting_at < intersection.size());
|
||||
const auto switch_left_and_right = [](Intersection &intersection) {
|
||||
const auto switch_left_and_right = [](Intersection &intersection)
|
||||
{
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
|
||||
for (auto &road : intersection)
|
||||
@@ -462,7 +466,8 @@ Intersection TurnHandler::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)
|
||||
@@ -656,24 +661,36 @@ bool TurnHandler::isCompatibleByRoadClass(const Intersection &intersection, cons
|
||||
// except if rightmost fork candidate is also a link road
|
||||
const auto is_right_link_class =
|
||||
node_based_graph.GetEdgeData(fork.getRight().eid).flags.road_classification.IsLinkClass();
|
||||
if (!std::all_of(fork.begin + 1, fork.end, [&](ConnectedRoad &road) {
|
||||
return is_right_link_class ==
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsLinkClass();
|
||||
}))
|
||||
if (!std::all_of(fork.begin + 1,
|
||||
fork.end,
|
||||
[&](ConnectedRoad &road)
|
||||
{
|
||||
return is_right_link_class == node_based_graph.GetEdgeData(road.eid)
|
||||
.flags.road_classification.IsLinkClass();
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &base) {
|
||||
const auto base_class = node_based_graph.GetEdgeData(base.eid).flags.road_classification;
|
||||
// check that there is no turn obvious == check that all turns are non-onvious
|
||||
return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &compare) {
|
||||
const auto compare_class =
|
||||
node_based_graph.GetEdgeData(compare.eid).flags.road_classification;
|
||||
return compare.eid == base.eid ||
|
||||
!(obviousByRoadClass(via_class, base_class, compare_class));
|
||||
return std::all_of(
|
||||
fork.begin,
|
||||
fork.end,
|
||||
[&](ConnectedRoad &base)
|
||||
{
|
||||
const auto base_class =
|
||||
node_based_graph.GetEdgeData(base.eid).flags.road_classification;
|
||||
// check that there is no turn obvious == check that all turns are non-onvious
|
||||
return std::all_of(
|
||||
fork.begin,
|
||||
fork.end,
|
||||
[&](ConnectedRoad &compare)
|
||||
{
|
||||
const auto compare_class =
|
||||
node_based_graph.GetEdgeData(compare.eid).flags.road_classification;
|
||||
return compare.eid == base.eid ||
|
||||
!(obviousByRoadClass(via_class, base_class, compare_class));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Checks whether a three-way-intersection coming from `via_edge` is a fork
|
||||
@@ -703,8 +720,11 @@ boost::optional<TurnHandler::Fork> TurnHandler::findFork(const EdgeID via_edge,
|
||||
// check if all entries in the fork range allow entry
|
||||
const bool only_valid_entries = intersection.hasAllValidEntries(fork->begin, fork->end);
|
||||
|
||||
const auto has_compatible_modes =
|
||||
std::all_of(fork->begin, fork->end, [&](const auto &road) {
|
||||
const auto has_compatible_modes = std::all_of(
|
||||
fork->begin,
|
||||
fork->end,
|
||||
[&](const auto &road)
|
||||
{
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode ==
|
||||
|
||||
@@ -26,9 +26,9 @@ const constexpr extractor::TurnLaneType::Mask tag_by_modifier[] = {
|
||||
|
||||
std::size_t getNumberOfTurns(const Intersection &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; });
|
||||
}
|
||||
|
||||
LaneDataVector augmentMultiple(const std::size_t none_index,
|
||||
@@ -41,7 +41,8 @@ LaneDataVector augmentMultiple(const std::size_t none_index,
|
||||
// entries?
|
||||
|
||||
// looking at the left side first
|
||||
const auto range = [&]() {
|
||||
const auto range = [&]()
|
||||
{
|
||||
if (none_index == 0)
|
||||
{
|
||||
// find first connection_count - lane_data.size() valid turns
|
||||
@@ -106,17 +107,18 @@ LaneDataVector augmentMultiple(const std::size_t none_index,
|
||||
const auto intersection_range_first = intersection.begin() + range.first;
|
||||
const auto intersection_range_end = intersection.begin() + range.second;
|
||||
const auto allowed_in_range =
|
||||
std::count_if(intersection_range_first, intersection_range_end, [](const auto &road) {
|
||||
return road.entry_allowed;
|
||||
});
|
||||
std::count_if(intersection_range_first,
|
||||
intersection_range_end,
|
||||
[](const auto &road) { return road.entry_allowed; });
|
||||
|
||||
if (allowed_in_range > 1 && lane_data[none_index].to - lane_data[none_index].from >= 1)
|
||||
{
|
||||
// check if there is a straight turn
|
||||
auto straight_itr =
|
||||
std::find_if(intersection_range_first, intersection_range_end, [](const auto &road) {
|
||||
return road.instruction.direction_modifier == DirectionModifier::Straight;
|
||||
});
|
||||
auto straight_itr = std::find_if(
|
||||
intersection_range_first,
|
||||
intersection_range_end,
|
||||
[](const auto &road)
|
||||
{ return road.instruction.direction_modifier == DirectionModifier::Straight; });
|
||||
|
||||
// we have a straight turn?
|
||||
if (straight_itr != intersection_range_end)
|
||||
|
||||
@@ -67,26 +67,26 @@ LaneDataVector laneDataFromDescription(const TurnLaneDescription &turn_lane_desc
|
||||
const auto num_lanes = boost::numeric_cast<LaneID>(turn_lane_description.size());
|
||||
|
||||
const auto setLaneData =
|
||||
[&](LaneMap &map, TurnLaneType::Mask full_mask, const LaneID current_lane) {
|
||||
const auto isSet = [&](const TurnLaneType::Mask test_mask) -> bool {
|
||||
return (test_mask & full_mask) == test_mask;
|
||||
};
|
||||
[&](LaneMap &map, TurnLaneType::Mask full_mask, const LaneID current_lane)
|
||||
{
|
||||
const auto isSet = [&](const TurnLaneType::Mask test_mask) -> bool
|
||||
{ return (test_mask & full_mask) == test_mask; };
|
||||
|
||||
for (const auto shift : util::irange<std::size_t>(0, TurnLaneType::NUM_TYPES))
|
||||
for (const auto shift : util::irange<std::size_t>(0, TurnLaneType::NUM_TYPES))
|
||||
{
|
||||
TurnLaneType::Mask mask = 1 << shift;
|
||||
if (isSet(mask))
|
||||
{
|
||||
TurnLaneType::Mask mask = 1 << shift;
|
||||
if (isSet(mask))
|
||||
auto map_iterator = map.find(mask);
|
||||
if (map_iterator == map.end())
|
||||
map[mask] = std::make_pair(current_lane, current_lane);
|
||||
else
|
||||
{
|
||||
auto map_iterator = map.find(mask);
|
||||
if (map_iterator == map.end())
|
||||
map[mask] = std::make_pair(current_lane, current_lane);
|
||||
else
|
||||
{
|
||||
map_iterator->second.first = current_lane;
|
||||
}
|
||||
map_iterator->second.first = current_lane;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
LaneMap lane_map;
|
||||
LaneID lane_nr = num_lanes - 1;
|
||||
@@ -108,7 +108,8 @@ LaneDataVector laneDataFromDescription(const TurnLaneDescription &turn_lane_desc
|
||||
std::sort(lane_data.begin(), lane_data.end());
|
||||
|
||||
// check whether a given turn lane string resulted in valid lane data
|
||||
const auto hasValidOverlaps = [](const LaneDataVector &lane_data) {
|
||||
const auto hasValidOverlaps = [](const LaneDataVector &lane_data)
|
||||
{
|
||||
// Allow an overlap of at most one. Larger overlaps would result in crossing another turn,
|
||||
// which is invalid
|
||||
for (std::size_t index = 1; index < lane_data.size(); ++index)
|
||||
@@ -134,15 +135,17 @@ LaneDataVector laneDataFromDescription(const TurnLaneDescription &turn_lane_desc
|
||||
|
||||
LaneDataVector::iterator findTag(const TurnLaneType::Mask tag, LaneDataVector &data)
|
||||
{
|
||||
return std::find_if(data.begin(), data.end(), [&](const TurnLaneData &lane_data) {
|
||||
return (tag & lane_data.tag) != TurnLaneType::empty;
|
||||
});
|
||||
return std::find_if(data.begin(),
|
||||
data.end(),
|
||||
[&](const TurnLaneData &lane_data)
|
||||
{ return (tag & lane_data.tag) != TurnLaneType::empty; });
|
||||
}
|
||||
LaneDataVector::const_iterator findTag(const TurnLaneType::Mask tag, const LaneDataVector &data)
|
||||
{
|
||||
return std::find_if(data.cbegin(), data.cend(), [&](const TurnLaneData &lane_data) {
|
||||
return (tag & lane_data.tag) != TurnLaneType::empty;
|
||||
});
|
||||
return std::find_if(data.cbegin(),
|
||||
data.cend(),
|
||||
[&](const TurnLaneData &lane_data)
|
||||
{ return (tag & lane_data.tag) != TurnLaneType::empty; });
|
||||
}
|
||||
|
||||
bool hasTag(const TurnLaneType::Mask tag, const LaneDataVector &data)
|
||||
|
||||
@@ -24,9 +24,9 @@ namespace
|
||||
{
|
||||
std::size_t getNumberOfTurns(const Intersection &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; });
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -158,10 +158,10 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
|
||||
return TurnLaneScenario::NONE;
|
||||
|
||||
// really don't touch roundabouts (#2626)
|
||||
if (intersection.end() !=
|
||||
std::find_if(intersection.begin(), intersection.end(), [](const auto &road) {
|
||||
return hasRoundaboutType(road.instruction);
|
||||
}))
|
||||
if (intersection.end() != std::find_if(intersection.begin(),
|
||||
intersection.end(),
|
||||
[](const auto &road)
|
||||
{ return hasRoundaboutType(road.instruction); }))
|
||||
return TurnLaneScenario::NONE;
|
||||
|
||||
// if only a uturn exists, there is nothing we can do
|
||||
@@ -233,7 +233,8 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
|
||||
if (via_edge == road.eid)
|
||||
return TurnLaneScenario::SLIPROAD;
|
||||
|
||||
const auto &closest_road = [&]() {
|
||||
const auto &closest_road = [&]()
|
||||
{
|
||||
if (road_index + 1 == previous_intersection.size())
|
||||
{
|
||||
BOOST_ASSERT(road_index > 1);
|
||||
@@ -419,7 +420,8 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data,
|
||||
return std::count_if(
|
||||
lane_data.begin(),
|
||||
lane_data.end(),
|
||||
[](const TurnLaneData &data) {
|
||||
[](const TurnLaneData &data)
|
||||
{
|
||||
return ((data.tag & TurnLaneType::merge_to_left) != TurnLaneType::empty) ||
|
||||
((data.tag & TurnLaneType::merge_to_right) != TurnLaneType::empty);
|
||||
}) +
|
||||
@@ -429,7 +431,8 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data,
|
||||
|
||||
// in case an intersection offers far more lane data items than actual turns, some of them
|
||||
// have to be for another intersection. A single additional item can be for an invalid bus lane.
|
||||
const auto num_turns = [&]() {
|
||||
const auto num_turns = [&]()
|
||||
{
|
||||
auto count = getNumberOfTurns(intersection);
|
||||
if (count < lane_data.size() && !intersection[0].entry_allowed &&
|
||||
lane_data.back().tag == TurnLaneType::uturn)
|
||||
@@ -453,10 +456,10 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data,
|
||||
|
||||
// more turns than lane data
|
||||
if (num_turns > lane_data.size() &&
|
||||
lane_data.end() ==
|
||||
std::find_if(lane_data.begin(), lane_data.end(), [](const TurnLaneData &data) {
|
||||
return data.tag == TurnLaneType::none;
|
||||
}))
|
||||
lane_data.end() == std::find_if(lane_data.begin(),
|
||||
lane_data.end(),
|
||||
[](const TurnLaneData &data)
|
||||
{ return data.tag == TurnLaneType::none; }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -485,7 +488,8 @@ bool TurnLaneHandler::isSimpleIntersection(const LaneDataVector &lane_data,
|
||||
// u-turn tags are at the outside of the lane-tags and require special handling, since
|
||||
// locating their best match requires knowledge on the neighboring tag. (see documentation
|
||||
// on findBestMatch/findBestMatchForReverse
|
||||
const auto best_match = [&]() {
|
||||
const auto best_match = [&]()
|
||||
{
|
||||
// normal tag or u-turn as only choice (no other tag present)
|
||||
if (data.tag != TurnLaneType::uturn || lane_data.size() == 1)
|
||||
return findBestMatch(data.tag, intersection);
|
||||
@@ -644,7 +648,8 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData(
|
||||
matched_at_second[none_index] = true;
|
||||
}
|
||||
|
||||
const auto augmentEntry = [&](TurnLaneData &data) {
|
||||
const auto augmentEntry = [&](TurnLaneData &data)
|
||||
{
|
||||
for (std::size_t lane = 0; lane < turn_lane_data.size(); ++lane)
|
||||
if (matched_at_second[lane])
|
||||
{
|
||||
@@ -713,15 +718,15 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
|
||||
std::distance(previous_intersection.begin(),
|
||||
std::find_if(previous_intersection.begin(),
|
||||
previous_intersection.end(),
|
||||
[](const ConnectedRoad &road) {
|
||||
return road.instruction.type == TurnType::Sliproad;
|
||||
}));
|
||||
[](const ConnectedRoad &road)
|
||||
{ return road.instruction.type == TurnType::Sliproad; }));
|
||||
|
||||
BOOST_ASSERT(sliproad_index <= previous_intersection.size());
|
||||
const auto &sliproad = previous_intersection[sliproad_index];
|
||||
|
||||
// code duplicatino with deduceScenario: TODO refactor
|
||||
const auto &main_road = [&]() {
|
||||
const auto &main_road = [&]()
|
||||
{
|
||||
if (sliproad_index + 1 == previous_intersection.size())
|
||||
{
|
||||
BOOST_ASSERT(sliproad_index > 1);
|
||||
|
||||
@@ -49,9 +49,8 @@ DirectionModifier::Enum getMatchingModifier(const TurnLaneType::Mask tag)
|
||||
// check whether a match of a given tag and a turn instruction can be seen as valid
|
||||
bool isValidMatch(const TurnLaneType::Mask tag, const TurnInstruction instruction)
|
||||
{
|
||||
const auto isMirroredModifier = [](const TurnInstruction instruction) {
|
||||
return instruction.type == TurnType::Merge;
|
||||
};
|
||||
const auto isMirroredModifier = [](const TurnInstruction instruction)
|
||||
{ return instruction.type == TurnType::Merge; };
|
||||
|
||||
if (tag == TurnLaneType::uturn)
|
||||
{
|
||||
@@ -114,7 +113,8 @@ typename Intersection::const_iterator findBestMatch(const TurnLaneType::Mask tag
|
||||
{
|
||||
return std::min_element(intersection.begin(),
|
||||
intersection.end(),
|
||||
[tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
|
||||
[tag](const ConnectedRoad &lhs, const ConnectedRoad &rhs)
|
||||
{
|
||||
// prefer valid matches
|
||||
if (isValidMatch(tag, lhs.instruction) !=
|
||||
isValidMatch(tag, rhs.instruction))
|
||||
@@ -144,7 +144,8 @@ typename Intersection::const_iterator findBestMatchForReverse(const TurnLaneType
|
||||
return std::min_element(
|
||||
intersection.begin() + std::distance(intersection.begin(), neighbor_itr),
|
||||
intersection.end(),
|
||||
[](const ConnectedRoad &lhs, const ConnectedRoad &rhs) {
|
||||
[](const ConnectedRoad &lhs, const ConnectedRoad &rhs)
|
||||
{
|
||||
const TurnLaneType::Mask tag = TurnLaneType::uturn;
|
||||
// prefer valid matches
|
||||
if (isValidMatch(tag, lhs.instruction) != isValidMatch(tag, rhs.instruction))
|
||||
@@ -197,7 +198,8 @@ Intersection triviallyMatchLanesToTurns(Intersection intersection,
|
||||
{
|
||||
std::size_t road_index = 1, lane = 0;
|
||||
|
||||
const auto matchRoad = [&](ConnectedRoad &road, const TurnLaneData &data) {
|
||||
const auto matchRoad = [&](ConnectedRoad &road, const TurnLaneData &data)
|
||||
{
|
||||
util::guidance::LaneTupleIdPair key{{LaneID(data.to - data.from + 1), data.from},
|
||||
lane_string_id};
|
||||
|
||||
|
||||
@@ -64,9 +64,8 @@ void partitionLevel(const std::vector<BisectionID> &node_to_bisection_id,
|
||||
std::accumulate(permutation.begin() + cell.begin,
|
||||
permutation.begin() + cell.end,
|
||||
BisectionID{0},
|
||||
[&node_to_bisection_id](const BisectionID lhs, const NodeID rhs) {
|
||||
return lhs | node_to_bisection_id[rhs];
|
||||
});
|
||||
[&node_to_bisection_id](const BisectionID lhs, const NodeID rhs)
|
||||
{ return lhs | node_to_bisection_id[rhs]; });
|
||||
// masks all bit strictly higher then cell.bit
|
||||
BOOST_ASSERT(sizeof(unsigned long long) * CHAR_BIT > sizeof(BisectionID) * CHAR_BIT);
|
||||
const BisectionID mask = (1ULL << (cell.bit + 1)) - 1;
|
||||
@@ -88,9 +87,8 @@ void partitionLevel(const std::vector<BisectionID> &node_to_bisection_id,
|
||||
std::uint32_t middle =
|
||||
std::partition(permutation.begin() + cell.begin,
|
||||
permutation.begin() + cell.end,
|
||||
[is_left_mask, &node_to_bisection_id](const auto node_id) {
|
||||
return node_to_bisection_id[node_id] & is_left_mask;
|
||||
}) -
|
||||
[is_left_mask, &node_to_bisection_id](const auto node_id)
|
||||
{ return node_to_bisection_id[node_id] & is_left_mask; }) -
|
||||
permutation.begin();
|
||||
|
||||
if (bit > 0)
|
||||
|
||||
@@ -19,10 +19,10 @@ const auto constexpr INVALID_LEVEL = std::numeric_limits<DinicMaxFlow::Level>::m
|
||||
auto makeHasNeighborNotInCheck(const DinicMaxFlow::SourceSinkNodes &set,
|
||||
const BisectionGraphView &view)
|
||||
{
|
||||
return [&](const NodeID nid) {
|
||||
const auto is_not_contained = [&set](const BisectionEdge &edge) {
|
||||
return set.count(edge.target) == 0;
|
||||
};
|
||||
return [&](const NodeID nid)
|
||||
{
|
||||
const auto is_not_contained = [&set](const BisectionEdge &edge)
|
||||
{ return set.count(edge.target) == 0; };
|
||||
return view.EndEdges(nid) !=
|
||||
std::find_if(view.BeginEdges(nid), view.EndEdges(nid), is_not_contained);
|
||||
};
|
||||
@@ -132,12 +132,12 @@ DinicMaxFlow::ComputeLevelGraph(const BisectionGraphView &view,
|
||||
levels[edge.target] = 0;
|
||||
}
|
||||
// check if there is flow present on an edge
|
||||
const auto has_flow = [&](const NodeID from, const NodeID to) {
|
||||
return flow[from].find(to) != flow[from].end();
|
||||
};
|
||||
const auto has_flow = [&](const NodeID from, const NodeID to)
|
||||
{ return flow[from].find(to) != flow[from].end(); };
|
||||
|
||||
// perform a relaxation step in the BFS algorithm
|
||||
const auto relax_node = [&](const NodeID node_id) {
|
||||
const auto relax_node = [&](const NodeID node_id)
|
||||
{
|
||||
// don't relax sink nodes
|
||||
if (sink_nodes.count(node_id))
|
||||
return;
|
||||
@@ -180,9 +180,11 @@ std::size_t DinicMaxFlow::BlockingFlow(FlowEdges &flow,
|
||||
std::size_t flow_increase = 0;
|
||||
|
||||
// augment the flow along a path in the level graph
|
||||
const auto augment_flow = [&flow](const std::vector<NodeID> &path) {
|
||||
const auto augment_flow = [&flow](const std::vector<NodeID> &path)
|
||||
{
|
||||
// add/remove flow edges from the current residual graph
|
||||
const auto augment_one = [&flow](const NodeID from, const NodeID to) {
|
||||
const auto augment_one = [&flow](const NodeID from, const NodeID to)
|
||||
{
|
||||
// check if there is flow in the opposite direction
|
||||
auto existing_edge = flow[to].find(from);
|
||||
if (existing_edge != flow[to].end())
|
||||
@@ -200,7 +202,8 @@ std::size_t DinicMaxFlow::BlockingFlow(FlowEdges &flow,
|
||||
[[maybe_unused]] auto _ = std::adjacent_find(path.begin(), path.end(), augment_one);
|
||||
};
|
||||
|
||||
const auto augment_all_paths = [&](const NodeID sink_node_id) {
|
||||
const auto augment_all_paths = [&](const NodeID sink_node_id)
|
||||
{
|
||||
// only augment sinks
|
||||
if (levels[sink_node_id] == INVALID_LEVEL)
|
||||
return;
|
||||
@@ -295,10 +298,10 @@ bool DinicMaxFlow::Validate(const BisectionGraphView &view,
|
||||
const SourceSinkNodes &sink_nodes) const
|
||||
{
|
||||
// sink and source cannot share a common node
|
||||
const auto separated =
|
||||
std::find_if(source_nodes.begin(), source_nodes.end(), [&sink_nodes](const auto node) {
|
||||
return sink_nodes.count(node);
|
||||
}) == source_nodes.end();
|
||||
const auto separated = std::find_if(source_nodes.begin(),
|
||||
source_nodes.end(),
|
||||
[&sink_nodes](const auto node)
|
||||
{ return sink_nodes.count(node); }) == source_nodes.end();
|
||||
|
||||
const auto invalid_id = [&view](const NodeID nid) { return nid >= view.NumberOfNodes(); };
|
||||
const auto in_range_source =
|
||||
|
||||
@@ -53,21 +53,25 @@ makeSpatialOrder(const BisectionGraphView &view, const double ratio, const doubl
|
||||
// adress of the very first node
|
||||
const auto node_zero = &(*view.Begin());
|
||||
|
||||
std::transform(view.Begin(), view.End(), std::back_inserter(embedding), [&](const auto &node) {
|
||||
const auto node_id = static_cast<NodeID>(&node - node_zero);
|
||||
return NodeWithCoordinate{node_id, node.coordinate};
|
||||
});
|
||||
std::transform(view.Begin(),
|
||||
view.End(),
|
||||
std::back_inserter(embedding),
|
||||
[&](const auto &node)
|
||||
{
|
||||
const auto node_id = static_cast<NodeID>(&node - node_zero);
|
||||
return NodeWithCoordinate{node_id, node.coordinate};
|
||||
});
|
||||
|
||||
const auto project = [slope](const auto &each) {
|
||||
const auto project = [slope](const auto &each)
|
||||
{
|
||||
auto lon = static_cast<std::int32_t>(each.coordinate.lon);
|
||||
auto lat = static_cast<std::int32_t>(each.coordinate.lat);
|
||||
|
||||
return slope * lon + (1. - std::fabs(slope)) * lat;
|
||||
};
|
||||
|
||||
const auto spatially = [&](const auto &lhs, const auto &rhs) {
|
||||
return project(lhs) < project(rhs);
|
||||
};
|
||||
const auto spatially = [&](const auto &lhs, const auto &rhs)
|
||||
{ return project(lhs) < project(rhs); };
|
||||
|
||||
const std::size_t n = ratio * embedding.size();
|
||||
|
||||
@@ -96,7 +100,8 @@ DinicMaxFlow::MinCut bestMinCut(const BisectionGraphView &view,
|
||||
DinicMaxFlow::MinCut best;
|
||||
best.num_edges = -1;
|
||||
|
||||
const auto get_balance = [&view, balance](const auto num_nodes_source) {
|
||||
const auto get_balance = [&view, balance](const auto num_nodes_source)
|
||||
{
|
||||
const auto perfect_balance = view.NumberOfNodes() / 2;
|
||||
const auto allowed_balance = balance * perfect_balance;
|
||||
const auto bigger_side =
|
||||
@@ -114,36 +119,41 @@ DinicMaxFlow::MinCut bestMinCut(const BisectionGraphView &view,
|
||||
|
||||
tbb::blocked_range<std::size_t> range{0, n, 1};
|
||||
|
||||
const auto balance_delta = [&view](const auto num_nodes_source) {
|
||||
const auto balance_delta = [&view](const auto num_nodes_source)
|
||||
{
|
||||
const std::int64_t difference =
|
||||
static_cast<std::int64_t>(view.NumberOfNodes()) / 2 - num_nodes_source;
|
||||
return std::abs(difference);
|
||||
};
|
||||
|
||||
tbb::parallel_for(range, [&](const auto &chunk) {
|
||||
for (auto round = chunk.begin(), end = chunk.end(); round != end; ++round)
|
||||
{
|
||||
const auto slope = -1. + round * (2. / n);
|
||||
tbb::parallel_for(range,
|
||||
[&](const auto &chunk)
|
||||
{
|
||||
for (auto round = chunk.begin(), end = chunk.end(); round != end; ++round)
|
||||
{
|
||||
const auto slope = -1. + round * (2. / n);
|
||||
|
||||
auto order = makeSpatialOrder(view, ratio, slope);
|
||||
auto cut = DinicMaxFlow()(view, order.sources, order.sinks);
|
||||
auto cut_balance = get_balance(cut.num_nodes_source);
|
||||
auto order = makeSpatialOrder(view, ratio, slope);
|
||||
auto cut = DinicMaxFlow()(view, order.sources, order.sinks);
|
||||
auto cut_balance = get_balance(cut.num_nodes_source);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> guard{lock};
|
||||
{
|
||||
std::lock_guard<std::mutex> guard{lock};
|
||||
|
||||
// Swap to keep the destruction of the old object outside of critical section.
|
||||
if (cut.num_edges * cut_balance < best.num_edges * best_balance ||
|
||||
(cut.num_edges == best.num_edges &&
|
||||
balance_delta(cut.num_nodes_source) < balance_delta(best.num_nodes_source)))
|
||||
{
|
||||
best_balance = cut_balance;
|
||||
std::swap(best, cut);
|
||||
}
|
||||
}
|
||||
// cut gets destroyed here
|
||||
}
|
||||
});
|
||||
// Swap to keep the destruction of the old object outside of
|
||||
// critical section.
|
||||
if (cut.num_edges * cut_balance < best.num_edges * best_balance ||
|
||||
(cut.num_edges == best.num_edges &&
|
||||
balance_delta(cut.num_nodes_source) <
|
||||
balance_delta(best.num_nodes_source)))
|
||||
{
|
||||
best_balance = cut_balance;
|
||||
std::swap(best, cut);
|
||||
}
|
||||
}
|
||||
// cut gets destroyed here
|
||||
}
|
||||
});
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
@@ -58,40 +58,48 @@ RecursiveBisection::RecursiveBisection(BisectionGraph &bisection_graph_,
|
||||
std::vector<TreeNode> forest;
|
||||
forest.reserve(last - first);
|
||||
|
||||
std::transform(first, last, std::back_inserter(forest), [this](auto graph) {
|
||||
return TreeNode{std::move(graph), internal_state.SCCDepth()};
|
||||
});
|
||||
std::transform(first,
|
||||
last,
|
||||
std::back_inserter(forest),
|
||||
[this](auto graph) {
|
||||
return TreeNode{std::move(graph), internal_state.SCCDepth()};
|
||||
});
|
||||
|
||||
using Feeder = tbb::feeder<TreeNode>;
|
||||
|
||||
TIMER_START(bisection);
|
||||
|
||||
// Bisect graph into two parts. Get partition point and recurse left and right in parallel.
|
||||
tbb::parallel_for_each(begin(forest), end(forest), [&](const TreeNode &node, Feeder &feeder) {
|
||||
const auto cut =
|
||||
computeInertialFlowCut(node.graph, num_optimizing_cuts, balance, boundary_factor);
|
||||
const auto center = internal_state.ApplyBisection(
|
||||
node.graph.Begin(), node.graph.End(), node.depth, cut.flags);
|
||||
tbb::parallel_for_each(
|
||||
begin(forest),
|
||||
end(forest),
|
||||
[&](const TreeNode &node, Feeder &feeder)
|
||||
{
|
||||
const auto cut =
|
||||
computeInertialFlowCut(node.graph, num_optimizing_cuts, balance, boundary_factor);
|
||||
const auto center = internal_state.ApplyBisection(
|
||||
node.graph.Begin(), node.graph.End(), node.depth, cut.flags);
|
||||
|
||||
const auto terminal = [&](const auto &node) {
|
||||
const auto maximum_depth = sizeof(BisectionID) * CHAR_BIT;
|
||||
const auto too_small = node.graph.NumberOfNodes() < maximum_cell_size;
|
||||
const auto too_deep = node.depth >= maximum_depth;
|
||||
return too_small || too_deep;
|
||||
};
|
||||
const auto terminal = [&](const auto &node)
|
||||
{
|
||||
const auto maximum_depth = sizeof(BisectionID) * CHAR_BIT;
|
||||
const auto too_small = node.graph.NumberOfNodes() < maximum_cell_size;
|
||||
const auto too_deep = node.depth >= maximum_depth;
|
||||
return too_small || too_deep;
|
||||
};
|
||||
|
||||
BisectionGraphView left_graph{bisection_graph, node.graph.Begin(), center};
|
||||
TreeNode left_node{std::move(left_graph), node.depth + 1};
|
||||
BisectionGraphView left_graph{bisection_graph, node.graph.Begin(), center};
|
||||
TreeNode left_node{std::move(left_graph), node.depth + 1};
|
||||
|
||||
if (!terminal(left_node))
|
||||
feeder.add(left_node);
|
||||
if (!terminal(left_node))
|
||||
feeder.add(left_node);
|
||||
|
||||
BisectionGraphView right_graph{bisection_graph, center, node.graph.End()};
|
||||
TreeNode right_node{std::move(right_graph), node.depth + 1};
|
||||
BisectionGraphView right_graph{bisection_graph, center, node.graph.End()};
|
||||
TreeNode right_node{std::move(right_graph), node.depth + 1};
|
||||
|
||||
if (!terminal(right_node))
|
||||
feeder.add(right_node);
|
||||
});
|
||||
if (!terminal(right_node))
|
||||
feeder.add(right_node);
|
||||
});
|
||||
|
||||
TIMER_STOP(bisection);
|
||||
|
||||
|
||||
@@ -45,9 +45,8 @@ RecursiveBisectionState::ApplyBisection(const NodeIterator const_begin,
|
||||
}
|
||||
|
||||
// Keep items with `0` as partition id to the left, move other to the right
|
||||
auto by_flag_bit = [this, flag](const auto &node) {
|
||||
return BisectionID{0} == (bisection_ids[node.original_id] & flag);
|
||||
};
|
||||
auto by_flag_bit = [this, flag](const auto &node)
|
||||
{ return BisectionID{0} == (bisection_ids[node.original_id] & flag); };
|
||||
|
||||
auto begin = bisection_graph.Begin() + std::distance(bisection_graph.CBegin(), const_begin);
|
||||
const auto end = begin + std::distance(const_begin, const_end);
|
||||
@@ -59,26 +58,34 @@ RecursiveBisectionState::ApplyBisection(const NodeIterator const_begin,
|
||||
std::transform(const_begin,
|
||||
const_end,
|
||||
mapping.begin(),
|
||||
[by_flag_bit, &lesser_id, &upper_id](const auto &node) {
|
||||
return by_flag_bit(node) ? lesser_id++ : upper_id++;
|
||||
});
|
||||
[by_flag_bit, &lesser_id, &upper_id](const auto &node)
|
||||
{ return by_flag_bit(node) ? lesser_id++ : upper_id++; });
|
||||
|
||||
// erase all edges that point into different partitions
|
||||
std::for_each(begin, end, [&](auto &node) {
|
||||
const auto node_flag = by_flag_bit(node);
|
||||
bisection_graph.RemoveEdges(node, [&](const BisectionGraph::EdgeT &edge) {
|
||||
const auto target_flag = by_flag_bit(*(const_begin + edge.target));
|
||||
return (node_flag != target_flag);
|
||||
});
|
||||
});
|
||||
std::for_each(begin,
|
||||
end,
|
||||
[&](auto &node)
|
||||
{
|
||||
const auto node_flag = by_flag_bit(node);
|
||||
bisection_graph.RemoveEdges(node,
|
||||
[&](const BisectionGraph::EdgeT &edge)
|
||||
{
|
||||
const auto target_flag =
|
||||
by_flag_bit(*(const_begin + edge.target));
|
||||
return (node_flag != target_flag);
|
||||
});
|
||||
});
|
||||
|
||||
auto center = std::stable_partition(begin, end, by_flag_bit);
|
||||
|
||||
// remap all remaining edges
|
||||
std::for_each(const_begin, const_end, [&](const auto &node) {
|
||||
for (auto &edge : bisection_graph.Edges(node))
|
||||
edge.target = mapping[edge.target];
|
||||
});
|
||||
std::for_each(const_begin,
|
||||
const_end,
|
||||
[&](const auto &node)
|
||||
{
|
||||
for (auto &edge : bisection_graph.Edges(node))
|
||||
edge.target = mapping[edge.target];
|
||||
});
|
||||
|
||||
return const_begin + std::distance(begin, center);
|
||||
}
|
||||
@@ -93,13 +100,13 @@ RecursiveBisectionState::PrePartitionWithSCC(const std::size_t small_component_s
|
||||
scc_algo.Run();
|
||||
|
||||
// Map Edges to Sccs
|
||||
const auto in_small = [&scc_algo, small_component_size](const NodeID node_id) {
|
||||
return scc_algo.GetComponentSize(scc_algo.GetComponentID(node_id)) <= small_component_size;
|
||||
};
|
||||
const auto in_small = [&scc_algo, small_component_size](const NodeID node_id)
|
||||
{ return scc_algo.GetComponentSize(scc_algo.GetComponentID(node_id)) <= small_component_size; };
|
||||
|
||||
const constexpr std::size_t small_component_id = -1;
|
||||
std::unordered_map<std::size_t, std::size_t> component_map;
|
||||
const auto transform_id = [&](const NodeID node_id) -> std::size_t {
|
||||
const auto transform_id = [&](const NodeID node_id) -> std::size_t
|
||||
{
|
||||
if (in_small(node_id))
|
||||
return small_component_id;
|
||||
else
|
||||
@@ -111,16 +118,19 @@ RecursiveBisectionState::PrePartitionWithSCC(const std::size_t small_component_s
|
||||
mapping[node.original_id] = component_map[transform_id(node.original_id)]++;
|
||||
|
||||
// needs to remove edges, if we should ever switch to directed graphs here
|
||||
std::stable_sort(
|
||||
bisection_graph.Begin(), bisection_graph.End(), [&](const auto &lhs, const auto &rhs) {
|
||||
return transform_id(lhs.original_id) < transform_id(rhs.original_id);
|
||||
});
|
||||
std::stable_sort(bisection_graph.Begin(),
|
||||
bisection_graph.End(),
|
||||
[&](const auto &lhs, const auto &rhs)
|
||||
{ return transform_id(lhs.original_id) < transform_id(rhs.original_id); });
|
||||
|
||||
// remap all remaining edges
|
||||
std::for_each(bisection_graph.Begin(), bisection_graph.End(), [&](const auto &node) {
|
||||
for (auto &edge : bisection_graph.Edges(node))
|
||||
edge.target = mapping[edge.target];
|
||||
});
|
||||
std::for_each(bisection_graph.Begin(),
|
||||
bisection_graph.End(),
|
||||
[&](const auto &node)
|
||||
{
|
||||
for (auto &edge : bisection_graph.Edges(node))
|
||||
edge.target = mapping[edge.target];
|
||||
});
|
||||
|
||||
std::vector<BisectionGraphView> views;
|
||||
auto last = bisection_graph.CBegin();
|
||||
@@ -139,7 +149,8 @@ RecursiveBisectionState::PrePartitionWithSCC(const std::size_t small_component_s
|
||||
}
|
||||
views.push_back(BisectionGraphView(bisection_graph, last, bisection_graph.CEnd()));
|
||||
|
||||
bool has_small_component = [&]() {
|
||||
bool has_small_component = [&]()
|
||||
{
|
||||
for (std::size_t i = 0; i < scc_algo.GetNumberOfComponents(); ++i)
|
||||
if (scc_algo.GetComponentSize(i) <= small_component_size)
|
||||
return true;
|
||||
@@ -154,7 +165,8 @@ RecursiveBisectionState::PrePartitionWithSCC(const std::size_t small_component_s
|
||||
// ceil(log_2(components))
|
||||
scc_levels = ceil(log(views.size()) / log(2.0));
|
||||
|
||||
const auto conscutive_component_id = [&](const NodeID nid) {
|
||||
const auto conscutive_component_id = [&](const NodeID nid)
|
||||
{
|
||||
const auto component_id = transform_id(nid);
|
||||
const auto itr = ordered_component_ids.find(component_id);
|
||||
BOOST_ASSERT(itr != ordered_component_ids.end());
|
||||
|
||||
@@ -46,10 +46,10 @@ std::vector<std::uint32_t> makePermutation(const DynamicEdgeBasedGraph &graph,
|
||||
// Nodes in the same cell will be sorted by cell ID on the level below
|
||||
for (const auto &partition : partitions)
|
||||
{
|
||||
std::stable_sort(
|
||||
ordering.begin(), ordering.end(), [&partition](const auto lhs, const auto rhs) {
|
||||
return partition[lhs] < partition[rhs];
|
||||
});
|
||||
std::stable_sort(ordering.begin(),
|
||||
ordering.end(),
|
||||
[&partition](const auto lhs, const auto rhs)
|
||||
{ return partition[lhs] < partition[rhs]; });
|
||||
}
|
||||
|
||||
// Now sort the nodes by the level at which they are a border node, descening.
|
||||
@@ -57,10 +57,10 @@ std::vector<std::uint32_t> makePermutation(const DynamicEdgeBasedGraph &graph,
|
||||
// whereas nodes that are nerver border nodes are sorted to the end of the array.
|
||||
// Note: Since we use a stable sort that preserves the cell sorting within each level
|
||||
auto border_level = getHighestBorderLevel(graph, partitions);
|
||||
std::stable_sort(
|
||||
ordering.begin(), ordering.end(), [&border_level](const auto lhs, const auto rhs) {
|
||||
return border_level[lhs] > border_level[rhs];
|
||||
});
|
||||
std::stable_sort(ordering.begin(),
|
||||
ordering.end(),
|
||||
[&border_level](const auto lhs, const auto rhs)
|
||||
{ return border_level[lhs] > border_level[rhs]; });
|
||||
|
||||
return util::orderingToPermutation(ordering);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ void validate(boost::any &v, const std::vector<std::string> &values, MaxCellSize
|
||||
std::transform(std::sregex_token_iterator(s.begin(), s.end(), re, -1),
|
||||
std::sregex_token_iterator(),
|
||||
std::back_inserter(output),
|
||||
[](const auto &x) {
|
||||
[](const auto &x)
|
||||
{
|
||||
try
|
||||
{
|
||||
return boost::lexical_cast<std::size_t>(x);
|
||||
@@ -215,7 +216,8 @@ try
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto check_file = [](const boost::filesystem::path &path) {
|
||||
auto check_file = [](const boost::filesystem::path &path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
{
|
||||
util::Log(logERROR) << "Input file " << path << " not found!";
|
||||
|
||||
@@ -343,10 +343,12 @@ try
|
||||
}
|
||||
else
|
||||
{
|
||||
std::packaged_task<int()> server_task([&] {
|
||||
routing_server->Run();
|
||||
return 0;
|
||||
});
|
||||
std::packaged_task<int()> server_task(
|
||||
[&]
|
||||
{
|
||||
routing_server->Run();
|
||||
return 0;
|
||||
});
|
||||
auto future = server_task.get_future();
|
||||
std::thread server_thread(std::move(server_task));
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ SegmentLookupTable readSegmentValues(const std::vector<std::string> &paths)
|
||||
// Check consistency of keys in the result lookup table
|
||||
auto result = parser(paths);
|
||||
const auto found_inconsistency =
|
||||
std::find_if(std::begin(result.lookup), std::end(result.lookup), [](const auto &entry) {
|
||||
return entry.first.from == entry.first.to;
|
||||
});
|
||||
std::find_if(std::begin(result.lookup),
|
||||
std::end(result.lookup),
|
||||
[](const auto &entry) { return entry.first.from == entry.first.to; });
|
||||
if (found_inconsistency != std::end(result.lookup))
|
||||
{
|
||||
util::Log(logWARNING) << "Empty segment in CSV with node " +
|
||||
|
||||
+125
-108
@@ -155,10 +155,11 @@ updateSegmentData(const UpdaterConfig &config,
|
||||
|
||||
// closure to convert SpeedSource value to weight and count fallbacks to durations
|
||||
std::atomic<std::uint32_t> fallbacks_to_duration{0};
|
||||
auto convertToWeight = [&profile_properties,
|
||||
&fallbacks_to_duration](const SegmentWeight &existing_weight,
|
||||
const SpeedSource &value,
|
||||
double distance_in_meters) {
|
||||
auto convertToWeight =
|
||||
[&profile_properties, &fallbacks_to_duration](const SegmentWeight &existing_weight,
|
||||
const SpeedSource &value,
|
||||
double distance_in_meters)
|
||||
{
|
||||
double rate = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
// if value.rate is not set, we fall back to duration
|
||||
@@ -211,96 +212,104 @@ updateSegmentData(const UpdaterConfig &config,
|
||||
|
||||
using DirectionalGeometryID = extractor::SegmentDataContainer::DirectionalGeometryID;
|
||||
auto range = tbb::blocked_range<DirectionalGeometryID>(0, segment_data.GetNumberOfGeometries());
|
||||
tbb::parallel_for(range, [&](const auto &range) {
|
||||
auto &counters = segment_speeds_counters.local();
|
||||
std::vector<double> segment_lengths;
|
||||
for (auto geometry_id = range.begin(); geometry_id < range.end(); geometry_id++)
|
||||
tbb::parallel_for(
|
||||
range,
|
||||
[&](const auto &range)
|
||||
{
|
||||
auto nodes_range = segment_data.GetForwardGeometry(geometry_id);
|
||||
|
||||
segment_lengths.clear();
|
||||
segment_lengths.reserve(nodes_range.size() + 1);
|
||||
util::for_each_pair(nodes_range, [&](const auto &u, const auto &v) {
|
||||
segment_lengths.push_back(util::coordinate_calculation::greatCircleDistance(
|
||||
coordinates[u], coordinates[v]));
|
||||
});
|
||||
|
||||
auto fwd_weights_range = segment_data.GetForwardWeights(geometry_id);
|
||||
auto fwd_durations_range = segment_data.GetForwardDurations(geometry_id);
|
||||
auto fwd_datasources_range = segment_data.GetForwardDatasources(geometry_id);
|
||||
bool fwd_was_updated = false;
|
||||
for (const auto segment_offset : util::irange<std::size_t>(0, fwd_weights_range.size()))
|
||||
auto &counters = segment_speeds_counters.local();
|
||||
std::vector<double> segment_lengths;
|
||||
for (auto geometry_id = range.begin(); geometry_id < range.end(); geometry_id++)
|
||||
{
|
||||
auto u = osm_node_ids[nodes_range[segment_offset]];
|
||||
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
||||
auto nodes_range = segment_data.GetForwardGeometry(geometry_id);
|
||||
|
||||
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
||||
// waste time updating them with traffic data
|
||||
if (u == v)
|
||||
continue;
|
||||
segment_lengths.clear();
|
||||
segment_lengths.reserve(nodes_range.size() + 1);
|
||||
util::for_each_pair(nodes_range,
|
||||
[&](const auto &u, const auto &v)
|
||||
{
|
||||
segment_lengths.push_back(
|
||||
util::coordinate_calculation::greatCircleDistance(
|
||||
coordinates[u], coordinates[v]));
|
||||
});
|
||||
|
||||
if (auto value = segment_speed_lookup({u, v}))
|
||||
auto fwd_weights_range = segment_data.GetForwardWeights(geometry_id);
|
||||
auto fwd_durations_range = segment_data.GetForwardDurations(geometry_id);
|
||||
auto fwd_datasources_range = segment_data.GetForwardDatasources(geometry_id);
|
||||
bool fwd_was_updated = false;
|
||||
for (const auto segment_offset :
|
||||
util::irange<std::size_t>(0, fwd_weights_range.size()))
|
||||
{
|
||||
auto segment_length = segment_lengths[segment_offset];
|
||||
auto new_duration = convertToDuration(value->speed, segment_length);
|
||||
auto new_weight =
|
||||
convertToWeight(fwd_weights_range[segment_offset], *value, segment_length);
|
||||
fwd_was_updated = true;
|
||||
auto u = osm_node_ids[nodes_range[segment_offset]];
|
||||
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
||||
|
||||
fwd_weights_range[segment_offset] = new_weight;
|
||||
fwd_durations_range[segment_offset] = new_duration;
|
||||
fwd_datasources_range[segment_offset] = value->source;
|
||||
counters[value->source] += 1;
|
||||
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
||||
// waste time updating them with traffic data
|
||||
if (u == v)
|
||||
continue;
|
||||
|
||||
if (auto value = segment_speed_lookup({u, v}))
|
||||
{
|
||||
auto segment_length = segment_lengths[segment_offset];
|
||||
auto new_duration = convertToDuration(value->speed, segment_length);
|
||||
auto new_weight = convertToWeight(
|
||||
fwd_weights_range[segment_offset], *value, segment_length);
|
||||
fwd_was_updated = true;
|
||||
|
||||
fwd_weights_range[segment_offset] = new_weight;
|
||||
fwd_durations_range[segment_offset] = new_duration;
|
||||
fwd_datasources_range[segment_offset] = value->source;
|
||||
counters[value->source] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
counters[LUA_SOURCE] += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (fwd_was_updated)
|
||||
updated_segments.push_back(GeometryID{geometry_id, true});
|
||||
|
||||
// In this case we want it oriented from in forward directions
|
||||
auto rev_weights_range =
|
||||
boost::adaptors::reverse(segment_data.GetReverseWeights(geometry_id));
|
||||
auto rev_durations_range =
|
||||
boost::adaptors::reverse(segment_data.GetReverseDurations(geometry_id));
|
||||
auto rev_datasources_range =
|
||||
boost::adaptors::reverse(segment_data.GetReverseDatasources(geometry_id));
|
||||
bool rev_was_updated = false;
|
||||
|
||||
for (const auto segment_offset :
|
||||
util::irange<std::size_t>(0, rev_weights_range.size()))
|
||||
{
|
||||
counters[LUA_SOURCE] += 1;
|
||||
auto u = osm_node_ids[nodes_range[segment_offset]];
|
||||
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
||||
|
||||
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
||||
// waste time updating them with traffic data
|
||||
if (u == v)
|
||||
continue;
|
||||
|
||||
if (auto value = segment_speed_lookup({v, u}))
|
||||
{
|
||||
auto segment_length = segment_lengths[segment_offset];
|
||||
auto new_duration = convertToDuration(value->speed, segment_length);
|
||||
auto new_weight = convertToWeight(
|
||||
rev_weights_range[segment_offset], *value, segment_length);
|
||||
rev_was_updated = true;
|
||||
|
||||
rev_weights_range[segment_offset] = new_weight;
|
||||
rev_durations_range[segment_offset] = new_duration;
|
||||
rev_datasources_range[segment_offset] = value->source;
|
||||
counters[value->source] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
counters[LUA_SOURCE] += 1;
|
||||
}
|
||||
}
|
||||
if (rev_was_updated)
|
||||
updated_segments.push_back(GeometryID{geometry_id, false});
|
||||
}
|
||||
if (fwd_was_updated)
|
||||
updated_segments.push_back(GeometryID{geometry_id, true});
|
||||
|
||||
// In this case we want it oriented from in forward directions
|
||||
auto rev_weights_range =
|
||||
boost::adaptors::reverse(segment_data.GetReverseWeights(geometry_id));
|
||||
auto rev_durations_range =
|
||||
boost::adaptors::reverse(segment_data.GetReverseDurations(geometry_id));
|
||||
auto rev_datasources_range =
|
||||
boost::adaptors::reverse(segment_data.GetReverseDatasources(geometry_id));
|
||||
bool rev_was_updated = false;
|
||||
|
||||
for (const auto segment_offset : util::irange<std::size_t>(0, rev_weights_range.size()))
|
||||
{
|
||||
auto u = osm_node_ids[nodes_range[segment_offset]];
|
||||
auto v = osm_node_ids[nodes_range[segment_offset + 1]];
|
||||
|
||||
// Self-loops are artifical segments (e.g. traffic light nodes), do not
|
||||
// waste time updating them with traffic data
|
||||
if (u == v)
|
||||
continue;
|
||||
|
||||
if (auto value = segment_speed_lookup({v, u}))
|
||||
{
|
||||
auto segment_length = segment_lengths[segment_offset];
|
||||
auto new_duration = convertToDuration(value->speed, segment_length);
|
||||
auto new_weight =
|
||||
convertToWeight(rev_weights_range[segment_offset], *value, segment_length);
|
||||
rev_was_updated = true;
|
||||
|
||||
rev_weights_range[segment_offset] = new_weight;
|
||||
rev_durations_range[segment_offset] = new_duration;
|
||||
rev_datasources_range[segment_offset] = value->source;
|
||||
counters[value->source] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
counters[LUA_SOURCE] += 1;
|
||||
}
|
||||
}
|
||||
if (rev_was_updated)
|
||||
updated_segments.push_back(GeometryID{geometry_id, false});
|
||||
}
|
||||
}); // parallel_for
|
||||
}); // parallel_for
|
||||
|
||||
counters_type merged_counters(num_counters, 0);
|
||||
for (const auto &counters : segment_speeds_counters)
|
||||
@@ -587,20 +596,22 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
if (update_edge_weights || update_turn_penalties || update_conditional_turns)
|
||||
{
|
||||
tbb::parallel_invoke(
|
||||
[&] {
|
||||
extractor::files::readSegmentData(config.GetPath(".osrm.geometry"), segment_data);
|
||||
},
|
||||
[&]
|
||||
{ extractor::files::readSegmentData(config.GetPath(".osrm.geometry"), segment_data); },
|
||||
[&] { extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data); },
|
||||
|
||||
[&] {
|
||||
[&]
|
||||
{
|
||||
extractor::files::readTurnWeightPenalty(
|
||||
config.GetPath(".osrm.turn_weight_penalties"), turn_weight_penalties);
|
||||
},
|
||||
[&] {
|
||||
[&]
|
||||
{
|
||||
extractor::files::readTurnDurationPenalty(
|
||||
config.GetPath(".osrm.turn_duration_penalties"), turn_duration_penalties);
|
||||
},
|
||||
[&] {
|
||||
[&]
|
||||
{
|
||||
extractor::files::readProfileProperties(config.GetPath(".osrm.properties"),
|
||||
profile_properties);
|
||||
});
|
||||
@@ -647,7 +658,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
std::transform(updated_turn_penalties.begin(),
|
||||
updated_turn_penalties.end(),
|
||||
updated_segments.begin() + offset,
|
||||
[&node_data, &edge_based_edge_list](const std::uint64_t turn_id) {
|
||||
[&node_data, &edge_based_edge_list](const std::uint64_t turn_id)
|
||||
{
|
||||
const auto node_id = edge_based_edge_list[turn_id].source;
|
||||
return node_data.GetGeometryID(node_id);
|
||||
});
|
||||
@@ -672,7 +684,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
std::transform(updated_turn_penalties.begin(),
|
||||
updated_turn_penalties.end(),
|
||||
updated_segments.begin() + offset,
|
||||
[&node_data, &edge_based_edge_list](const std::uint64_t turn_id) {
|
||||
[&node_data, &edge_based_edge_list](const std::uint64_t turn_id)
|
||||
{
|
||||
const auto node_id = edge_based_edge_list[turn_id].source;
|
||||
return node_data.GetGeometryID(node_id);
|
||||
});
|
||||
@@ -680,13 +693,13 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
|
||||
tbb::parallel_sort(updated_segments.begin(),
|
||||
updated_segments.end(),
|
||||
[](const GeometryID lhs, const GeometryID rhs) {
|
||||
return std::tie(lhs.id, lhs.forward) < std::tie(rhs.id, rhs.forward);
|
||||
});
|
||||
[](const GeometryID lhs, const GeometryID rhs)
|
||||
{ return std::tie(lhs.id, lhs.forward) < std::tie(rhs.id, rhs.forward); });
|
||||
|
||||
using WeightAndDuration = std::tuple<EdgeWeight, EdgeDuration>;
|
||||
const auto compute_new_weight_and_duration =
|
||||
[&](const GeometryID geometry_id) -> WeightAndDuration {
|
||||
[&](const GeometryID geometry_id) -> WeightAndDuration
|
||||
{
|
||||
EdgeWeight new_weight = {0};
|
||||
EdgeDuration new_duration = {0};
|
||||
if (geometry_id.forward)
|
||||
@@ -728,7 +741,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
|
||||
std::vector<WeightAndDuration> accumulated_segment_data(updated_segments.size());
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, updated_segments.size()),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
for (auto index = range.begin(); index < range.end(); ++index)
|
||||
{
|
||||
accumulated_segment_data[index] =
|
||||
@@ -736,16 +750,16 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
}
|
||||
});
|
||||
|
||||
const auto update_edge = [&](extractor::EdgeBasedEdge &edge) {
|
||||
const auto update_edge = [&](extractor::EdgeBasedEdge &edge)
|
||||
{
|
||||
const auto node_id = edge.source;
|
||||
const auto geometry_id = node_data.GetGeometryID(node_id);
|
||||
auto updated_iter = std::lower_bound(updated_segments.begin(),
|
||||
updated_segments.end(),
|
||||
geometry_id,
|
||||
[](const GeometryID lhs, const GeometryID rhs) {
|
||||
return std::tie(lhs.id, lhs.forward) <
|
||||
std::tie(rhs.id, rhs.forward);
|
||||
});
|
||||
auto updated_iter = std::lower_bound(
|
||||
updated_segments.begin(),
|
||||
updated_segments.end(),
|
||||
geometry_id,
|
||||
[](const GeometryID lhs, const GeometryID rhs)
|
||||
{ return std::tie(lhs.id, lhs.forward) < std::tie(rhs.id, rhs.forward); });
|
||||
if (updated_iter != updated_segments.end() && updated_iter->id == geometry_id.id &&
|
||||
updated_iter->forward == geometry_id.forward)
|
||||
{
|
||||
@@ -806,7 +820,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
if (updated_segments.size() > 0)
|
||||
{
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, edge_based_edge_list.size()),
|
||||
[&](const auto &range) {
|
||||
[&](const auto &range)
|
||||
{
|
||||
for (auto index = range.begin(); index < range.end(); ++index)
|
||||
{
|
||||
update_edge(edge_based_edge_list[index]);
|
||||
@@ -817,11 +832,13 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
if (update_turn_penalties || update_conditional_turns)
|
||||
{
|
||||
tbb::parallel_invoke(
|
||||
[&] {
|
||||
[&]
|
||||
{
|
||||
extractor::files::writeTurnWeightPenalty(
|
||||
config.GetPath(".osrm.turn_weight_penalties"), turn_weight_penalties);
|
||||
},
|
||||
[&] {
|
||||
[&]
|
||||
{
|
||||
extractor::files::writeTurnDurationPenalty(
|
||||
config.GetPath(".osrm.turn_duration_penalties"), turn_duration_penalties);
|
||||
});
|
||||
|
||||
@@ -317,7 +317,8 @@ double findClosestDistance(const std::vector<Coordinate> &lhs, const std::vector
|
||||
{
|
||||
double current_min = std::numeric_limits<double>::max();
|
||||
|
||||
const auto compute_minimum_distance_in_rhs = [¤t_min, &rhs](const Coordinate coordinate) {
|
||||
const auto compute_minimum_distance_in_rhs = [¤t_min, &rhs](const Coordinate coordinate)
|
||||
{
|
||||
current_min =
|
||||
std::min(current_min, findClosestDistance(coordinate, rhs.begin(), rhs.end()));
|
||||
return false;
|
||||
@@ -331,9 +332,8 @@ double findClosestDistance(const std::vector<Coordinate> &lhs, const std::vector
|
||||
std::vector<double> getDeviations(const std::vector<Coordinate> &from,
|
||||
const std::vector<Coordinate> &to)
|
||||
{
|
||||
auto find_deviation = [&to](const Coordinate coordinate) {
|
||||
return findClosestDistance(coordinate, to.begin(), to.end());
|
||||
};
|
||||
auto find_deviation = [&to](const Coordinate coordinate)
|
||||
{ return findClosestDistance(coordinate, to.begin(), to.end()); };
|
||||
|
||||
std::vector<double> deviations_from;
|
||||
deviations_from.reserve(from.size());
|
||||
@@ -385,9 +385,9 @@ double computeArea(const std::vector<Coordinate> &polygon)
|
||||
// ⚠ ref_latitude is the standard parallel for the equirectangular projection
|
||||
// that is not an area-preserving projection
|
||||
const auto ref_point =
|
||||
std::min_element(polygon.begin(), polygon.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.lat < rhs.lat;
|
||||
});
|
||||
std::min_element(polygon.begin(),
|
||||
polygon.end(),
|
||||
[](const auto &lhs, const auto &rhs) { return lhs.lat < rhs.lat; });
|
||||
const auto ref_latitude = ref_point->lat;
|
||||
|
||||
// Compute area of under a curve and a line that is parallel the equator with ref_latitude
|
||||
|
||||
+2
-1
@@ -73,7 +73,8 @@ void Log::Init()
|
||||
{
|
||||
const bool is_terminal = IsStdoutATTY();
|
||||
|
||||
auto format = [is_terminal](const char *level, const char *color) {
|
||||
auto format = [is_terminal](const char *level, const char *color)
|
||||
{
|
||||
const auto timestamp = std::chrono::system_clock::now();
|
||||
return fmt::format("{}[{:%FT%H:%M:}{:%S}] [{}] ",
|
||||
is_terminal ? color : "",
|
||||
|
||||
@@ -327,13 +327,9 @@ struct opening_hours_grammar : qi::grammar<Iterator, Skipper, std::vector<Openin
|
||||
|
||||
// clang-format on
|
||||
|
||||
BOOST_SPIRIT_DEBUG_NODES((time_domain)(rule_sequence)(any_rule_separator)(
|
||||
selector_sequence)(wide_range_selectors)(small_range_selectors)(time_selector)(
|
||||
timespan)(time)(extended_time)(variable_time)(weekday_selector)(weekday_sequence)(
|
||||
weekday_range)(holiday_sequence)(nth_entry)(nth)(day_offset)(week_selector)(week)(
|
||||
monthday_selector)(monthday_range)(date_offset)(date_from)(date_to)(variable_date)(
|
||||
year_selector)(year_range)(plus_or_minus)(hour_minutes)(extended_hour_minutes)(comment)(
|
||||
hour)(extended_hour)(minute)(daynum)(weeknum)(year));
|
||||
BOOST_SPIRIT_DEBUG_NODES(
|
||||
(
|
||||
time_domain)(rule_sequence)(any_rule_separator)(selector_sequence)(wide_range_selectors)(small_range_selectors)(time_selector)(timespan)(time)(extended_time)(variable_time)(weekday_selector)(weekday_sequence)(weekday_range)(holiday_sequence)(nth_entry)(nth)(day_offset)(week_selector)(week)(monthday_selector)(monthday_range)(date_offset)(date_from)(date_to)(variable_date)(year_selector)(year_range)(plus_or_minus)(hour_minutes)(extended_hour_minutes)(comment)(hour)(extended_hour)(minute)(daynum)(weeknum)(year));
|
||||
}
|
||||
|
||||
qi::rule<Iterator, Skipper, std::vector<OpeningHours>()> time_domain;
|
||||
|
||||
@@ -79,7 +79,8 @@ void Timezoner::LoadLocalTimesRTree(rapidjson::Document &geojson, std::time_t ut
|
||||
// Lambda function that returns local time in the tzname time zone
|
||||
// Thread safety: MT-Unsafe const:env
|
||||
std::unordered_map<std::string, struct tm> local_time_memo;
|
||||
auto get_local_time_in_tz = [utc_time, &local_time_memo](const char *tzname) {
|
||||
auto get_local_time_in_tz = [utc_time, &local_time_memo](const char *tzname)
|
||||
{
|
||||
auto it = local_time_memo.find(tzname);
|
||||
if (it == local_time_memo.end())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user