From b269834946b2c0674e6c28f6be97849e0d01a0d5 Mon Sep 17 00:00:00 2001 From: vng Date: Sun, 28 Feb 2021 12:56:12 +0300 Subject: [PATCH 01/16] [drape] Do not draw 3D area with more than 10K vertexes. Signed-off-by: vng --- drape_frontend/area_shape.cpp | 5 ++++- drape_frontend/backend_renderer.cpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drape_frontend/area_shape.cpp b/drape_frontend/area_shape.cpp index 46c94e5cc1..ff702c0a72 100644 --- a/drape_frontend/area_shape.cpp +++ b/drape_frontend/area_shape.cpp @@ -41,7 +41,10 @@ void AreaShape::Draw(ref_ptr context, ref_ptr } if (m_params.m_is3D) - DrawArea3D(context, batcher, colorUv, outlineUv, region.GetTexture()); + { + if (m_vertexes.size() < 10000) + DrawArea3D(context, batcher, colorUv, outlineUv, region.GetTexture()); + } else if (m_params.m_hatching) DrawHatchingArea(context, batcher, colorUv, region.GetTexture(), textures->GetHatchingTexture()); else diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 43216af1a9..6f127ce92b 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -695,7 +695,9 @@ void BackendRenderer::RenderFrame() void BackendRenderer::InitContextDependentResources() { + // Increase this value for big features. uint32_t constexpr kBatchSize = 5000; + m_batchersPool = make_unique_dp>(kReadingThreadsCount, std::bind(&BackendRenderer::FlushGeometry, this, _1, _2, _3), kBatchSize, kBatchSize); -- 2.45.3 From 2df3cb338df447c15cc86b32826b900956b4702c Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sun, 11 Jun 2023 10:40:21 -0300 Subject: [PATCH 02/16] [routing] Service speed factor <= Tertiary speed factor. Signed-off-by: Viktor Govako --- routing/routing_integration_tests/turn_test.cpp | 14 ++++++++++++++ routing_common/car_model_coefs.hpp | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/routing/routing_integration_tests/turn_test.cpp b/routing/routing_integration_tests/turn_test.cpp index e154b210ae..a8dc973243 100644 --- a/routing/routing_integration_tests/turn_test.cpp +++ b/routing/routing_integration_tests/turn_test.cpp @@ -1296,6 +1296,20 @@ UNIT_TEST(Cyprus_A1_A5_TurnTestNextRoad) TEST_EQUAL(ri.m_destination_ref, "A5", ()); } +UNIT_TEST(Zurich_UseMainTurn) +{ + TRouteResult const routeResult = + integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Car), + mercator::FromLatLon(47.364832, 8.5656975), {0., 0.}, + mercator::FromLatLon(47.3640678, 8.56567312)); + + Route const & route = *routeResult.first; + RouterResultCode const result = routeResult.second; + TEST_EQUAL(result, RouterResultCode::NoError, ()); + integration::TestTurnCount(route, 1); + integration::TestRouteLength(route, 135.573); +} + namespace { template void TestNoTurns(ContT const & cont) diff --git a/routing_common/car_model_coefs.hpp b/routing_common/car_model_coefs.hpp index 6f4f3c1e1e..04b85014e6 100644 --- a/routing_common/car_model_coefs.hpp +++ b/routing_common/car_model_coefs.hpp @@ -35,8 +35,8 @@ HighwayBasedFactors const kHighwayBasedFactors = { // By VNG: Changed 0.3 -> 0.95 for Road and 0.3 -> 1.0 for Track. // They are already have very small speeds (10, 5 respectively). // There are no (99%) traffic lights or pedestrian crossings on this kind of roads. - {HighwayType::HighwayService, InOutCityFactor(0.80)}, - {HighwayType::HighwayRoad, InOutCityFactor(0.95)}, + {HighwayType::HighwayService, InOutCityFactor(0.70)}, + {HighwayType::HighwayRoad, InOutCityFactor(0.90)}, {HighwayType::HighwayTrack, InOutCityFactor(1.0)}, {HighwayType::ManMadePier, InOutCityFactor(0.90)}, -- 2.45.3 From fe8b552d36ef47b03564a83fa28339530d417b6b Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sun, 4 Jun 2023 18:18:36 -0300 Subject: [PATCH 03/16] [search] Fixed airport search with empty names. Signed-off-by: Viktor Govako --- search/ranker.cpp | 4 +-- .../search_quality_tests/real_mwm_tests.cpp | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/search/ranker.cpp b/search/ranker.cpp index f823b9f9d1..cd09b7268e 100644 --- a/search/ranker.cpp +++ b/search/ranker.cpp @@ -374,8 +374,8 @@ public: }, Delimiters()); // Factor is a number of the rest, not common matched tokens in Feature' name. Bigger is worse. - info.m_commonTokensFactor = min(3, count - int(info.m_tokenRanges[info.m_type].Size())); - ASSERT_GREATER_OR_EQUAL(info.m_commonTokensFactor, 0, ()); + // Example when count == 0: UTH airport has empty name, but "ut" is a _common_ token. + info.m_commonTokensFactor = min(3, std::max(0, count - int(info.m_tokenRanges[info.m_type].Size()))); } res.SetRankingInfo(info); diff --git a/search/search_quality/search_quality_tests/real_mwm_tests.cpp b/search/search_quality/search_quality_tests/real_mwm_tests.cpp index b4985d1cdd..7036cacb76 100644 --- a/search/search_quality/search_quality_tests/real_mwm_tests.cpp +++ b/search/search_quality/search_quality_tests/real_mwm_tests.cpp @@ -530,4 +530,33 @@ UNIT_CLASS_TEST(MwmTestsFixture, Generic_Buildings_Rank) TEST_LESS(SortedByDistance(range, center), 1000.0, ()); } } + +UNIT_CLASS_TEST(MwmTestsFixture, UTH_Airport) +{ + auto const aeroportType = classif().GetTypeByPath({"aeroway", "aerodrome", "international"}); + + // Under UTH airport. + ms::LatLon const center(17.3867863, 102.7775625); + SetViewportAndLoadMaps(center); + + // "ut" query is _common_ + auto request = MakeRequest("ut", "en"); + auto const & results = request->Results(); + + bool found = false; + // The first 5 will be cities suggestions. + for (size_t i = 0; i < 10; ++i) + { + auto const & r = results[i]; + if (r.GetResultType() == search::Result::Type::Feature && + EqualClassifType(r.GetFeatureType(), aeroportType)) + { + found = true; + break; + } + } + + TEST(found, (results)); +} + } // namespace real_mwm_tests -- 2.45.3 From 8b018de74dffb50bdc79099176943ec0cc4f2e44 Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sun, 4 Jun 2023 18:37:21 -0300 Subject: [PATCH 04/16] [search][generator] Do not generate ranks for Transport POIs. Signed-off-by: Viktor Govako --- indexer/caching_rank_table_loader.cpp | 9 +- indexer/caching_rank_table_loader.hpp | 4 +- indexer/indexer_tests/rank_table_test.cpp | 57 +---- indexer/rank_table.cpp | 211 +++--------------- indexer/rank_table.hpp | 4 +- search/dummy_rank_table.cpp | 6 +- .../search_quality_tests/real_mwm_tests.cpp | 17 +- 7 files changed, 50 insertions(+), 258 deletions(-) diff --git a/indexer/caching_rank_table_loader.cpp b/indexer/caching_rank_table_loader.cpp index dbaa3627ba..e540c7a797 100644 --- a/indexer/caching_rank_table_loader.cpp +++ b/indexer/caching_rank_table_loader.cpp @@ -3,14 +3,7 @@ #include "search/dummy_rank_table.hpp" #include "indexer/data_source.hpp" -#include "indexer/feature.hpp" -#include "defines.hpp" - -namespace -{ -uint8_t const kNoRank = 0; -} // namespace CachingRankTableLoader::CachingRankTableLoader(DataSource const & dataSource, std::string const & sectionName) @@ -23,7 +16,7 @@ uint8_t CachingRankTableLoader::Get(FeatureID const & featureId) const auto const handle = m_dataSource.GetMwmHandleById(featureId.m_mwmId); if (!handle.IsAlive()) - return kNoRank; + return search::RankTable::kNoRank; auto it = m_deserializers.find(featureId.m_mwmId); diff --git a/indexer/caching_rank_table_loader.hpp b/indexer/caching_rank_table_loader.hpp index 2e80429ae7..c8dc5d5b40 100644 --- a/indexer/caching_rank_table_loader.hpp +++ b/indexer/caching_rank_table_loader.hpp @@ -6,7 +6,6 @@ #include "base/macros.hpp" -#include #include #include #include @@ -20,13 +19,14 @@ class CachingRankTableLoader public: CachingRankTableLoader(DataSource const & dataSource, std::string const & sectionName); + /// @return 0 if there is no rank for feature. uint8_t Get(FeatureID const & featureId) const; void OnMwmDeregistered(platform::LocalCountryFile const & localFile); private: DataSource const & m_dataSource; std::string const m_sectionName; - mutable std::map const> m_deserializers; + mutable std::map> m_deserializers; DISALLOW_COPY(CachingRankTableLoader); }; diff --git a/indexer/indexer_tests/rank_table_test.cpp b/indexer/indexer_tests/rank_table_test.cpp index 879c33dc86..07a4287011 100644 --- a/indexer/indexer_tests/rank_table_test.cpp +++ b/indexer/indexer_tests/rank_table_test.cpp @@ -85,8 +85,7 @@ UNIT_TEST(RankTableBuilder_EndToEnd) base::CopyFileX(originalMapPath, mapPath); SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, mapPath)); - platform::LocalCountryFile localFile = - platform::LocalCountryFile::MakeForTesting("minsk-pass-copy"); + auto const localFile = platform::LocalCountryFile::MakeForTesting("minsk-pass-copy"); TEST(localFile.OnDisk(MapFileType::Map), ()); vector ranks; @@ -106,57 +105,3 @@ UNIT_TEST(RankTableBuilder_EndToEnd) TestTable(ranks, mapPath); } - -UNIT_TEST(RankTableBuilder_WrongEndianness) -{ - char const kTestFile[] = "test.mwm"; - SCOPE_GUARD(cleanup, bind(&FileWriter::DeleteFileX, kTestFile)); - - vector ranks = {0, 1, 2, 3, 4}; - { - FilesContainerW wcont(kTestFile); - search::RankTableBuilder::Create(ranks, wcont, SEARCH_RANKS_FILE_TAG); - } - - // Load rank table in host endianness. - unique_ptr table; - { - FilesContainerR rcont(kTestFile); - table = search::RankTable::Load(rcont, SEARCH_RANKS_FILE_TAG); - TEST(table.get(), ()); - TestTable(ranks, *table); - } - - // Serialize rank table in opposite endianness. - { - vector data; - { - MemWriter writer(data); - table->Serialize(writer, false /* preserveHostEndianness */); - } - - FilesContainerW wcont(kTestFile); - wcont.Write(data, SEARCH_RANKS_FILE_TAG); - } - - // Try to load rank table from opposite endianness. - { - FilesContainerR rcont(kTestFile); - auto table = search::RankTable::Load(rcont, SEARCH_RANKS_FILE_TAG); - TEST(table.get(), ()); - TestTable(ranks, *table); - } - - // It's impossible to map rank table from opposite endianness. - { - FilesMappingContainer mcont(kTestFile); - auto table = search::RankTable::Load(mcont, SEARCH_RANKS_FILE_TAG); - TEST(!table.get(), ()); - } - - // Try to re-create rank table in test file. - TEST(search::SearchRankTableBuilder::CreateIfNotExists(kTestFile), ()); - - // Try to load and map rank table - both methods should work now. - TestTable(ranks, kTestFile); -} diff --git a/indexer/rank_table.cpp b/indexer/rank_table.cpp index d7511fbf6e..348e05d00a 100644 --- a/indexer/rank_table.cpp +++ b/indexer/rank_table.cpp @@ -1,17 +1,10 @@ #include "indexer/rank_table.hpp" -#include "indexer/classificator.hpp" #include "indexer/data_header.hpp" -#include "indexer/feature_algo.hpp" #include "indexer/feature_impl.hpp" -#include "indexer/feature_utils.hpp" #include "indexer/features_vector.hpp" #include "indexer/ftypes_matcher.hpp" -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" - -#include "coding/endianness.hpp" #include "coding/files_container.hpp" #include "coding/file_writer.hpp" #include "coding/memory_region.hpp" @@ -20,54 +13,30 @@ #include "coding/succinct_mapper.hpp" #include "coding/writer.hpp" -#include "base/assert.hpp" +#include "base/exception.hpp" #include "base/logging.hpp" -#include "base/macros.hpp" -#include "base/math.hpp" #include -#include #include -#include #include "defines.hpp" -using namespace std; namespace search { +using namespace std; + namespace { -uint64_t const kVersionOffset = 0; -uint64_t const kFlagsOffset = 1; -uint64_t const kHeaderSize = 8; - -enum class CheckResult -{ - CorruptedHeader, - EndiannessMismatch, - EndiannessMatch -}; - -template -CheckResult CheckEndianness(TReader && reader) -{ - if (reader.Size() < kHeaderSize) - return CheckResult::CorruptedHeader; - uint8_t flags; - reader.Read(kFlagsOffset, &flags, sizeof(flags)); - bool const isHostBigEndian = IsBigEndianMacroBased(); - bool const isDataBigEndian = flags & 1; - if (isHostBigEndian != isDataBigEndian) - return CheckResult::EndiannessMismatch; - return CheckResult::EndiannessMatch; -} +size_t constexpr kVersionOffset = 0; +size_t constexpr kHeaderSize = 8; unique_ptr GetMemoryRegionForTag(FilesContainerR const & rcont, FilesContainerBase::Tag const & tag) { if (!rcont.IsExist(tag)) - return unique_ptr(); + return {}; + FilesContainerR::TReader reader = rcont.GetReader(tag); vector buffer(static_cast(reader.Size())); reader.Read(0, buffer.data(), buffer.size()); @@ -78,13 +47,13 @@ unique_ptr GetMemoryRegionForTag(FilesMappingContainer const FilesContainerBase::Tag const & tag) { if (!mcont.IsExist(tag)) - return unique_ptr(); + return {}; + FilesMappingContainer::Handle handle = mcont.Map(tag); return make_unique(std::move(handle)); } -// RankTable version 1, uses simple dense coding to store and access -// array of ranks. +// RankTable version 0, uses simple dense coding to store and access array of ranks. class RankTableV0 : public RankTable { public: @@ -99,7 +68,7 @@ public: // May be there is a better way to inject this code. Without this check search engine crashes here. //ASSERT_LESS(i, Size(), ()); if (i >= Size()) - return 0; + return kNoRank; return m_coding.Get(i); } @@ -107,60 +76,23 @@ public: RankTable::Version GetVersion() const override { return V0; } void Serialize(Writer & writer, bool preserveHostEndianness) override { - static uint64_t const padding = 0; - uint8_t const version = GetVersion(); - uint8_t const flags = preserveHostEndianness ? IsBigEndianMacroBased() : !IsBigEndianMacroBased(); - writer.Write(&version, sizeof(version)); - writer.Write(&flags, sizeof(flags)); - writer.Write(&padding, 6); - if (preserveHostEndianness) - Freeze(m_coding, writer, "SimpleDenseCoding"); - else - ReverseFreeze(m_coding, writer, "SimpleDenseCoding"); + size_t constexpr kVersionSize = sizeof(version); + writer.Write(&version, kVersionSize); + + uint64_t const padding = 0; + static_assert(kHeaderSize % 8 == 0); // next succinct vector should be aligned + writer.Write(&padding, kHeaderSize - kVersionSize); + + Freeze(m_coding, writer, "SimpleDenseCoding"); } // Loads RankTableV0 from a raw memory region. - static unique_ptr Load(unique_ptr && region) + template static unique_ptr Load(unique_ptr && region) { - if (!region.get()) - return unique_ptr(); - - auto const result = - CheckEndianness(MemReader(region->ImmutableData(), static_cast(region->Size()))); - if (result != CheckResult::EndiannessMatch) - return unique_ptr(); - auto table = make_unique(); - coding::Map(table->m_coding, region->ImmutableData() + kHeaderSize, "SimpleDenseCoding"); table->m_region = std::move(region); - return table; - } - - // Loads RankTableV0 from a raw memory region. Modifies region in - // the case of endianness mismatch. - static unique_ptr Load(unique_ptr && region) - { - if (!region.get()) - return unique_ptr(); - - unique_ptr table; - switch ( - CheckEndianness(MemReader(region->ImmutableData(), static_cast(region->Size())))) - { - case CheckResult::CorruptedHeader: - break; - case CheckResult::EndiannessMismatch: - table.reset(new RankTableV0()); - coding::ReverseMap(table->m_coding, region->MutableData() + kHeaderSize, "SimpleDenseCoding"); - table->m_region = std::move(region); - break; - case CheckResult::EndiannessMatch: - table.reset(new RankTableV0()); - coding::Map(table->m_coding, region->ImmutableData() + kHeaderSize, "SimpleDenseCoding"); - table->m_region = std::move(region); - break; - } + coding::Map(table->m_coding, table->m_region->ImmutableData() + kHeaderSize, "SimpleDenseCoding"); return table; } @@ -176,7 +108,6 @@ void SerializeRankTable(RankTable & table, FilesContainerW & wcont, string const { if (wcont.IsExist(sectionName)) wcont.DeleteSection(sectionName); - ASSERT(!wcont.IsExist(sectionName), ()); vector buffer; { @@ -217,77 +148,22 @@ unique_ptr LoadRankTable(unique_ptr && region) return {}; } -uint8_t CalcEventRank(FeatureType & /*ft*/) -{ - //TODO: add custom event processing, i.e. fc2018. - return 0; -} - -uint8_t CalcTransportRank(FeatureType & ft) -{ - uint8_t const kTransportRank = 2; - if (ftypes::IsRailwayStationChecker::Instance()(ft) || - ftypes::IsSubwayStationChecker::Instance()(ft) || ftypes::IsAirportChecker::Instance()(ft)) - { - return kTransportRank; - } - - return 0; -} - // Calculates search rank for a feature. uint8_t CalcSearchRank(FeatureType & ft) { - auto const eventRank = CalcEventRank(ft); - auto const transportRank = CalcTransportRank(ft); - auto const populationRank = feature::PopulationToRank(ftypes::GetPopulation(ft)); - - return base::Clamp(eventRank + transportRank + populationRank, 0, - static_cast(numeric_limits::max())); + return feature::PopulationToRank(ftypes::GetPopulation(ft)); } // Creates rank table if it does not exists in |rcont| or has wrong -// endianness. Otherwise (table exists and has correct format) returns -// null. +// endianness. Otherwise (table exists and has correct format) returns null. unique_ptr CreateSearchRankTableIfNotExists(FilesContainerR & rcont) { - unique_ptr table; - if (rcont.IsExist(SEARCH_RANKS_FILE_TAG)) - { - switch (CheckEndianness(rcont.GetReader(SEARCH_RANKS_FILE_TAG))) - { - case CheckResult::CorruptedHeader: - { - // Worst case - we need to create rank table from scratch. - break; - } - case CheckResult::EndiannessMismatch: - { - // Try to copy whole serialized data and instantiate table via - // reverse mapping. - auto region = GetMemoryRegionForTag(rcont, SEARCH_RANKS_FILE_TAG); - table = LoadRankTable(std::move(region)); - break; - } - case CheckResult::EndiannessMatch: - { - // Table exists and has proper format. Nothing to do here. - return unique_ptr(); - } - } - } + return {}; - // Table doesn't exist or has wrong format. It's better to create it - // from scratch. - if (!table) - { - vector ranks; - SearchRankTableBuilder::CalcSearchRanks(rcont, ranks); - table = make_unique(ranks); - } - - return table; + vector ranks; + SearchRankTableBuilder::CalcSearchRanks(rcont, ranks); + return make_unique(ranks); } } // namespace @@ -313,37 +189,6 @@ void SearchRankTableBuilder::CalcSearchRanks(FilesContainerR & rcont, vector table; - { - ModelReaderPtr reader = platform::GetCountryReader(localFile, MapFileType::Map); - if (!reader.GetPtr()) - return false; - - mapPath = reader.GetName(); - - FilesContainerR rcont(reader); - table = CreateSearchRankTableIfNotExists(rcont); - } - - if (table) - SerializeRankTable(*table, mapPath, SEARCH_RANKS_FILE_TAG); - - return true; - } - catch (exception & e) - { - LOG(LWARNING, ("Can' create rank table for:", localFile, ":", e.what())); - return false; - } -} - // static bool SearchRankTableBuilder::CreateIfNotExists(string const & mapPath) noexcept { @@ -360,7 +205,7 @@ bool SearchRankTableBuilder::CreateIfNotExists(string const & mapPath) noexcept return true; } - catch (exception & e) + catch (RootException const & e) { LOG(LWARNING, ("Can' create rank table for:", mapPath, ":", e.what())); return false; diff --git a/indexer/rank_table.hpp b/indexer/rank_table.hpp index 6f2a19886c..7a26a2fa86 100644 --- a/indexer/rank_table.hpp +++ b/indexer/rank_table.hpp @@ -48,7 +48,8 @@ public: virtual ~RankTable() = default; - // Returns rank of the i-th feature. + static uint8_t constexpr kNoRank = 0; + /// @return rank of the i-th feature, or kNoRank if there is no rank. virtual uint8_t Get(uint64_t i) const = 0; // Returns total number of ranks (or features, as there is a 1-1 correspondence). @@ -112,7 +113,6 @@ public: // // Return true if rank table was successfully generated and written // or already exists and has correct format. - static bool CreateIfNotExists(platform::LocalCountryFile const & localFile) noexcept; static bool CreateIfNotExists(std::string const & mapPath) noexcept; }; } // namespace search diff --git a/search/dummy_rank_table.cpp b/search/dummy_rank_table.cpp index 9d54b9f220..ec357ac588 100644 --- a/search/dummy_rank_table.cpp +++ b/search/dummy_rank_table.cpp @@ -2,16 +2,14 @@ #include "base/macros.hpp" -#include - namespace search { -uint8_t DummyRankTable::Get(uint64_t /* i */) const { return 0; } +uint8_t DummyRankTable::Get(uint64_t /* i */) const { return kNoRank; } uint64_t DummyRankTable::Size() const { NOTIMPLEMENTED(); - return std::numeric_limits::max(); + return 0; } RankTable::Version DummyRankTable::GetVersion() const diff --git a/search/search_quality/search_quality_tests/real_mwm_tests.cpp b/search/search_quality/search_quality_tests/real_mwm_tests.cpp index 7036cacb76..cddf8e9360 100644 --- a/search/search_quality/search_quality_tests/real_mwm_tests.cpp +++ b/search/search_quality/search_quality_tests/real_mwm_tests.cpp @@ -474,9 +474,9 @@ UNIT_CLASS_TEST(MwmTestsFixture, Street_BusStop) auto const & results = request->Results(); TEST_GREATER(results.size(), kTopPoiResultsCount, ()); - // Top results are Hotel and Street. - Range const range(results, 0, 3); - EqualClassifType(range, GetClassifTypes({{"tourism", "hotel"}, {"shop", "supermarket"}, {"highway"}})); + // Top results are Hotel and Street (sometimes bus stop). + Range const range(results); + EqualClassifType(range, GetClassifTypes({{"tourism", "hotel"}, {"highway", "bus_stop"}, {"highway", "residential"}})); } { @@ -500,6 +500,17 @@ UNIT_CLASS_TEST(MwmTestsFixture, Street_BusStop) EqualClassifType(range, GetClassifTypes({{"highway", "bus_stop"}})); TEST_LESS(SortedByDistance(range, center), 5000.0, ()); } + + { + auto request = MakeRequest("Juncal train", "en"); + auto const & results = request->Results(); + TEST_GREATER(results.size(), kTopPoiResultsCount, ()); + + // First result is a train station in other MWM, >200km away. + TEST(EqualClassifType(results[0].GetFeatureType(), classif().GetTypeByPath({"railway", "station"})), ()); + double const dist = ms::DistanceOnEarth(center, mercator::ToLatLon(results[0].GetFeatureCenter())); + TEST_GREATER(dist, 2.0E5, ()); + } } UNIT_CLASS_TEST(MwmTestsFixture, Generic_Buildings_Rank) -- 2.45.3 From 51b20ea661e408df3fff58b7ec25bb83c15a0110 Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sun, 11 Jun 2023 14:52:21 -0300 Subject: [PATCH 05/16] [search] Fixed unclassified/service/road streets rank. Signed-off-by: Viktor Govako --- indexer/ftypes_matcher.cpp | 6 +++--- indexer/ftypes_matcher.hpp | 1 + search/ranking_info.cpp | 2 ++ .../search_quality_tests/real_mwm_tests.cpp | 18 +++++++++++++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 8c065b6990..ecf1926bb2 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -346,16 +346,16 @@ IsWayChecker::IsWayChecker() {"primary", Regular}, {"primary_link", Regular}, {"residential", Residential}, - {"road", Outdoor}, + {"road", Minors}, {"secondary", Regular}, {"secondary_link",Regular}, - {"service", Residential}, + {"service", Minors}, {"tertiary", Regular}, {"tertiary_link", Regular}, {"track", Outdoor}, {"trunk", Motorway}, {"trunk_link", Motorway}, - {"unclassified", Outdoor}, + {"unclassified", Minors}, }; m_ranks.Reserve(std::size(types)); diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index 65eb507c9f..c4611a541b 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -222,6 +222,7 @@ public: Pedestrian, Cycleway, Outdoor, + Minors, Residential, Regular, Motorway, diff --git a/search/ranking_info.cpp b/search/ranking_info.cpp index 35fd65edfc..34e1ec175d 100644 --- a/search/ranking_info.cpp +++ b/search/ranking_info.cpp @@ -84,6 +84,7 @@ double constexpr kStreetType[] = { 0, // Pedestrian 0, // Cycleway 0, // Outdoor + 0.004, // Minors 0.004, // Residential 0.005, // Regular 0.006, // Motorway @@ -404,6 +405,7 @@ std::string DebugPrint(StreetType type) case StreetType::Pedestrian: return "Pedestrian"; case StreetType::Cycleway: return "Cycleway"; case StreetType::Outdoor: return "Outdoor"; + case StreetType::Minors: return "Minors"; case StreetType::Residential: return "Residential"; case StreetType::Regular: return "Regular"; case StreetType::Motorway: return "Motorway"; diff --git a/search/search_quality/search_quality_tests/real_mwm_tests.cpp b/search/search_quality/search_quality_tests/real_mwm_tests.cpp index cddf8e9360..8e8b3df0a2 100644 --- a/search/search_quality/search_quality_tests/real_mwm_tests.cpp +++ b/search/search_quality/search_quality_tests/real_mwm_tests.cpp @@ -533,7 +533,6 @@ UNIT_CLASS_TEST(MwmTestsFixture, Generic_Buildings_Rank) { auto request = MakeRequest("dia ", "en"); auto const & results = request->Results(); - LOG(LINFO, (results)); TEST_GREATER(results.size(), kTopPoiResultsCount, ()); Range const range(results); @@ -570,4 +569,21 @@ UNIT_CLASS_TEST(MwmTestsFixture, UTH_Airport) TEST(found, (results)); } +// https://github.com/organicmaps/organicmaps/issues/5186 +UNIT_CLASS_TEST(MwmTestsFixture, Milan_Streets) +{ + // Milan + ms::LatLon const center(45.46411, 9.19045); + SetViewportAndLoadMaps(center); + + auto request = MakeRequest("Via Domenichino", "it"); + auto const & results = request->Results(); + + size_t constexpr kResultsCount = 2; + TEST_GREATER(results.size(), kResultsCount, ()); + + Range const range(results, 0, kResultsCount); + TEST_LESS(SortedByDistance(range, center), 20000.0, ()); +} + } // namespace real_mwm_tests -- 2.45.3 From bdde6e6d50bd40c7e82355599d0616863935d21b Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sun, 11 Jun 2023 15:37:38 -0300 Subject: [PATCH 06/16] [search] Added common Spanish _prefix_ misprints. Signed-off-by: Viktor Govako --- indexer/search_string_utils.cpp | 3 ++ .../processor_test.cpp | 30 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/indexer/search_string_utils.cpp b/indexer/search_string_utils.cpp index 7ded9149e9..6f32e2a950 100644 --- a/indexer/search_string_utils.cpp +++ b/indexer/search_string_utils.cpp @@ -30,6 +30,9 @@ std::vector const kAllowedMisprints = { MakeUniString("ао"), MakeUniString("еиэ"), MakeUniString("шщ"), + // Spanish + MakeUniString("jh"), // "Jose" <-> "Hose" + MakeUniString("fh"), // "Hernández" <-> "Fernández" }; std::pair const kPreprocessReplacements[] = { diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp index 8bf5998de9..885622a04b 100644 --- a/search/search_integration_tests/processor_test.cpp +++ b/search/search_integration_tests/processor_test.cpp @@ -559,7 +559,7 @@ UNIT_CLASS_TEST(ProcessorTest, TestRankingInfo_PureCategory) } } -UNIT_CLASS_TEST(ProcessorTest, TestRankingInfo_ErrorsMade) +UNIT_CLASS_TEST(ProcessorTest, RankingInfo_ErrorsMade_1) { TestCity chekhov({0, 0}, "Чеховъ Антонъ Павловичъ", "ru", 100 /* rank */); @@ -605,6 +605,7 @@ UNIT_CLASS_TEST(ProcessorTest, TestRankingInfo_ErrorsMade) checkErrors("Cafe Yesenina", ErrorsMade(0)); checkErrors("Cafe Jesenina", ErrorsMade(1)); + /// @see search_string_utils.cpp, kAllowedMisprints // We allow only Y->{E, J, I, U} misprints for the first letter. checkErrors("Cafe Esenina", ErrorsMade(2)); @@ -634,6 +635,33 @@ UNIT_CLASS_TEST(ProcessorTest, TestRankingInfo_ErrorsMade) checkErrors("лермонтов чеховъ антон павлович", ErrorsMade(2)); } +// https://github.com/organicmaps/organicmaps/issues/5296 +UNIT_CLASS_TEST(ProcessorTest, RankingInfo_ErrorsMade_2) +{ + TestStreet hernandes({{-0.5, -0.5}, {0, 0}, {0.5, 0.5}}, "José Hernández", "es"); + + auto wonderlandId = BuildCountry("Wonderland", [&](TestMwmBuilder & builder) + { + builder.Add(hernandes); + }); + + SetViewport(m2::RectD(-1, -1, 1, 1)); + + auto checkErrors = [&](string const & query, ErrorsMade const & errorsMade) + { + auto request = MakeRequest(query, "es"); + auto const & results = request->Results(); + + Rules rules{ExactMatch(wonderlandId, hernandes)}; + TEST(ResultsMatch(results, rules), (query)); + TEST_EQUAL(results.size(), 1, (query)); + TEST_EQUAL(results[0].GetRankingInfo().m_errorsMade, errorsMade, (query)); + }; + + checkErrors("Hose", ErrorsMade(1)); + checkErrors("Fernández", ErrorsMade(1)); +} + UNIT_CLASS_TEST(ProcessorTest, TestHouseNumbers) { TestCity greenCity({0, 0}, "Зеленоград", "ru", 100 /* rank */); -- 2.45.3 From 3093c9c5484612b54336560468a9fc1dbd9cb42d Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sun, 11 Jun 2023 15:54:33 -0300 Subject: [PATCH 07/16] [search] Added "the" as a stopword in ranking. Signed-off-by: Viktor Govako --- search/ranking_utils.cpp | 2 +- .../search_quality_tests/real_mwm_tests.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/search/ranking_utils.cpp b/search/ranking_utils.cpp index 31da4e0b5f..203406319e 100644 --- a/search/ranking_utils.cpp +++ b/search/ranking_utils.cpp @@ -112,7 +112,7 @@ bool IsStopWord(UniString const & s) // Don't want to put _full_ stopwords list, not to break current ranking. // Only 2-letters and the most common. char const * arr[] = { - "a", "s", // English + "a", "s", "the", // English "am", "im", "an", // German "d", "de", "di", "da", "la", "le", // French, Spanish, Italian "и", "я" // Cyrillic diff --git a/search/search_quality/search_quality_tests/real_mwm_tests.cpp b/search/search_quality/search_quality_tests/real_mwm_tests.cpp index 8e8b3df0a2..c5a565c893 100644 --- a/search/search_quality/search_quality_tests/real_mwm_tests.cpp +++ b/search/search_quality/search_quality_tests/real_mwm_tests.cpp @@ -586,4 +586,21 @@ UNIT_CLASS_TEST(MwmTestsFixture, Milan_Streets) TEST_LESS(SortedByDistance(range, center), 20000.0, ()); } +// https://github.com/organicmaps/organicmaps/issues/5150 +UNIT_CLASS_TEST(MwmTestsFixture, London_RedLion) +{ + // Milan + ms::LatLon const center(51.49263, -0.12877); + SetViewportAndLoadMaps(center); + + auto request = MakeRequest("Red Lion", "en"); + auto const & results = request->Results(); + + TEST_GREATER(results.size(), kPopularPoiResultsCount, ()); + + // Top first results "The Red Lion" in 5 km. + Range const range(results); + TEST_LESS(SortedByDistance(range, center), 5000.0, ()); +} + } // namespace real_mwm_tests -- 2.45.3 From 57b31173e887d99d363f5d82c03be89dd378603d Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Mon, 12 Jun 2023 09:52:06 -0300 Subject: [PATCH 08/16] [search] Fixed addr:interpolation result rank (same as building address). Signed-off-by: Viktor Govako --- search/geocoder.cpp | 13 +++++++++---- search/intersection_result.hpp | 10 ++++++++-- search/model.cpp | 8 +++++++- search/ranker.cpp | 13 +++++++++++-- .../search_quality_tests/real_mwm_tests.cpp | 17 +++++++++++++++++ 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/search/geocoder.cpp b/search/geocoder.cpp index cbd55fb746..be3f17b5ac 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -1436,8 +1436,8 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken, CBV con } } - // Following code creates a fake layer with buildings and - // intersects it with the streets layer. + // Following code creates a fake TYPE_BUILDING layer and intersects it with the streets layer. + // Controversial: we can emit streets like buildings here. Filtered in IsFakeBuildingButStreet(). layers.emplace_back(); SCOPE_GUARD(cleanupGuard, [&]{ layers.pop_back(); }); @@ -1445,7 +1445,8 @@ void Geocoder::MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken, CBV con InitLayer(Model::TYPE_BUILDING, m_postcodes.m_tokenRange, layer); vector features; - m_postcodes.m_countryFeatures.ForEach([&features](uint64_t bit) { + m_postcodes.m_countryFeatures.ForEach([&features](uint64_t bit) + { features.push_back(base::asserted_cast(bit)); }); layer.m_sortedFeatures = &features; @@ -1683,8 +1684,12 @@ void Geocoder::FindPaths(BaseContext & ctx) return true; }; - m_finder.ForEachReachableVertex(*m_matcher, sortedLayers, [&](IntersectionResult const & result) { + m_finder.ForEachReachableVertex(*m_matcher, sortedLayers, [&](IntersectionResult const & result) + { ASSERT(result.IsValid(), ()); + if (result.IsFakeBuildingButStreet()) + return; + EmitResult(ctx, m_context->GetId(), result.InnermostResult(), innermostLayer.m_type, innermostLayer.m_tokenRange, &result, ctx.AllTokensUsed(), isExactMatch(ctx, result)); diff --git a/search/intersection_result.hpp b/search/intersection_result.hpp index 926ca297a1..509c15e035 100644 --- a/search/intersection_result.hpp +++ b/search/intersection_result.hpp @@ -16,13 +16,19 @@ struct IntersectionResult void Set(Model::Type type, uint32_t id); - // Returns the first valid feature among the [SUBPOI, COMPLEX_POI, BUILDING, - // STREET]. + // Returns the first valid feature among the [SUBPOI, COMPLEX_POI, BUILDING, STREET]. uint32_t InnermostResult() const; // Returns true when at least one valid feature exists. inline bool IsValid() const { return InnermostResult() != kInvalidId; } + // Building == Streets means that we have actual street result, but got here + // via _fake_ TYPE_BUILDING layer (see MatchPOIsAndBuildings). + inline bool IsFakeBuildingButStreet() const + { + return m_building != kInvalidId && m_building == m_street; + } + // Clears all fields to an invalid state. void Clear(); diff --git a/search/model.cpp b/search/model.cpp index 8ed1f6ca4a..c2d60b0cf2 100644 --- a/search/model.cpp +++ b/search/model.cpp @@ -111,7 +111,13 @@ public: bool operator()(FeatureType & ft) const { - return !ft.GetHouseNumber().empty() || IsBuildingChecker::Instance()(ft); + if (!ft.GetHouseNumber().empty()) + return true; + + if (ft.GetGeomType() == feature::GeomType::Line) + return IsAddressInterpolChecker::Instance()(ft); + else + return IsBuildingChecker::Instance()(ft); } }; } // namespace diff --git a/search/ranker.cpp b/search/ranker.cpp index cd09b7268e..628d0505a8 100644 --- a/search/ranker.cpp +++ b/search/ranker.cpp @@ -143,8 +143,17 @@ NameScores GetNameScores(FeatureType & ft, Geocoder::Params const & params, } if (type == Model::TYPE_BUILDING) - UpdateNameScores(ft.GetHouseNumber(), StringUtf8Multilang::kDefaultCode, sliceNoCategories, - bestScores); + { + if (ft.GetGeomType() == feature::GeomType::Line) + { + // Separate case for addr:interpolation (Building + Line). + ASSERT(!ft.GetRef().empty(), ()); + // Just assign SUBSTRING with no errors (was checked in HouseNumbersMatch). + bestScores.UpdateIfBetter(NameScores(NameScore::SUBSTRING, ErrorsMade(0), false, 4)); + } + else + UpdateNameScores(ft.GetHouseNumber(), StringUtf8Multilang::kDefaultCode, sliceNoCategories, bestScores); + } if (ftypes::IsAirportChecker::Instance()(ft)) { diff --git a/search/search_quality/search_quality_tests/real_mwm_tests.cpp b/search/search_quality/search_quality_tests/real_mwm_tests.cpp index c5a565c893..bac545317a 100644 --- a/search/search_quality/search_quality_tests/real_mwm_tests.cpp +++ b/search/search_quality/search_quality_tests/real_mwm_tests.cpp @@ -603,4 +603,21 @@ UNIT_CLASS_TEST(MwmTestsFixture, London_RedLion) TEST_LESS(SortedByDistance(range, center), 5000.0, ()); } +UNIT_CLASS_TEST(MwmTestsFixture, AddrInterpolation_Rank) +{ + // Buenos Aires (Palermo) + ms::LatLon const center(-34.57852, -58.42567); + SetViewportAndLoadMaps(center); + + auto request = MakeRequest("Sante Fe 1176", "en"); + auto const & results = request->Results(); + + TEST_GREATER(results.size(), kPopularPoiResultsCount, ()); + + // Top first address results in 50 km. + Range const range(results); + EqualClassifType(range, GetClassifTypes({{"addr:interpolation"}})); + TEST_LESS(SortedByDistance(range, center), 50000.0, ()); +} + } // namespace real_mwm_tests -- 2.45.3 From da5f13d6b30e9579f43c94bd9163ee1550ce6d43 Mon Sep 17 00:00:00 2001 From: endim8 Date: Tue, 13 Jun 2023 13:13:12 +0100 Subject: [PATCH 09/16] link to DEBUG_COMMANDS.md in debug commands section Signed-off-by: Harry Bond --- docs/INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 6f99e547ee..fb56e295df 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -268,7 +268,7 @@ To switch themes you can enter this commands: - `?vlight` - Day theme for vehicle navigation - `?vdark` - Night theme for vehicle navigation -There are also other commands for turning on/off isolines, antialiasing, etc. Check [the code](https://github.com/organicmaps/organicmaps/blob/6ae19b40c2b7a515338eb128547df05da13bdb78/map/framework.cpp#L2570-L2671) to learn about them. +There are also other commands for turning on/off isolines, antialiasing, etc. Check [DEBUG_COMMANDS.md](DEBUG_COMMANDS.md) to learn about them. ### More options -- 2.45.3 From e751ec3bc721eae12178282dd483cd9cdf19eee0 Mon Sep 17 00:00:00 2001 From: endim8 Date: Mon, 12 Jun 2023 14:54:07 +0100 Subject: [PATCH 10/16] Update INSTALL.md: fix dependency Signed-off-by: Harry Bond --- docs/INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index fb56e295df..ff8b4f3e53 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -130,7 +130,7 @@ sudo dnf install -y \ freetype-devel \ libicu-devel \ libstdc++-devel \ - libgl1-mesa-devel \ + mesa-libGL-devel \ libglvnd-devel \ qt6-qtbase-devel \ qt6-qtsvg-devel \ -- 2.45.3 From cd91d5d121807de9b88fad628f9e4a48e4fd955f Mon Sep 17 00:00:00 2001 From: Konstantin Pastbin Date: Wed, 7 Jun 2023 15:30:22 +0300 Subject: [PATCH 11/16] [doc] Add desktop-specific search commands Signed-off-by: Konstantin Pastbin --- docs/DEBUG_COMMANDS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/DEBUG_COMMANDS.md b/docs/DEBUG_COMMANDS.md index d37d4ee060..ae8d261505 100644 --- a/docs/DEBUG_COMMANDS.md +++ b/docs/DEBUG_COMMANDS.md @@ -27,6 +27,13 @@ For more information, please see the source code at [`Framework::ParseSearchQuer - `?isolines`: Enable the isolines layer. - `?no-isolines`: Disable the isolines layer. +### 3D mode (for the Qt desktop app only) +- `?3d`: Enable 3D (perspective) mode. +- `?b3d`: Enable 3D buildings. +- `?2d`: Disable 3D mode and buildings. + +The source code is at [`SearchPanel::Try3dModeCmd`](../qt/search_panel.cpp). + ### Information - `?debug-info`: Show renderer version, zoom scale and FPS counter in the top left corner of the map. -- 2.45.3 From 1b1b206ff6bb5972500f94221e92ff80bf4ab35a Mon Sep 17 00:00:00 2001 From: Alexander Borsuk Date: Tue, 13 Jun 2023 23:17:42 +0200 Subject: [PATCH 12/16] Fixed UB/assert when parsing GPX Signed-off-by: Alexander Borsuk --- kml/serdes_gpx.cpp | 2 +- kml/serdes_gpx.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kml/serdes_gpx.cpp b/kml/serdes_gpx.cpp index 3dd5c25c51..cc91312f8e 100644 --- a/kml/serdes_gpx.cpp +++ b/kml/serdes_gpx.cpp @@ -91,7 +91,7 @@ bool GpxParser::MakeValid() bool GpxParser::Push(std::string_view tag) { - m_tags.push_back(tag); + m_tags.push_back(std::string{tag}); if (GetTagFromEnd(0) == gpx::kWpt) m_geometryType = GEOMETRY_TYPE_POINT; else if (GetTagFromEnd(0) == gpx::kTrkPt || GetTagFromEnd(0) == gpx::kRtePt) diff --git a/kml/serdes_gpx.hpp b/kml/serdes_gpx.hpp index 9c780b4d9c..0c118920aa 100644 --- a/kml/serdes_gpx.hpp +++ b/kml/serdes_gpx.hpp @@ -46,7 +46,7 @@ private: CategoryData m_compilationData; CategoryData * m_categoryData; // never null - std::vector m_tags; + std::vector m_tags; GeometryType m_geometryType; MultiGeometry m_geometry; uint32_t m_color; -- 2.45.3 From 2aa39da71dd8c098ab580c46185c72034ac19ab3 Mon Sep 17 00:00:00 2001 From: Alexander Borsuk Date: Tue, 13 Jun 2023 22:45:34 +0200 Subject: [PATCH 13/16] [qt] More contrast download button and label text color Signed-off-by: Alexander Borsuk --- qt/mainwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qt/mainwindow.cpp b/qt/mainwindow.cpp index e651a857ea..d00071117a 100644 --- a/qt/mainwindow.cpp +++ b/qt/mainwindow.cpp @@ -447,6 +447,8 @@ Framework & MainWindow::GetFramework() const void MainWindow::CreateCountryStatusControls() { + setStyleSheet("QPushButton { color: black; } QLabel { color: black; }"); + QHBoxLayout * mainLayout = new QHBoxLayout(); m_downloadButton = new QPushButton("Download"); mainLayout->addWidget(m_downloadButton, 0, Qt::AlignHCenter); -- 2.45.3 From 67aa775abb61b9d6c8b69815d411c2007bc2c796 Mon Sep 17 00:00:00 2001 From: cyber-toad <128428520+cyber-toad@users.noreply.github.com> Date: Wed, 14 Jun 2023 14:16:39 +0200 Subject: [PATCH 14/16] [gpx] Use string_view for bookmark file extensions (#5284) * [gpx] Use string_view for bookmark file extensions Signed-off-by: cyber-toad * Fixed string_view to string conversion Signed-off-by: Alexander Borsuk * Follow-up fixes Signed-off-by: Alexander Borsuk * Review fixes Signed-off-by: Alexander Borsuk * Compile fix Signed-off-by: Alexander Borsuk * append does not create a temporary :) Signed-off-by: Alexander Borsuk * Avoid duplicate path Signed-off-by: Alexander Borsuk --------- Signed-off-by: cyber-toad Signed-off-by: Alexander Borsuk Co-authored-by: Alexander Borsuk --- android/jni/app/organicmaps/Framework.cpp | 10 ++++++++-- map/bookmark_helpers.cpp | 22 +++++++++++++--------- map/bookmark_helpers.hpp | 10 +++++----- map/bookmark_manager.cpp | 8 ++++---- map/bookmark_manager.hpp | 2 +- map/map_tests/bookmarks_test.cpp | 2 +- platform/platform.cpp | 6 +++--- platform/platform.hpp | 2 +- 8 files changed, 36 insertions(+), 26 deletions(-) diff --git a/android/jni/app/organicmaps/Framework.cpp b/android/jni/app/organicmaps/Framework.cpp index ac5ad0a6af..34c64a2835 100644 --- a/android/jni/app/organicmaps/Framework.cpp +++ b/android/jni/app/organicmaps/Framework.cpp @@ -1106,8 +1106,14 @@ Java_app_organicmaps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGetBookmarksFilesExts(JNIEnv * env, jclass) { - const vector exts = { kKmzExtension, kKmlExtension, kKmbExtension, kGpxExtension }; - return jni::ToJavaStringArray(env, exts); + static std::array const kBookmarkExtensions = { + std::string{kKmzExtension}, + std::string{kKmlExtension}, + std::string{kKmbExtension}, + std::string{kGpxExtension} + }; + + return jni::ToJavaStringArray(env, kBookmarkExtensions); } JNIEXPORT void JNICALL diff --git a/map/bookmark_helpers.cpp b/map/bookmark_helpers.cpp index 15c9512a71..d1b54efc59 100644 --- a/map/bookmark_helpers.cpp +++ b/map/bookmark_helpers.cpp @@ -245,17 +245,25 @@ std::string RemoveInvalidSymbols(std::string const & name) return strings::ToUtf8(filtered); } -std::string GenerateUniqueFileName(const std::string & path, std::string name, std::string const & ext) + +std::string GenerateUniqueFileName(std::string const & path, std::string name, std::string_view ext) { // Remove extension, if file name already contains it. if (strings::EndsWith(name, ext)) name.resize(name.size() - ext.size()); size_t counter = 1; - std::string suffix; - while (Platform::IsFileExistsByFullPath(base::JoinPath(path, name + suffix + ext))) + std::string suffix, res; + do + { + res = name; + res = base::JoinPath(path, res.append(suffix).append(ext)); + if (!Platform::IsFileExistsByFullPath(res)) + break; suffix = strings::to_string(counter++); - return base::JoinPath(path, name + suffix + ext); + } while (true); + + return res; } std::string GenerateValidAndUniqueFilePathForKML(std::string const & fileName) @@ -264,13 +272,9 @@ std::string GenerateValidAndUniqueFilePathForKML(std::string const & fileName) if (filePath.empty()) filePath = kDefaultBookmarksFileName; - return GenerateUniqueFileName(GetBookmarksDirectory(), std::move(filePath)); + return GenerateUniqueFileName(GetBookmarksDirectory(), std::move(filePath), kKmlExtension); } -std::string const kKmzExtension = ".kmz"; -std::string const kKmlExtension = ".kml"; -std::string const kKmbExtension = ".kmb"; -std::string const kGpxExtension = ".gpx"; std::string const kDefaultBookmarksFileName = "Bookmarks"; // Populate empty category & track names based on file name: assign file name to category name, diff --git a/map/bookmark_helpers.hpp b/map/bookmark_helpers.hpp index e539988b95..e2cabe2a5e 100644 --- a/map/bookmark_helpers.hpp +++ b/map/bookmark_helpers.hpp @@ -65,10 +65,10 @@ enum class BookmarkBaseType : uint16_t Count }; -extern std::string const kKmzExtension; -extern std::string const kKmlExtension; -extern std::string const kKmbExtension; -extern std::string const kGpxExtension; +std::string_view constexpr kKmzExtension = ".kmz"; +std::string_view constexpr kKmlExtension = ".kml"; +std::string_view constexpr kKmbExtension = ".kmb"; +std::string_view constexpr kGpxExtension = ".gpx"; extern std::string const kDefaultBookmarksFileName; enum class KmlFileType @@ -93,7 +93,7 @@ inline std::string DebugPrint(KmlFileType fileType) /// @{ std::string GetBookmarksDirectory(); std::string RemoveInvalidSymbols(std::string const & name); -std::string GenerateUniqueFileName(const std::string & path, std::string name, std::string const & ext = kKmlExtension); +std::string GenerateUniqueFileName(const std::string & path, std::string name, std::string_view ext = kKmlExtension); std::string GenerateValidAndUniqueFilePathForKML(std::string const & fileName); /// @} diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 34ecb9cb0c..945fcf497f 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -81,7 +81,7 @@ BookmarkManager::SharingResult GetFileForSharing(BookmarkManager::KMLDataCollect if (fileName.empty()) fileName = base::GetNameFromFullPathWithoutExt(kmlToShare.first); - auto const filePath = base::JoinPath(GetPlatform().TmpDir(), fileName + kKmlExtension); + auto const filePath = base::JoinPath(GetPlatform().TmpDir(), fileName.append(kKmlExtension)); SCOPE_GUARD(fileGuard, std::bind(&base::DeleteFileX, filePath)); auto const categoryId = kmlToShare.second->m_categoryData.m_id; @@ -92,7 +92,7 @@ BookmarkManager::SharingResult GetFileForSharing(BookmarkManager::KMLDataCollect "Bookmarks file does not exist."); } - auto const tmpFilePath = base::JoinPath(GetPlatform().TmpDir(), fileName + kKmzExtension); + auto const tmpFilePath = base::JoinPath(GetPlatform().TmpDir(), fileName.append(kKmzExtension)); if (!CreateZipFromPathDeflatedAndDefaultCompression(filePath, tmpFilePath)) { return BookmarkManager::SharingResult(categoryId, BookmarkManager::SharingResult::Code::ArchiveError, @@ -1798,7 +1798,7 @@ void BookmarkManager::ClearCategories() } BookmarkManager::KMLDataCollectionPtr BookmarkManager::LoadBookmarks( - std::string const & dir, std::string const & ext, KmlFileType fileType, + std::string const & dir, std::string_view ext, KmlFileType fileType, BookmarksChecker const & checker) { Platform::FilesList files; @@ -2588,7 +2588,7 @@ BookmarkManager::KMLDataCollectionPtr BookmarkManager::PrepareToSaveBookmarks( if (name.empty()) name = kDefaultBookmarksFileName; - file = GenerateUniqueFileName(fileDir, std::move(name)); + file = GenerateUniqueFileName(fileDir, std::move(name), kKmlExtension); group->SetFileName(file); } diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index 0e2d4f497e..e8882fc7f7 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -603,7 +603,7 @@ private: void LoadBookmarkRoutine(std::string const & filePath, bool isTemporaryFile); using BookmarksChecker = std::function; - KMLDataCollectionPtr LoadBookmarks(std::string const & dir, std::string const & ext, + KMLDataCollectionPtr LoadBookmarks(std::string const & dir, std::string_view ext, KmlFileType fileType, BookmarksChecker const & checker); void GetDirtyGroups(kml::GroupIdSet & dirtyGroups) const; diff --git a/map/map_tests/bookmarks_test.cpp b/map/map_tests/bookmarks_test.cpp index 1c687b7a8c..c37f9e66f0 100644 --- a/map/map_tests/bookmarks_test.cpp +++ b/map/map_tests/bookmarks_test.cpp @@ -494,7 +494,7 @@ UNIT_TEST(Bookmarks_UniqueFileName) { string const BASE = "SomeUniqueFileName"; string const FILEBASE = "./" + BASE; - string const FILENAME = FILEBASE + kKmlExtension; + string const FILENAME = FILEBASE + string{kKmlExtension}; { FileWriter file(FILENAME); diff --git a/platform/platform.cpp b/platform/platform.cpp index e14ca2c295..54f65002da 100644 --- a/platform/platform.cpp +++ b/platform/platform.cpp @@ -214,13 +214,13 @@ void Platform::GetFontNames(FilesList & res) const LOG(LINFO, ("Available font files:", (res))); } -void Platform::GetFilesByExt(std::string const & directory, std::string const & ext, FilesList & outFiles) +void Platform::GetFilesByExt(std::string const & directory, std::string_view ext, FilesList & outFiles) { // Transform extension mask to regexp (.mwm -> \.mwm$) ASSERT ( !ext.empty(), () ); ASSERT_EQUAL ( ext[0], '.' , () ); - - GetFilesByRegExp(directory, '\\' + ext + '$', outFiles); + std::string regexp = "\\"; + GetFilesByRegExp(directory, regexp.append(ext).append("$"), outFiles); } // static diff --git a/platform/platform.hpp b/platform/platform.hpp index d185c60228..e18ff07000 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -210,7 +210,7 @@ public: /// @param directory directory path with slash at the end //@{ /// @param ext files extension to find, like ".mwm". - static void GetFilesByExt(std::string const & directory, std::string const & ext, + static void GetFilesByExt(std::string const & directory, std::string_view ext, FilesList & outFiles); static void GetFilesByRegExp(std::string const & directory, std::string const & regexp, FilesList & outFiles); -- 2.45.3 From 90c39c07ce1ed4abf062672864c082f0e6574de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <135858315+andre1110@users.noreply.github.com> Date: Thu, 15 Jun 2023 03:38:58 +0700 Subject: [PATCH 15/16] [ios] Fixed bookmark list descriptions (#5300) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ios] Show the list description in BookmarksListInfoView Fixes #4799 Signed-off-by: André <135858315+andre1110@users.noreply.github.com> * [cleanup] Spelling fix Signed-off-by: André <135858315+andre1110@users.noreply.github.com> * Apply suggestions from code review Signed-off-by: André <135858315+andre1110@users.noreply.github.com> * Added CSS for plain text descriptions Signed-off-by: André <135858315+andre1110@users.noreply.github.com> --------- Signed-off-by: André <135858315+andre1110@users.noreply.github.com> --- .../CoreApi/Bookmarks/MWMBookmarkGroup.h | 1 + .../CoreApi/Bookmarks/MWMBookmarkGroup.m | 4 +++ .../CoreApi/Bookmarks/MWMBookmarksManager.h | 1 + .../CoreApi/Bookmarks/MWMBookmarksManager.mm | 5 +++ .../BookmarksListInfoViewController.swift | 19 ++++++++--- .../BookmarksListInfoViewController.xib | 2 +- .../BookmarksListInterfaces.swift | 6 ++-- .../BookmarksListPresenter.swift | 16 +++++---- .../BookmarksList/BookmarksListRouter.swift | 34 +++++++++++++++++-- .../BookmarksListViewController.swift | 2 +- 10 files changed, 74 insertions(+), 16 deletions(-) diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h index f867bc2b41..6e5d34c8d8 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.h @@ -28,6 +28,7 @@ NS_SWIFT_NAME(BookmarkGroup) @property(nonatomic, readonly, getter=isVisible) BOOL visible; @property(nonatomic, readonly, getter=isEmpty) BOOL empty; @property(nonatomic, readonly) BOOL hasDescription; +@property(nonatomic, readonly) BOOL isHtmlDescription; @property(nonatomic, readonly) MWMBookmarkGroupAccessStatus accessStatus; @property(nonatomic, readonly) NSArray *bookmarks; @property(nonatomic, readonly) NSArray *tracks; diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m index 3c991fa6a7..7cfd57950b 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarkGroup.m @@ -84,4 +84,8 @@ return [self.manager getCategoryGroupType:self.categoryId]; } +- (BOOL)isHtmlDescription { + return [self.manager isHtmlDescription:self.categoryId]; +} + @end diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h index 5afef3cc85..5898dc6d39 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.h @@ -47,6 +47,7 @@ NS_SWIFT_NAME(BookmarksManager) - (MWMBookmarkGroupType)getCategoryGroupType:(MWMMarkGroupID)groupId; - (nullable NSURL *)getCategoryImageUrl:(MWMMarkGroupID)groupId; - (BOOL)hasExtraInfo:(MWMMarkGroupID)groupId; +- (BOOL)isHtmlDescription:(MWMMarkGroupID)groupId; - (MWMMarkGroupID)createCategoryWithName:(NSString *)name; - (void)setCategory:(MWMMarkGroupID)groupId name:(NSString *)name; diff --git a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm index f784405dc8..e10dd71c17 100644 --- a/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm +++ b/iphone/CoreApi/CoreApi/Bookmarks/MWMBookmarksManager.mm @@ -287,6 +287,11 @@ static BookmarkManager::SortingType convertSortingTypeToCore(MWMBookmarksSorting return !data.m_description.empty() || !data.m_annotation.empty(); } +- (BOOL)isHtmlDescription:(MWMMarkGroupID)groupId { + auto const description = GetPreferredBookmarkStr(self.bm.GetCategoryData(groupId).m_description); + return strings::IsHTML(description); +} + - (MWMMarkGroupID)createCategoryWithName:(NSString *)name { auto groupId = self.bm.CreateBookmarkCategory(name.UTF8String); diff --git a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift index 75771818db..762d8fc636 100644 --- a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift +++ b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.swift @@ -4,7 +4,7 @@ protocol BookmarksListInfoViewControllerDelegate: AnyObject { } final class BookmarksListInfoViewController: UIViewController { - var info: IBookmakrsListInfoViewModel? { + var info: IBookmarksListInfoViewModel? { didSet { guard isViewLoaded, let info = info else { return } updateInfo(info) @@ -26,17 +26,23 @@ final class BookmarksListInfoViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - descriptionButton.setTitle(L("placepage_place_description").uppercased(), for: .normal) separatorsConstraints.forEach { $0.constant = 1 / UIScreen.main.scale } + descriptionButton.titleLabel?.numberOfLines = 2 guard let info = info else { return } updateInfo(info) } - private func updateInfo(_ info: IBookmakrsListInfoViewModel) { + private func updateInfo(_ info: IBookmarksListInfoViewModel) { titleLabel.text = info.title descriptionButton.isHidden = !info.hasDescription - + if info.hasDescription { + let description = info.isHtmlDescription + ? BookmarksListInfoViewController.getPlainText(info.description) + : info.description + descriptionButton.setTitle(description, for: .normal) + } + titleImageView.isHidden = true if let imageUrl = info.imageUrl { titleImageView.wi_setImage(with: imageUrl, transitionDuration: 0) { [weak self] (image, error) in @@ -46,4 +52,9 @@ final class BookmarksListInfoViewController: UIViewController { } } } + + private static func getPlainText(_ htmlText: String) -> String? { + let formattedText = NSAttributedString.string(withHtml: htmlText, defaultAttributes: [:]) + return formattedText?.string + } } diff --git a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib index f79f370e30..aa13283583 100644 --- a/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib +++ b/iphone/Maps/Bookmarks/BookmarksList/BookmarksListInfoViewController.xib @@ -60,7 +60,7 @@ -