#pragma once #include "search/projection_on_street.hpp" #include "indexer/feature_decl.hpp" #include "indexer/index.hpp" #include "indexer/ftypes_matcher.hpp" #include "geometry/point2d.hpp" #include "base/macros.hpp" #include "std/string.hpp" #include "std/queue.hpp" namespace search { class FeatureLoader { Index const & m_index; unique_ptr m_guard; void CreateLoader(MwmSet::MwmId const & mwmId); public: FeatureLoader(Index const & index); WARN_UNUSED_RESULT bool Load(FeatureID const & id, FeatureType & f); inline void Free() { m_guard.reset(); } template void ForEachInRect(m2::RectD const & rect, ToDo toDo); }; struct ParsedNumber { string m_fullN; int m_startN, m_endN; public: /// @todo Pass correct "American" notation flag. ParsedNumber(string const & number, bool american = false); inline string const & GetNumber() const { return m_fullN; } inline bool IsOdd() const { return (m_startN % 2 == 1); } inline int GetIntNumber() const { return m_startN; } bool IsIntersect(ParsedNumber const & number, int offset = 0) const; }; class House { ParsedNumber m_number; m2::PointD m_point; public: House(string const & number, m2::PointD const & point) : m_number(number), m_point(point) { } inline string const & GetNumber() const { return m_number.GetNumber(); } inline int GetIntNumber() const { return m_number.GetIntNumber(); } inline m2::PointD const & GetPosition() const { return m_point; } /// @return \n /// -1 - no match; /// 0 - full match; /// 1 - integer number match with odd (even). /// 2 - integer number match. int GetMatch(ParsedNumber const & number) const; bool GetNearbyMatch(ParsedNumber const & number) const; }; // NOTE: DO NOT DELETE instances of this class by a pointer/reference // to ProjectionOnStreet, because both classes have non-virtual destructors. struct HouseProjection : public ProjectionOnStreet { House const * m_house; /// Distance in mercator, from street beginning to projection on street double m_streetDistance; inline bool IsOdd() const { return (m_house->GetIntNumber() % 2 == 1); } struct LessDistance { bool operator() (HouseProjection const * p1, HouseProjection const * p2) const { return p1->m_distMeters < p2->m_distMeters; } }; class EqualHouse { House const * m_house; public: EqualHouse(House const * h) : m_house(h) {} bool operator() (HouseProjection const * p) const { return m_house == p->m_house; } }; }; // many features combines to street class Street { string m_name; string m_processedName; public: void SetName(string const & name); vector m_points; vector m_houses; double m_length; /// Length in mercator int m_number; /// Some ordered number after merging bool m_housesRead; Street() : m_length(0.0), m_number(-1), m_housesRead(false) {} void Reverse(); void SortHousesProjection(); /// Get limit rect for street with ortho offset to the left and right. m2::RectD GetLimitRect(double offsetMeters) const; double GetLength() const; double GetPrefixLength(size_t numSegs) const; inline static bool IsSameStreets(Street const * s1, Street const * s2) { return s1->m_processedName == s2->m_processedName; } inline string const & GetDbgName() const { return m_processedName; } inline string const & GetName() const { return m_name; } }; class MergedStreet { double m_length; public: deque m_cont; MergedStreet() : m_length(0.0) {} string const & GetDbgName() const; string const & GetName() const; bool IsHousesRead() const; void FinishReadingHouses(); HouseProjection const * GetHousePivot(bool isOdd, bool & sign) const; struct GreaterLength { bool operator() (MergedStreet const & s1, MergedStreet const & s2) const { return (s1.m_length > s2.m_length); } }; inline void Swap(MergedStreet & s) { m_cont.swap(s.m_cont); std::swap(m_length, s.m_length); } public: struct Index { size_t s, h; Index() : s(0), h(0) {} }; inline Index Begin() const { Index i; Next(i); return i; } inline void Inc(Index & i) const { ++i.h; Next(i); } inline bool IsEnd(Index const & i) const { return i.s == m_cont.size(); } inline HouseProjection const & Get(Index const & i) const { ASSERT(!IsEnd(i), ()); return m_cont[i.s]->m_houses[i.h]; } private: void Erase(Index & i); void Next(Index & i) const; }; inline void swap(MergedStreet & s1, MergedStreet & s2) { s1.Swap(s2); } struct HouseResult { House const * m_house; MergedStreet const * m_street; HouseResult(House const * house, MergedStreet const * street) : m_house(house), m_street(street) { } inline bool operator<(HouseResult const & a) const { return m_house < a.m_house; } inline bool operator==(HouseResult const & a) const { return m_house == a.m_house; } m2::PointD const & GetOrg() const { return m_house->GetPosition(); } }; inline string DebugPrint(HouseResult const & r) { return r.m_house->GetNumber() + ", " + r.m_street->GetName(); } class HouseDetector { FeatureLoader m_loader; typedef map StreetMapT; StreetMapT m_id2st; typedef map HouseMapT; HouseMapT m_id2house; vector > m_end2st; vector m_streets; double m_metres2Mercator; int m_streetNum; double m_houseOffsetM; typedef pair StreetPtr; StreetPtr FindConnection(Street const * st, bool beg) const; void MergeStreets(Street * st); template void ReadHouse(FeatureType const & f, Street * st, ProjectionCalcT & calc); void ReadHouses(Street * st); void SetMetres2Mercator(double factor); double GetApprLengthMeters(int index) const; public: HouseDetector(Index const & index); ~HouseDetector(); int LoadStreets(vector const & ids); /// @return number of different joined streets. int MergeStreets(); static int const DEFAULT_OFFSET_M = 200; void ReadAllHouses(double offsetMeters = DEFAULT_OFFSET_M); void GetHouseForName(string const & houseNumber, vector & res); void ClearCaches(); void ClearUnusedStreets(vector const & ids); }; }