diff options
author | mpimenov <mpimenov@users.noreply.github.com> | 2016-12-16 18:04:38 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-16 18:04:38 +0300 |
commit | 1845dff887ea8701a62ba58c10fac220caf3a496 (patch) | |
tree | 66ea48bc7664e90fff142d8e2497efb7bdefe0d3 | |
parent | 14018c2c15b2618af2dea6885e450040d184feb6 (diff) | |
parent | 1d55a585cf3f1f7ecd710d3fdf71c7bd0b5c6971 (diff) |
Merge pull request #5019 from bykoianko/release-70-turn-fixbeta-530
[release] Bugfix in turn generation system.
-rw-r--r-- | routing/bicycle_directions.cpp | 44 | ||||
-rw-r--r-- | routing/bicycle_directions.hpp | 6 | ||||
-rw-r--r-- | routing/car_router.cpp | 15 | ||||
-rw-r--r-- | routing/loaded_path_segment.hpp | 11 | ||||
-rw-r--r-- | routing/osrm_path_segment_factory.cpp | 4 | ||||
-rw-r--r-- | routing/routing_result_graph.hpp | 2 | ||||
-rw-r--r-- | routing/routing_tests/turns_generator_test.cpp | 10 | ||||
-rw-r--r-- | routing/turn_candidate.hpp | 10 | ||||
-rw-r--r-- | routing/turns.cpp | 76 | ||||
-rw-r--r-- | routing/turns.hpp | 39 | ||||
-rw-r--r-- | routing/turns_generator.cpp | 8 |
11 files changed, 170 insertions, 55 deletions
diff --git a/routing/bicycle_directions.cpp b/routing/bicycle_directions.cpp index f910cc7b77..5f2a5395f5 100644 --- a/routing/bicycle_directions.cpp +++ b/routing/bicycle_directions.cpp @@ -23,7 +23,7 @@ class RoutingResult : public IRoutingResult { public: RoutingResult(IRoadGraph::TEdgeVector const & routeEdges, - BicycleDirectionsEngine::TAdjacentEdgesMap const & adjacentEdges, + BicycleDirectionsEngine::AdjacentEdgesMap const & adjacentEdges, TUnpackedPathSegments const & pathSegments) : m_routeEdges(routeEdges) , m_adjacentEdges(adjacentEdges) @@ -39,8 +39,7 @@ public: // turns::IRoutingResult overrides: TUnpackedPathSegments const & GetSegments() const override { return m_pathSegments; } - - void GetPossibleTurns(TNodeId node, m2::PointD const & /* ingoingPoint */, + void GetPossibleTurns(UniNodeId const & node, m2::PointD const & /* ingoingPoint */, m2::PointD const & /* junctionPoint */, size_t & ingoingCount, TurnCandidates & outgoingTurns) const override { @@ -74,7 +73,7 @@ public: private: IRoadGraph::TEdgeVector const & m_routeEdges; - BicycleDirectionsEngine::TAdjacentEdgesMap const & m_adjacentEdges; + BicycleDirectionsEngine::AdjacentEdgesMap const & m_adjacentEdges; TUnpackedPathSegments const & m_pathSegments; double m_routeLength; }; @@ -104,7 +103,8 @@ void BicycleDirectionsEngine::Generate(IRoadGraph const & graph, vector<Junction auto emptyPathWorkaround = [&]() { turns.emplace_back(pathSize - 1, turns::TurnDirection::ReachedYourDestination); - this->m_adjacentEdges[0] = AdjacentEdges(1); // There's one ingoing edge to the finish. + // There's one ingoing edge to the finish. + this->m_adjacentEdges[UniNodeId(UniNodeId::Type::Mwm)] = AdjacentEdges(1); }; if (pathSize == 1) @@ -129,7 +129,7 @@ void BicycleDirectionsEngine::Generate(IRoadGraph const & graph, vector<Junction } // Filling |m_adjacentEdges|. - m_adjacentEdges.insert(make_pair(0, AdjacentEdges(0))); + m_adjacentEdges.insert(make_pair(UniNodeId(UniNodeId::Type::Mwm), AdjacentEdges(0))); for (size_t i = 1; i < pathSize; ++i) { if (cancellable.IsCancelled()) @@ -147,6 +147,9 @@ void BicycleDirectionsEngine::Generate(IRoadGraph const & graph, vector<Junction adjacentEdges.m_outgoingTurns.candidates.reserve(outgoingEdges.size()); ASSERT_EQUAL(routeEdges.size(), pathSize - 1, ()); FeatureID const inFeatureId = routeEdges[i - 1].GetFeatureId(); + uint32_t const inSegId = routeEdges[i - 1].GetSegId(); + bool const inIsForward = routeEdges[i - 1].IsForward(); + UniNodeId const uniNodeId(inFeatureId, inSegId, inIsForward); for (auto const & edge : outgoingEdges) { @@ -162,24 +165,22 @@ void BicycleDirectionsEngine::Generate(IRoadGraph const & graph, vector<Junction auto const highwayClass = ftypes::GetHighwayClass(ft); ASSERT_NOT_EQUAL(highwayClass, ftypes::HighwayClass::Error, ()); ASSERT_NOT_EQUAL(highwayClass, ftypes::HighwayClass::Undefined, ()); - adjacentEdges.m_outgoingTurns.candidates.emplace_back(0.0 /* angle */, outFeatureId.m_index, + adjacentEdges.m_outgoingTurns.candidates.emplace_back(0.0 /* angle */, uniNodeId, highwayClass); } - LoadedPathSegment pathSegment; + LoadedPathSegment pathSegment(UniNodeId::Type::Mwm); // @TODO(bykoianko) This place should be fixed. Putting |prevJunction| and |currJunction| // for every route edge leads that all route points are duplicated. It's because // prevJunction == path[i - 1] and currJunction == path[i]. if (inFeatureId.IsValid()) - LoadPathGeometry(inFeatureId, {prevJunction, currJunction}, pathSegment); - pathSegment.m_trafficSegs = { - {inFeatureId.m_index, - static_cast<uint16_t>(routeEdges[i - 1].GetSegId()), - routeEdges[i - 1].IsForward() ? TrafficInfo::RoadSegmentId::kForwardDirection - : TrafficInfo::RoadSegmentId::kReverseDirection - }}; - - m_adjacentEdges.insert(make_pair(inFeatureId.m_index, move(adjacentEdges))); + LoadPathGeometry(uniNodeId, {prevJunction, currJunction}, pathSegment); + pathSegment.m_trafficSegs = {{inFeatureId.m_index, static_cast<uint16_t>(inSegId), + inIsForward ? TrafficInfo::RoadSegmentId::kForwardDirection + : TrafficInfo::RoadSegmentId::kReverseDirection}}; + + auto const it = m_adjacentEdges.insert(make_pair(uniNodeId, move(adjacentEdges))); + ASSERT(it.second, ()); m_pathSegments.push_back(move(pathSegment)); } @@ -210,20 +211,21 @@ Index::FeaturesLoaderGuard & BicycleDirectionsEngine::GetLoader(MwmSet::MwmId co return *m_loader; } -void BicycleDirectionsEngine::LoadPathGeometry(FeatureID const & featureId, +void BicycleDirectionsEngine::LoadPathGeometry(UniNodeId const & uniNodeId, vector<Junction> const & path, LoadedPathSegment & pathSegment) { pathSegment.Clear(); - if (!featureId.IsValid()) + if (!uniNodeId.GetFeature().IsValid()) { ASSERT(false, ()); return; } FeatureType ft; - if (!GetLoader(featureId.m_mwmId).GetFeatureByIndex(featureId.m_index, ft)) + if (!GetLoader(uniNodeId.GetFeature().m_mwmId) + .GetFeatureByIndex(uniNodeId.GetFeature().m_index, ft)) { // The feature can't be read, therefore path geometry can't be // loaded. @@ -239,7 +241,7 @@ void BicycleDirectionsEngine::LoadPathGeometry(FeatureID const & featureId, ft.GetName(FeatureType::DEFAULT_LANG, pathSegment.m_name); - pathSegment.m_nodeId = featureId.m_index; + pathSegment.m_nodeId = uniNodeId; pathSegment.m_onRoundabout = ftypes::IsRoundAboutChecker::Instance()(ft); pathSegment.m_path = path; // @TODO(bykoianko) It's better to fill pathSegment.m_weight. diff --git a/routing/bicycle_directions.hpp b/routing/bicycle_directions.hpp index da72f28372..7056428df0 100644 --- a/routing/bicycle_directions.hpp +++ b/routing/bicycle_directions.hpp @@ -22,7 +22,7 @@ public: size_t m_ingoingTurnsCount; }; - using TAdjacentEdgesMap = map<TNodeId, AdjacentEdges>; + using AdjacentEdgesMap = map<UniNodeId, AdjacentEdges>; BicycleDirectionsEngine(Index const & index); @@ -34,10 +34,10 @@ public: private: Index::FeaturesLoaderGuard & GetLoader(MwmSet::MwmId const & id); - void LoadPathGeometry(FeatureID const & featureId, vector<Junction> const & path, + void LoadPathGeometry(UniNodeId const & uniNodeId, vector<Junction> const & path, LoadedPathSegment & pathSegment); - TAdjacentEdgesMap m_adjacentEdges; + AdjacentEdgesMap m_adjacentEdges; TUnpackedPathSegments m_pathSegments; Index const & m_index; unique_ptr<Index::FeaturesLoaderGuard> m_loader; diff --git a/routing/car_router.cpp b/routing/car_router.cpp index 1f4cd434e4..e05a2386d8 100644 --- a/routing/car_router.cpp +++ b/routing/car_router.cpp @@ -66,7 +66,7 @@ class OSRMRoutingResult : public turns::IRoutingResult public: // turns::IRoutingResult overrides: TUnpackedPathSegments const & GetSegments() const override { return m_loadedSegments; } - void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint, + void GetPossibleTurns(UniNodeId const & node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, size_t & ingoingCount, turns::TurnCandidates & outgoingTurns) const override { @@ -87,9 +87,10 @@ public: // Filtering virtual edges. vector<NodeID> adjacentNodes; ingoingCount = 0; - for (EdgeID const e : m_routingMapping.m_dataFacade.GetAdjacentEdgeRange(node)) + for (EdgeID const e : m_routingMapping.m_dataFacade.GetAdjacentEdgeRange(node.GetNodeId())) { - QueryEdge::EdgeData const data = m_routingMapping.m_dataFacade.GetEdgeData(e, node); + QueryEdge::EdgeData const data = + m_routingMapping.m_dataFacade.GetEdgeData(e, node.GetNodeId()); if (data.shortcut) continue; if (data.forward) @@ -105,11 +106,11 @@ public: for (NodeID const adjacentNode : geomNodes) { - if (adjacentNode == node) + if (adjacentNode == node.GetNodeId()) continue; for (EdgeID const e : m_routingMapping.m_dataFacade.GetAdjacentEdgeRange(adjacentNode)) { - if (m_routingMapping.m_dataFacade.GetTarget(e) != node) + if (m_routingMapping.m_dataFacade.GetTarget(e) != node.GetNodeId()) continue; QueryEdge::EdgeData const data = m_routingMapping.m_dataFacade.GetEdgeData(e, adjacentNode); if (data.shortcut) @@ -145,7 +146,7 @@ public: outgoingTurns.isCandidatesAngleValid = true; double const a = my::RadToDeg(turns::PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint)); - outgoingTurns.candidates.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft)); + outgoingTurns.candidates.emplace_back(a, UniNodeId(targetNode), ftypes::GetHighwayClass(ft)); } sort(outgoingTurns.candidates.begin(), outgoingTurns.candidates.end(), @@ -171,7 +172,7 @@ public: for (auto const & pathSegments : m_rawResult.unpackedPathSegments) { auto numSegments = pathSegments.size(); - m_loadedSegments.resize(numSegments); + m_loadedSegments.resize(numSegments, LoadedPathSegment(UniNodeId::Type::Osrm)); for (size_t segmentIndex = 0; segmentIndex < numSegments; ++segmentIndex) { bool isStartNode = (segmentIndex == 0); diff --git a/routing/loaded_path_segment.hpp b/routing/loaded_path_segment.hpp index 72fd2f61eb..d9dd5c8bcb 100644 --- a/routing/loaded_path_segment.hpp +++ b/routing/loaded_path_segment.hpp @@ -33,24 +33,21 @@ struct LoadedPathSegment vector<turns::SingleLaneInfo> m_lanes; string m_name; TEdgeWeight m_weight; /*!< Time in seconds to pass the segment. */ - TNodeId m_nodeId; /*!< May be NodeId for OSRM router or FeatureId::index for graph router. */ + UniNodeId m_nodeId; /*!< May be either NodeID for OSRM route or + mwm id, feature id, segment id and direction for A*. */ vector<traffic::TrafficInfo::RoadSegmentId> m_trafficSegs; /*!< Traffic segments for |m_path|. */ ftypes::HighwayClass m_highwayClass; bool m_onRoundabout; bool m_isLink; - LoadedPathSegment() - { - Clear(); - } - + LoadedPathSegment(UniNodeId::Type type) : m_nodeId(type) { Clear(); } void Clear() { m_path.clear(); m_lanes.clear(); m_name.clear(); m_weight = 0; - m_nodeId = 0; + m_nodeId.Clear(); m_trafficSegs.clear(); m_highwayClass = ftypes::HighwayClass::Undefined; m_onRoundabout = false; diff --git a/routing/osrm_path_segment_factory.cpp b/routing/osrm_path_segment_factory.cpp index 3005d8ec19..c790364fc5 100644 --- a/routing/osrm_path_segment_factory.cpp +++ b/routing/osrm_path_segment_factory.cpp @@ -102,7 +102,7 @@ void OsrmPathSegmentFactory(RoutingMapping & mapping, Index const & index, buffer_vector<TSeg, 8> buffer; mapping.m_segMapping.ForEachFtSeg(osrmPathSegment.node, MakeBackInsertFunctor(buffer)); loadedPathSegment.m_weight = osrmPathSegment.segmentWeight * kOSRMWeightToSecondsMultiplier; - loadedPathSegment.m_nodeId = osrmPathSegment.node; + loadedPathSegment.m_nodeId = UniNodeId(osrmPathSegment.node); if (buffer.empty()) { LOG(LERROR, ("Can't unpack geometry for map:", mapping.GetCountryName(), " node: ", @@ -125,7 +125,7 @@ void OsrmPathSegmentFactory(RoutingMapping & mapping, Index const & index, RawPa ASSERT(isStartNode || isEndNode, ("This function process only corner cases.")); loadedPathSegment.Clear(); - loadedPathSegment.m_nodeId = osrmPathSegment.node; + loadedPathSegment.m_nodeId = UniNodeId(osrmPathSegment.node); if (!startGraphNode.segment.IsValid() || !endGraphNode.segment.IsValid()) return; buffer_vector<TSeg, 8> buffer; diff --git a/routing/routing_result_graph.hpp b/routing/routing_result_graph.hpp index 2fac67733d..8736a942dc 100644 --- a/routing/routing_result_graph.hpp +++ b/routing/routing_result_graph.hpp @@ -21,7 +21,7 @@ public: virtual TUnpackedPathSegments const & GetSegments() const = 0; /// \brief For a |node|, |junctionPoint| and |ingoingPoint| (point before the |node|) /// this method computes number of ingoing ways to |junctionPoint| and fills |outgoingTurns|. - virtual void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint, + virtual void GetPossibleTurns(UniNodeId const & node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, size_t & ingoingCount, TurnCandidates & outgoingTurns) const = 0; virtual double GetPathLength() const = 0; diff --git a/routing/routing_tests/turns_generator_test.cpp b/routing/routing_tests/turns_generator_test.cpp index f55e296d9a..f4f2b2bdfb 100644 --- a/routing/routing_tests/turns_generator_test.cpp +++ b/routing/routing_tests/turns_generator_test.cpp @@ -326,25 +326,25 @@ UNIT_TEST(TestCalculateMercatorDistanceAlongRoute) UNIT_TEST(TestCheckUTurnOnRoute) { - TUnpackedPathSegments pathSegments(4); + TUnpackedPathSegments pathSegments(4, LoadedPathSegment(UniNodeId::Type::Osrm)); pathSegments[0].m_name = "A road"; pathSegments[0].m_weight = 1; - pathSegments[0].m_nodeId = 0; + pathSegments[0].m_nodeId = UniNodeId(0 /* node id */); pathSegments[0].m_highwayClass = ftypes::HighwayClass::Trunk; pathSegments[0].m_onRoundabout = false; pathSegments[0].m_isLink = false; pathSegments[0].m_path = {{{0, 0}, 0}, {{0, 1}, 0}}; pathSegments[1] = pathSegments[0]; - pathSegments[1].m_nodeId = 1; + pathSegments[1].m_nodeId = UniNodeId(1 /* node id */); pathSegments[1].m_path = {{{0, 1}, 0}, {{0, 0}, 0}}; pathSegments[2] = pathSegments[0]; - pathSegments[2].m_nodeId = 2; + pathSegments[2].m_nodeId = UniNodeId(2 /* node id */); pathSegments[2].m_path = {{{0, 0}, 0}, {{0, 1}, 0}}; pathSegments[3] = pathSegments[0]; - pathSegments[3].m_nodeId = 3; + pathSegments[3].m_nodeId = UniNodeId(3 /* node id */); pathSegments[3].m_path.clear(); // Zigzag test. diff --git a/routing/turn_candidate.hpp b/routing/turn_candidate.hpp index d18f150d03..d4fb7f4f04 100644 --- a/routing/turn_candidate.hpp +++ b/routing/turn_candidate.hpp @@ -26,17 +26,19 @@ struct TurnCandidate */ double angle; /*! - * node is a possible node (a possible way) from the juction. - * May be NodeId for OSRM router or FeatureId::index for graph router. + * |m_nodeId| is a possible node (a possible way) from the juction. + * |m_nodeId| contain either only unique NodeID for OSRM case or mwm id, feature id, segment id + * and direction in case of A*. */ - TNodeId node; + UniNodeId m_nodeId; /*! * \brief highwayClass field for the road class caching. Because feature reading is a long * function. */ ftypes::HighwayClass highwayClass; - TurnCandidate(double a, TNodeId n, ftypes::HighwayClass c) : angle(a), node(n), highwayClass(c) + TurnCandidate(double a, UniNodeId const & n, ftypes::HighwayClass c) + : angle(a), m_nodeId(n), highwayClass(c) { } }; diff --git a/routing/turns.cpp b/routing/turns.cpp index c63145eff5..c002bb1aaf 100644 --- a/routing/turns.cpp +++ b/routing/turns.cpp @@ -51,9 +51,83 @@ static_assert(g_turnNames.size() == static_cast<size_t>(TurnDirection::Count), namespace routing { -namespace turns +// UniNodeId ------------------------------------------------------------------- +bool UniNodeId::operator==(UniNodeId const & rhs) const +{ + if (m_type != rhs.m_type) + return false; + + switch (m_type) + { + case Type::Osrm: return m_nodeId == rhs.m_nodeId; + case Type::Mwm: + return m_featureId == rhs.m_featureId && m_segId == rhs.m_segId && m_forward == rhs.m_forward; + } +} + +bool UniNodeId::operator<(UniNodeId const & rhs) const +{ + if (m_type != rhs.m_type) + return m_type < rhs.m_type; + + switch (m_type) + { + case Type::Osrm: return m_nodeId < rhs.m_nodeId; + case Type::Mwm: + if (m_featureId != rhs.m_featureId) + return m_featureId < rhs.m_featureId; + + if (m_segId != rhs.m_segId) + return m_segId < rhs.m_segId; + + return m_forward < rhs.m_forward; + } +} + +void UniNodeId::Clear() +{ + m_featureId = FeatureID(); + m_segId = 0; + m_forward = true; + m_nodeId = SPECIAL_NODEID; +} + +uint32_t UniNodeId::GetNodeId() const +{ + ASSERT_EQUAL(m_type, Type::Osrm, ()); + return m_nodeId; +} + +FeatureID const & UniNodeId::GetFeature() const +{ + ASSERT_EQUAL(m_type, Type::Mwm, ()); + return m_featureId; +} + +uint32_t UniNodeId::GetSegId() const +{ + ASSERT_EQUAL(m_type, Type::Mwm, ()); + return m_segId; +} + +bool UniNodeId::IsForward() const { + ASSERT_EQUAL(m_type, Type::Mwm, ()); + return m_forward; +} +string DebugPrint(UniNodeId::Type type) +{ + switch (type) + { + case UniNodeId::Type::Osrm: return "Osrm"; + case UniNodeId::Type::Mwm: return "Mwm"; + } +} + +namespace turns +{ +// SingleLaneInfo -------------------------------------------------------------- bool SingleLaneInfo::operator==(SingleLaneInfo const & other) const { return m_lane == other.m_lane && m_isRecommended == other.m_isRecommended; diff --git a/routing/turns.hpp b/routing/turns.hpp index 05773bcc46..43d1fd3820 100644 --- a/routing/turns.hpp +++ b/routing/turns.hpp @@ -1,5 +1,7 @@ #pragma once +#include "indexer/feature_decl.hpp" + #include "geometry/point2d.hpp" #include "3party/osrm/osrm-backend/typedefs.h" @@ -14,6 +16,43 @@ namespace routing using TNodeId = uint32_t; using TEdgeWeight = double; +/// \brief Unique identification for a road edge between two junctions (joints). +/// In case of OSRM it's NodeID and in case of RoadGraph (IndexGraph) +/// it's mwm id, feature id, segment id and direction. +struct UniNodeId +{ + enum class Type + { + Osrm, + Mwm, + }; + + UniNodeId(Type type) : m_type(type) {} + UniNodeId(FeatureID const & featureId, uint32_t segId, bool forward) + : m_type(Type::Mwm), m_featureId(featureId), m_segId(segId), m_forward(forward) + { + } + UniNodeId(uint32_t nodeId) : m_type(Type::Osrm), m_nodeId(nodeId) {} + bool operator==(UniNodeId const & rh) const; + bool operator<(UniNodeId const & rh) const; + void Clear(); + uint32_t GetNodeId() const; + FeatureID const & GetFeature() const; + uint32_t GetSegId() const; + bool IsForward() const; + +private: + Type m_type; + /// \note In case of OSRM unique id is kept in |m_featureId.m_index|. + /// So |m_featureId.m_mwmId|, |m_segId| and |m_forward| have default values. + FeatureID m_featureId; // |m_featureId.m_index| is NodeID for OSRM. + uint32_t m_segId = 0; // Not valid for OSRM. + bool m_forward = true; // Segment direction in |m_featureId|. + NodeID m_nodeId = SPECIAL_NODEID; +}; + +string DebugPrint(UniNodeId::Type type); + namespace turns { /// @todo(vbykoianko) It's a good idea to gather all the turns information into one entity. diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp index a8f04925bb..29c9b99664 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -45,7 +45,7 @@ bool KeepTurnByHighwayClass(TurnDirection turn, TurnCandidates const & possibleT ftypes::HighwayClass maxClassForPossibleTurns = ftypes::HighwayClass::Error; for (auto const & t : possibleTurns.candidates) { - if (t.node == turnInfo.m_outgoing.m_nodeId) + if (t.m_nodeId == turnInfo.m_outgoing.m_nodeId) continue; ftypes::HighwayClass const highwayClass = t.highwayClass; if (static_cast<int>(highwayClass) > static_cast<int>(maxClassForPossibleTurns)) @@ -84,7 +84,7 @@ bool KeepRoundaboutTurnByHighwayClass(TurnDirection turn, TurnCandidates const & { for (auto const & t : possibleTurns.candidates) { - if (t.node == turnInfo.m_outgoing.m_nodeId) + if (t.m_nodeId == turnInfo.m_outgoing.m_nodeId) continue; if (static_cast<int>(t.highwayClass) != static_cast<int>(ftypes::HighwayClass::Service)) return true; @@ -615,9 +615,9 @@ void GetTurnDirection(IRoutingResult const & result, TurnInfo & turnInfo, TurnIt } else { - if (nodes.candidates.front().node == turnInfo.m_outgoing.m_nodeId) + if (nodes.candidates.front().m_nodeId == turnInfo.m_outgoing.m_nodeId) turn.m_turn = LeftmostDirection(turnAngle); - else if (nodes.candidates.back().node == turnInfo.m_outgoing.m_nodeId) + else if (nodes.candidates.back().m_nodeId == turnInfo.m_outgoing.m_nodeId) turn.m_turn = RightmostDirection(turnAngle); else turn.m_turn = intermediateDirection; |