[Routing] Fixes: #2422 + GetTurnDirection() refactoring #2427

Merged
AntonM030481 merged 9 commits from navigation-turn-directions-2422 into master 2022-04-22 08:46:20 +00:00
2 changed files with 111 additions and 146 deletions

View file

@ -328,17 +328,17 @@ UNIT_TEST(TestRightmostDirection)
TEST_EQUAL(RightmostDirection(90.), CarDirection::TurnRight, ());
TEST_EQUAL(RightmostDirection(45.), CarDirection::TurnSlightRight, ());
TEST_EQUAL(RightmostDirection(0.), CarDirection::GoStraight, ());
TEST_EQUAL(RightmostDirection(-20.), CarDirection::TurnSlightLeft, ());
TEST_EQUAL(RightmostDirection(-90.), CarDirection::TurnLeft, ());
TEST_EQUAL(RightmostDirection(-170.), CarDirection::TurnSharpLeft, ());
TEST_EQUAL(RightmostDirection(-20.), CarDirection::GoStraight, ());
TEST_EQUAL(RightmostDirection(-90.), CarDirection::GoStraight, ());
TEST_EQUAL(RightmostDirection(-170.), CarDirection::GoStraight, ());
}
UNIT_TEST(TestLeftmostDirection)
vng commented 2022-04-21 17:29:42 +00:00 (Migrated from github.com)
Review

Could you explain why 90 degrees is TurnRight and -90 degrees is GoStraight?
The same with others .. Am I miss something with these angles?

Could you explain why 90 degrees is TurnRight and -90 degrees is GoStraight? The same with others .. Am I miss something with these angles?
AntonM030481 commented 2022-04-21 18:01:44 +00:00 (Migrated from github.com)
Review

I was trying to explain it in RighmostDirection() definition:

// For sure it's incorrect to give directions TurnLeft or TurnSlighLeft if we need the rightmost turn.
// So GoStraight direction is given even for needed sharp left turn when other turns on the left and are more sharp.
// The reason: the rightmost turn is the most straight one here.

If necessary I can make it more clear or move comments to \brief section.

I was trying to explain it in RighmostDirection() definition: ``` // For sure it's incorrect to give directions TurnLeft or TurnSlighLeft if we need the rightmost turn. // So GoStraight direction is given even for needed sharp left turn when other turns on the left and are more sharp. // The reason: the rightmost turn is the most straight one here. ``` If necessary I can make it more clear or move comments to \brief section.
vng commented 2022-04-21 18:12:23 +00:00 (Migrated from github.com)
Review

Ok, but could you also provide an example (in brief or description or when RighmostDirection/LeftmostDirection functions are called), who decided that the turn is "rightmost" or "leftmost"?
What does "rightmost/leftmost" actually mean?

Ok, but could you also provide an example (in brief or description or when RighmostDirection/LeftmostDirection functions are called), who decided that the turn is "rightmost" or "leftmost"? What does "rightmost/leftmost" actually mean?
vng commented 2022-04-21 18:14:26 +00:00 (Migrated from github.com)
Review

I see this block but can't understand what does it mean?

if (nodes.candidates.front().m_segment == firstOutgoingSeg)
  turn.m_turn = LeftmostDirection(turnAngle);
else if (nodes.candidates.back().m_segment == firstOutgoingSeg)
  turn.m_turn = RightmostDirection(turnAngle);
else
  turn.m_turn = intermediateDirection;
I see this block but can't understand what does it mean? ``` if (nodes.candidates.front().m_segment == firstOutgoingSeg) turn.m_turn = LeftmostDirection(turnAngle); else if (nodes.candidates.back().m_segment == firstOutgoingSeg) turn.m_turn = RightmostDirection(turnAngle); else turn.m_turn = intermediateDirection; ```
vng commented 2022-04-21 18:16:06 +00:00 (Migrated from github.com)
Review

Ah, if nodes.candidates are sorted by direction angle, then it makes sense :)
Ok, please, add some comments, but now I got the logic!

Ah, if nodes.candidates are sorted by direction angle, then it makes sense :) Ok, please, add some comments, but now I got the logic!
AntonM030481 commented 2022-04-21 18:27:17 +00:00 (Migrated from github.com)
Review

Running road_access_test.cpp::RoadAccess_WayBlockedWhenStartButOpenWhenReach
FAILED
routing_tests/index_graph_tools.cpp:606 TEST(base::AlmostEqualAbs(pathWeight, expectedWeight, kEpsilon)) 10804 12802 [5: (0, 1) (1, 2) (2, 3) (3, 4) (4, 5) ]

Running opening_hours_serdes_tests.cpp::BitReaderWriter_OpeningHoursSerDes_MonthHours_Usage
FAILED
routing_tests/opening_hours_serdes_tests.cpp:823 TEST(oh.IsClosed(GetUnixtimeByDate(2020, Month::May, 6, 01 , 00 )))

