[Routing] Fix of rare cases

Better handling of nodes.isCandidatesAngleValid == false
from IRoutingResult::GetPossibleTurns() in GetTurnDirection().

Signed-off-by: Anton Makouski <anton.makouski@gmail.com>
This commit is contained in:
Anton Makouski 2022-05-16 11:17:34 +03:00
parent be8f4e064e
commit 525b03154b
5 changed files with 55 additions and 15 deletions

View file

@ -429,6 +429,8 @@ void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingS
("Turn candidates should be sorted by its angle field."));
}
/// @todo Proper handling of isCandidatesAngleValid == False, when we don't have angles of candidates.
if (nodes.candidates.size() == 0)
return;
@ -437,11 +439,10 @@ void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingS
return;
Segment firstOutgoingSeg;
bool const isFirstOutgoingSegValid = turnInfo.m_outgoing->m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSeg);
if (!isFirstOutgoingSegValid)
if (!turnInfo.m_outgoing->m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSeg))
return;
CorrectCandidatesSegmentByOutgoing(turnInfo, firstOutgoingSeg, nodes.candidates);
CorrectCandidatesSegmentByOutgoing(turnInfo, firstOutgoingSeg, nodes);
RemoveUTurnCandidate(turnInfo, numMwmIds, nodes.candidates);
auto const & turnCandidates = nodes.candidates;
@ -496,7 +497,7 @@ void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingS
turn.m_turn = intermediateDirection;
if (turnCandidates.size() >= 2)
if (turnCandidates.size() >= 2 && nodes.isCandidatesAngleValid)
CorrectRightmostAndLeftmost(turnCandidates, firstOutgoingSeg, turnAngle, turn);
}

View file

@ -8,14 +8,14 @@
namespace routing
{
using namespace std;
using namespace turns;
PedestrianDirectionsEngine::PedestrianDirectionsEngine(MwmDataSource & dataSource, shared_ptr<NumMwmIds> numMwmIds)
: DirectionsEngine(dataSource, move(numMwmIds))
{
}
using namespace std;
using namespace turns;
// Angles in degrees for finding route segments with no actual forks.
double constexpr kMaxForwardAngleCandidates = 95.0;
double constexpr kMaxForwardAngleActual = 60.0;
@ -59,6 +59,11 @@ size_t PedestrianDirectionsEngine::GetTurnDirection(IRoutingResult const & resul
return 0;
}
Segment firstOutgoingSeg;
if (!turnInfo.m_outgoing->m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSeg))
return 0;
CorrectCandidatesSegmentByOutgoing(turnInfo, firstOutgoingSeg, nodes);
RemoveUTurnCandidate(turnInfo, numMwmIds, nodes.candidates);
// If there is no fork on the road we don't need to generate any turn. It is pointless because

View file

@ -182,9 +182,11 @@ UNIT_TEST(TurnsNearAltufievskoeShosseLongFakeSegmentTest)
integration::TestTurnCount(route, 3 /* expectedTurnCount */);
/// @todo Problem with outgoingTurns from RoutingEngineResult::GetPossibleTurns at (turn_m_index == 3)
/// For some reason for both of outgoingTurns angles are 0, but it is expected to be -90 and +90.
/// But this does not prevent from proper directions.
// Complicated case.
// RoutingEngineResult::GetPossibleTurns at (turn_m_index == 3)
// return nodes with isCandidatesAngleValid and 2 candidates with m_angle == 0
// In fact they are -90 and +90, but we don't know it.
// But this should not prevent from proper directions.
integration::GetNthTurn(route, 0).TestValid().TestDirection(CarDirection::TurnRight);
integration::GetNthTurn(route, 1).TestValid().TestDirection(CarDirection::TurnLeft);
integration::GetNthTurn(route, 2).TestValid().TestDirection(CarDirection::TurnRight);

View file

@ -269,13 +269,16 @@ double CalcTurnAngle(IRoutingResult const & result,
}
void CorrectCandidatesSegmentByOutgoing(TurnInfo const & turnInfo, Segment const & firstOutgoingSeg,
std::vector<TurnCandidate> & candidates)
TurnCandidates & nodes)
{
double const turnAngle = CalcOneSegmentTurnAngle(turnInfo);
auto IsFirstOutgoingSeg = [&firstOutgoingSeg](TurnCandidate const & turnCandidate) { return turnCandidate.m_segment == firstOutgoingSeg; };
if (find_if(candidates.begin(), candidates.end(), IsFirstOutgoingSeg) == candidates.end())
auto & candidates = nodes.candidates;
auto it = find_if(candidates.begin(), candidates.end(), IsFirstOutgoingSeg);
if (it == candidates.end())
{
double const turnAngle = CalcOneSegmentTurnAngle(turnInfo);
auto DoesAngleMatch = [&turnAngle](TurnCandidate const & turnCandidate) { return base::AlmostEqualAbs(turnCandidate.m_angle, turnAngle, 0.001); };
auto DoesAngleMatch = [&turnAngle](TurnCandidate const & turnCandidate)
{ return base::AlmostEqualAbs(turnCandidate.m_angle, turnAngle, 0.001) || abs(turnCandidate.m_angle) + abs(turnAngle) > 359.999; };
auto it = find_if(candidates.begin(), candidates.end(), DoesAngleMatch);
if (it != candidates.end())
{
@ -283,6 +286,35 @@ void CorrectCandidatesSegmentByOutgoing(TurnInfo const & turnInfo, Segment const
ASSERT(it->m_segment.GetSegmentIdx() == firstOutgoingSeg.GetSegmentIdx() && it->m_segment.IsForward() == firstOutgoingSeg.IsForward(), ());
it->m_segment = firstOutgoingSeg;
}
else if (nodes.isCandidatesAngleValid)
ASSERT(false, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true."));
else
{
LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment and isCandidatesAngleValid == false"));
if (candidates.size() == 1)
{
ASSERT(candidates.front().m_segment.GetMwmId() != firstOutgoingSeg.GetMwmId(), ());
ASSERT(candidates.front().m_segment.GetSegmentIdx() == firstOutgoingSeg.GetSegmentIdx() && candidates.front().m_segment.IsForward() == firstOutgoingSeg.IsForward(), ());
candidates.front().m_segment = firstOutgoingSeg;
nodes.isCandidatesAngleValid = true;
LOG(LWARNING, ("but since candidates.size() == 1, this was fixed."));
}
else
LOG(LWARNING, ("and since candidates.size() > 1, this can't be fixed."));
}
}
else
{
if (nodes.isCandidatesAngleValid)
ASSERT((base::AlmostEqualAbs(it->m_angle, turnAngle, 0.001) || abs(it->m_angle) + abs(turnAngle) > 359.999), ());
else
{
it->m_angle = turnAngle;
if (candidates.size() == 1)
nodes.isCandidatesAngleValid = true;
else
LOG(LWARNING, ("isCandidatesAngleValid == false, and this can't be fixed."));
}
}
}

View file

@ -76,7 +76,7 @@ bool HasSingleForwardTurn(TurnCandidates const & turnCandidates, float maxForwar
// It may happened if |firstOutgoingSeg| and candidates in |turnCandidates| are from different mwms.
// Let's identify it in turnCandidates by angle and update according turnCandidate.
void CorrectCandidatesSegmentByOutgoing(TurnInfo const & turnInfo, Segment const & firstOutgoingSeg,
std::vector<TurnCandidate> & candidates);
TurnCandidates & nodes);
/*!
* \brief Returns ingoing point or outgoing point for turns.