diff --git a/defines.hpp b/defines.hpp index 71d18a375..b16b76dc0 100644 --- a/defines.hpp +++ b/defines.hpp @@ -4,6 +4,7 @@ #define DATA_FILE_EXTENSION ".mwm" #define DATA_FILE_EXTENSION_TMP ".mwm.tmp" +#define RELATIONS_FILE_EXTENSION_TMP ".rels.tmp" #define DIFF_FILE_EXTENSION ".mwmdiff" #define DIFF_APPLYING_FILE_EXTENSION ".diff.applying" #define FONT_FILE_EXTENSION ".ttf" @@ -22,8 +23,11 @@ #define OFFSET_EXT ".offs" #define ID2REL_EXT ".id2rel" +auto constexpr TMP_OFFSETS_EXT = OFFSET_EXT EXTENSION_TMP; + #define CENTERS_FILE_TAG "centers" #define FEATURES_FILE_TAG "features" +#define RELATIONS_FILE_TAG "relations" #define GEOMETRY_FILE_TAG "geom" #define TRIANGLE_FILE_TAG "trg" #define INDEX_FILE_TAG "idx" @@ -36,7 +40,7 @@ #define POSTCODE_POINTS_FILE_TAG "postcode_points" #define POSTCODES_FILE_TAG "postcodes" #define CITIES_BOUNDARIES_FILE_TAG "cities_boundaries" -#define FEATURE_TO_OSM_FILE_TAG "feature_to_osm" +#define FEATURE_TO_OSM_FILE_TAG "feature_to_osm" // not used in prod #define HEADER_FILE_TAG "header" #define VERSION_FILE_TAG "version" #define METADATA_FILE_TAG "meta" @@ -47,6 +51,7 @@ #define ROUTING_FILE_TAG "routing" #define CROSS_MWM_FILE_TAG "cross_mwm" #define FEATURE_OFFSETS_FILE_TAG "offs" +#define RELATION_OFFSETS_FILE_TAG "rel_offs" #define SEARCH_RANKS_FILE_TAG "ranks" #define POPULARITY_RANKS_FILE_TAG "popularity" #define REGION_INFO_FILE_TAG "rgninfo" diff --git a/generator/centers_table_builder.cpp b/generator/centers_table_builder.cpp index 88ef1f6fd..dd05d3796 100644 --- a/generator/centers_table_builder.cpp +++ b/generator/centers_table_builder.cpp @@ -24,7 +24,7 @@ bool BuildCentersTableFromDataFile(std::string const & filename, bool forceRebui if (!forceRebuild && rcont.IsExist(CENTERS_FILE_TAG)) return true; - auto const table = feature::FeaturesOffsetsTable::Load(rcont); + auto const table = feature::FeaturesOffsetsTable::Load(rcont, FEATURE_OFFSETS_FILE_TAG); if (!table) { LOG(LERROR, ("Can't load offsets table from:", filename)); @@ -32,7 +32,7 @@ bool BuildCentersTableFromDataFile(std::string const & filename, bool forceRebui } feature::DataHeader const header(rcont); - FeaturesVector const features(rcont, header, table.get(), nullptr); + FeaturesVector const features(rcont, header, table.get(), nullptr, nullptr); builder.SetGeometryParams(header.GetBounds()); features.ForEach([&](FeatureType & ft, uint32_t featureId) { builder.Put(featureId, feature::GetCenter(ft)); }); diff --git a/generator/feature_builder.cpp b/generator/feature_builder.cpp index dba90fd59..805413f0c 100644 --- a/generator/feature_builder.cpp +++ b/generator/feature_builder.cpp @@ -631,7 +631,10 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi CHECK(type != GeomType::Undefined, ()); if (type == GeomType::Point) { - serial::SavePoint(sink, m_center, params); + uint64_t const encoded = + coding::EncodePointDeltaAsUint(PointDToPointU(m_center, params.GetCoordBits()), params.GetBasePoint()); + CHECK_GREATER(bits::NumHiZeroBits64(encoded), 1, ()); + WriteVarUint(sink, encoded << 1); // Relations control bit return; } @@ -657,6 +660,9 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi bitSink.Write(trgCount != 0 ? trgCount : data.m_trgMask, 4); bitSink.Write(trgCount == 0 ? 1 : 0, 1); } + + // Relations control bit + bitSink.Write(0, 1); } if (type == GeomType::Line) diff --git a/generator/feature_segments_checker/feature_segments_checker.cpp b/generator/feature_segments_checker/feature_segments_checker.cpp index ce8e79a75..aea1ef913 100644 --- a/generator/feature_segments_checker/feature_segments_checker.cpp +++ b/generator/feature_segments_checker/feature_segments_checker.cpp @@ -156,7 +156,8 @@ public: void operator()(FeatureType & f, uint32_t const & id) { - f.ParseHeader2(); + f.ParseAllBeforeGeometry(); + if (!GetBicycleModel().IsRoad(feature::TypesHolder(f))) { ++m_notRoadCount; diff --git a/generator/statistics.cpp b/generator/statistics.cpp index 157657561..d58c72409 100644 --- a/generator/statistics.cpp +++ b/generator/statistics.cpp @@ -50,7 +50,7 @@ public: void operator()(FeatureType & f, uint32_t) { - f.ParseHeader2(); + f.ParseAllBeforeGeometry(); FeatureType::InnerGeomStat const innerStats = f.GetInnerStats(); diff --git a/libs/drape/color.hpp b/libs/drape/color.hpp index 719d65203..5fc447e6f 100644 --- a/libs/drape/color.hpp +++ b/libs/drape/color.hpp @@ -15,6 +15,7 @@ struct Color constexpr Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) : Color(red << 24 | green << 16 | blue << 8 | alpha) {} + constexpr Color(uint8_t red, uint8_t green, uint8_t blue) : Color(red, green, blue, 255) {} constexpr Color(uint32_t rgb, uint8_t alpha) : Color(ExtractByte(rgb, 2), ExtractByte(rgb, 1), ExtractByte(rgb, 0), alpha) {} @@ -58,6 +59,10 @@ struct Color { return {ExtractByte(argb, 2), ExtractByte(argb, 1), ExtractByte(argb, 0), ExtractByte(argb, 3)}; } + constexpr static Color FromRGBA(uint32_t rgba) + { + return {ExtractByte(rgba, 3), ExtractByte(rgba, 2), ExtractByte(rgba, 1), ExtractByte(rgba, 0)}; + } private: constexpr static uint8_t ExtractByte(uint32_t number, uint8_t byteIdx) { return (number >> (8 * byteIdx)) & 0xFF; } diff --git a/libs/indexer/CMakeLists.txt b/libs/indexer/CMakeLists.txt index 48af2c680..feccdb2c9 100644 --- a/libs/indexer/CMakeLists.txt +++ b/libs/indexer/CMakeLists.txt @@ -103,10 +103,11 @@ set(SRC metadata_serdes.hpp mwm_set.cpp mwm_set.hpp - postcodes_matcher.cpp # it's in indexer due to editor which is in indexer and depends on postcodes_marcher - postcodes_matcher.hpp # it's in indexer due to editor which is in indexer and depends on postcodes_marcher + postcodes_matcher.cpp # it's in indexer EditableMapObject depends on postcodes_matcher + postcodes_matcher.hpp # it's in indexer EditableMapObject depends on postcodes_matcher rank_table.cpp rank_table.hpp + route_relation.hpp road_shields_parser.cpp road_shields_parser.hpp scale_index.hpp diff --git a/libs/indexer/feature.cpp b/libs/indexer/feature.cpp index c534e6e16..610b76f2e 100644 --- a/libs/indexer/feature.cpp +++ b/libs/indexer/feature.cpp @@ -244,6 +244,7 @@ std::unique_ptr FeatureType::CreateFromMapObject(osm::MapObject con ft->m_parsed.m_types = true; ft->m_header = CalculateHeader(emo.GetTypes().Size(), headerGeomType, ft->m_params); ft->m_parsed.m_header2 = true; + ft->m_parsed.m_relations = true; ft->m_id = emo.GetID(); return ft; @@ -305,7 +306,17 @@ void FeatureType::ParseCommon() if (GetGeomType() == GeomType::Point) { - m_center = serial::LoadPoint(source, m_loadInfo->GetDefGeometryCodingParams()); + uint64_t decoded = ReadVarUint(source); + + if (m_loadInfo->m_version >= DatSectionHeader::Version::V1) + { + m_hasRelations = (decoded & 0x1) == 1; + decoded >>= 1; + } + + auto const & cp = m_loadInfo->GetDefGeometryCodingParams(); + m_center = PointUToPointD(coding::DecodePointDeltaFromUint(decoded, cp.GetBasePoint()), cp.GetCoordBits()); + m_limitRect.Add(m_center); } @@ -329,13 +340,7 @@ int8_t FeatureType::GetLayer() return m_params.layer; } -// TODO: there is a room to store more information in Header2 (geometry header), -// but it needs a mwm version change. -// 1st bit - inner / outer flag -// 4 more bits - inner points/triangles count or outer geom offsets mask -// (but actually its enough to store number of the first existing geom level only - 2 bits) -// 3-5 more bits are spare -// One of them could be used for a closed line flag to avoid storing identical first + last points. +// TODO: One of the free bits could be used for a closed line flag to avoid storing identical first + last points. void FeatureType::ParseHeader2() { if (m_parsed.m_header2) @@ -347,7 +352,10 @@ void FeatureType::ParseHeader2() auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); if (headerGeomType != HeaderGeomType::Line && headerGeomType != HeaderGeomType::Area) + { + m_offsets.m_relations = m_offsets.m_header2; return; + } BitSource bitSource(m_data.data() + m_offsets.m_header2); uint8_t elemsCount = bitSource.Read(4); @@ -362,13 +370,15 @@ void FeatureType::ParseHeader2() } else { - ASSERT_EQUAL(m_loadInfo->m_version, DatSectionHeader::Version::V1, ()); + ASSERT(m_loadInfo->m_version >= DatSectionHeader::Version::V1, ()); bool const isOuter = (bitSource.Read(1) == 1); if (isOuter) { geomScalesMask = elemsCount; elemsCount = 0; } + + m_hasRelations = (bitSource.Read(1) == 1); } ArrayByteSource src(bitSource.RoundPtr()); @@ -426,6 +436,23 @@ void FeatureType::ParseHeader2() } } + m_offsets.m_relations = CalcOffset(src, m_data.data()); +} + +void FeatureType::ParseRelations() +{ + if (m_parsed.m_relations) + return; + + ParseHeader2(); + + ArrayByteSource src(m_data.data() + m_offsets.m_relations); + + if (m_hasRelations) + ReadVarUInt32SortedShortArray(src, m_relationIDs); + + m_parsed.m_relations = true; + // Size of the whole header incl. inner geometry / triangles. m_innerStats.m_size = CalcOffset(src, m_data.data()); } @@ -442,7 +469,7 @@ void FeatureType::ResetGeometry() if (GetGeomType() != GeomType::Point) m_limitRect = m2::RectD(); - m_parsed.m_header2 = m_parsed.m_points = m_parsed.m_triangles = false; + m_parsed.m_relations = m_parsed.m_header2 = m_parsed.m_points = m_parsed.m_triangles = false; m_offsets.m_pts.clear(); m_offsets.m_trg.clear(); m_ptsSimpMask = 0; @@ -501,9 +528,9 @@ void FeatureType::ParseGeometry(int scale) FeatureType::GeomStat FeatureType::GetOuterGeometryStats() { - CHECK(m_loadInfo && m_parsed.m_header2 && !m_parsed.m_points, ("Call geometry stats first and once!")); + CHECK(m_loadInfo && m_parsed.m_relations && !m_parsed.m_points, ()); size_t const scalesCount = m_loadInfo->GetScalesCount(); - ASSERT_LESS_OR_EQUAL(scalesCount, DataHeader::kMaxScalesCount, ("MWM has too many geometry scales!")); + ASSERT_LESS_OR_EQUAL(scalesCount, DataHeader::kMaxScalesCount, ()); FeatureType::GeomStat res; auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); @@ -576,10 +603,9 @@ void FeatureType::ParseTriangles(int scale) FeatureType::GeomStat FeatureType::GetOuterTrianglesStats() { - CHECK(m_loadInfo && m_parsed.m_header2 && !m_parsed.m_triangles, ("Call geometry stats first and once!")); + CHECK(m_loadInfo && m_parsed.m_relations && !m_parsed.m_triangles, ()); int const scalesCount = m_loadInfo->GetScalesCount(); - ASSERT_LESS_OR_EQUAL(scalesCount, static_cast(DataHeader::kMaxScalesCount), - ("MWM has too many geometry scales!")); + ASSERT_LESS_OR_EQUAL(scalesCount, static_cast(DataHeader::kMaxScalesCount), ()); FeatureType::GeomStat res; auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); @@ -868,3 +894,16 @@ bool FeatureType::HasMetadata(feature::Metadata::EType type) return base::FindIf(m_metaIds, [&type](auto const & v) { return v.first == type; }) != m_metaIds.end(); } + +FeatureType::RelationIDsV const & FeatureType::GetRelations() +{ + ParseRelations(); + return m_relationIDs; +} + +/// @pre id is from m_relationIDs. +feature::RouteRelationBase FeatureType::ReadRelation(uint32_t id) +{ + ParseRelations(); + return m_loadInfo->ReadRelation(id); +} diff --git a/libs/indexer/feature.hpp b/libs/indexer/feature.hpp index c2b4ce582..7ae3a2422 100644 --- a/libs/indexer/feature.hpp +++ b/libs/indexer/feature.hpp @@ -1,6 +1,7 @@ #pragma once #include "indexer/feature_data.hpp" #include "indexer/metadata_serdes.hpp" +#include "indexer/route_relation.hpp" #include "geometry/point2d.hpp" #include "geometry/rect2d.hpp" @@ -82,6 +83,8 @@ public: FeatureID const & GetID() const { return m_id; } void ParseHeader2(); + void ParseRelations(); + void ParseAllBeforeGeometry() { ParseRelations(); } void ResetGeometry(); void ParseGeometry(int scale); void ParseTriangles(int scale); @@ -195,31 +198,41 @@ public: GeomStat GetOuterTrianglesStats(); //@} + using RelationIDsV = feature::ShortArray; + RelationIDsV const & GetRelations(); + + feature::RouteRelationBase ReadRelation(uint32_t id); + private: struct ParsedFlags { bool m_types : 1; bool m_common : 1; bool m_header2 : 1; + bool m_relations : 1; bool m_points : 1; bool m_triangles : 1; bool m_metadata : 1; bool m_metaIds : 1; ParsedFlags() { Reset(); } - void Reset() { m_types = m_common = m_header2 = m_points = m_triangles = m_metadata = m_metaIds = false; } + void Reset() + { + m_types = m_common = m_header2 = m_relations = m_points = m_triangles = m_metadata = m_metaIds = false; + } }; struct Offsets { uint32_t m_common = 0; uint32_t m_header2 = 0; + uint32_t m_relations = 0; GeometryOffsets m_pts; GeometryOffsets m_trg; void Reset() { - m_common = m_header2 = 0; + m_common = m_header2 = m_relations = 0; m_pts.clear(); m_trg.clear(); } @@ -252,6 +265,9 @@ private: Offsets m_offsets; uint32_t m_ptsSimpMask = 0; + RelationIDsV m_relationIDs; + bool m_hasRelations = false; + InnerGeomStat m_innerStats; DISALLOW_COPY_AND_MOVE(FeatureType); diff --git a/libs/indexer/feature_source.cpp b/libs/indexer/feature_source.cpp index da75bb095..5d42ccb6f 100644 --- a/libs/indexer/feature_source.cpp +++ b/libs/indexer/feature_source.cpp @@ -19,8 +19,8 @@ FeatureSource::FeatureSource(MwmSet::MwmHandle const & handle) : m_handle(handle return; auto const & value = *m_handle.GetValue(); - m_vector = std::make_unique(value.m_cont, value.GetHeader(), value.m_table.get(), - value.m_metaDeserializer.get()); + m_vector = std::make_unique(value.m_cont, value.GetHeader(), value.m_ftTable.get(), + value.m_relTable.get(), value.m_metaDeserializer.get()); } size_t FeatureSource::GetNumFeatures() const diff --git a/libs/indexer/features_offsets_table.cpp b/libs/indexer/features_offsets_table.cpp index 392b319f3..865fad811 100644 --- a/libs/indexer/features_offsets_table.cpp +++ b/libs/indexer/features_offsets_table.cpp @@ -1,10 +1,7 @@ #include "indexer/features_offsets_table.hpp" -#include "indexer/dat_section_header.hpp" #include "indexer/features_vector.hpp" -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" #include "platform/platform.hpp" #include "coding/files_container.hpp" @@ -14,11 +11,11 @@ #include "base/logging.hpp" #include "base/scope_guard.hpp" +namespace feature +{ using namespace platform; using namespace std; -namespace feature -{ void FeaturesOffsetsTable::Builder::PushOffset(uint32_t const offset) { ASSERT(m_offsets.empty() || m_offsets.back() < offset, ()); @@ -63,14 +60,14 @@ unique_ptr FeaturesOffsetsTable::Load(string const & fileP } // static -unique_ptr FeaturesOffsetsTable::Load(FilesContainerR const & cont) +unique_ptr FeaturesOffsetsTable::Load(FilesContainerR const & cont, std::string const & tag) { unique_ptr table(new FeaturesOffsetsTable()); table->m_file.Open(cont.GetFileName()); - auto p = cont.GetAbsoluteOffsetAndSize(FEATURE_OFFSETS_FILE_TAG); + auto p = cont.GetAbsoluteOffsetAndSize(tag); ASSERT(p.first % 4 == 0, (p.first)); // will get troubles in succinct otherwise - table->m_handle.Assign(table->m_file.Map(p.first, p.second, FEATURE_OFFSETS_FILE_TAG)); + table->m_handle.Assign(table->m_file.Map(p.first, p.second, tag)); succinct::mapper::map(table->m_table, table->m_handle.GetData()); return table; @@ -80,9 +77,7 @@ void FeaturesOffsetsTable::Build(FilesContainerR const & cont, string const & st { Builder builder; FeaturesVector::ForEachOffset(cont, [&builder](uint32_t offset) { builder.PushOffset(offset); }); - - unique_ptr table(Build(builder)); - table->Save(storePath); + Build(builder)->Save(storePath); } void FeaturesOffsetsTable::Save(string const & filePath) @@ -123,7 +118,7 @@ bool BuildOffsetsTable(string const & filePath) { try { - string const destPath = filePath + ".offsets"; + string const destPath = filePath + TMP_OFFSETS_EXT; SCOPE_GUARD(fileDeleter, bind(FileWriter::DeleteFileX, destPath)); { @@ -140,5 +135,4 @@ bool BuildOffsetsTable(string const & filePath) return false; } } - } // namespace feature diff --git a/libs/indexer/features_offsets_table.hpp b/libs/indexer/features_offsets_table.hpp index 8be075f64..c050981b1 100644 --- a/libs/indexer/features_offsets_table.hpp +++ b/libs/indexer/features_offsets_table.hpp @@ -66,7 +66,7 @@ public: /// Load table by full path to the table file. static std::unique_ptr Load(std::string const & filePath); - static std::unique_ptr Load(FilesContainerR const & cont); + static std::unique_ptr Load(FilesContainerR const & cont, std::string const & tag); static void Build(FilesContainerR const & cont, std::string const & storePath); FeaturesOffsetsTable(FeaturesOffsetsTable const &) = delete; diff --git a/libs/indexer/features_vector.cpp b/libs/indexer/features_vector.cpp index b7c45d0a6..c1d4d8f73 100644 --- a/libs/indexer/features_vector.cpp +++ b/libs/indexer/features_vector.cpp @@ -5,10 +5,11 @@ #include "platform/constants.hpp" FeaturesVector::FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header, - feature::FeaturesOffsetsTable const * table, + feature::FeaturesOffsetsTable const * ftTable, + feature::FeaturesOffsetsTable const * relTable, indexer::MetadataDeserializer * metaDeserializer) - : m_loadInfo(cont, header, metaDeserializer) - , m_table(table) + : m_loadInfo(cont, header, relTable, metaDeserializer) + , m_table(ftTable) { InitRecordsReader(); } @@ -44,9 +45,12 @@ FeaturesVectorTest::FeaturesVectorTest(std::string const & filePath) FeaturesVectorTest::FeaturesVectorTest(FilesContainerR const & cont) : m_cont(cont) , m_header(m_cont) - , m_vector(m_cont, m_header, nullptr, nullptr) + , m_vector(m_cont, m_header, nullptr, nullptr, nullptr) { - m_vector.m_table = feature::FeaturesOffsetsTable::Load(m_cont).release(); + m_vector.m_table = feature::FeaturesOffsetsTable::Load(m_cont, FEATURE_OFFSETS_FILE_TAG).release(); + + if (m_cont.IsExist(RELATION_OFFSETS_FILE_TAG)) + m_vector.m_loadInfo.m_relTable = feature::FeaturesOffsetsTable::Load(m_cont, RELATION_OFFSETS_FILE_TAG).release(); if (m_cont.IsExist(METADATA_FILE_TAG)) m_vector.m_loadInfo.m_metaDeserializer = indexer::MetadataDeserializer::Load(m_cont).release(); @@ -56,4 +60,5 @@ FeaturesVectorTest::~FeaturesVectorTest() { delete m_vector.m_table; delete m_vector.m_loadInfo.m_metaDeserializer; + delete m_vector.m_loadInfo.m_relTable; } diff --git a/libs/indexer/features_vector.hpp b/libs/indexer/features_vector.hpp index b7280c4c4..a9037a1c0 100644 --- a/libs/indexer/features_vector.hpp +++ b/libs/indexer/features_vector.hpp @@ -21,7 +21,8 @@ class FeaturesVector public: FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header, - feature::FeaturesOffsetsTable const * table, indexer::MetadataDeserializer * metaDeserializer); + feature::FeaturesOffsetsTable const * ftTable, feature::FeaturesOffsetsTable const * relTable, + indexer::MetadataDeserializer * metaDeserializer); std::unique_ptr GetByIndex(uint32_t index) const; @@ -55,7 +56,8 @@ public: private: /// Actually, this ctor is needed only for ForEachOffset call. /// Didn't find a better solution without big refactoring. - FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header) : m_loadInfo(cont, header, nullptr) + FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header) + : m_loadInfo(cont, header, nullptr, nullptr) { InitRecordsReader(); } diff --git a/libs/indexer/indexer_tests/features_offsets_table_test.cpp b/libs/indexer/indexer_tests/features_offsets_table_test.cpp index 2752cf1ec..305d78429 100644 --- a/libs/indexer/indexer_tests/features_offsets_table_test.cpp +++ b/libs/indexer/indexer_tests/features_offsets_table_test.cpp @@ -81,7 +81,7 @@ UNIT_TEST(FeaturesOffsetsTable_ReadWrite) FeaturesOffsetsTable::Build(baseContainer, indexFile); - unique_ptr table(FeaturesOffsetsTable::Load(baseContainer)); + unique_ptr table(FeaturesOffsetsTable::Load(baseContainer, FEATURE_OFFSETS_FILE_TAG)); TEST(table.get() && table->size() > minFeaturesCount, ()); unique_ptr loadedTable(FeaturesOffsetsTable::Load(indexFile)); diff --git a/libs/indexer/indexer_tests/features_vector_test.cpp b/libs/indexer/indexer_tests/features_vector_test.cpp index e5a6c02f9..7d12eeba0 100644 --- a/libs/indexer/indexer_tests/features_vector_test.cpp +++ b/libs/indexer/indexer_tests/features_vector_test.cpp @@ -48,7 +48,8 @@ UNIT_TEST(FeaturesVectorTest_ParseMetadata) TEST(handle.IsAlive(), ()); auto const * value = handle.GetValue(); - FeaturesVector fv(value->m_cont, value->GetHeader(), value->m_table.get(), value->m_metaDeserializer.get()); + FeaturesVector fv(value->m_cont, value->GetHeader(), value->m_ftTable.get(), value->m_relTable.get(), + value->m_metaDeserializer.get()); map actual; fv.ForEach([&](FeatureType & ft, uint32_t index) diff --git a/libs/indexer/mwm_set.cpp b/libs/indexer/mwm_set.cpp index b16191f1a..58d762e9e 100644 --- a/libs/indexer/mwm_set.cpp +++ b/libs/indexer/mwm_set.cpp @@ -394,12 +394,19 @@ MwmValue::~MwmValue() {} void MwmValue::SetTable(MwmInfoEx & info) { - m_table = info.m_table.lock(); - if (m_table) - return; + m_ftTable = info.m_ftTable.lock(); + if (!m_ftTable) + { + m_ftTable = feature::FeaturesOffsetsTable::Load(m_cont, FEATURE_OFFSETS_FILE_TAG); + info.m_ftTable = m_ftTable; + } - m_table = feature::FeaturesOffsetsTable::Load(m_cont); - info.m_table = m_table; + m_relTable = info.m_relTable.lock(); + if (!m_relTable && m_cont.IsExist(RELATION_OFFSETS_FILE_TAG)) + { + m_relTable = feature::FeaturesOffsetsTable::Load(m_cont, RELATION_OFFSETS_FILE_TAG); + info.m_relTable = m_relTable; + } } string DebugPrint(MwmSet::RegResult result) diff --git a/libs/indexer/mwm_set.hpp b/libs/indexer/mwm_set.hpp index 5d309f21a..0c7fda49c 100644 --- a/libs/indexer/mwm_set.hpp +++ b/libs/indexer/mwm_set.hpp @@ -115,7 +115,7 @@ private: // only in MwmValue::SetTable() method, which, in turn, is called // only in the MwmSet critical section, protected by a lock. So, // there's an implicit synchronization on this field. - std::weak_ptr m_table; + std::weak_ptr m_ftTable, m_relTable; }; class MwmValue; @@ -387,7 +387,8 @@ private: feature::DataHeader m_header; public: - std::shared_ptr m_table; + // m_ftTable should always present, m_relTable maybe nullptr. + std::shared_ptr m_ftTable, m_relTable; std::unique_ptr m_metaDeserializer; std::unique_ptr m_house2street, m_house2place; diff --git a/libs/indexer/rank_table.cpp b/libs/indexer/rank_table.cpp index 90bcece6d..8016a430c 100644 --- a/libs/indexer/rank_table.cpp +++ b/libs/indexer/rank_table.cpp @@ -182,7 +182,7 @@ unique_ptr RankTable::Load(FilesMappingContainer const & mcont, strin void SearchRankTableBuilder::CalcSearchRanks(FilesContainerR & rcont, vector & ranks) { feature::DataHeader header(rcont); - FeaturesVector featuresVector(rcont, header, nullptr, nullptr); + FeaturesVector featuresVector(rcont, header, nullptr, nullptr, nullptr); featuresVector.ForEach([&ranks](FeatureType & ft, uint32_t /* index */) { ranks.push_back(CalcSearchRank(ft)); }); } diff --git a/libs/indexer/route_relation.hpp b/libs/indexer/route_relation.hpp new file mode 100644 index 000000000..979717e24 --- /dev/null +++ b/libs/indexer/route_relation.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include "coding/read_write_utils.hpp" +#include "coding/string_utf8_multilang.hpp" + +#include "base/buffer_vector.hpp" + +#include "drape/color.hpp" + +#include +#include + +namespace feature +{ + +class RouteRelationBase // like RelationType (FeatureType) +{ +public: + enum class Type : uint8_t + { + Foot = 0, + Hiking, + + Bicycle, + MTB, + + Bus, + Train, + Tram, + Trolleybus, + }; + enum IdxAndFlags : uint8_t + { + CycleNetworkIdx = 0, + OperatorIdx = 1, + OfficialRefIdx = 2, + FromIdx = 3, + ToIdx = 4, + WikipediaIdx = 5, + CountIdx = 6, + + HasColor = 0x40, + HasName = 0x80, + }; + + static constexpr dp::Color kEmptyColor = dp::Color::Transparent(); + + void SetParam(std::string_view s, IdxAndFlags idx) { m_params[idx] = s; } + std::string_view GetParam(IdxAndFlags idx) const { return m_params[idx]; } + + Type GetType() const { return m_type; } + dp::Color GetColor() const { return m_color; } + std::string const & GetRef() const { return m_ref; } + std::string const & GetNetwork() const { return m_network; } + + RouteRelationBase() = default; + + /// @todo Can optimize by storing color as an index in a palette (1 byte). + + template + void Write(TSink & sink) const + { + WriteToSink(sink, uint8_t(m_type)); + + uint8_t flags = 0; + + if (m_color != kEmptyColor) + flags |= HasColor; + if (!m_name.IsEmpty()) + flags |= HasName; + + for (int i = 0; i < CountIdx; ++i) + if (!m_params[i].empty()) + flags |= (1 << i); + + WriteToSink(sink, flags); + + if (flags & HasColor) + WriteToSink(sink, m_color.GetRGBA()); + + if (flags & HasName) + m_name.WriteNonEmpty(sink); + + rw::Write(sink, m_network); + rw::Write(sink, m_ref); + + for (int i = 0; i < CountIdx; ++i) + if (!m_params[i].empty()) + rw::WriteNonEmpty(sink, m_params[i]); + } + + template + void Read(TSource & src) + { + m_type = static_cast(ReadPrimitiveFromSource(src)); + + uint8_t const flags = ReadPrimitiveFromSource(src); + + if (flags & HasColor) + m_color = dp::Color::FromRGBA(ReadPrimitiveFromSource(src)); + + if (flags & HasName) + m_name.ReadNonEmpty(src); + + rw::Read(src, m_network); + rw::Read(src, m_ref); + + for (int i = 0; i < CountIdx; ++i) + if (flags & (1 << i)) + rw::ReadNonEmpty(src, m_params[i]); + } + +protected: + StringUtf8Multilang m_name; + std::string m_network, m_ref; + std::array m_params; + + dp::Color m_color = kEmptyColor; + Type m_type; // from route or route_master tag + + friend class RelationBuilder; +}; + +using ShortArray = buffer_vector; + +class RouteRelation : public RouteRelationBase +{ +public: + enum Flags : uint8_t + { + HasRelationMembers = 0x1, + HasParents = 0x2, + }; + + RouteRelation() = default; + + /// @todo Use RecordReader + buffers? + template + void Read(TSource & src) + { + RouteRelationBase::Read(src); + + uint32_t const sz = ReadVarUint(src); + m_ftMembers.reserve(sz); + uint32_t prev = 0; + for (size_t i = 0; i < sz; ++i) + { + m_ftMembers.push_back(prev + ReadVarUint(src)); + prev = m_ftMembers.back(); + } + + uint8_t const flags = ReadPrimitiveFromSource(src); + + if (flags & HasRelationMembers) + ReadVarUInt32SortedShortArray(src, m_relMembers); + + if (flags & HasParents) + ReadVarUInt32SortedShortArray(src, m_relParents); + } + +private: + std::vector m_ftMembers; + ShortArray m_relMembers; + ShortArray m_relParents; +}; + +} // namespace feature diff --git a/libs/indexer/shared_load_info.cpp b/libs/indexer/shared_load_info.cpp index 638fa7a53..d0735e371 100644 --- a/libs/indexer/shared_load_info.cpp +++ b/libs/indexer/shared_load_info.cpp @@ -1,15 +1,18 @@ #include "indexer/shared_load_info.hpp" #include "indexer/feature_impl.hpp" +#include "indexer/features_offsets_table.hpp" #include "defines.hpp" namespace feature { SharedLoadInfo::SharedLoadInfo(FilesContainerR const & cont, DataHeader const & header, + feature::FeaturesOffsetsTable const * relTable, indexer::MetadataDeserializer * metaDeserializer) : m_cont(cont) , m_header(header) + , m_relTable(relTable) , m_metaDeserializer(metaDeserializer) {} @@ -28,4 +31,15 @@ SharedLoadInfo::Reader SharedLoadInfo::GetTrianglesReader(size_t ind) const return m_cont.GetReader(GetTagForIndex(TRIANGLE_FILE_TAG, ind)); } +RouteRelationBase SharedLoadInfo::ReadRelation(uint32_t id) const +{ + auto reader = m_cont.GetReader(RELATIONS_FILE_TAG); + ReaderSource src(reader); + src.Skip(m_relTable->GetFeatureOffset(id)); + + RouteRelationBase res; + res.Read(src); + return res; +} + } // namespace feature diff --git a/libs/indexer/shared_load_info.hpp b/libs/indexer/shared_load_info.hpp index e16927f1e..e0c00620b 100644 --- a/libs/indexer/shared_load_info.hpp +++ b/libs/indexer/shared_load_info.hpp @@ -2,6 +2,7 @@ #include "indexer/dat_section_header.hpp" #include "indexer/data_header.hpp" +#include "indexer/route_relation.hpp" #include "coding/files_container.hpp" #include "coding/geometry_coding.hpp" @@ -15,6 +16,8 @@ class MetadataDeserializer; namespace feature { +class FeaturesOffsetsTable; + // This info is created once per FeaturesVector. class SharedLoadInfo { @@ -22,12 +25,14 @@ public: using Reader = FilesContainerR::TReader; SharedLoadInfo(FilesContainerR const & cont, DataHeader const & header, - indexer::MetadataDeserializer * metaDeserializer); + feature::FeaturesOffsetsTable const * relTable, indexer::MetadataDeserializer * metaDeserializer); Reader GetDataReader() const; Reader GetGeometryReader(size_t ind) const; Reader GetTrianglesReader(size_t ind) const; + RouteRelationBase ReadRelation(uint32_t id) const; + serial::GeometryCodingParams const & GetDefGeometryCodingParams() const { return m_header.GetDefGeometryCodingParams(); @@ -47,6 +52,7 @@ private: DataHeader const & m_header; public: + feature::FeaturesOffsetsTable const * m_relTable; indexer::MetadataDeserializer * m_metaDeserializer; feature::DatSectionHeader::Version m_version; diff --git a/libs/map/mwm_tests/multithread_mwm_test.cpp b/libs/map/mwm_tests/multithread_mwm_test.cpp index 3c441425b..59427f711 100644 --- a/libs/map/mwm_tests/multithread_mwm_test.cpp +++ b/libs/map/mwm_tests/multithread_mwm_test.cpp @@ -29,7 +29,8 @@ public: m_src.ForEachFeature(r, [this](FeatureType & ft) { - ft.ParseHeader2(); + ft.ParseAllBeforeGeometry(); + (void)ft.GetOuterGeometryStats(); (void)ft.GetOuterTrianglesStats(); diff --git a/libs/routing/routing_integration_tests/concurrent_feature_parsing_test.cpp b/libs/routing/routing_integration_tests/concurrent_feature_parsing_test.cpp index 7ccde102e..04606cac4 100644 --- a/libs/routing/routing_integration_tests/concurrent_feature_parsing_test.cpp +++ b/libs/routing/routing_integration_tests/concurrent_feature_parsing_test.cpp @@ -42,7 +42,7 @@ void TestConcurrentAccessToFeatures(string const & mwm) auto const handle = dataSource.GetMwmHandleByCountryFile(countryFile); TEST(handle.IsAlive(), (local)); - auto const featureNumber = handle.GetValue()->m_table->size(); + auto const featureNumber = handle.GetValue()->m_ftTable->size(); // Note. If hardware_concurrency() returns 0 it means that number of core is not defined. // If hardware_concurrency() returns 1 it means that only one core is available. // In the both cases 2 threads should be used for this test. diff --git a/libs/search/mwm_context.cpp b/libs/search/mwm_context.cpp index d70b37bc6..add1f7700 100644 --- a/libs/search/mwm_context.cpp +++ b/libs/search/mwm_context.cpp @@ -17,7 +17,8 @@ void CoverRect(m2::RectD const & rect, int scale, covering::Intervals & result) MwmContext::MwmContext(MwmSet::MwmHandle handle) : m_handle(std::move(handle)) , m_value(*m_handle.GetValue()) - , m_vector(m_value.m_cont, m_value.GetHeader(), m_value.m_table.get(), m_value.m_metaDeserializer.get()) + , m_vector(m_value.m_cont, m_value.GetHeader(), m_value.m_ftTable.get(), m_value.m_relTable.get(), + m_value.m_metaDeserializer.get()) , m_index(m_value.m_cont.GetReader(INDEX_FILE_TAG)) , m_centers(m_value) , m_editableSource(m_handle) diff --git a/tools/feature_list/feature_list.cpp b/tools/feature_list/feature_list.cpp index eec415ca3..079888876 100644 --- a/tools/feature_list/feature_list.cpp +++ b/tools/feature_list/feature_list.cpp @@ -194,7 +194,8 @@ public: void Process(FeatureType & f, map const & ft2osm) { - f.ParseHeader2(); + f.ParseAllBeforeGeometry(); + string const & category = GetReadableType(f); auto const & meta = f.GetMetadata();