Running opening_hours_serdes_tests.cpp::BitReaderWriter_OpeningHoursSerDes_Weekday_Usage_2
FAILED
routing_tests/opening_hours_serdes_tests.cpp:750 TEST(oh.IsOpen(GetUnixtimeByDate(2023, Month::Apr, Weekday::Saturday, 13 , 30 )))

Running road_access_test.cpp::RoadAccess_WayBlockedWhenStartButOpenWhenReach FAILED routing_tests/index_graph_tools.cpp:606 TEST(base::AlmostEqualAbs(pathWeight, expectedWeight, kEpsilon)) 10804 12802 [5: (0, 1) (1, 2) (2, 3) (3, 4) (4, 5) ] Running opening_hours_serdes_tests.cpp::BitReaderWriter_OpeningHoursSerDes_MonthHours_Usage FAILED routing_tests/opening_hours_serdes_tests.cpp:823 TEST(oh.IsClosed(GetUnixtimeByDate(2020, Month::May, 6, 01 , 00 ))) Running opening_hours_serdes_tests.cpp::BitReaderWriter_OpeningHoursSerDes_Weekday_Usage_2 FAILED routing_tests/opening_hours_serdes_tests.cpp:750 TEST(oh.IsOpen(GetUnixtimeByDate(2023, Month::Apr, Weekday::Saturday, 13 , 30 )))
vng commented 2022-04-21 18:38:28 +00:00 (Migrated from github.com)
Review

What is your env (Linux/MacOS) and toolchain (gcc/clang --version)?
Looks like OpeningHours (boost/spirit) is buggy on your system.
Do you have boost submodule latest and updated?

What is your env (Linux/MacOS) and toolchain (gcc/clang --version)? Looks like OpeningHours (boost/spirit) is buggy on your system. Do you have boost submodule latest and updated?
vng commented 2022-04-21 18:50:38 +00:00 (Migrated from github.com)
Review

BTW, try to run ./opening_hours_tests

BTW, try to run ./opening_hours_tests
AntonM030481 commented 2022-04-21 19:16:13 +00:00 (Migrated from github.com)
Review

MacOS 12.13.1
Apple clang version 13.1.6 (clang-1316.0.21.2)
Target: x86_64-apple-darwin21.4.0
Thread model: posix

Boost just pulled.

*** 12 failures are detected in the test module "OpeningHours"

MacOS 12.13.1 Apple clang version 13.1.6 (clang-1316.0.21.2) Target: x86_64-apple-darwin21.4.0 Thread model: posix Boost just pulled. *** 12 failures are detected in the test module "OpeningHours"
AntonM030481 commented 2022-04-21 19:19:10 +00:00 (Migrated from github.com)
Review

Added:

// turnCandidates are sorted by angle from leftmost to rightmost.
if (turnCandidates.front().m_segment == firstOutgoingSeg)
Added: ``` // turnCandidates are sorted by angle from leftmost to rightmost. if (turnCandidates.front().m_segment == firstOutgoingSeg) ```
vng commented 2022-04-21 19:23:40 +00:00 (Migrated from github.com)
Review

Strange, because I have exactly the same toolchain ..

Strange, because I have exactly the same toolchain ..
AntonM030481 commented 2022-04-21 20:23:56 +00:00 (Migrated from github.com)
Review

Do I need any additional data to run the tests?
I used "--filter=blob:limit=128k"

Do I need any additional data to run the tests? I used "--filter=blob:limit=128k"
vng commented 2022-04-21 20:36:29 +00:00 (Migrated from github.com)
Review

No, you don't .. Could you show me:
cat 3party/boost/boost/version.hpp | grep "VERSION"
cat 3party/boost/boost/spirit/include/version.hpp | grep "VERSION"
cat 3party/boost/boost/phoenix/version.hpp | grep "VERSION"

No, you don't .. Could you show me: cat 3party/boost/boost/version.hpp | grep "VERSION" cat 3party/boost/boost/spirit/include/version.hpp | grep "VERSION" cat 3party/boost/boost/phoenix/version.hpp | grep "VERSION"
AntonM030481 commented 2022-04-26 08:43:31 +00:00 (Migrated from github.com)
Review
#define BOOST_VERSION 107900
#define BOOST_LIB_VERSION "1_79"

#define SPIRIT_VERSION 0x2059
#define SPIRIT_PIZZA_VERSION SUPER_HOT_SPANISH_SARDINES  // :-O

