2016-02-24 04:29:23 -05:00
|
|
|
#include "engine/guidance/post_processing.hpp"
|
|
|
|
#include "engine/guidance/turn_instruction.hpp"
|
|
|
|
#include "engine/guidance/guidance_toolkit.hpp"
|
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace engine
|
|
|
|
{
|
|
|
|
namespace guidance
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
bool canMergeTrivially(const PathData &destination, const PathData &source)
|
|
|
|
{
|
|
|
|
return destination.exit == 0 && destination.name_id == source.name_id &&
|
|
|
|
destination.travel_mode == source.travel_mode && isSilent(destination.turn_instruction);
|
|
|
|
}
|
|
|
|
|
|
|
|
PathData forwardInto(PathData destination, const PathData &source)
|
|
|
|
{
|
|
|
|
// Merge a turn into a silent turn
|
|
|
|
// Overwrites turn instruction and increases exit NR
|
|
|
|
destination.duration_until_turn += source.duration_until_turn;
|
|
|
|
destination.exit = source.exit;
|
|
|
|
return destination;
|
|
|
|
}
|
|
|
|
|
|
|
|
PathData accumulateInto(PathData destination, const PathData &source)
|
|
|
|
{
|
|
|
|
// Merge a turn into a silent turn
|
|
|
|
// Overwrites turn instruction and increases exit NR
|
|
|
|
BOOST_ASSERT(canMergeTrivially(destination, source));
|
|
|
|
destination.duration_until_turn += source.duration_until_turn;
|
|
|
|
destination.exit = source.exit + 1;
|
|
|
|
return destination;
|
|
|
|
}
|
|
|
|
|
|
|
|
PathData mergeInto(PathData destination, const PathData &source)
|
|
|
|
{
|
|
|
|
if (source.turn_instruction == TurnInstruction::NO_TURN())
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(canMergeTrivially(destination, source));
|
|
|
|
return detail::forwardInto(destination, source);
|
|
|
|
}
|
|
|
|
if (source.turn_instruction == TurnType::Suppressed &&
|
|
|
|
detail::canMergeTrivially(destination, source))
|
|
|
|
{
|
2016-02-24 08:03:51 -05:00
|
|
|
return detail::forwardInto(destination, source);
|
2016-02-24 04:29:23 -05:00
|
|
|
}
|
|
|
|
if (source.turn_instruction.type == TurnType::StayOnRoundabout)
|
|
|
|
{
|
2016-02-24 08:03:51 -05:00
|
|
|
return detail::forwardInto(destination, source);
|
|
|
|
}
|
|
|
|
if (entersRoundabout(source.turn_instruction))
|
|
|
|
{
|
|
|
|
return detail::forwardInto(destination, source);
|
2016-02-24 04:29:23 -05:00
|
|
|
}
|
|
|
|
return destination;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
2016-02-24 08:03:51 -05:00
|
|
|
void print(const std::vector<std::vector<PathData>> &leg_data)
|
2016-02-24 04:29:23 -05:00
|
|
|
{
|
2016-02-24 08:03:51 -05:00
|
|
|
std::cout << "Path\n";
|
|
|
|
int legnr = 0;
|
|
|
|
for (const auto &leg : leg_data)
|
|
|
|
{
|
|
|
|
std::cout << "\tLeg: " << ++legnr << "\n";
|
|
|
|
int segment = 0;
|
|
|
|
for (const auto &data : leg)
|
|
|
|
{
|
|
|
|
std::cout << "\t\t[" << ++segment << "]: " << (int)data.turn_instruction.type << " "
|
|
|
|
<< (int)data.turn_instruction.direction_modifier << " exit: " << data.exit
|
|
|
|
<< "\n";
|
|
|
|
}
|
2016-02-24 04:29:23 -05:00
|
|
|
}
|
2016-02-24 08:03:51 -05:00
|
|
|
std::cout << std::endl;
|
2016-02-24 04:29:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::vector<PathData>> postProcess(std::vector<std::vector<PathData>> leg_data)
|
|
|
|
{
|
2016-02-25 12:31:29 -05:00
|
|
|
if (leg_data.empty())
|
|
|
|
return leg_data;
|
2016-02-24 08:03:51 -05:00
|
|
|
|
|
|
|
#define PRINT_DEBUG 0
|
2016-02-24 04:29:23 -05:00
|
|
|
unsigned carry_exit = 0;
|
2016-02-24 08:03:51 -05:00
|
|
|
#if PRINT_DEBUG
|
|
|
|
std::cout << "[POSTPROCESSING ITERATION]" << std::endl;
|
|
|
|
std::cout << "Input\n";
|
|
|
|
print(leg_data);
|
|
|
|
#endif
|
2016-02-24 04:29:23 -05:00
|
|
|
// Count Street Exits forward
|
2016-02-24 08:03:51 -05:00
|
|
|
bool on_roundabout = false;
|
2016-02-24 04:29:23 -05:00
|
|
|
for (auto &path_data : leg_data)
|
|
|
|
{
|
2016-02-25 12:31:29 -05:00
|
|
|
if (not path_data.empty())
|
|
|
|
path_data[0].exit = carry_exit;
|
2016-02-25 08:40:26 -05:00
|
|
|
|
2016-02-24 04:29:23 -05:00
|
|
|
for (std::size_t data_index = 0; data_index + 1 < path_data.size(); ++data_index)
|
|
|
|
{
|
2016-02-25 12:31:29 -05:00
|
|
|
if (entersRoundabout(path_data[data_index].turn_instruction))
|
2016-02-24 08:03:51 -05:00
|
|
|
{
|
|
|
|
path_data[data_index].exit += 1;
|
|
|
|
on_roundabout = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isSilent(path_data[data_index].turn_instruction) &&
|
2016-02-25 12:31:29 -05:00
|
|
|
path_data[data_index].turn_instruction != TurnInstruction::NO_TURN())
|
2016-02-24 08:03:51 -05:00
|
|
|
{
|
|
|
|
path_data[data_index].exit += 1;
|
|
|
|
}
|
|
|
|
if (leavesRoundabout(path_data[data_index].turn_instruction))
|
|
|
|
{
|
|
|
|
if (!on_roundabout)
|
|
|
|
{
|
2016-02-25 12:31:29 -05:00
|
|
|
BOOST_ASSERT(leg_data[0][0].turn_instruction.type == TurnType::NO_TURN());
|
2016-02-24 08:03:51 -05:00
|
|
|
if (path_data[data_index].turn_instruction.type == ExitRoundabout)
|
|
|
|
leg_data[0][0].turn_instruction.type = TurnType::EnterRoundabout;
|
|
|
|
if (path_data[data_index].turn_instruction.type == ExitRotary)
|
|
|
|
leg_data[0][0].turn_instruction.type = TurnType::EnterRotary;
|
|
|
|
path_data[data_index].exit += 1;
|
|
|
|
}
|
|
|
|
on_roundabout = false;
|
|
|
|
}
|
2016-02-24 04:29:23 -05:00
|
|
|
if (path_data[data_index].turn_instruction.type == TurnType::EnterRoundaboutAtExit)
|
|
|
|
{
|
2016-02-24 08:03:51 -05:00
|
|
|
path_data[data_index].exit += 1;
|
2016-02-24 04:29:23 -05:00
|
|
|
path_data[data_index].turn_instruction.type = TurnType::EnterRoundabout;
|
|
|
|
}
|
|
|
|
else if (path_data[data_index].turn_instruction.type == TurnType::EnterRotaryAtExit)
|
|
|
|
{
|
|
|
|
path_data[data_index].exit += 1;
|
|
|
|
path_data[data_index].turn_instruction.type = TurnType::EnterRotary;
|
|
|
|
}
|
|
|
|
|
2016-02-24 08:03:51 -05:00
|
|
|
if (isSilent(path_data[data_index].turn_instruction) ||
|
|
|
|
entersRoundabout(path_data[data_index].turn_instruction))
|
2016-02-24 04:29:23 -05:00
|
|
|
{
|
|
|
|
path_data[data_index + 1] =
|
|
|
|
detail::mergeInto(path_data[data_index + 1], path_data[data_index]);
|
|
|
|
}
|
|
|
|
carry_exit = path_data[data_index].exit;
|
|
|
|
}
|
|
|
|
}
|
2016-02-24 08:03:51 -05:00
|
|
|
#if PRINT_DEBUG
|
|
|
|
std::cout << "Merged\n";
|
|
|
|
print(leg_data);
|
|
|
|
#endif
|
|
|
|
on_roundabout = false;
|
2016-02-24 04:29:23 -05:00
|
|
|
// Move Roundabout exit numbers to front
|
|
|
|
for (auto rev_itr = leg_data.rbegin(); rev_itr != leg_data.rend(); ++rev_itr)
|
|
|
|
{
|
|
|
|
auto &path_data = *rev_itr;
|
|
|
|
for (std::size_t data_index = path_data.size(); data_index > 1; --data_index)
|
|
|
|
{
|
2016-02-24 08:03:51 -05:00
|
|
|
if (entersRoundabout(path_data[data_index - 1].turn_instruction))
|
|
|
|
{
|
2016-02-25 12:31:29 -05:00
|
|
|
if (!on_roundabout && !leavesRoundabout(path_data[data_index - 1].turn_instruction))
|
|
|
|
path_data[data_index - 1].exit = 0;
|
2016-02-24 08:03:51 -05:00
|
|
|
on_roundabout = false;
|
|
|
|
}
|
|
|
|
if (on_roundabout)
|
2016-02-24 04:29:23 -05:00
|
|
|
{
|
|
|
|
path_data[data_index - 2].exit = path_data[data_index - 1].exit;
|
|
|
|
}
|
2016-02-25 12:31:29 -05:00
|
|
|
if (leavesRoundabout(path_data[data_index - 1].turn_instruction) &&
|
|
|
|
!entersRoundabout(path_data[data_index - 1].turn_instruction))
|
2016-02-24 08:03:51 -05:00
|
|
|
{
|
|
|
|
path_data[data_index - 2].exit = path_data[data_index - 1].exit;
|
|
|
|
on_roundabout = true;
|
|
|
|
}
|
2016-02-24 04:29:23 -05:00
|
|
|
}
|
|
|
|
auto prev_leg = std::next(rev_itr);
|
|
|
|
if (!path_data.empty() && prev_leg != leg_data.rend())
|
|
|
|
{
|
2016-02-24 08:03:51 -05:00
|
|
|
if (on_roundabout && path_data[0].exit)
|
2016-02-24 04:29:23 -05:00
|
|
|
prev_leg->back().exit = path_data[0].exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-24 08:03:51 -05:00
|
|
|
#if PRINT_DEBUG
|
|
|
|
std::cout << "Move To Front\n";
|
|
|
|
print(leg_data);
|
|
|
|
#endif
|
|
|
|
// silence silent turns for good
|
2016-02-24 04:29:23 -05:00
|
|
|
for (auto &path_data : leg_data)
|
|
|
|
{
|
|
|
|
for (auto &data : path_data)
|
|
|
|
{
|
2016-02-25 12:31:29 -05:00
|
|
|
if (isSilent(data.turn_instruction) || (leavesRoundabout(data.turn_instruction) &&
|
|
|
|
!entersRoundabout(data.turn_instruction)))
|
2016-02-24 08:03:51 -05:00
|
|
|
{
|
2016-02-24 04:29:23 -05:00
|
|
|
data.turn_instruction = TurnInstruction::NO_TURN();
|
2016-02-24 08:03:51 -05:00
|
|
|
data.exit = 0;
|
|
|
|
}
|
2016-02-24 04:29:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::move(leg_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace guidance
|
|
|
|
} // namespace engine
|
|
|
|
} // namespace osrm
|