#pragma once #include "routing/segment.hpp" #include "routing_common/num_mwm_id.hpp" #include "indexer/feature_decl.hpp" #include "geometry/point2d.hpp" #include #include #include #include namespace routing { /// \brief Unique identification for a road edge between two junctions (joints). The identifier /// is represented by an mwm id, a feature id, a range of segment ids [|m_startSegId|, |m_endSegId|], /// a direction and type. struct SegmentRange { friend std::string DebugPrint(SegmentRange const & segmentRange); SegmentRange() = default; SegmentRange(FeatureID const & featureId, uint32_t startSegId, uint32_t endSegId, bool forward, m2::PointD const & start, m2::PointD const & end); bool operator==(SegmentRange const & rh) const; bool operator<(SegmentRange const & rh) const; void Clear(); bool IsEmpty() const; FeatureID const & GetFeature() const; /// \returns true if the instance of SegmentRange is correct. bool IsCorrect() const; /// \brief Fills |segment| with the first segment of this SegmentRange. /// \returns true if |segment| is filled and false otherwise. bool GetFirstSegment(NumMwmIds const & numMwmIds, Segment & segment) const; bool GetLastSegment(NumMwmIds const & numMwmIds, Segment & segment) const; private: bool GetSegmentBySegId(uint32_t segId, NumMwmIds const & numMwmIds, Segment & segment) const; FeatureID m_featureId; // Note. If SegmentRange represents two directional feature |m_endSegId| is greater // than |m_startSegId| if |m_forward| == true. uint32_t m_startSegId = 0; // The first segment index of SegmentRange. uint32_t m_endSegId = 0; // The last segment index of SegmentRange. bool m_forward = true; // Segment direction in |m_featureId|. // Note. According to current implementation SegmentRange is filled based on instances of // Edge class in IDirectionsEngine::GetSegmentRangeAndAdjacentEdges() method. In Edge class // to identify fake edges (part of real and completely fake) is used coordinates of beginning // and ending of the edge. To keep SegmentRange instances unique for unique edges // in case of fake edges it's necessary to have |m_start| and |m_end| fields below. // @TODO(bykoianko) It's necessary to get rid of |m_start| and |m_end|. // Fake edges in IndexGraph is identified by instances of Segment // with Segment::m_mwmId == kFakeNumMwmId. So instead of |m_featureId| field in this class // number mwm id field and feature id (uint32_t) should be used and |m_start| and |m_end| // should be removed. To do that classes IndexRoadGraph, BicycleDirectionsEngine, // PedestrianDirectionsEngine and other should be significant refactored. m2::PointD m_start; // Coordinates of start of last Edge in SegmentRange. m2::PointD m_end; // Coordinates of end of SegmentRange. }; namespace turns { /// @todo(vbykoianko) It's a good idea to gather all the turns information into one entity. /// For the time being several separate entities reflect the turn information. Like Route::TTurns double constexpr kFeaturesNearTurnMeters = 3.0; /*! * \warning The order of values below shall not be changed. * TurnRight(TurnLeft) must have a minimal value and * TurnSlightRight(TurnSlightLeft) must have a maximum value * \warning The values of TurnDirection shall be synchronized with values of TurnDirection enum in * java. */ enum class CarDirection { None = 0, GoStraight, TurnRight, TurnSharpRight, TurnSlightRight, TurnLeft, TurnSharpLeft, TurnSlightLeft, UTurnLeft, UTurnRight, EnterRoundAbout, LeaveRoundAbout, StayOnRoundAbout, StartAtEndOfStreet, ReachedYourDestination, ExitHighwayToLeft, ExitHighwayToRight, Count /**< This value is used for internals only. */ }; std::string DebugPrint(CarDirection const l); /*! * \warning The values of PedestrianDirectionType shall be synchronized with values in java */ enum class PedestrianDirection { None = 0, Upstairs, Downstairs, LiftGate, Gate, ReachedYourDestination, Count /**< This value is used for internals only. */ }; std::string DebugPrint(PedestrianDirection const l); /*! * \warning The values of LaneWay shall be synchronized with values of LaneWay enum in java. */ enum class LaneWay { None = 0, Reverse, SharpLeft, Left, SlightLeft, MergeToRight, Through, MergeToLeft, SlightRight, Right, SharpRight, Count /**< This value is used for internals only. */ }; std::string DebugPrint(LaneWay const l); typedef std::vector TSingleLane; struct SingleLaneInfo { TSingleLane m_lane; bool m_isRecommended = false; SingleLaneInfo() = default; SingleLaneInfo(std::initializer_list const & l) : m_lane(l) {} bool operator==(SingleLaneInfo const & other) const; }; std::string DebugPrint(SingleLaneInfo const & singleLaneInfo); struct TurnItem { TurnItem() : m_index(std::numeric_limits::max()), m_turn(CarDirection::None), m_exitNum(0), m_keepAnyway(false), m_pedestrianTurn(PedestrianDirection::None) { } TurnItem(uint32_t idx, CarDirection t, uint32_t exitNum = 0) : m_index(idx), m_turn(t), m_exitNum(exitNum), m_keepAnyway(false) , m_pedestrianTurn(PedestrianDirection::None) { } TurnItem(uint32_t idx, PedestrianDirection p) : m_index(idx), m_turn(CarDirection::None), m_exitNum(0), m_keepAnyway(false) , m_pedestrianTurn(p) { } bool operator==(TurnItem const & rhs) const { return m_index == rhs.m_index && m_turn == rhs.m_turn && m_lanes == rhs.m_lanes && m_exitNum == rhs.m_exitNum && m_sourceName == rhs.m_sourceName && m_targetName == rhs.m_targetName && m_keepAnyway == rhs.m_keepAnyway && m_pedestrianTurn == rhs.m_pedestrianTurn; } uint32_t m_index; /*!< Index of point on route polyline (number of segment + 1). */ CarDirection m_turn; /*!< The turn instruction of the TurnItem */ std::vector m_lanes; /*!< Lane information on the edge before the turn. */ uint32_t m_exitNum; /*!< Number of exit on roundabout. */ std::string m_sourceName; /*!< Name of the street which the ingoing edge belongs to */ std::string m_targetName; /*!< Name of the street which the outgoing edge belongs to */ /*! * \brief m_keepAnyway is true if the turn shall not be deleted * and shall be demonstrated to an end user. */ bool m_keepAnyway; /*! * \brief m_pedestrianTurn is type of corresponding direction for a pedestrian, or None * if there is no pedestrian specific direction */ PedestrianDirection m_pedestrianTurn; }; std::string DebugPrint(TurnItem const & turnItem); struct TurnItemDist { TurnItemDist(TurnItem const & turnItem, double distMeters) : m_turnItem(turnItem), m_distMeters(distMeters) { } TurnItemDist() = default; TurnItem m_turnItem; double m_distMeters = 0.0; }; std::string DebugPrint(TurnItemDist const & turnItemDist); std::string const GetTurnString(CarDirection turn); bool IsLeftTurn(CarDirection t); bool IsRightTurn(CarDirection t); bool IsLeftOrRightTurn(CarDirection t); bool IsStayOnRoad(CarDirection t); bool IsGoStraightOrSlightTurn(CarDirection t); /*! * \param l A variant of going along a lane. * \param t A turn direction. * \return True if @l corresponds with @t exactly. For example it returns true * when @l equals to LaneWay::Right and @t equals to TurnDirection::TurnRight. * Otherwise it returns false. */ bool IsLaneWayConformedTurnDirection(LaneWay l, CarDirection t); /*! * \param l A variant of going along a lane. * \param t A turn direction. * \return True if @l corresponds with @t approximately. For example it returns true * when @l equals to LaneWay::Right and @t equals to TurnDirection::TurnSlightRight. * Otherwise it returns false. */ bool IsLaneWayConformedTurnDirectionApproximately(LaneWay l, CarDirection t); /*! * \brief Parse lane information which comes from @lanesString * \param lanesString lane information. Example through|through|through|through;right * \param lanes the result of parsing. * \return true if @lanesString parsed successfully, false otherwise. * Note 1: if @lanesString is empty returns false. * Note 2: @laneString is passed by value on purpose. It'll be used(changed) in the method. */ bool ParseLanes(std::string lanesString, std::vector & lanes); void SplitLanes(std::string const & lanesString, char delimiter, std::vector & lanes); bool ParseSingleLane(std::string const & laneString, char delimiter, TSingleLane & lane); /*! * \returns pi minus angle from vector [junctionPoint, ingoingPoint] * to vector [junctionPoint, outgoingPoint]. A counterclockwise rotation. * Angle is in range [-pi, pi]. */ double PiMinusTwoVectorsAngle(m2::PointD const & junctionPoint, m2::PointD const & ingoingPoint, m2::PointD const & outgoingPoint); } // namespace turns } // namespace routing