diff options
Diffstat (limited to 'routing/cross_mwm_connector.hpp')
-rw-r--r-- | routing/cross_mwm_connector.hpp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/routing/cross_mwm_connector.hpp b/routing/cross_mwm_connector.hpp new file mode 100644 index 0000000000..22ef84de61 --- /dev/null +++ b/routing/cross_mwm_connector.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include "routing/segment.hpp" + +#include "geometry/point2d.hpp" + +#include "base/assert.hpp" + +#include <cmath> +#include <limits> +#include <unordered_map> +#include <vector> + +namespace routing +{ +class CrossMwmConnector final +{ +public: + CrossMwmConnector() : m_mwmId(kFakeNumMwmId) {} + explicit CrossMwmConnector(NumMwmId mwmId) : m_mwmId(mwmId) {} + + void AddTransition(uint32_t featureId, uint32_t segmentIdx, bool oneWay, bool forwardIsEnter, + m2::PointD const & backPoint, m2::PointD const & frontPoint); + + bool IsTransition(Segment const & segment, bool isOutgoing) const; + m2::PointD const & GetPoint(Segment const & segment, bool front) const; + void GetEdgeList(Segment const & segment, bool isOutgoing, + std::vector<SegmentEdge> & edges) const; + + std::vector<Segment> const & GetEnters() const { return m_enters; } + std::vector<Segment> const & GetExits() const { return m_exits; } + bool HasWeights() const { return !m_weights.empty(); } + bool WeightsWereLoaded() const; + + template <typename CalcWeight> + void FillWeights(CalcWeight && calcWeight) + { + CHECK_EQUAL(m_weightsLoadState, WeightsLoadState::Unknown, ()); + CHECK(m_weights.empty(), ()); + + m_weights.reserve(m_enters.size() * m_exits.size()); + for (Segment const & enter : m_enters) + { + for (Segment const & exit : m_exits) + { + double const weight = calcWeight(enter, exit); + // Edges weights should be >= astar heuristic, so use std::ceil. + m_weights.push_back(static_cast<Weight>(std::ceil(weight))); + } + } + } + +private: + // This is an internal type for storing edges weights. + // Weight is the time requred for the route to pass. + // Weight is measured in seconds rounded upwards. + using Weight = uint32_t; + + static Weight constexpr kNoRoute = 0; + + struct Key + { + Key() = default; + + Key(uint32_t featureId, uint32_t segmentIdx) : m_featureId(featureId), m_segmentIdx(segmentIdx) + { + } + + bool operator==(Key const & key) const + { + return m_featureId == key.m_featureId && m_segmentIdx == key.m_segmentIdx; + } + + uint32_t m_featureId = 0; + uint32_t m_segmentIdx = 0; + }; + + struct HashKey + { + size_t operator()(Key const & key) const + { + return std::hash<uint64_t>()((static_cast<uint64_t>(key.m_featureId) << 32) + + static_cast<uint64_t>(key.m_segmentIdx)); + } + }; + + struct Transition + { + Transition() = default; + + Transition(uint32_t enterIdx, uint32_t exitIdx, bool oneWay, bool forwardIsEnter, + m2::PointD const & backPoint, m2::PointD const & frontPoint) + : m_enterIdx(enterIdx) + , m_exitIdx(exitIdx) + , m_backPoint(backPoint) + , m_frontPoint(frontPoint) + , m_oneWay(oneWay) + , m_forwardIsEnter(forwardIsEnter) + { + } + + uint32_t m_enterIdx = 0; + uint32_t m_exitIdx = 0; + // Endpoints of transition segment. + // m_backPoint = points[segmentIdx] + // m_frontPoint = points[segmentIdx + 1] + m2::PointD m_backPoint = m2::PointD::Zero(); + m2::PointD m_frontPoint = m2::PointD::Zero(); + bool m_oneWay = false; + // Transition represents both forward and backward segments with same featureId, segmentIdx. + // m_forwardIsEnter == true means: forward segment is enter to mwm: + // Enter means: m_backPoint is outside mwm borders, m_frontPoint is inside. + bool m_forwardIsEnter = false; + }; + + enum class WeightsLoadState + { + Unknown, + NotExists, + ReadyToLoad, + Loaded + }; + + friend class CrossMwmConnectorSerializer; + friend std::string DebugPrint(WeightsLoadState state); + + void AddEdge(Segment const & segment, Weight weight, std::vector<SegmentEdge> & edges) const; + Transition const & GetTransition(Segment const & segment) const; + Weight GetWeight(size_t enterIdx, size_t exitIdx) const; + + NumMwmId const m_mwmId; + std::vector<Segment> m_enters; + std::vector<Segment> m_exits; + std::unordered_map<Key, Transition, HashKey> m_transitions; + WeightsLoadState m_weightsLoadState = WeightsLoadState::Unknown; + uint64_t m_weightsOffset = 0; + std::vector<Weight> m_weights; +}; +} // namespace routing |