diff --git a/map/address_finder.cpp b/map/address_finder.cpp new file mode 100644 index 0000000000..2ac45e7692 --- /dev/null +++ b/map/address_finder.cpp @@ -0,0 +1,341 @@ +#include "framework.hpp" + +#include "../indexer/classificator.hpp" + + +namespace +{ + class FeatureInfoT + { + double m_dist; + + public: + FeatureInfoT(double d, feature::TypesHolder & types, string & name, m2::PointD const & pt) + : m_dist(d), m_types(types), m_pt(pt) + { + m_name.swap(name); + } + + bool operator<(FeatureInfoT const & rhs) const + { + return (m_dist < rhs.m_dist); + } + + void Swap(FeatureInfoT & rhs) + { + swap(m_dist, rhs.m_dist); + m_name.swap(rhs.m_name); + swap(m_types, rhs.m_types); + } + + string m_name; + feature::TypesHolder m_types; + m2::PointD m_pt; + }; + + void swap(FeatureInfoT & i1, FeatureInfoT & i2) + { + i1.Swap(i2); + } + + class DoGetFeatureInfoBase + { + protected: + virtual double GetCompareEpsilon(feature::EGeomType type) const = 0; + virtual double NeedProcess(feature::TypesHolder const & types) const = 0; + + static double GetCompareEpsilonImpl(feature::EGeomType type, double eps) + { + using namespace feature; + switch (type) + { + case GEOM_POINT: return 0.0 * eps; + case GEOM_LINE: return 1.0 * eps; + case GEOM_AREA: return 2.0 * eps; + default: + ASSERT ( false, () ); + return numeric_limits::max(); + } + } + + public: + DoGetFeatureInfoBase(m2::PointD const & pt, double eps, int scale) + : m_pt(pt), m_eps(eps), m_scale(scale) + { + } + + void operator() (FeatureType const & f) + { + feature::TypesHolder types(f); + if (NeedProcess(types)) + { + double const d = f.GetDistance(m_pt, m_scale); + ASSERT_GREATER_OR_EQUAL(d, 0.0, ()); + + if (d <= m_eps) + { + string defName, intName; + f.GetPreferredDrawableNames(defName, intName); + + feature::EGeomType const geomType = types.GetGeoType(); + m2::PointD const pt = (geomType == feature::GEOM_POINT) ? f.GetCenter() : m2::PointD(); + + m_cont.push_back(FeatureInfoT(d + GetCompareEpsilon(geomType), types, defName, pt)); + } + } + } + + void SortResults() + { + sort(m_cont.begin(), m_cont.end()); + } + + protected: + m2::PointD m_pt; + double m_eps; + int m_scale; + + vector m_cont; + }; + + class DoGetFeatureTypes : public DoGetFeatureInfoBase + { + protected: + virtual double GetCompareEpsilon(feature::EGeomType type) const + { + return GetCompareEpsilonImpl(type, m_eps); + } + virtual double NeedProcess(feature::TypesHolder const &) const + { + return true; + } + + public: + DoGetFeatureTypes(m2::PointD const & pt, double eps, int scale) + : DoGetFeatureInfoBase(pt, eps, scale) + { + } + + void GetFeatureTypes(size_t count, vector & types) + { + SortResults(); + + Classificator const & c = classif(); + + for (size_t i = 0; i < min(count, m_cont.size()); ++i) + for (size_t j = 0; j < m_cont[i].m_types.Size(); ++j) + types.push_back(c.GetFullObjectName(m_cont[i].m_types[j])); + } + }; +} + +void Framework::GetFeatureTypes(m2::PointD pt, vector & types) const +{ + pt = m_navigator.ShiftPoint(pt); + + int const sm = 20; + m2::RectD pixR(m2::PointD(pt.x - sm, pt.y - sm), m2::PointD(pt.x + sm, pt.y + sm)); + + m2::RectD glbR; + m_navigator.Screen().PtoG(pixR, glbR); + + int const scale = GetDrawScale(); + DoGetFeatureTypes getTypes(m_navigator.Screen().PtoG(pt), + max(glbR.SizeX(), glbR.SizeY()) / 2.0, + scale); + + m_model.ForEachFeature(glbR, getTypes, scale); + + getTypes.GetFeatureTypes(5, types); +} + + +namespace +{ + class DoGetAddressInfo : public DoGetFeatureInfoBase + { + public: + class TypeChecker + { + vector m_localities, m_streets, m_buildings; + + template + void FillMatch(char const * (& arr)[count][ind], vector & vec) + { + STATIC_ASSERT ( count > 0 ); + STATIC_ASSERT ( ind > 0 ); + + Classificator const & c = classif(); + + vec.reserve(count); + for (size_t i = 0; i < count; ++i) + { + vector v(arr[i], arr[i] + ind); + vec.push_back(c.GetTypeByPath(v)); + } + } + + static bool IsMatchImpl(vector const & vec, feature::TypesHolder const & types) + { + for (size_t i = 0; i < types.Size(); ++i) + { + uint32_t type = types[i]; + ftype::TruncValue(type, 2); + + if (find(vec.begin(), vec.end(), type) != vec.end()) + return true; + } + + return false; + } + + public: + TypeChecker() + { + char const * arrLocalities[][2] = { + { "place", "city" }, + { "place", "town" }, + { "place", "village" } + //{ "place", "hamlet" } + }; + + char const * arrStreet[][2] = { + { "highway", "primary" }, + { "highway", "secondary" }, + { "highway", "residential" }, + { "highway", "tertiary" }, + { "highway", "living_street" }, + { "highway", "service" } + }; + + char const * arrBuilding[][1] = { + { "building" } + }; + + FillMatch(arrLocalities, m_localities); + FillMatch(arrStreet, m_streets); + FillMatch(arrBuilding, m_buildings); + } + + bool IsLocality(feature::TypesHolder const & types) const + { + return IsMatchImpl(m_localities, types); + } + bool IsStreet(feature::TypesHolder const & types) const + { + return IsMatchImpl(m_streets, types); + } + bool IsBuilding(feature::TypesHolder const & types) const + { + return IsMatchImpl(m_buildings, types); + } + }; + + TypeChecker const & m_checker; + bool m_doLocalities; + + protected: + virtual double GetCompareEpsilon(feature::EGeomType type) const + { + return GetCompareEpsilonImpl(type, 5.0 * MercatorBounds::degreeInMetres); + } + virtual double NeedProcess(feature::TypesHolder const & types) const + { + return (!m_doLocalities || + (types.GetGeoType() == feature::GEOM_POINT && m_checker.IsLocality(types))); + } + + public: + DoGetAddressInfo(m2::PointD const & pt, double eps, int scale, + TypeChecker const & checker) + : DoGetFeatureInfoBase(pt, eps, scale), + m_checker(checker), m_doLocalities(false) + { + } + + void PrepareForLocalities() + { + m_doLocalities = true; + m_cont.clear(); + } + + void FillAddress(Framework::AddressInfo & info) + { + SortResults(); + + for (size_t i = 0; i < m_cont.size(); ++i) + { + bool const isStreet = m_checker.IsStreet(m_cont[i].m_types); + //bool const isBuilding = m_checker.IsBuilding(m_cont[i].m_types); + + if (info.m_street.empty() && isStreet) + info.m_street = m_cont[i].m_name; + + //if (info.m_house.empty() && isBuilding) + // info.m_house = m_cont[i].m_house; + + if (info.m_name.empty()) + { + if (m_cont[i].m_types.GetGeoType() != feature::GEOM_LINE) + info.m_name = m_cont[i].m_name; + } + + if (!(info.m_street.empty() || info.m_name.empty())) + break; + } + } + + void FillLocality(Framework::AddressInfo & info, Framework const & fm) + { + SortResults(); + + for (size_t i = 0; i < m_cont.size(); ++i) + { + if (!m_cont[i].m_name.empty() && fm.GetCountryName(m_cont[i].m_pt) == info.m_country) + { + info.m_city = m_cont[i].m_name; + break; + } + } + } + }; +} + +void Framework::GetAddressInfo(m2::PointD pt, AddressInfo & info) const +{ + pt = m_navigator.Screen().PtoG(m_navigator.ShiftPoint(pt)); + + info.m_country = GetCountryName(pt); + if (info.m_country.empty()) + { + LOG(LINFO, ("Can't find region for point ", pt)); + return; + } + + int const scale = scales::GetUpperScale(); + double const addressR = 200.0; + double const localityR = 20000; + + static DoGetAddressInfo::TypeChecker checker; + + // first of all - get an address + { + DoGetAddressInfo getAddress(pt, addressR, scale, checker); + + m_model.ForEachFeature( + MercatorBounds::RectByCenterXYAndSizeInMeters(pt, addressR), getAddress, scale); + + getAddress.FillAddress(info); + } + + // now - get the locality + { + DoGetAddressInfo getLocality(pt, localityR, scale, checker); + getLocality.PrepareForLocalities(); + + m_model.ForEachFeature( + MercatorBounds::RectByCenterXYAndSizeInMeters(pt, localityR), getLocality, scale); + + getLocality.FillLocality(info, *this); + } +} diff --git a/map/framework.cpp b/map/framework.cpp index 5c30ddf9f6..dcb01bf3d9 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -17,7 +17,6 @@ #include "../indexer/categories_holder.hpp" #include "../indexer/feature.hpp" #include "../indexer/scales.hpp" -#include "../indexer/classificator.hpp" #include "../coding/parse_xml.hpp" // LoadFromKML @@ -395,24 +394,8 @@ void Framework::SetNeedRedraw(bool flag) void Framework::Invalidate(bool doForceUpdate) { - if (m_renderPolicy) - { - m_renderPolicy->SetForceUpdate(doForceUpdate); - m_renderPolicy->GetWindowHandle()->invalidate(); - m_renderPolicy->SetInvalidRect(m2::AnyRectD(m2::RectD(MercatorBounds::minX, - MercatorBounds::minY, - MercatorBounds::maxX, - MercatorBounds::maxY))); - } - else - { - m_hasPendingInvalidate = true; - m_doForceUpdate = doForceUpdate; - m_invalidRect = m2::AnyRectD(m2::RectD(MercatorBounds::minX, - MercatorBounds::minY, - MercatorBounds::maxX, - MercatorBounds::maxY)); - } + InvalidateRect(m2::RectD(MercatorBounds::minX, MercatorBounds::minY, + MercatorBounds::maxX, MercatorBounds::maxY), doForceUpdate); } void Framework::InvalidateRect(m2::RectD const & rect, bool doForceUpdate) @@ -481,7 +464,8 @@ int Framework::GetDrawScale() const return 0; } -/*double Framework::GetCurrentScale() const +/* +double Framework::GetCurrentScale() const { m2::PointD textureCenter(m_navigator.Screen().PixelRect().Center()); m2::RectD glbRect; @@ -491,7 +475,8 @@ int Framework::GetDrawScale() const textureCenter + m2::PointD(scaleEtalonSize / 2, scaleEtalonSize / 2)), glbRect); return scales::GetScaleLevelD(glbRect); -}*/ +} +*/ RenderPolicy::TRenderFn Framework::DrawModelFn() { @@ -620,7 +605,7 @@ void Framework::SetViewportCenter(m2::PointD const & pt) static int const theMetersFactor = 6; -void Framework::CheckMinGlobalRect(m2::RectD & rect) +void Framework::CheckMinGlobalRect(m2::RectD & rect) const { m2::RectD const minRect = MercatorBounds::RectByCenterXYAndSizeInMeters( rect.Center(), theMetersFactor * m_metresMinWidth); @@ -754,7 +739,7 @@ void Framework::StopDrag(DragEvent const & e) { m2::PointD const pt = m_navigator.ShiftPoint(e.Pos()); - m_navigator.StopDrag(pt, 0./*m_timer.ElapsedSeconds()*/, true); + m_navigator.StopDrag(pt, ElapsedSeconds(), true); #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, m2::PointD(0, 0)); @@ -900,7 +885,7 @@ void Framework::StopScale(ScaleEvent const & e) // LOG(LINFO, ("StopScale", e.Pt1(), e.Pt2())); } -search::Engine * Framework::GetSearchEngine() +search::Engine * Framework::GetSearchEngine() const { // Classical "double check" synchronization pattern. if (!m_pSearchEngine) @@ -921,6 +906,11 @@ search::Engine * Framework::GetSearchEngine() return m_pSearchEngine.get(); } +string Framework::GetCountryName(m2::PointD const & pt) const +{ + return GetSearchEngine()->GetCountryName(pt); +} + void Framework::PrepareSearch(bool hasPt, double lat, double lon) { GetSearchEngine()->PrepareSearch(GetCurrentViewport(), hasPt, lat, lon); @@ -931,7 +921,7 @@ void Framework::Search(search::SearchParams const & params) GetSearchEngine()->Search(params, GetCurrentViewport()); } -bool Framework::GetCurrentPosition(double & lat, double & lon) +bool Framework::GetCurrentPosition(double & lat, double & lon) const { if (m_locationState.IsValidPosition()) { @@ -1035,116 +1025,7 @@ void Framework::DeleteOldMaps() m_lowestMapVersion = MAXIMUM_VERSION_TO_DELETE + 1; } -namespace -{ - class DoGetFeatureTypes - { - typedef vector TypesC; - - class DistanceT - { - double m_dist; - - public: - DistanceT(double d, TypesC & types) : m_dist(d) - { - m_types.swap(types); - } - - bool operator<(DistanceT const & rhs) const - { - return (m_dist < rhs.m_dist); - } - - TypesC m_types; - }; - - class DoParseTypes - { - Classificator const & m_c; - - public: - DoParseTypes() : m_c(classif()) {} - - void operator() (uint32_t t) - { - m_types.push_back(m_c.GetFullObjectName(t)); - } - - TypesC m_types; - }; - - double GetCompareEpsilon(feature::EGeomType type) const - { - using namespace feature; - switch (type) - { - case GEOM_POINT: return 0.0 * m_eps; - case GEOM_LINE: return 1.0 * m_eps; - case GEOM_AREA: return 2.0 * m_eps; - default: - ASSERT ( false, () ); - return numeric_limits::max(); - } - } - - m2::PointD m_pt; - double m_eps; - int m_scale; - - vector m_cont; - - public: - DoGetFeatureTypes(m2::PointD const & pt, double eps, int scale) - : m_pt(pt), m_eps(eps), m_scale(scale) - { - } - - void operator() (FeatureType const & f) - { - double const d = f.GetDistance(m_pt, m_scale); - ASSERT_GREATER_OR_EQUAL(d, 0.0, ()); - - if (d <= m_eps) - { - DoParseTypes doParse; - f.ForEachTypeRef(doParse); - - m_cont.push_back(DistanceT(d + GetCompareEpsilon(f.GetFeatureType()), doParse.m_types)); - } - } - - void GetFeatureTypes(size_t count, TypesC & types) - { - sort(m_cont.begin(), m_cont.end()); - - for (size_t i = 0; i < min(count, m_cont.size()); ++i) - types.insert(types.end(), m_cont[i].m_types.begin(), m_cont[i].m_types.end()); - } - }; -} - -void Framework::GetFeatureTypes(m2::PointD pt, vector & types) const -{ - pt = m_navigator.ShiftPoint(pt); - - int const sm = 20; - m2::RectD pixR(m2::PointD(pt.x - sm, pt.y - sm), m2::PointD(pt.x + sm, pt.y + sm)); - - m2::RectD glbR; - m_navigator.Screen().PtoG(pixR, glbR); - - int const scale = GetDrawScale(); - DoGetFeatureTypes getTypes(m_navigator.Screen().PtoG(pt), - max(glbR.SizeX() / 2.0, glbR.SizeY() / 2.0), - scale); - - m_model.ForEachFeature(glbR, getTypes, scale); - - getTypes.GetFeatureTypes(5, types); -} - -string Framework::GetCountryCodeByPosition(double lat, double lon) +string Framework::GetCountryCodeByPosition(double lat, double lon) const { return GetSearchEngine()->GetCountryCode(m2::PointD( MercatorBounds::LonToX(lon), MercatorBounds::LatToY(lat))); diff --git a/map/framework.hpp b/map/framework.hpp index bf5032f186..caed3649b0 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -56,7 +56,7 @@ namespace search { class Result; } class Framework { protected: - scoped_ptr m_pSearchEngine; + mutable scoped_ptr m_pSearchEngine; model::FeaturesFetcher m_model; Navigator m_navigator; @@ -158,18 +158,20 @@ public: private: inline m2::RectD GetCurrentViewport() const { return m_navigator.Screen().ClipRect(); } - search::Engine * GetSearchEngine(); + search::Engine * GetSearchEngine() const; - void CheckMinGlobalRect(m2::RectD & r); + void CheckMinGlobalRect(m2::RectD & r) const; public: void PrepareSearch(bool hasPt, double lat = 0.0, double lon = 0.0); void Search(search::SearchParams const & params); - bool GetCurrentPosition(double & lat, double & lon); + bool GetCurrentPosition(double & lat, double & lon) const; void ShowSearchResult(search::Result const & res); + string GetCountryName(m2::PointD const & pt) const; + /// @return country code in ISO 3166-1 alpha-2 format (two small letters) or empty string - string GetCountryCodeByPosition(double lat, double lon); + string GetCountryCodeByPosition(double lat, double lon) const; void SetMaxWorldRect(); @@ -199,8 +201,18 @@ public: Invalidate(true); } + /// @name + /// @param[in] pt Current touch point in device pixel coordinates. + //@{ void GetFeatureTypes(m2::PointD pt, vector & types) const; + struct AddressInfo + { + string m_country, m_city, m_street, m_house, m_name; + }; + void GetAddressInfo(m2::PointD pt, AddressInfo & info) const; + //@} + virtual void BeginPaint(shared_ptr const & e); /// Function for calling from platform dependent-paint function. virtual void DoPaint(shared_ptr const & e); diff --git a/map/map.pro b/map/map.pro index 45e1bf907e..9c7b9d3fb3 100644 --- a/map/map.pro +++ b/map/map.pro @@ -84,7 +84,8 @@ SOURCES += \ queued_renderer.cpp \ events.cpp \ basic_tiling_render_policy.cpp \ - render_policy_mt.cpp + render_policy_mt.cpp \ + address_finder.cpp !iphone*:!bada*:!android* { HEADERS += qgl_render_context.hpp diff --git a/search/search_engine.cpp b/search/search_engine.cpp index 03e28ffb7e..c1e26bc973 100644 --- a/search/search_engine.cpp +++ b/search/search_engine.cpp @@ -277,4 +277,11 @@ string Engine::GetCountryCode(m2::PointD const & pt) const return info.m_flag; } +string Engine::GetCountryName(m2::PointD const & pt) const +{ + storage::CountryInfo info; + m_pData->m_infoGetter.GetRegionInfo(pt, info); + return info.m_name; +} + } // namespace search diff --git a/search/search_engine.hpp b/search/search_engine.hpp index 6612af6500..298a4ae75f 100644 --- a/search/search_engine.hpp +++ b/search/search_engine.hpp @@ -42,6 +42,7 @@ public: string GetCountryFile(m2::PointD const & pt) const; string GetCountryCode(m2::PointD const & pt) const; + string GetCountryName(m2::PointD const & pt) const; private: static const int RESULTS_COUNT = 15;