#pragma once #include "search/feature_loader.hpp" #include "search/projection_on_street.hpp" #include "indexer/feature_decl.hpp" #include "indexer/ftypes_matcher.hpp" #include "geometry/point2d.hpp" #include "base/macros.hpp" #include #include #include #include #include class DataSourceBase; namespace search { struct ParsedNumber { public: /// @todo Pass correct "American" notation flag. ParsedNumber(std::string const & number, bool american = false); std::string const & GetNumber() const { return m_fullN; } bool IsOdd() const { return (m_startN % 2 == 1); } int GetIntNumber() const { return m_startN; } bool IsIntersect(ParsedNumber const & number, int offset = 0) const; private: std::string m_fullN; int m_startN; int m_endN; }; class House { public: House(std::string const & number, m2::PointD const & point) : m_number(number), m_point(point) {} std::string const & GetNumber() const { return m_number.GetNumber(); } int GetIntNumber() const { return m_number.GetIntNumber(); } 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; private: ParsedNumber m_number; m2::PointD m_point; }; // 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 { struct LessDistance { bool operator()(HouseProjection const * p1, HouseProjection const * p2) const { return p1->m_distMeters < p2->m_distMeters; } }; class EqualHouse { public: EqualHouse(House const * h) : m_house(h) {} bool operator() (HouseProjection const * p) const { return m_house == p->m_house; } private: House const * m_house; }; bool IsOdd() const { return (m_house->GetIntNumber() % 2 == 1); } House const * m_house; /// Distance in mercator, from street beginning to projection on street double m_streetDistance; }; // many features combines to street class Street { public: 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; static bool IsSameStreets(Street const * s1, Street const * s2) { return s1->m_processedName == s2->m_processedName; } void SetName(std::string const & name); std::string const & GetDbgName() const { return m_processedName; } std::string const & GetName() const { return m_name; } std::vector m_points; std::vector m_houses; double m_length; /// Length in mercator int m_number; /// Some ordered number after merging bool m_housesRead; private: std::string m_name; std::string m_processedName; }; class MergedStreet { public: struct Index { size_t s, h; Index() : s(0), h(0) {} }; struct GreaterLength { bool operator() (MergedStreet const & s1, MergedStreet const & s2) const { return (s1.m_length > s2.m_length); } }; MergedStreet() : m_length(0.0) {} std::string const & GetDbgName() const; std::string const & GetName() const; bool IsHousesRead() const; void FinishReadingHouses(); HouseProjection const * GetHousePivot(bool isOdd, bool & sign) const; void Swap(MergedStreet & s) { m_cont.swap(s.m_cont); std::swap(m_length, s.m_length); } Index Begin() const { Index i; Next(i); return i; } void Inc(Index & i) const { ++i.h; Next(i); } bool IsEnd(Index const & i) const { return i.s == m_cont.size(); } HouseProjection const & Get(Index const & i) const { ASSERT(!IsEnd(i), ()); return m_cont[i.s]->m_houses[i.h]; } std::deque m_cont; private: void Erase(Index & i); void Next(Index & i) const; double m_length; }; struct HouseResult { HouseResult(House const * house, MergedStreet const * street) : m_house(house), m_street(street) { } bool operator<(HouseResult const & a) const { return m_house < a.m_house; } bool operator==(HouseResult const & a) const { return m_house == a.m_house; } m2::PointD const & GetOrg() const { return m_house->GetPosition(); } House const * m_house; MergedStreet const * m_street; }; class HouseDetector { public: using StreetMap = std::map; using HouseMap = std::map; using StreetPtr = std::pair; static int const DEFAULT_OFFSET_M = 200; HouseDetector(DataSourceBase const & dataSource); ~HouseDetector(); int LoadStreets(std::vector const & ids); /// @return number of different joined streets. int MergeStreets(); void ReadAllHouses(double offsetMeters = DEFAULT_OFFSET_M); void GetHouseForName(std::string const & houseNumber, std::vector & res); void ClearCaches(); void ClearUnusedStreets(std::vector const & ids); private: StreetPtr FindConnection(Street const * st, bool beg) const; void MergeStreets(Street * st); template void ReadHouse(FeatureType const & f, Street * st, ProjectionCalculator & calc); void ReadHouses(Street * st); void SetMetres2Mercator(double factor); double GetApprLengthMeters(int index) const; FeatureLoader m_loader; StreetMap m_id2st; HouseMap m_id2house; std::vector> m_end2st; std::vector m_streets; double m_metres2Mercator; int m_streetNum; double m_houseOffsetM; }; std::string DebugPrint(HouseProjection const & p); std::string DebugPrint(HouseResult const & r); } // namespace search