diff --git a/android/build.gradle b/android/build.gradle index 33dfc54100..e8b1bf3b88 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,7 +26,7 @@ buildscript { ext.googleFirebaseServicesEnabled = project.hasProperty('firebase') ?: googleFirebaseServicesDefault dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.3.1' if (googleMobileServicesEnabled) { println("Building with Google Mobile Services") diff --git a/android/jni/com/mapswithme/maps/SearchEngine.cpp b/android/jni/com/mapswithme/maps/SearchEngine.cpp index 3a1ce381af..2a5f4f9c54 100644 --- a/android/jni/com/mapswithme/maps/SearchEngine.cpp +++ b/android/jni/com/mapswithme/maps/SearchEngine.cpp @@ -82,34 +82,26 @@ jobject ToJavaResult(Result const & result, search::ProductInfo const & productI env->ReleaseIntArrayElements(ranges.get(), rawArr, 0); ms::LatLon ll = ms::LatLon::Zero(); - string distance; - double distanceInMeters = 0.0; - if (result.HasPoint()) - { - auto const center = result.GetFeatureCenter(); - ll = mercator::ToLatLon(center); - if (hasPosition) - { - distanceInMeters = ms::DistanceOnEarth(lat, lon, - mercator::YToLat(center.y), - mercator::XToLon(center.x)); - distance = measurement_utils::FormatDistance(distanceInMeters); - } - } - - bool popularityHasHigherPriority = PopularityHasHigherPriority(hasPosition, distanceInMeters); + ll = mercator::ToLatLon(result.GetFeatureCenter()); if (result.IsSuggest()) { jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString())); jni::TScopedLocalRef suggest(env, jni::ToJavaString(env, result.GetSuggestionString())); - jobject ret = env->NewObject(g_resultClass, g_suggestConstructor, name.get(), suggest.get(), ll.m_lat, ll.m_lon, ranges.get()); - ASSERT(ret, ()); - return ret; + return env->NewObject(g_resultClass, g_suggestConstructor, name.get(), suggest.get(), ll.m_lat, ll.m_lon, ranges.get()); } - auto const isFeature = result.GetResultType() == Result::Type::Feature; + string distance; + double distanceInMeters = 0.0; + if (result.HasPoint() && hasPosition) + { + distanceInMeters = ms::DistanceOnEarth(lat, lon, ll.m_lat, ll.m_lon); + distance = measurement_utils::FormatDistance(distanceInMeters); + } + + bool const popularityHasHigherPriority = PopularityHasHigherPriority(hasPosition, distanceInMeters); + bool const isFeature = result.GetResultType() == Result::Type::Feature; jni::TScopedLocalRef featureId(env, usermark_helper::CreateFeatureId(env, isFeature ? result.GetFeatureID() : kEmptyFeatureId)); @@ -137,12 +129,9 @@ jobject ToJavaResult(Result const & result, search::ProductInfo const & productI g_popularityConstructor, /// @todo Restore when popularity will be available 0/*static_cast(result.GetRankingInfo().m_popularity)*/)); - jobject ret = - env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.m_lat, ll.m_lon, - ranges.get(), result.IsHotel(), result.GetStarsCount(), popularity.get()); - ASSERT(ret, ()); - return ret; + return env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.m_lat, ll.m_lon, + ranges.get(), result.IsHotel(), result.GetStarsCount(), popularity.get()); } jobjectArray BuildSearchResults(vector const & productInfo, diff --git a/android/src/com/mapswithme/maps/search/SearchAdapter.java b/android/src/com/mapswithme/maps/search/SearchAdapter.java index 0862167911..c0f711bb67 100644 --- a/android/src/com/mapswithme/maps/search/SearchAdapter.java +++ b/android/src/com/mapswithme/maps/search/SearchAdapter.java @@ -25,9 +25,6 @@ import com.mapswithme.util.ThemeUtils; import com.mapswithme.util.UiUtils; import com.mapswithme.util.Utils; -import static com.mapswithme.maps.search.SearchResult.TYPE_RESULT; -import static com.mapswithme.maps.search.SearchResult.TYPE_SUGGEST; - class SearchAdapter extends RecyclerView.Adapter { private final SearchFragment mSearchFragment; @@ -123,7 +120,7 @@ class SearchAdapter extends RecyclerView.Adapter -#include #include namespace dp @@ -231,22 +227,23 @@ std::string SquareHandle::GetOverlayDebugInfo() } #endif +/// @param[in] minZoomLevel Minimum visible zoom level (less is better) +/// @param[in] rank Rank of the feature (bigger is better) +/// @param[in] depth Manual priority from styles (bigger is better) uint64_t CalculateOverlayPriority(int minZoomLevel, uint8_t rank, float depth) { - // Overlay priority consider the following: - // - Minimum visible zoom level (the less the better); - // - Manual priority from styles (equals to the depth); - // - Rank of the feature (the more the better); - // [1 byte - zoom][4 bytes - priority][1 byte - rank][2 bytes - 0xFFFF]. - uint8_t const minZoom = 0xFF - static_cast(std::max(minZoomLevel, 0)); + // Even if minZoomLevel < 0 (-1 is not visible), we will get more consistent |minZoom| value (less is worse). + ASSERT_GREATER_OR_EQUAL(minZoomLevel, 0, ()); + uint8_t const minZoom = 0xFF - static_cast(minZoomLevel); - float const kMinDepth = -100000.0f; - float const kMaxDepth = 100000.0f; + float constexpr kMinDepth = -100000.0f; + float constexpr kMaxDepth = 100000.0f; float const d = base::Clamp(depth, kMinDepth, kMaxDepth) - kMinDepth; - auto const priority = static_cast(d); + // Pack into uint64_t priority value (bigger is better). + // [1 byte - zoom][4 bytes - priority][1 byte - rank][2 bytes - 0xFFFF]. return (static_cast(minZoom) << 56) | - (static_cast(priority) << 24) | + (static_cast(d) << 24) | (static_cast(rank) << 16) | static_cast(0xFFFF); } diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 6c6e923d04..9ff3181a23 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1882,14 +1882,12 @@ void FrontendRenderer::BuildOverlayTree(ScreenBase const & modelView) void FrontendRenderer::PrepareBucket(dp::RenderState const & state, drape_ptr & bucket) { CHECK(m_context != nullptr, ()); - auto program = m_gpuProgramManager->GetProgram(state.GetProgram()); - auto program3d = m_gpuProgramManager->GetProgram(state.GetProgram3d()); - bool const isPerspective = m_userEventStream.GetCurrentScreen().isPerspective(); - if (isPerspective) - program3d->Bind(); - else - program->Bind(); - bucket->GetBuffer()->Build(m_context, isPerspective ? program3d : program); + + auto program = m_gpuProgramManager->GetProgram(m_userEventStream.GetCurrentScreen().isPerspective() ? + state.GetProgram3d() : state.GetProgram()); + + program->Bind(); + bucket->GetBuffer()->Build(m_context, program); } void FrontendRenderer::RenderSingleGroup(ref_ptr context, diff --git a/generator/generator_tests_support/test_feature.hpp b/generator/generator_tests_support/test_feature.hpp index dde4110c55..654878d446 100644 --- a/generator/generator_tests_support/test_feature.hpp +++ b/generator/generator_tests_support/test_feature.hpp @@ -171,7 +171,7 @@ public: void SetHouseNumber(std::string const & houseNumber) { m_houseNumber = houseNumber; } void SetStreetName(std::string_view name) { m_streetName = name; } - void SetType(uint32_t type) { m_types.assign(1 /* count */, type); } + void SetTypes(std::initializer_list const & types) { m_types.assign(types); } void SetTypes(std::initializer_list const & types); protected: diff --git a/indexer/feature_visibility.cpp b/indexer/feature_visibility.cpp index 6dc0fdceeb..53a65d4f04 100644 --- a/indexer/feature_visibility.cpp +++ b/indexer/feature_visibility.cpp @@ -114,9 +114,6 @@ namespace return false; } - /// Warning: Geometry of features with always existing types will be indexed in mwm on all - /// zoom levels. If you add an always existing type to drawing types, the displacement of icons - /// may work not correctly. bool TypeAlwaysExists(uint32_t type, GeomType g = GeomType::Undefined) { auto const & cl = classif(); @@ -189,6 +186,11 @@ namespace /// @} } // namespace +bool IsCategoryNondrawableType(uint32_t type) +{ + return TypeAlwaysExists(type); +} + bool IsUsefulType(uint32_t type) { return IsUsefulNondrawableType(type) || classif().GetObject(type)->IsDrawableAny(); @@ -241,7 +243,9 @@ bool IsDrawableForIndexClassifOnly(TypesHolder const & types, int level) Classificator const & c = classif(); for (uint32_t t : types) { - if (TypeAlwaysExists(t) || c.GetObject(t)->IsDrawable(level)) + // By VNG: TypeAlwaysExists check was removed. These kind of types (internet, recycling, fee, access, etc) + // should NOT influence on draw priority and index visibility. Some fancy logic may be broken .. + if (c.GetObject(t)->IsDrawable(level)) return true; } diff --git a/indexer/feature_visibility.hpp b/indexer/feature_visibility.hpp index 941e499f67..cab998262b 100644 --- a/indexer/feature_visibility.hpp +++ b/indexer/feature_visibility.hpp @@ -18,6 +18,7 @@ namespace feature { class TypesHolder; + bool IsCategoryNondrawableType(uint32_t type); bool IsUsefulType(uint32_t type); bool IsDrawableForIndex(FeatureType & ft, int level); bool IsDrawableForIndex(TypesHolder const & types, m2::RectD limitRect, int level); diff --git a/indexer/search_string_utils.cpp b/indexer/search_string_utils.cpp index df921463f5..0cdb24be2b 100644 --- a/indexer/search_string_utils.cpp +++ b/indexer/search_string_utils.cpp @@ -292,9 +292,8 @@ public: } private: - /// @todo Print most common street tokens for each country on generator stage (OSM ground truth) - /// and compare with these synonyms. - /// For example, I have doubts about: 'gaten', 'granden', 'vagen', XXXen nordic synonyms. + /// @todo Print most common street tokens for each country on generator stage + /// (OSM ground truth) and compare with these synonyms. StreetsSynonymsHolder() { char const * affics[] = @@ -365,7 +364,8 @@ private: "मार्ग", "marg", // Norwegian - Norsk - "vei", "veien", "vn", "gate", "gaten", "gt", "plass", "plassen", "sving", "svingen", "sv", + // Details here: https://github.com/organicmaps/organicmaps/issues/3616 + "vei", "veien", "veg", "vegen", "vn", "gata", "gate", "gaten", "gt", "plass", "plassen", "sving", "sv", "allé", // Polish - Polski "aleja", "aleje", "aleji", "alejach", "aleją", "plac", "placu", "placem", "ulica", "ulicy", diff --git a/iphone/Maps/Core/Search/MWMSearch.mm b/iphone/Maps/Core/Search/MWMSearch.mm index 9428b86ab1..8c4cadf252 100644 --- a/iphone/Maps/Core/Search/MWMSearch.mm +++ b/iphone/Maps/Core/Search/MWMSearch.mm @@ -174,14 +174,6 @@ using Observers = NSHashTable; return [MWMSearch manager]->m_productInfo[index]; } -+ (BOOL)isFeatureAt:(NSUInteger)index in:(std::vector const &)array { - auto const &result = [self resultWithContainerIndex:index]; - if (result.GetResultType() != search::Result::Type::Feature) - return NO; - auto const &resultFeatureID = result.GetFeatureID(); - return std::binary_search(array.begin(), array.end(), resultFeatureID); -} - + (MWMSearchItemType)resultTypeWithRow:(NSUInteger)row { auto itemsIndex = [MWMSearch manager].itemsIndex; return [itemsIndex resultTypeWithRow:row]; diff --git a/iphone/Maps/Core/Search/MWMSearchItemType.h b/iphone/Maps/Core/Search/MWMSearchItemType.h index 77bd68e899..c0466510de 100644 --- a/iphone/Maps/Core/Search/MWMSearchItemType.h +++ b/iphone/Maps/Core/Search/MWMSearchItemType.h @@ -1,7 +1,5 @@ typedef NS_ENUM(NSUInteger, MWMSearchItemType) { // Order == priority. MWMSearchItemTypeRegular, - MWMSearchItemTypeMopub, - MWMSearchItemTypeFacebook, MWMSearchItemTypeSuggestion }; diff --git a/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm b/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm index 0ce971bfe1..c3b25ab909 100644 --- a/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm +++ b/iphone/Maps/UI/Search/TableView/MWMSearchTableViewController.mm @@ -81,28 +81,26 @@ NSString *GetLocalizedTypeName(search::Result const &result) { NSAssert(false, @"Invalid reload with outdated SearchIndex"); return [tableView dequeueReusableCellWithCellClass:[MWMSearchCommonCell class] indexPath:indexPath]; } + auto const row = indexPath.row; auto const containerIndex = [MWMSearch containerIndexWithRow:row]; - switch ([MWMSearch resultTypeWithRow:row]) { - case MWMSearchItemTypeRegular: { - auto cell = - static_cast([tableView dequeueReusableCellWithCellClass:[MWMSearchCommonCell class] - indexPath:indexPath]); - auto const &result = [MWMSearch resultWithContainerIndex:containerIndex]; - auto const &productInfo = [MWMSearch productInfoWithContainerIndex:containerIndex]; - auto const typeName = GetLocalizedTypeName(result); - [cell config:result productInfo:productInfo - localizedTypeName:typeName]; + auto const & result = [MWMSearch resultWithContainerIndex:containerIndex]; + + switch ([MWMSearch resultTypeWithRow:row]) + { + case MWMSearchItemTypeRegular: + { + auto cell = static_cast( + [tableView dequeueReusableCellWithCellClass:[MWMSearchCommonCell class] indexPath:indexPath]); + auto const & productInfo = [MWMSearch productInfoWithContainerIndex:containerIndex]; + [cell config:result productInfo:productInfo localizedTypeName:GetLocalizedTypeName(result)]; return cell; } - case MWMSearchItemTypeMopub: - case MWMSearchItemTypeFacebook: { - } - case MWMSearchItemTypeSuggestion: { + case MWMSearchItemTypeSuggestion: + { auto cell = static_cast( [tableView dequeueReusableCellWithCellClass:[MWMSearchSuggestionCell class] indexPath:indexPath]); - auto const &suggestion = [MWMSearch resultWithContainerIndex:containerIndex]; - [cell config:suggestion localizedTypeName:@""]; + [cell config:result localizedTypeName:@""]; cell.isLastCell = row == [MWMSearch suggestionsCount] - 1; return cell; } @@ -115,22 +113,22 @@ NSString *GetLocalizedTypeName(search::Result const &result) { id delegate = self.delegate; auto const row = indexPath.row; auto const containerIndex = [MWMSearch containerIndexWithRow:row]; - switch ([MWMSearch resultTypeWithRow:row]) { - case MWMSearchItemTypeRegular: { - SearchTextField *textField = delegate.searchTextField; + auto const & result = [MWMSearch resultWithContainerIndex:containerIndex]; + + switch ([MWMSearch resultTypeWithRow:row]) + { + case MWMSearchItemTypeRegular: + { + SearchTextField const * textField = delegate.searchTextField; [MWMSearch saveQuery:textField.text forInputLocale:textField.textInputMode.primaryLanguage]; - auto const &result = [MWMSearch resultWithContainerIndex:containerIndex]; [delegate processSearchWithResult:result]; break; } - case MWMSearchItemTypeMopub: - case MWMSearchItemTypeFacebook: + case MWMSearchItemTypeSuggestion: + { + [delegate searchText:@(result.GetSuggestionString().c_str()) forInputLocale:nil + withCategory:result.GetResultType() == search::Result::Type::PureSuggest]; break; - case MWMSearchItemTypeSuggestion: { - auto const &suggestion = [MWMSearch resultWithContainerIndex:containerIndex]; - NSString *suggestionString = @(suggestion.GetSuggestionString().c_str()); - /// @todo Pass withCategory:YES if we tap on category suggestion (not street or city)? - [delegate searchText:suggestionString forInputLocale:nil withCategory:NO]; } } } diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp index 11a09f456d..c00b118daa 100644 --- a/search/search_integration_tests/processor_test.cpp +++ b/search/search_integration_tests/processor_test.cpp @@ -3169,14 +3169,12 @@ UNIT_CLASS_TEST(ProcessorTest, PoiStreetCity_FancyMatch) UNIT_CLASS_TEST(ProcessorTest, ComplexPoi_Rank) { - auto const & cl = classif(); - TestBuilding landuse({-1, -1, 1, 1}, "Telekom", "5", "xxx", "de"); - landuse.AddType(cl.GetTypeByPath({"landuse", "commercial"})); + landuse.AddType(classif().GetTypeByPath({"landuse", "commercial"})); TestPOI poiInMall({0, 0}, "yyy", "de"); - poiInMall.SetType(cl.GetTypeByPath({"shop", "clothes"})); + poiInMall.SetTypes({{"shop", "clothes"}}); TestPOI telekom({2, 2}, "Telekom shop", "de"); - telekom.SetType(cl.GetTypeByPath({"shop", "mobile_phone"})); + telekom.SetTypes({{"shop", "mobile_phone"}}); auto countryId = BuildCountry("Wonderland", [&](TestMwmBuilder & builder) { diff --git a/search/search_integration_tests/smoke_test.cpp b/search/search_integration_tests/smoke_test.cpp index 1ab7a0a78f..34a9fdccdb 100644 --- a/search/search_integration_tests/smoke_test.cpp +++ b/search/search_integration_tests/smoke_test.cpp @@ -12,6 +12,7 @@ #include "indexer/classificator.hpp" #include "indexer/feature_meta.hpp" +#include "indexer/feature_visibility.hpp" #include "geometry/point2d.hpp" #include "geometry/rect2d.hpp" @@ -156,7 +157,7 @@ UNIT_CLASS_TEST(SmokeTest, TypesSkipperTest) auto const & cl = classif(); for (auto const & path : arr) { - feature::TypesHolder types; + TypesHolder types; types.Add(cl.GetTypeByPath(path)); TEST(!skipper.SkipAlways(types), (path)); @@ -226,28 +227,32 @@ UNIT_CLASS_TEST(SmokeTest, CategoriesTest) auto const & holder = GetDefaultCategories(); + uint32_t const cafeType = cl.GetTypeByPath({"amenity", "cafe"}); + auto testCategory = [&](uint32_t type, CategoriesHolder::Category const &) { - if (invisibleTypes.find(type) != invisibleTypes.end()) + if (invisibleTypes.count(type) > 0) return; bool categoryIsSearchable = true; - if (notSupportedTypes.find(type) != notSupportedTypes.end()) + if (notSupportedTypes.count(type) > 0) categoryIsSearchable = false; string const countryName = "Wonderland"; TestPOI poi(m2::PointD(1.0, 1.0), "poi", "en"); - poi.SetType(type); + if (IsCategoryNondrawableType(type)) + poi.SetTypes({type, cafeType}); + else + poi.SetTypes({type}); auto id = BuildMwm(countryName, DataHeader::MapType::Country, [&](TestMwmBuilder & builder) { builder.AddSafe(poi); }); - { - Rules rules = {ExactMatch(id, poi)}; - auto const query = holder.GetReadableFeatureType(type, CategoriesHolder::kEnglishCode); - TEST(CategoryMatch(query, categoryIsSearchable ? rules : Rules{}), (query)); - } + Rules rules = {ExactMatch(id, poi)}; + auto const query = holder.GetReadableFeatureType(type, CategoriesHolder::kEnglishCode); + TEST(CategoryMatch(query, categoryIsSearchable ? rules : Rules{}), (query)); + DeregisterMap(countryName); };