diff --git a/routing/bicycle_directions.cpp b/routing/bicycle_directions.cpp index 69e13b5bbc..baa5309d4a 100644 --- a/routing/bicycle_directions.cpp +++ b/routing/bicycle_directions.cpp @@ -16,6 +16,7 @@ #include "indexer/index.hpp" #include "indexer/scales.hpp" +#include "geometry/mercator.hpp" #include "geometry/point2d.hpp" #include @@ -50,10 +51,14 @@ public: // turns::IRoutingResult overrides: TUnpackedPathSegments const & GetSegments() const override { return m_pathSegments; } - void GetPossibleTurns(SegmentRange const & segmentRange, m2::PointD const & /* ingoingPoint */, - m2::PointD const & /* junctionPoint */, size_t & ingoingCount, + void GetPossibleTurns(SegmentRange const & segmentRange, m2::PointD const & ingoingPoint, + m2::PointD const & junctionPoint, size_t & ingoingCount, TurnCandidates & outgoingTurns) const override { + CHECK(!segmentRange.IsClear(), ("SegmentRange presents a fake feature. ingoingPoint:", + MercatorBounds::ToLatLon(ingoingPoint), + "junctionPoint:", MercatorBounds::ToLatLon(junctionPoint))); + ingoingCount = 0; outgoingTurns.candidates.clear(); @@ -145,6 +150,13 @@ bool IsJoint(IRoadGraph::TEdgeVector const & ingoingEdges, namespace routing { +// BicycleDirectionsEngine::AdjacentEdges --------------------------------------------------------- +bool BicycleDirectionsEngine::AdjacentEdges::operator==(AdjacentEdges const & rhs) const +{ + return m_outgoingTurns == rhs.m_outgoingTurns && m_ingoingTurnsCount == rhs.m_ingoingTurnsCount; +} + +// BicycleDirectionsEngine ------------------------------------------------------------------------ BicycleDirectionsEngine::BicycleDirectionsEngine(Index const & index, shared_ptr numMwmIds) : m_index(index), m_numMwmIds(numMwmIds) { @@ -348,9 +360,18 @@ void BicycleDirectionsEngine::FillPathSegmentsAndAdjacentEdgesMap( CHECK_EQUAL(prevSegments.size() + 1, prevJunctionSize, ()); pathSegment.m_segments = move(prevSegments); - auto const it = m_adjacentEdges.insert(make_pair(segmentRange, move(adjacentEdges))); - ASSERT(it.second, ()); - UNUSED_VALUE(it); + if (!segmentRange.IsClear()) + { + auto const it = m_adjacentEdges.find(segmentRange); + // A route may be build through intermediate points. So it may contain the same |segmentRange| + // several times. But in that case |adjacentEdges| corresponds to |segmentRange| + // should be the same as well. + ASSERT(it == m_adjacentEdges.cend() || it->second == adjacentEdges, + ("segmentRange:", segmentRange, "corresponds to adjacent edges which aren't equal.")); + + m_adjacentEdges.insert(it, make_pair(segmentRange, move(adjacentEdges))); + } + m_pathSegments.push_back(move(pathSegment)); prevJunctions.clear(); diff --git a/routing/bicycle_directions.hpp b/routing/bicycle_directions.hpp index 142eb3504b..64064165bd 100644 --- a/routing/bicycle_directions.hpp +++ b/routing/bicycle_directions.hpp @@ -19,6 +19,8 @@ public: struct AdjacentEdges { explicit AdjacentEdges(size_t ingoingTurnsCount = 0) : m_ingoingTurnsCount(ingoingTurnsCount) {} + bool operator==(AdjacentEdges const & rhs) const; + bool operator!=(AdjacentEdges const & rhs) const { return !(*this == rhs); } turns::TurnCandidates m_outgoingTurns; size_t m_ingoingTurnsCount; diff --git a/routing/routing_result_graph.hpp b/routing/routing_result_graph.hpp index bddbf3b12e..92be3b9839 100644 --- a/routing/routing_result_graph.hpp +++ b/routing/routing_result_graph.hpp @@ -19,8 +19,10 @@ class IRoutingResult public: /// \returns information about all route segments. virtual TUnpackedPathSegments const & GetSegments() const = 0; - /// \brief For a |segmentRange|, |junctionPoint| and |ingoingPoint| (point before the |node|) + /// \brief For a |segmentRange|, |junctionPoint| and |ingoingPoint| (point before the |junctionPoint|) /// this method computes number of ingoing ways to |junctionPoint| and fills |outgoingTurns|. + /// \note This method should not be called for |segmentRange| of fake edges. + /// So method |segmentRange.IsClear()| should return false. virtual void GetPossibleTurns(SegmentRange const & segmentRange, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, size_t & ingoingCount, TurnCandidates & outgoingTurns) const = 0; diff --git a/routing/turn_candidate.hpp b/routing/turn_candidate.hpp index f5ba69b39a..e6bcc0e448 100644 --- a/routing/turn_candidate.hpp +++ b/routing/turn_candidate.hpp @@ -40,6 +40,12 @@ struct TurnCandidate : angle(a), m_segmentRange(segmentRange), highwayClass(c) { } + + bool operator==(TurnCandidate const & rhs) const + { + return angle == rhs.angle && m_segmentRange == rhs.m_segmentRange && + highwayClass == rhs.highwayClass; + } }; struct TurnCandidates @@ -48,6 +54,11 @@ struct TurnCandidates bool isCandidatesAngleValid; explicit TurnCandidates(bool angleValid = true) : isCandidatesAngleValid(angleValid) {} + + bool operator==(TurnCandidates const & rhs) const + { + return candidates == rhs.candidates && isCandidatesAngleValid == rhs.isCandidatesAngleValid; + } }; } // namespace routing diff --git a/routing/turns.cpp b/routing/turns.cpp index 15069973b5..6bc8c1970c 100644 --- a/routing/turns.cpp +++ b/routing/turns.cpp @@ -89,6 +89,11 @@ void SegmentRange::Clear() m_forward = true; } +bool SegmentRange::IsClear() const +{ + return m_featureId == FeatureID() && m_startSegId == 0 && m_endSegId == 0 && m_forward; +} + FeatureID const & SegmentRange::GetFeature() const { return m_featureId; @@ -99,6 +104,17 @@ bool SegmentRange::IsCorrect() const return (m_forward && m_startSegId <= m_endSegId) || (!m_forward && m_endSegId <= m_startSegId); } +string DebugPrint(SegmentRange const & segmentRange) +{ + stringstream out; + out << "SegmentRange [ m_featureId = " << DebugPrint(segmentRange.m_featureId) + << ", m_startSegId = " << segmentRange.m_startSegId + << ", m_endSegId = " << segmentRange.m_endSegId + << ", m_forward = " << segmentRange.m_forward + << ", ]" << endl; + return out.str(); +} + namespace turns { // SingleLaneInfo --------------------------------------------------------------------------------- diff --git a/routing/turns.hpp b/routing/turns.hpp index adbe32d711..8218ce0c2c 100644 --- a/routing/turns.hpp +++ b/routing/turns.hpp @@ -16,17 +16,19 @@ namespace routing /// and a direction. struct SegmentRange { + friend string DebugPrint(SegmentRange const & segmentRange); + SegmentRange() = default; SegmentRange(FeatureID const & featureId, uint32_t startSegId, uint32_t endSegId, bool forward); bool operator==(SegmentRange const & rh) const; bool operator<(SegmentRange const & rh) const; void Clear(); + bool IsClear() const; FeatureID const & GetFeature() const; /// \returns true if the instance of SegmentRange is correct. bool IsCorrect() const; private: - FeatureID m_featureId; // Note. If SegmentRange represents two directional feature |m_endSegId| is greater // than |m_startSegId| if |m_forward| == true. @@ -35,6 +37,8 @@ private: bool m_forward = true; // Segment direction in |m_featureId|. }; +string DebugPrint(SegmentRange const & segmentRange); + 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 fd3195dceb..928002e1a8 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -539,7 +539,7 @@ CarDirection IntermediateDirection(const double angle) void GetTurnDirection(IRoutingResult const & result, TurnInfo & turnInfo, TurnItem & turn) { - if (!turnInfo.IsSegmentsValid()) + if (!turnInfo.IsSegmentsValid() || turnInfo.m_ingoing.m_segmentRange.IsClear()) return; ASSERT(!turnInfo.m_ingoing.m_path.empty(), ());