diff --git a/android/jni/com/mapswithme/maps/SearchEngine.cpp b/android/jni/com/mapswithme/maps/SearchEngine.cpp index 8e2b7c3e50..0667f488f8 100644 --- a/android/jni/com/mapswithme/maps/SearchEngine.cpp +++ b/android/jni/com/mapswithme/maps/SearchEngine.cpp @@ -68,9 +68,11 @@ jobject ToJavaResult(Result result, bool hasPosition, double lat, double lon) g_framework->NativeFramework()->LoadSearchResultMetadata(result); + auto const address = g_framework->NativeFramework()->GetSearchResultAddress(result); + jstring featureType = jni::ToJavaString(env, result.GetFeatureType()); - jstring region = jni::ToJavaString(env, result.GetRegionString()); - jstring dist = jni::ToJavaString(env, distance.c_str()); + jstring region = jni::ToJavaString(env, address.FormatAddress()); + jstring dist = jni::ToJavaString(env, distance); jstring cuisine = jni::ToJavaString(env, result.GetCuisine()); jobject desc = env->NewObject(g_descriptionClass, g_descriptionConstructor, featureType, region, @@ -84,10 +86,9 @@ jobject ToJavaResult(Result result, bool hasPosition, double lat, double lon) env->DeleteLocalRef(cuisine); jstring name = jni::ToJavaString(env, result.GetString()); + ms::LatLon const ll = MercatorBounds::ToLatLon(result.GetFeatureCenter()); - double const poiLat = MercatorBounds::YToLat(result.GetFeatureCenter().y); - double const poiLon = MercatorBounds::XToLon(result.GetFeatureCenter().x); - jobject ret = env->NewObject(g_resultClass, g_resultConstructor, name, desc, poiLat, poiLon, ranges); + jobject ret = env->NewObject(g_resultClass, g_resultConstructor, name, desc, ll.lat, ll.lon, ranges); ASSERT(ret, ()); env->DeleteLocalRef(name); env->DeleteLocalRef(desc); diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 355438edad..2880d6ec43 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -147,6 +147,21 @@ IsStreetChecker const & IsStreetChecker::Instance() return inst; } +IsAddressObjectChecker::IsAddressObjectChecker() : BaseChecker(1 /* level */) +{ + auto paths = { "building", "amenity", "shop", "tourism", "historic", "office", "craft" }; + + Classificator const & c = classif(); + for (auto const & p : paths) + m_types.push_back(c.GetTypeByPath({p})); +} + +IsAddressObjectChecker const & IsAddressObjectChecker::Instance() +{ + static const IsAddressObjectChecker inst; + return inst; +} + IsVillageChecker::IsVillageChecker() { // TODO (@y, @m, @vng): this list must be up-to-date with diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index c2d47ec568..48bb6348fd 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -84,6 +84,13 @@ public: static IsStreetChecker const & Instance(); }; +class IsAddressObjectChecker : public BaseChecker +{ + IsAddressObjectChecker(); +public: + static IsAddressObjectChecker const & Instance(); +}; + class IsVillageChecker : public BaseChecker { IsVillageChecker(); diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/Search/MWMSearchManager.mm b/iphone/Maps/Classes/CustomViews/MapViewControls/Search/MWMSearchManager.mm index 2069233b46..3e69ccbf85 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/Search/MWMSearchManager.mm +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/Search/MWMSearchManager.mm @@ -188,7 +188,7 @@ extern NSString * const kSearchStateKey = @"SearchStateKey"; f.SaveSearchQuery(query); MapsAppDelegate * a = MapsAppDelegate.theApp; MWMRoutingPlaneMode const m = a.routingPlaneMode; - MWMRoutePoint const p = {result.GetFeatureCenter(), @(result.GetString())}; + MWMRoutePoint const p = {result.GetFeatureCenter(), @(result.GetString().c_str())}; if (m == MWMRoutingPlaneModeSearchSource) [self.delegate buildRouteFrom:p]; else if (m == MWMRoutingPlaneModeSearchDestination) diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCell.mm b/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCell.mm index 8adf9427df..7cd588cf61 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCell.mm +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCell.mm @@ -25,7 +25,7 @@ if (result.GetResultType() == search::Result::RESULT_FEATURE) GetFramework().LoadSearchResultMetadata(result); - NSString * title = @(result.GetString()); + NSString * title = @(result.GetString().c_str()); if (!title) { self.titleLabel.text = @""; diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCommonCell.mm b/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCommonCell.mm index 6a77157a22..fdb9a5a9b5 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCommonCell.mm +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/Search/TableView/MWMSearchCommonCell.mm @@ -26,18 +26,15 @@ - (void)config:(search::Result &)result forHeight:(BOOL)forHeight { [super config:result]; - self.typeLabel.text = @(result.GetFeatureType()).capitalizedString; - search::AddressInfo info {}; - info.MakeFrom(result); - string const address = info.FormatAddress(); - string const location = address.empty() ? result.GetRegionString() : address; - self.locationLabel.text = @(location.c_str()); + self.typeLabel.text = @(result.GetFeatureType().c_str()).capitalizedString; + search::AddressInfo const info = GetFramework().GetSearchResultAddress(result); + self.locationLabel.text = @(info.FormatAddress().c_str()); [self.locationLabel sizeToFit]; if (!forHeight) { NSUInteger const starsCount = result.GetStarsCount(); - NSString * cuisine = @(result.GetCuisine()); + NSString * cuisine = @(result.GetCuisine().c_str()); if (starsCount > 0) [self setInfoRating:starsCount]; else if (cuisine.length > 0) diff --git a/map/address_finder.cpp b/map/address_finder.cpp index 7b4f74b80f..e0d97ed58b 100644 --- a/map/address_finder.cpp +++ b/map/address_finder.cpp @@ -464,8 +464,13 @@ search::AddressInfo Framework::GetAddressInfoAtPoint(m2::PointD const & mercator search::ReverseGeocoder coder(m_model.GetIndex()); search::ReverseGeocoder::Address addr; coder.GetNearbyAddress(mercator, addr); - info.m_house = addr.GetHouseNumber(); - info.m_street = addr.GetStreetName(); + + // Limit distance to nearest address with 200 meters. + if (addr.GetDistance() < 200.0) + { + info.m_house = addr.GetHouseNumber(); + info.m_street = addr.GetStreetName(); + } return info; } diff --git a/map/framework.cpp b/map/framework.cpp index 710723f343..3f93e5234c 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1305,6 +1305,42 @@ size_t Framework::ShowSearchResults(search::Results const & results) return count; } +search::AddressInfo Framework::GetSearchResultAddress(search::Result const & res) const +{ + search::AddressInfo info; + if (res.IsSuggest()) + return info; + + /// @todo Optimize this stuff according to the facct, that feature is + /// already reading in many cases during process search result. + auto const & id = res.GetFeatureID(); + if (id.IsValid()) + { + Index::FeaturesLoaderGuard loader(m_model.GetIndex(), id.m_mwmId); + FeatureType ft; + loader.GetFeatureByIndex(id.m_index, ft); + if (ft.GetFeatureType() == feature::GEOM_LINE || + !ftypes::IsAddressObjectChecker::Instance()(ft)) + { + return info; + } + } + + info = GetMercatorAddressInfo(res.GetFeatureCenter()); + + string const & type = res.GetFeatureType(); + if (!type.empty()) + info.m_types.push_back(type); + + // Assign name if it's not equal with type. + string const & name = res.GetString(); + if (name != type) + info.m_name = name; + + info.m_city = res.GetRegion(); + return info; +} + void Framework::FillSearchResultsMarks(search::Results const & results) { UserMarkControllerGuard guard(m_bmManager, UserMarkType::SEARCH_MARK); diff --git a/map/framework.hpp b/map/framework.hpp index f991052952..5a228b4a2a 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -403,13 +403,11 @@ public: void LoadSearchResultMetadata(search::Result & res) const; void ShowSearchResult(search::Result const & res); + size_t ShowSearchResults(search::Results const & results); + search::AddressInfo GetSearchResultAddress(search::Result const & res) const; void StartInteractiveSearch(search::SearchParams const & params); - - size_t ShowSearchResults(search::Results const & results); - bool IsInteractiveSearchActive() const { return !m_lastInteractiveSearchParams.m_query.empty(); } - void CancelInteractiveSearch(); list const & GetLastSearchQueries() const { return m_searchQuerySaver.Get(); } diff --git a/qt/search_panel.cpp b/qt/search_panel.cpp index b0d08b33f8..8bf37450f1 100644 --- a/qt/search_panel.cpp +++ b/qt/search_panel.cpp @@ -120,7 +120,7 @@ void SearchPanel::OnSearchResult(ResultsT * res) { ResultT const & e = *i; - QString s = QString::fromUtf8(e.GetString()); + QString s = QString::fromUtf8(e.GetString().c_str()); QString strHigh; int pos = 0; for (size_t r = 0; r < e.GetHighlightRangesCount(); ++r) @@ -138,11 +138,11 @@ void SearchPanel::OnSearchResult(ResultsT * res) int const rowCount = m_pTable->rowCount(); m_pTable->insertRow(rowCount); m_pTable->setCellWidget(rowCount, 1, new QLabel(strHigh)); - m_pTable->setItem(rowCount, 2, create_item(QString::fromUtf8(e.GetRegionString()))); + m_pTable->setItem(rowCount, 2, create_item(QString::fromUtf8(e.GetRegion().c_str()))); if (e.GetResultType() == ResultT::RESULT_FEATURE) { - m_pTable->setItem(rowCount, 0, create_item(QString::fromUtf8(e.GetFeatureType()))); + m_pTable->setItem(rowCount, 0, create_item(QString::fromUtf8(e.GetFeatureType().c_str()))); m_pTable->setItem(rowCount, 3, create_item(m_pDrawWidget->GetDistance(e).c_str())); } diff --git a/search/result.cpp b/search/result.cpp index eceb9a28b5..3e27f56ecd 100644 --- a/search/result.cpp +++ b/search/result.cpp @@ -149,13 +149,9 @@ pair const & Result::GetHighlightRange(size_t idx) const void Result::AppendCity(string const & name) { - if (name.empty()) - return; - - if (m_region.empty()) + // No need to store mwm file name if we have valid city name. + if (!name.empty()) m_region = name; - else - m_region += (", " + name); } string Result::ToStringForStats() const @@ -235,20 +231,6 @@ size_t Results::GetSuggestsCount() const // AddressInfo implementation //////////////////////////////////////////////////////////////////////////////////// -void AddressInfo::MakeFrom(Result const & res) -{ - ASSERT_NOT_EQUAL(res.GetResultType(), Result::RESULT_SUGGEST_PURE, ()); - - string const & type = res.GetFeatureType(); - if (!type.empty()) - m_types.push_back(type); - - // assign name if it's not equal with type - string const & name = res.GetString(); - if (name != type) - m_name = name; -} - bool AddressInfo::IsEmptyName() const { return m_name.empty() && m_house.empty(); @@ -281,12 +263,12 @@ string AddressInfo::FormatPinText() const string AddressInfo::FormatAddress() const { - string result = m_house; - if (!m_street.empty()) + string result = m_street; + if (!m_house.empty()) { if (!result.empty()) - result += ' '; - result += m_street; + result += ", "; + result += m_house; } if (!m_city.empty()) { @@ -342,4 +324,9 @@ void AddressInfo::Clear() m_types.clear(); } +string DebugPrint(AddressInfo const & info) +{ + return info.FormatNameAndAddress(); +} + } // namespace search diff --git a/search/result.hpp b/search/result.hpp index 7a29cc0a86..54b44ef4c4 100644 --- a/search/result.hpp +++ b/search/result.hpp @@ -56,10 +56,10 @@ public: /// Strings that is displayed in the GUI. //@{ - char const * GetString() const { return m_str.c_str(); } - char const * GetRegionString() const { return m_region.c_str(); } - char const * GetFeatureType() const { return m_type.c_str(); } - char const * GetCuisine() const { return m_metadata.m_cuisine.c_str(); } + string const & GetString() const { return m_str; } + string const & GetRegion() const { return m_region; } + string const & GetFeatureType() const { return m_type; } + string const & GetCuisine() const { return m_metadata.m_cuisine; } //@} bool IsClosed() const { return m_metadata.m_isClosed; } @@ -186,8 +186,6 @@ struct AddressInfo string m_country, m_city, m_street, m_house, m_name; vector m_types; - void MakeFrom(search::Result const & res); - string GetPinName() const; // Caroline string GetPinType() const; // shop @@ -198,6 +196,8 @@ struct AddressInfo string GetBestType() const; bool IsEmptyName() const; + friend string DebugPrint(AddressInfo const & info); + void Clear(); }; diff --git a/search/reverse_geocoder.hpp b/search/reverse_geocoder.hpp index c54a0356fe..656620ba39 100644 --- a/search/reverse_geocoder.hpp +++ b/search/reverse_geocoder.hpp @@ -62,6 +62,7 @@ public: string GetHouseNumber() const { return m_building.m_name; } string GetStreetName() const { return m_street.m_name; } + double GetDistance() const { return m_building.m_distanceMeters; } }; void GetNearbyStreets(m2::PointD const & center, vector & streets) const; diff --git a/search/v2/search_model.cpp b/search/v2/search_model.cpp index 786611add9..0715e23f18 100644 --- a/search/v2/search_model.cpp +++ b/search/v2/search_model.cpp @@ -11,6 +11,7 @@ namespace search { namespace v2 { +/// This checkers should be similar with ftypes::IsAddressObjectChecker, plus public transort. namespace { class OneLevelPOIChecker : public ftypes::BaseChecker @@ -20,7 +21,7 @@ public: { Classificator const & c = classif(); - auto paths = {"amenity", "historic", "office", "railway", "shop", "sport", "tourism"}; + auto paths = { "amenity", "historic", "office", "railway", "shop", "sport", "tourism", "craft" }; for (auto const & path : paths) m_types.push_back(c.GetTypeByPath({path})); }