diff --git a/routing/osrm_router.cpp b/routing/osrm_router.cpp index f9782d6230..982461fd9a 100644 --- a/routing/osrm_router.cpp +++ b/routing/osrm_router.cpp @@ -68,7 +68,8 @@ public: } virtual void GetPossibleTurns(NodeID node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, - turns::TTurnCandidates & candidates) const override + size_t & ingoingCount, + turns::TTurnCandidates & outgoingTurns) const override { double const kReadCrossEpsilon = 1.0E-4; double const kFeaturesNearTurnMeters = 3.0; @@ -87,14 +88,21 @@ public: // Filtering virtual edges. vector adjacentNodes; + ingoingCount = 0; for (EdgeID const e : m_routingMapping.m_dataFacade.GetAdjacentEdgeRange(node)) { QueryEdge::EdgeData const data = m_routingMapping.m_dataFacade.GetEdgeData(e, node); - if (data.forward && !data.shortcut) + if (data.shortcut) + continue; + if (data.forward) { adjacentNodes.push_back(m_routingMapping.m_dataFacade.GetTarget(e)); ASSERT_NOT_EQUAL(m_routingMapping.m_dataFacade.GetTarget(e), SPECIAL_NODEID, ()); } + else + { + ++ingoingCount; + } } for (NodeID const adjacentNode : geomNodes) @@ -106,8 +114,12 @@ public: if (m_routingMapping.m_dataFacade.GetTarget(e) != node) continue; QueryEdge::EdgeData const data = m_routingMapping.m_dataFacade.GetEdgeData(e, adjacentNode); - if (!data.shortcut && data.backward) + if (data.shortcut) + continue; + if (data.backward) adjacentNodes.push_back(adjacentNode); + else + ++ingoingCount; } } @@ -132,10 +144,10 @@ public: double const a = my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint)); - candidates.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft)); + outgoingTurns.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft)); } - sort(candidates.begin(), candidates.end(), + sort(outgoingTurns.begin(), outgoingTurns.end(), [](turns::TurnCandidate const & t1, turns::TurnCandidate const & t2) { return t1.angle < t2.angle; diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp index 794f91dc03..9336d6624e 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -40,51 +40,6 @@ double PiMinusTwoVectorsAngle(m2::PointD const & p, m2::PointD const & p1, m2::P return math::pi - ang::TwoVectorsAngle(p, p1, p2); } -/*! - * \brief The Point2Geometry class is responsable for looking for all adjacent to junctionPoint - * road network edges. Including the current edge. - */ -class Point2Geometry -{ - m2::PointD m_junctionPoint, m_ingoingPoint; - TGeomTurnCandidate & m_candidates; - -public: - Point2Geometry(m2::PointD const & junctionPoint, m2::PointD const & ingoingPoint, - TGeomTurnCandidate & candidates) - : m_junctionPoint(junctionPoint), m_ingoingPoint(ingoingPoint), m_candidates(candidates) - { - } - - void operator()(FeatureType const & ft) - { - if (!CarModel::Instance().IsRoad(ft)) - return; - ft.ParseGeometry(FeatureType::BEST_GEOMETRY); - size_t const count = ft.GetPointsCount(); - ASSERT_GREATER(count, 1, ()); - - // @TODO(vbykoianko) instead of checking all the feature points probably - // it's enough just to check the start and the finish of the feature. - for (size_t i = 0; i < count; ++i) - { - if (MercatorBounds::DistanceOnEarth(m_junctionPoint, ft.GetPoint(i)) < - kFeaturesNearTurnMeters) - { - if (i > 0) - m_candidates.push_back(my::RadToDeg( - PiMinusTwoVectorsAngle(m_junctionPoint, m_ingoingPoint, ft.GetPoint(i - 1)))); - if (i < count - 1) - m_candidates.push_back(my::RadToDeg( - PiMinusTwoVectorsAngle(m_junctionPoint, m_ingoingPoint, ft.GetPoint(i + 1)))); - return; - } - } - } - - DISALLOW_COPY_AND_MOVE(Point2Geometry); -}; - /*! * \brief Returns false when * - the route leads from one big road to another one; @@ -160,10 +115,11 @@ bool DiscardTurnByIngoingAndOutgoingEdges(TurnDirection intermediateDirection, turn.m_sourceName == turn.m_targetName; } +// 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, - TTurnCandidates const & nodes) + size_t const turnEdgesCount) { double const turnAngle = my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPointOneSegment, outgoingPoint)); @@ -172,7 +128,7 @@ bool KeepTurnByIngoingEdges(m2::PointD const & junctionPoint, // The code below is resposible 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 && nodes.size() > 2); + return hasMultiTurns || (!isGoStraightOrSlightTurn && turnEdgesCount > 1); } bool FixupLaneSet(TurnDirection turn, vector & lanes, @@ -474,12 +430,6 @@ bool TurnInfo::IsSegmentsValid() const return true; } -// @todo(vbykoianko) This method shall to be refactored. It shall be split into several -// methods. All the functionality shall be moved to the turns_generator unit. - -// @todo(vbykoianko) For the time being MakeTurnAnnotation generates the turn annotation -// and the route polyline at the same time. It is better to generate it separately -// to be able to use the route without turn annotation. IRouter::ResultCode MakeTurnAnnotation(turns::IRoutingResultGraph const & result, RouterDelegate const & delegate, vector & points, Route::TTurns & turnsDir, Route::TTimes & times, @@ -560,8 +510,7 @@ IRouter::ResultCode MakeTurnAnnotation(turns::IRoutingResultGraph const & result points.back() = result.GetEndPoint(); times.push_back(Route::TTimeItem(points.size() - 1, estimatedTime)); - turnsDir.emplace_back(turns::TurnItem(static_cast(points.size()) - 1, - turns::TurnDirection::ReachedYourDestination)); + turnsDir.emplace_back(turns::TurnItem(static_cast(points.size()) - 1, turns::TurnDirection::ReachedYourDestination)); turns::FixupTurns(points, turnsDir); #ifdef DEBUG @@ -797,6 +746,8 @@ void GetTurnDirection(IRoutingResultGraph const & result, TurnInfo & turnInfo, T ASSERT_LESS(MercatorBounds::DistanceOnEarth(turnInfo.m_ingoing.m_path.back(), turnInfo.m_outgoing.m_path.front()), kFeaturesNearTurnMeters, ()); + ASSERT(!turnInfo.m_ingoing.m_path.empty(), ()); + ASSERT(!turnInfo.m_outgoing.m_path.empty(), ()); m2::PointD const junctionPoint = turnInfo.m_ingoing.m_path.back(); m2::PointD const ingoingPoint = GetPointForTurn(turnInfo.m_ingoing.m_path, junctionPoint, @@ -820,8 +771,9 @@ void GetTurnDirection(IRoutingResultGraph const & result, TurnInfo & turnInfo, T ASSERT_GREATER(turnInfo.m_ingoing.m_path.size(), 1, ()); m2::PointD const ingoingPointOneSegment = turnInfo.m_ingoing.m_path[turnInfo.m_ingoing.m_path.size() - 2]; TTurnCandidates nodes; + size_t ingoingCount; result.GetPossibleTurns(turnInfo.m_ingoing.m_nodeId, ingoingPointOneSegment, junctionPoint, - nodes); + ingoingCount, nodes); size_t const numNodes = nodes.size(); bool const hasMultiTurns = numNodes > 1; @@ -865,7 +817,7 @@ void GetTurnDirection(IRoutingResultGraph const & result, TurnInfo & turnInfo, T kNotSoCloseMinDistMeters, GetIngoingPointIndex); if (!KeepTurnByIngoingEdges(junctionPoint, notSoCloseToTheTurnPoint, outgoingPoint, hasMultiTurns, - nodes)) + nodes.size() + ingoingCount)) { turn.m_turn = TurnDirection::NoTurn; return; diff --git a/routing/turns_generator.hpp b/routing/turns_generator.hpp index ff2acbfffe..ea96be9e33 100644 --- a/routing/turns_generator.hpp +++ b/routing/turns_generator.hpp @@ -102,7 +102,8 @@ public: virtual vector const & GetSegments() const = 0; virtual void GetPossibleTurns(NodeID node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, - TTurnCandidates & candidates) const = 0; + size_t & ingoingCount, + TTurnCandidates & outgoingTurns) const = 0; virtual double GetShortestPathLength() const = 0; virtual m2::PointD const & GetStartPoint() const = 0; virtual m2::PointD const & GetEndPoint() const = 0;