#define BOOST_PHOENIX_VERSION   0x3200    // 3.2.0
#define BOOST_PHOENIX_VERSION_NUMBER = BOOST_VERSION_NUMBER(3,2,0)
``` #define BOOST_VERSION 107900 #define BOOST_LIB_VERSION "1_79" #define SPIRIT_VERSION 0x2059 #define SPIRIT_PIZZA_VERSION SUPER_HOT_SPANISH_SARDINES // :-O #define BOOST_PHOENIX_VERSION 0x3200 // 3.2.0 #define BOOST_PHOENIX_VERSION_NUMBER = BOOST_VERSION_NUMBER(3,2,0) ```
biodranik commented 2022-04-26 11:52:45 +00:00 (Migrated from github.com)
Review
$ ../omim-build-debug/opening_hours_tests
Running 23 test cases...
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1348: error: in "OpeningHours_TestIsActive": check IsActive(rules[0], time) has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1351: error: in "OpeningHours_TestIsActive": check IsActive(rules[1], time) has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1458: error: in "OpeningHours_TestIsActive": check IsActive(rules[0], time) has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1478: error: in "OpeningHours_TestIsActive": check IsActive(rules[0], time) has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1553: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2021-05-08 19:40") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1592: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-07-09 16:50") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1615: error: in "OpeningHours_TestIsOpen": check IsClosed(rules, "2012-10-08 15:59") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1628: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-04-10 07:15") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1629: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-05-01 07:15") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1630: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-04-11 07:15") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1649: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2017-05-31 23:35") has failed
/Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1659: error: in "OpeningHours_TestIsOpen": check !IsOpen(rules, "2017-05-31 23:35") has failed

*** 12 failures are detected in the test module "OpeningHours"
``` $ ../omim-build-debug/opening_hours_tests Running 23 test cases... /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1348: error: in "OpeningHours_TestIsActive": check IsActive(rules[0], time) has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1351: error: in "OpeningHours_TestIsActive": check IsActive(rules[1], time) has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1458: error: in "OpeningHours_TestIsActive": check IsActive(rules[0], time) has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1478: error: in "OpeningHours_TestIsActive": check IsActive(rules[0], time) has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1553: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2021-05-08 19:40") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1592: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-07-09 16:50") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1615: error: in "OpeningHours_TestIsOpen": check IsClosed(rules, "2012-10-08 15:59") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1628: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-04-10 07:15") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1629: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-05-01 07:15") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1630: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2015-04-11 07:15") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1649: error: in "OpeningHours_TestIsOpen": check IsOpen(rules, "2017-05-31 23:35") has failed /Users/alex/Developer/omim/omim/3party/opening_hours/opening_hours_tests/opening_hours_tests.cpp:1659: error: in "OpeningHours_TestIsOpen": check !IsOpen(rules, "2017-05-31 23:35") has failed *** 12 failures are detected in the test module "OpeningHours" ```
{
TEST_EQUAL(LeftmostDirection(180.), CarDirection::TurnSharpRight, ());
TEST_EQUAL(LeftmostDirection(170.), CarDirection::TurnSharpRight, ());
TEST_EQUAL(LeftmostDirection(90.), CarDirection::TurnRight, ());
TEST_EQUAL(LeftmostDirection(45.), CarDirection::TurnSlightRight, ());
TEST_EQUAL(LeftmostDirection(180.), CarDirection::GoStraight, ());
TEST_EQUAL(LeftmostDirection(170.), CarDirection::GoStraight, ());
TEST_EQUAL(LeftmostDirection(90.), CarDirection::GoStraight, ());
TEST_EQUAL(LeftmostDirection(45.), CarDirection::GoStraight, ());
TEST_EQUAL(LeftmostDirection(0.), CarDirection::GoStraight, ());
TEST_EQUAL(LeftmostDirection(-20.), CarDirection::TurnSlightLeft, ());
TEST_EQUAL(LeftmostDirection(-90.), CarDirection::TurnLeft, ());

View file

@ -125,7 +125,7 @@ bool GetTurnHighwayClasses(TurnCandidates const & possibleTurns, TurnInfo const
{
// Let's consider all outgoing segments except for
// (1) route outgoing segment
// (2) a U-turn segment (inversedLastIngoingSegment)
// (2) a U-turn segment (inversedLastIngoingSegment).
if (t.m_segment == firstOutgoingSegment || t.m_segment == inversedLastIngoingSegment)
continue;
ftypes::HighwayClass const highwayClass = t.m_highwayClass;
@ -180,7 +180,7 @@ bool DiscardTurnByHighwayClass(TurnCandidates const & possibleTurns, TurnInfo co
int constexpr kMaxHighwayClassDiffForService = 1;
TurnHighwayClasses turnHighwayClasses;
// Looks like a bug. If no info received turn should not be discarded
// Looks like a bug. If no info received turn should not be discarded.
if (!GetTurnHighwayClasses(possibleTurns, turnInfo, numMwmIds, turnHighwayClasses))
return true;
@ -197,19 +197,26 @@ bool DiscardTurnByHighwayClass(TurnCandidates const & possibleTurns, TurnInfo co
}
/// * \returns false when
/// * for routes which go straight and don't go to a smaller road:
biodranik commented 2022-04-20 13:27:25 +00:00 (Migrated from github.com)
Review
bool DiscardTurnByNoAlignedAlternatives(std::vector<TurnCandidate> const & candidatesWithoutUturn, TurnInfo const & turnInfo,

Надо соблюдать наше текущее соглашение о форматировании.

```suggestion bool DiscardTurnByNoAlignedAlternatives(std::vector<TurnCandidate> const & candidatesWithoutUturn, TurnInfo const & turnInfo, ``` Надо соблюдать наше текущее соглашение о форматировании.
AntonM030481 commented 2022-04-20 15:05:51 +00:00 (Migrated from github.com)
Review

ок

ок
/// * - any alternative GoStraight or SlightTurn turn
/// * for other routes:
/// * - any alternative turn to a bigger road
/// * - or any alternative turn to a similar road if the turn's angle is less than kMaxAbsAngleSameRoadClass degrees (wider than SlightTurn)
/// * - or any alternative turn to a smaller road if it's GoStraight or SlightTurn.
/// * Returns true otherwise.
/// \param possibleTurns is all possible ways out from a junction.
/// \param turnRoute is current route turn
/// \param turnCandidates is all possible ways out from a junction except uturn.
/// \param turnInfo is information about ingoing and outgoing segments of the route.
/// it is supposed that current turn is GoStraight or SlightTurn
bool DiscardTurnByNoAlignedAlternatives(TurnCandidates const & possibleTurns, TurnInfo const & turnInfo,
bool DiscardTurnByNoAlignedAlternatives(TurnItem const & turnRoute,
std::vector<TurnCandidate> const & turnCandidates,
TurnInfo const & turnInfo,
NumMwmIds const & numMwmIds)
{
double constexpr kMaxAbsAngleSameRoadClass = 70.0;
biodranik commented 2022-04-20 13:28:04 +00:00 (Migrated from github.com)
Review

Это можно в одну строку вместо двух, и точку в конце.

Это можно в одну строку вместо двух, и точку в конце.
AntonM030481 commented 2022-04-20 15:06:16 +00:00 (Migrated from github.com)
Review

ок

ок
ftypes::HighwayClass outgoingRouteRoadClass = turnInfo.m_outgoing.m_highwayClass;
ftypes::HighwayClass ingoingRouteRoadClass = turnInfo.m_ingoing.m_highwayClass;
// The turn should be kept if there's no any information about feature id of outgoing segment
// just to be on the safe side. It may happen in case of outgoing segment is a finish segment.
@ -217,38 +224,40 @@ bool DiscardTurnByNoAlignedAlternatives(TurnCandidates const & possibleTurns, Tu
if (!turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSegment))
return false;
Segment inversedLastIngoingSegment;
if (!turnInfo.m_ingoing.m_segmentRange.GetLastSegment(numMwmIds, inversedLastIngoingSegment))
return false;
inversedLastIngoingSegment.Inverse();
for (auto const & t : possibleTurns.candidates)
for (auto const & t : turnCandidates)
{
// Let's consider all outgoing segments except for
// (1) route outgoing segment
// (2) a U-turn segment (inversedLastIngoingSegment)
if (t.m_segment == firstOutgoingSegment || t.m_segment == inversedLastIngoingSegment)
// Let's consider all outgoing segments except for route outgoing segment.
if (t.m_segment == firstOutgoingSegment)
continue;
ftypes::HighwayClass const highwayClass = t.m_highwayClass;
// @note The bigger is the road, the lesser is HighwayClass value.
if (static_cast<int>(highwayClass) < static_cast<int>(outgoingRouteRoadClass))
if (turnRoute.m_turn == CarDirection::GoStraight && static_cast<int>(outgoingRouteRoadClass) >= static_cast<int>(ingoingRouteRoadClass))
{
// Any alternative turn to a bigger road keeps the turn direction.
return false;
}
else if (highwayClass == outgoingRouteRoadClass)
{
// Any alternative turn to a similar road keeps the turn direction if the turn's angle is less than
// kMaxAbsAngleSameRoadClass degrees (wider than SlightTurn).
if (fabs(t.m_angle) < kMaxAbsAngleSameRoadClass)
return false;
}
else // static_cast<int>(highwayClass) > static_cast<int>(outgoingRouteRoadClass)
{
// Any alternative turn to a smaller road keeps the turn direction if it's GoStraight or SlightTurn.
if (IsGoStraightOrSlightTurn(IntermediateDirection(t.m_angle)))
return false;
}
else
{
ftypes::HighwayClass const highwayClass = t.m_highwayClass;
// @note The bigger is the road, the lesser is HighwayClass value.
if (static_cast<int>(highwayClass) < static_cast<int>(outgoingRouteRoadClass))
{
// Any alternative turn to a bigger road keeps the turn direction.
return false;
}
else if (highwayClass == outgoingRouteRoadClass)
{
// Any alternative turn to a similar road keeps the turn direction if the turn's angle is less than
// kMaxAbsAngleSameRoadClass degrees (wider than SlightTurn).
if (fabs(t.m_angle) < kMaxAbsAngleSameRoadClass)
return false;
}
else // static_cast<int>(highwayClass) > static_cast<int>(outgoingRouteRoadClass)
{
// Any alternative turn to a smaller road keeps the turn direction if it's GoStraight or SlightTurn.
if (IsGoStraightOrSlightTurn(IntermediateDirection(t.m_angle)))
return false;
}
}
}
return true;
}
@ -256,7 +265,7 @@ bool DiscardTurnByNoAlignedAlternatives(TurnCandidates const & possibleTurns, Tu
/*!
* \brief Returns false when other possible turns leads to service roads;
*/
bool KeepRoundaboutTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTurns,
bool KeepRoundaboutTurnByHighwayClass(TurnCandidates const & possibleTurns,
TurnInfo const & turnInfo, NumMwmIds const & numMwmIds)
{
Segment firstOutgoingSegment;
@ -273,50 +282,10 @@ bool KeepRoundaboutTurnByHighwayClass(CarDirection turn, TurnCandidates const &
return false;
}
bool DoAllTurnCandidatesGoAlmostStraight(vector<TurnCandidate> const & candidates)
{
return all_of(candidates.cbegin(), candidates.cend(), [](TurnCandidate const & c) {
return IsGoStraightOrSlightTurn(IntermediateDirection(c.m_angle));
});
}
/// \brief Analyzes its args and makes a decision if it's possible to have a turn at this junction
/// or not.
/// \returns true if based on this analysis there's no turn at this junction and
/// false if the junction should be considered as possible turn.
bool DiscardTurnByIngoingAndOutgoingEdges(CarDirection intermediateDirection, bool hasMultiTurns,
TurnInfo const & turnInfo, TurnItem const & turn,
TurnCandidates const & turnCandidates)
{
if (turn.m_keepAnyway || turnInfo.m_ingoing.m_onRoundabout ||
turnInfo.m_outgoing.m_onRoundabout ||
turnInfo.m_ingoing.m_highwayClass != turnInfo.m_outgoing.m_highwayClass)
{
return false;
}
// @TODO(bykoianko) If all turn candidates go almost straight and there are several ways
// from the junction (|hasMultiTurns| == true) the turn will be discarded.
// If all turn candidates go almost straight and there is only one way
// from the junction (|hasMultiTurns| == false) the turn will not be discarded in this method,
// and then may be kept. It means that in some cases if there are two or more possible
// ways from a junction the turn may be discarded and if there is only one way out
// the turn may be kept. This code should be redesigned.
if (turnCandidates.isCandidatesAngleValid &&
DoAllTurnCandidatesGoAlmostStraight(turnCandidates.candidates))
{
return !hasMultiTurns;
}
return ((!hasMultiTurns && IsGoStraightOrSlightTurn(intermediateDirection)) ||
(hasMultiTurns && intermediateDirection == CarDirection::GoStraight));
}
// turnEdgesCount calculates both ingoing ond outgoing edges without user's edge.
bool KeepTurnByIngoingEdges(m2::PointD const & junctionPoint,
m2::PointD const & ingoingPointOneSegment,
m2::PointD const & outgoingPoint, bool hasMultiTurns,
size_t const turnEdgesCount)
size_t const ingoingEdgesCount)
{
double const turnAngle =
base::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPointOneSegment, outgoingPoint));
@ -325,7 +294,7 @@ bool KeepTurnByIngoingEdges(m2::PointD const & junctionPoint,
// The code below is responsible for cases when there is only one way to leave the junction.
// Such junction has to be kept as a turn when it's not a slight turn and it has ingoing edges
// (one or more);
return hasMultiTurns || (!isGoStraightOrSlightTurn && turnEdgesCount > 1);
return hasMultiTurns || (!isGoStraightOrSlightTurn && ingoingEdgesCount > 0);
}
bool FixupLaneSet(CarDirection turn, vector<SingleLaneInfo> & lanes,
@ -574,7 +543,8 @@ bool GetPrevInSegmentRoutePoint(RoutePointIndex const & index, RoutePointIndex &
void GoStraightCorrection(TurnCandidate const & notRouteCandidate, CarDirection turnToSet,
TurnItem & turn)
{
CHECK_EQUAL(turn.m_turn, CarDirection::GoStraight, ());
if (turn.m_turn != CarDirection::GoStraight)
return;
if (!IsGoStraightOrSlightTurn(IntermediateDirection(notRouteCandidate.m_angle)))
return;
@ -981,11 +951,11 @@ CarDirection RightmostDirection(const double angle)
static vector<pair<double, CarDirection>> const kLowerBounds = {
{157., CarDirection::TurnSharpRight},
{50., CarDirection::TurnRight},
{2., CarDirection::TurnSlightRight},
{-10., CarDirection::GoStraight},
{-50., CarDirection::TurnSlightLeft},
{-157., CarDirection::TurnLeft},
{-180., CarDirection::TurnSharpLeft}};
{10., CarDirection::TurnSlightRight},
// For sure it's incorrect to give directions TurnLeft or TurnSlighLeft if we need the rightmost turn.
// So GoStraight direction is given even for needed sharp left turn when other turns on the left and are more sharp.
// The reason: the rightmost turn is the most straight one here.
{-180., CarDirection::GoStraight}};
return FindDirectionByAngle(kLowerBounds, angle);
}
@ -1054,6 +1024,18 @@ bool HasMultiTurns(NumMwmIds const & numMwmIds, TurnCandidates const & turnCandi
return !OneOfTurnCandidatesGoesAlongIngoingSegment(numMwmIds, turnCandidates, turnInfo);
}
void RemoveUTurnCandidate(TurnInfo const & turnInfo, NumMwmIds const & numMwmIds, std::vector<TurnCandidate> & turnCandidates)
{
Segment lastIngoingSegment;
if (turnInfo.m_ingoing.m_segmentRange.GetLastSegment(numMwmIds, lastIngoingSegment))
{
if (turnCandidates.front().m_segment.IsInverse(lastIngoingSegment))
turnCandidates.erase(turnCandidates.begin());
else if (turnCandidates.back().m_segment.IsInverse(lastIngoingSegment))
turnCandidates.pop_back();
}
}
/// \returns true if there is exactly 1 turn in |turnCandidates| with angle less then
/// |kMaxForwardAngleCandidates|.
bool HasSingleForwardTurn(TurnCandidates const & turnCandidates)
@ -1152,60 +1134,41 @@ void GetTurnDirection(IRoutingResult const & result, size_t outgoingSegmentIndex
return;
bool const hasMultiTurns = HasMultiTurns(numMwmIds, nodes, turnInfo);
RemoveUTurnCandidate(turnInfo, numMwmIds, nodes.candidates);
auto const & turnCandidates = nodes.candidates;
ASSERT(hasMultiTurns == (turnCandidates.size() >= 2),
("hasMultiTurns is true if there are two or more possible ways which don't go along an ingoing segment and false otherwise"));
// Check for enter or exit to/from roundabout.
if (turnInfo.m_ingoing.m_onRoundabout || turnInfo.m_outgoing.m_onRoundabout)
{
bool const keepTurnByHighwayClass = KeepRoundaboutTurnByHighwayClass(nodes, turnInfo, numMwmIds);
turn.m_turn = GetRoundaboutDirection(turnInfo.m_ingoing.m_onRoundabout,
biodranik commented 2022-04-20 13:29:18 +00:00 (Migrated from github.com)
Review
  // Check for enter or exit to/from roundabout.
```suggestion // Check for enter or exit to/from roundabout. ```
biodranik commented 2022-04-20 13:30:18 +00:00 (Migrated from github.com)
Review

Тогда уже и hasMultiTurns на отдельную строку.

Тогда уже и hasMultiTurns на отдельную строку.
biodranik commented 2022-04-20 13:30:45 +00:00 (Migrated from github.com)
Review

Не надо тут переносить на новую строку.

Не надо тут переносить на новую строку.
AntonM030481 commented 2022-04-20 15:06:34 +00:00 (Migrated from github.com)
Review

ок

ок
AntonM030481 commented 2022-04-20 15:06:56 +00:00 (Migrated from github.com)
Review

ок

ок
AntonM030481 commented 2022-04-20 15:07:43 +00:00 (Migrated from github.com)
Review

ок

ок
turnInfo.m_outgoing.m_onRoundabout,
hasMultiTurns,
keepTurnByHighwayClass);
return;
}
// Checking for exits from highways.
Segment firstOutgoingSeg;
bool const isFirstOutgoingSegValid =
turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSeg);
if (!turnInfo.m_ingoing.m_onRoundabout && isFirstOutgoingSegValid &&
if (isFirstOutgoingSegValid &&
IsExit(nodes, turnInfo, firstOutgoingSeg, intermediateDirection, turn.m_turn))
{
return;
}
if (DiscardTurnByIngoingAndOutgoingEdges(intermediateDirection, hasMultiTurns, turnInfo, turn, nodes))
return;
if (!hasMultiTurns || !nodes.isCandidatesAngleValid)
{
turn.m_turn = intermediateDirection;
}
else
{
if (isFirstOutgoingSegValid)
{
if (nodes.candidates.front().m_segment == firstOutgoingSeg)
turn.m_turn = LeftmostDirection(turnAngle);
else if (nodes.candidates.back().m_segment == firstOutgoingSeg)
turn.m_turn = RightmostDirection(turnAngle);
else
turn.m_turn = intermediateDirection;
}
else
{
turn.m_turn = intermediateDirection;
}
}
if (turnInfo.m_ingoing.m_onRoundabout || turnInfo.m_outgoing.m_onRoundabout)
{
bool const keepTurnByHighwayClass =
KeepRoundaboutTurnByHighwayClass(turn.m_turn, nodes, turnInfo, numMwmIds);
turn.m_turn = GetRoundaboutDirection(turnInfo.m_ingoing.m_onRoundabout,
turnInfo.m_outgoing.m_onRoundabout, hasMultiTurns,
keepTurnByHighwayClass);
return;
}
turn.m_turn = intermediateDirection;
// Note 1. If the road significantly changes its direction this turn shall be kept here.
// Note 2. If there's only one exit from this junction (nodes.candidates.size() == 1)
// this turn should be kept (because it was kept by previous logic as an exception).
// Note 3. Keeping a turn at this point means that the decision to keep this turn or not
// Note 2. Keeping a turn at this point means that the decision to keep this turn or not
// will be made after.
if (!turn.m_keepAnyway && IsGoStraightOrSlightTurn(turn.m_turn) && nodes.candidates.size() != 1)
if (!turn.m_keepAnyway && IsGoStraightOrSlightTurn(turn.m_turn))
{
vng commented 2022-04-20 16:41:16 +00:00 (Migrated from github.com)
Review

Хм, такое вообще потенциально небезопасно, грубо говоря мы делаем memcpy(dest, src) где src, dest на одном буфере. Я бы написал так:

std::vector candidatesWithoutUturn;
if (...)
{
  auto const & src = nodes.candidates;
  if (..)
    candidatesWithoutUturn.assign(src.begin() + 1, src.end());
  else if (..)
    candidatesWithoutUturn.assign(src.begin(), src.end() - 1);
  else
    candidatesWithoutUturn = src;
}
else
  candidatesWithoutUturn = nodes.candidates;
Хм, такое вообще потенциально небезопасно, грубо говоря мы делаем memcpy(dest, src) где src, dest на одном буфере. Я бы написал так: ``` std::vector candidatesWithoutUturn; if (...) { auto const & src = nodes.candidates; if (..) candidatesWithoutUturn.assign(src.begin() + 1, src.end()); else if (..) candidatesWithoutUturn.assign(src.begin(), src.end() - 1); else candidatesWithoutUturn = src; } else candidatesWithoutUturn = nodes.candidates; ```
biodranik commented 2022-04-20 16:50:13 +00:00 (Migrated from github.com)
Review

Почему бы не использовать candidatesWithoutUturn.erase(candidatesWithoutUturn.begin()); и candidatesWithoutUturn.erase(candidatesWithoutUturn.rbegin());?

Почему бы не использовать `candidatesWithoutUturn.erase(candidatesWithoutUturn.begin());` и `candidatesWithoutUturn.erase(candidatesWithoutUturn.rbegin());`?
vng commented 2022-04-20 17:07:51 +00:00 (Migrated from github.com)
Review

Тогда уж, pop_front(), pop_back(). В моем варианте меньше манипуляций с вектором. Он только присваивается, когда erase/pop_front() сделает его переалокацию.

Тогда уж, pop_front(), pop_back(). В моем варианте меньше манипуляций с вектором. Он только присваивается, когда erase/pop_front() сделает его переалокацию.
biodranik commented 2022-04-20 22:20:11 +00:00 (Migrated from github.com)
Review

pop_back() да, а вот когда это у вектора появился pop_front() ? :)

pop_back() да, а вот когда это у вектора появился pop_front() ? :)
AntonM030481 commented 2022-04-21 13:34:34 +00:00 (Migrated from github.com)
Review

Исправил

Исправил
if (DiscardTurnByHighwayClass(nodes, turnInfo, numMwmIds, turn.m_turn) ||
biodranik commented 2022-04-20 13:31:13 +00:00 (Migrated from github.com)
Review
  auto candidatesWithoutUturn = nodes.candidates;
```suggestion auto candidatesWithoutUturn = nodes.candidates; ```
biodranik commented 2022-04-20 13:32:31 +00:00 (Migrated from github.com)
Review

Почему это условие должно выполняться? Надо комментарий в пустых скобках.

Почему это условие должно выполняться? Надо комментарий в пустых скобках.
biodranik commented 2022-04-20 13:34:29 +00:00 (Migrated from github.com)
Review

А по сути — зачем здесь создавать копию nodes.candidates? Если нужно модифицировать, то нужна ссылка:
auto & candidates_without_uturn = nodes.candidates;

А по сути — зачем здесь создавать копию nodes.candidates? Если нужно модифицировать, то нужна ссылка: `auto & candidates_without_uturn = nodes.candidates;`
biodranik commented 2022-04-20 13:38:52 +00:00 (Migrated from github.com)
Review

Если часто нужно удалять первый элемент вектора, то имеет смысл использовать не вектор, а другую структуру данных, list или deque. @vng что думаешь?

Если часто нужно удалять первый элемент вектора, то имеет смысл использовать не вектор, а другую структуру данных, list или deque. @vng что думаешь?
AntonM030481 commented 2022-04-20 15:40:03 +00:00 (Migrated from github.com)
Review

это хороший вопрос.
выглядит так, что этот uturn нигде не нужен в GetTurnDirection.
из того, где все еще используется nodes:

  • KeepRoundaboutTurnByHighwayClass - не нужен (и не мешает)
  • IsExit - не нужен (и не мешает)
  • DiscardTurnByIngoingAndOutgoingEdges - очень запутанный метод. Предположительно, там не нужен и мешает!
  • проверка на nodes.candidates.size() != 1 - предположительно не нужен. Зависит от DiscardTurnByIngoingAndOutgoingEdges
  • DiscardTurnByHighwayClass - не нужен. Обратить внимание: вызывается также из GetNextCrossSegmentRoutePoint.

Предлагаю вместе разобраться с DiscardTurnByIngoingAndOutgoingEdges и модифицировать оригинал.

это хороший вопрос. выглядит так, что этот uturn нигде не нужен в GetTurnDirection. из того, где все еще используется nodes: - KeepRoundaboutTurnByHighwayClass - не нужен (и не мешает) - IsExit - не нужен (и не мешает) - DiscardTurnByIngoingAndOutgoingEdges - очень запутанный метод. Предположительно, там не нужен и мешает! - проверка на nodes.candidates.size() != 1 - предположительно не нужен. Зависит от DiscardTurnByIngoingAndOutgoingEdges - DiscardTurnByHighwayClass - не нужен. Обратить внимание: вызывается также из GetNextCrossSegmentRoutePoint. Предлагаю вместе разобраться с DiscardTurnByIngoingAndOutgoingEdges и модифицировать оригинал.
AntonM030481 commented 2022-04-20 15:40:21 +00:00 (Migrated from github.com)
Review

ок

ок
DiscardTurnByNoAlignedAlternatives(nodes, turnInfo, numMwmIds))
DiscardTurnByNoAlignedAlternatives(turn, turnCandidates, turnInfo, numMwmIds))
{
turn.m_turn = CarDirection::None;
return;
@ -1219,47 +1182,49 @@ void GetTurnDirection(IRoutingResult const & result, size_t outgoingSegmentIndex
vehicleSettings.m_notSoCloseMaxDistMeters, false /* forward */);
// Removing a slight turn if there's only one way to leave the turn and there's no ingoing edges.
if (!KeepTurnByIngoingEdges(junctionPoint, notSoCloseToTheTurnPoint, outgoingPoint, hasMultiTurns,
nodes.candidates.size() + ingoingCount))
if (!KeepTurnByIngoingEdges(junctionPoint, notSoCloseToTheTurnPoint, outgoingPoint, hasMultiTurns, ingoingCount))
{
turn.m_turn = CarDirection::None;
return;
}
// Removing a slight turn if ingoing and outgoing edges are not links and all other
// possible ways out are links.
// possible ways out (except of uturn) are links.
if (!turnInfo.m_ingoing.m_isLink && !turnInfo.m_outgoing.m_isLink &&
turnInfo.m_ingoing.m_highwayClass == turnInfo.m_outgoing.m_highwayClass &&
GetLinkCount(nodes.candidates) + 1 == nodes.candidates.size())
GetLinkCount(turnCandidates) + 1 == turnCandidates.size())
{
turn.m_turn = CarDirection::None;
return;
}
}
if (turn.m_turn == CarDirection::GoStraight)
if (turnCandidates.size() >= 2)
{
if (!hasMultiTurns)
turn.m_turn = CarDirection::None;
// If the route goes along the rightmost or the leftmost way among available ones:
// 1. RightmostDirection or LeftmostDirection is selected
// 2. If the turn direction is |CarDirection::GoStraight|
biodranik commented 2022-04-20 13:36:55 +00:00 (Migrated from github.com)
Review
      // Compare with the closest right candidate.
```suggestion // Compare with the closest right candidate. ```
AntonM030481 commented 2022-04-20 15:40:37 +00:00 (Migrated from github.com)
Review

ок

ок
// and there's another GoStraight or SlightTurn turn
// GoStraight is corrected to TurnSlightRight/TurnSlightLeft
// to avoid ambiguity: 2 or more almost straight turns and GoStraight direction.
// Note. If the turn direction is |CarDirection::GoStraight| and there's only one extra way out
// from the junction the direction may be corrected in some cases. So two turn candidates
// (one for the route and an extra one) require special processing.
if (nodes.candidates.size() != 2)
return;
if (nodes.candidates.front().m_segment == firstOutgoingSeg)
// turnCandidates are sorted by angle from leftmost to rightmost.
if (turnCandidates.front().m_segment == firstOutgoingSeg)
{
// The route goes along the leftmost candidate.
GoStraightCorrection(nodes.candidates.back(), CarDirection::TurnSlightLeft, turn);
// The route goes along the leftmost candidate.
turn.m_turn = LeftmostDirection(turnAngle);
// Compare with the closest left candidate.
GoStraightCorrection(turnCandidates[1], CarDirection::TurnSlightLeft, turn);
}
else if (nodes.candidates.back().m_segment == firstOutgoingSeg)
else if (turnCandidates.back().m_segment == firstOutgoingSeg)
{
// The route goes along the rightmost candidate.
GoStraightCorrection(nodes.candidates.front(), CarDirection::TurnSlightRight, turn);
// The route goes along the rightmost candidate.
turn.m_turn = RightmostDirection(turnAngle);
// Compare with the closest right candidate.
GoStraightCorrection(turnCandidates[turnCandidates.size() - 2], CarDirection::TurnSlightRight, turn);
}
// Note. It's possible that |firstOutgoingSeg| is not contained in |nodes.candidates|.
// It may happened if |firstOutgoingSeg| and candidates in |nodes.candidates| are
// Note. It's possible that |firstOutgoingSeg| is not contained in |turnCandidates|.
// It may happened if |firstOutgoingSeg| and candidates in |turnCandidates| are
// from different mwms.
}
}