[feature] Added RouteRelation and linked it with FeatureType.

Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
This commit is contained in:
Viktor Govako
2025-06-25 23:58:19 -03:00
committed by Konstantin Pastbin
parent 315bba2a22
commit b85c11ea5a
26 changed files with 336 additions and 63 deletions

View File

@@ -4,6 +4,7 @@
#define DATA_FILE_EXTENSION ".mwm" #define DATA_FILE_EXTENSION ".mwm"
#define DATA_FILE_EXTENSION_TMP ".mwm.tmp" #define DATA_FILE_EXTENSION_TMP ".mwm.tmp"
#define RELATIONS_FILE_EXTENSION_TMP ".rels.tmp"
#define DIFF_FILE_EXTENSION ".mwmdiff" #define DIFF_FILE_EXTENSION ".mwmdiff"
#define DIFF_APPLYING_FILE_EXTENSION ".diff.applying" #define DIFF_APPLYING_FILE_EXTENSION ".diff.applying"
#define FONT_FILE_EXTENSION ".ttf" #define FONT_FILE_EXTENSION ".ttf"
@@ -22,8 +23,11 @@
#define OFFSET_EXT ".offs" #define OFFSET_EXT ".offs"
#define ID2REL_EXT ".id2rel" #define ID2REL_EXT ".id2rel"
auto constexpr TMP_OFFSETS_EXT = OFFSET_EXT EXTENSION_TMP;
#define CENTERS_FILE_TAG "centers" #define CENTERS_FILE_TAG "centers"
#define FEATURES_FILE_TAG "features" #define FEATURES_FILE_TAG "features"
#define RELATIONS_FILE_TAG "relations"
#define GEOMETRY_FILE_TAG "geom" #define GEOMETRY_FILE_TAG "geom"
#define TRIANGLE_FILE_TAG "trg" #define TRIANGLE_FILE_TAG "trg"
#define INDEX_FILE_TAG "idx" #define INDEX_FILE_TAG "idx"
@@ -36,7 +40,7 @@
#define POSTCODE_POINTS_FILE_TAG "postcode_points" #define POSTCODE_POINTS_FILE_TAG "postcode_points"
#define POSTCODES_FILE_TAG "postcodes" #define POSTCODES_FILE_TAG "postcodes"
#define CITIES_BOUNDARIES_FILE_TAG "cities_boundaries" #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 HEADER_FILE_TAG "header"
#define VERSION_FILE_TAG "version" #define VERSION_FILE_TAG "version"
#define METADATA_FILE_TAG "meta" #define METADATA_FILE_TAG "meta"
@@ -47,6 +51,7 @@
#define ROUTING_FILE_TAG "routing" #define ROUTING_FILE_TAG "routing"
#define CROSS_MWM_FILE_TAG "cross_mwm" #define CROSS_MWM_FILE_TAG "cross_mwm"
#define FEATURE_OFFSETS_FILE_TAG "offs" #define FEATURE_OFFSETS_FILE_TAG "offs"
#define RELATION_OFFSETS_FILE_TAG "rel_offs"
#define SEARCH_RANKS_FILE_TAG "ranks" #define SEARCH_RANKS_FILE_TAG "ranks"
#define POPULARITY_RANKS_FILE_TAG "popularity" #define POPULARITY_RANKS_FILE_TAG "popularity"
#define REGION_INFO_FILE_TAG "rgninfo" #define REGION_INFO_FILE_TAG "rgninfo"

View File

@@ -24,7 +24,7 @@ bool BuildCentersTableFromDataFile(std::string const & filename, bool forceRebui
if (!forceRebuild && rcont.IsExist(CENTERS_FILE_TAG)) if (!forceRebuild && rcont.IsExist(CENTERS_FILE_TAG))
return true; return true;
auto const table = feature::FeaturesOffsetsTable::Load(rcont); auto const table = feature::FeaturesOffsetsTable::Load(rcont, FEATURE_OFFSETS_FILE_TAG);
if (!table) if (!table)
{ {
LOG(LERROR, ("Can't load offsets table from:", filename)); 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); 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()); builder.SetGeometryParams(header.GetBounds());
features.ForEach([&](FeatureType & ft, uint32_t featureId) { builder.Put(featureId, feature::GetCenter(ft)); }); features.ForEach([&](FeatureType & ft, uint32_t featureId) { builder.Put(featureId, feature::GetCenter(ft)); });

View File

@@ -631,7 +631,10 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi
CHECK(type != GeomType::Undefined, ()); CHECK(type != GeomType::Undefined, ());
if (type == GeomType::Point) 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; 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 ? trgCount : data.m_trgMask, 4);
bitSink.Write(trgCount == 0 ? 1 : 0, 1); bitSink.Write(trgCount == 0 ? 1 : 0, 1);
} }
// Relations control bit
bitSink.Write(0, 1);
} }
if (type == GeomType::Line) if (type == GeomType::Line)

View File

@@ -156,7 +156,8 @@ public:
void operator()(FeatureType & f, uint32_t const & id) void operator()(FeatureType & f, uint32_t const & id)
{ {
f.ParseHeader2(); f.ParseAllBeforeGeometry();
if (!GetBicycleModel().IsRoad(feature::TypesHolder(f))) if (!GetBicycleModel().IsRoad(feature::TypesHolder(f)))
{ {
++m_notRoadCount; ++m_notRoadCount;

View File

@@ -50,7 +50,7 @@ public:
void operator()(FeatureType & f, uint32_t) void operator()(FeatureType & f, uint32_t)
{ {
f.ParseHeader2(); f.ParseAllBeforeGeometry();
FeatureType::InnerGeomStat const innerStats = f.GetInnerStats(); FeatureType::InnerGeomStat const innerStats = f.GetInnerStats();

View File

@@ -15,6 +15,7 @@ struct Color
constexpr Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) constexpr Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
: Color(red << 24 | green << 16 | blue << 8 | 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) constexpr Color(uint32_t rgb, uint8_t alpha)
: Color(ExtractByte(rgb, 2), ExtractByte(rgb, 1), ExtractByte(rgb, 0), 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)}; 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: private:
constexpr static uint8_t ExtractByte(uint32_t number, uint8_t byteIdx) { return (number >> (8 * byteIdx)) & 0xFF; } constexpr static uint8_t ExtractByte(uint32_t number, uint8_t byteIdx) { return (number >> (8 * byteIdx)) & 0xFF; }

View File

@@ -103,10 +103,11 @@ set(SRC
metadata_serdes.hpp metadata_serdes.hpp
mwm_set.cpp mwm_set.cpp
mwm_set.hpp mwm_set.hpp
postcodes_matcher.cpp # 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 due to editor which is in indexer and depends on postcodes_marcher postcodes_matcher.hpp # it's in indexer EditableMapObject depends on postcodes_matcher
rank_table.cpp rank_table.cpp
rank_table.hpp rank_table.hpp
route_relation.hpp
road_shields_parser.cpp road_shields_parser.cpp
road_shields_parser.hpp road_shields_parser.hpp
scale_index.hpp scale_index.hpp

View File

@@ -244,6 +244,7 @@ std::unique_ptr<FeatureType> FeatureType::CreateFromMapObject(osm::MapObject con
ft->m_parsed.m_types = true; ft->m_parsed.m_types = true;
ft->m_header = CalculateHeader(emo.GetTypes().Size(), headerGeomType, ft->m_params); ft->m_header = CalculateHeader(emo.GetTypes().Size(), headerGeomType, ft->m_params);
ft->m_parsed.m_header2 = true; ft->m_parsed.m_header2 = true;
ft->m_parsed.m_relations = true;
ft->m_id = emo.GetID(); ft->m_id = emo.GetID();
return ft; return ft;
@@ -305,7 +306,17 @@ void FeatureType::ParseCommon()
if (GetGeomType() == GeomType::Point) if (GetGeomType() == GeomType::Point)
{ {
m_center = serial::LoadPoint(source, m_loadInfo->GetDefGeometryCodingParams()); uint64_t decoded = ReadVarUint<uint64_t>(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); m_limitRect.Add(m_center);
} }
@@ -329,13 +340,7 @@ int8_t FeatureType::GetLayer()
return m_params.layer; return m_params.layer;
} }
// TODO: there is a room to store more information in Header2 (geometry header), // TODO: One of the free bits could be used for a closed line flag to avoid storing identical first + last points.
// 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.
void FeatureType::ParseHeader2() void FeatureType::ParseHeader2()
{ {
if (m_parsed.m_header2) if (m_parsed.m_header2)
@@ -347,7 +352,10 @@ void FeatureType::ParseHeader2()
auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE); auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE);
if (headerGeomType != HeaderGeomType::Line && headerGeomType != HeaderGeomType::Area) if (headerGeomType != HeaderGeomType::Line && headerGeomType != HeaderGeomType::Area)
{
m_offsets.m_relations = m_offsets.m_header2;
return; return;
}
BitSource bitSource(m_data.data() + m_offsets.m_header2); BitSource bitSource(m_data.data() + m_offsets.m_header2);
uint8_t elemsCount = bitSource.Read(4); uint8_t elemsCount = bitSource.Read(4);
@@ -362,13 +370,15 @@ void FeatureType::ParseHeader2()
} }
else 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); bool const isOuter = (bitSource.Read(1) == 1);
if (isOuter) if (isOuter)
{ {
geomScalesMask = elemsCount; geomScalesMask = elemsCount;
elemsCount = 0; elemsCount = 0;
} }
m_hasRelations = (bitSource.Read(1) == 1);
} }
ArrayByteSource src(bitSource.RoundPtr()); 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. // Size of the whole header incl. inner geometry / triangles.
m_innerStats.m_size = CalcOffset(src, m_data.data()); m_innerStats.m_size = CalcOffset(src, m_data.data());
} }
@@ -442,7 +469,7 @@ void FeatureType::ResetGeometry()
if (GetGeomType() != GeomType::Point) if (GetGeomType() != GeomType::Point)
m_limitRect = m2::RectD(); 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_pts.clear();
m_offsets.m_trg.clear(); m_offsets.m_trg.clear();
m_ptsSimpMask = 0; m_ptsSimpMask = 0;
@@ -501,9 +528,9 @@ void FeatureType::ParseGeometry(int scale)
FeatureType::GeomStat FeatureType::GetOuterGeometryStats() 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(); 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; FeatureType::GeomStat res;
auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE); auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE);
@@ -576,10 +603,9 @@ void FeatureType::ParseTriangles(int scale)
FeatureType::GeomStat FeatureType::GetOuterTrianglesStats() 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(); int const scalesCount = m_loadInfo->GetScalesCount();
ASSERT_LESS_OR_EQUAL(scalesCount, static_cast<int>(DataHeader::kMaxScalesCount), ASSERT_LESS_OR_EQUAL(scalesCount, static_cast<int>(DataHeader::kMaxScalesCount), ());
("MWM has too many geometry scales!"));
FeatureType::GeomStat res; FeatureType::GeomStat res;
auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE); auto const headerGeomType = static_cast<HeaderGeomType>(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(); 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);
}

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "indexer/feature_data.hpp" #include "indexer/feature_data.hpp"
#include "indexer/metadata_serdes.hpp" #include "indexer/metadata_serdes.hpp"
#include "indexer/route_relation.hpp"
#include "geometry/point2d.hpp" #include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp" #include "geometry/rect2d.hpp"
@@ -82,6 +83,8 @@ public:
FeatureID const & GetID() const { return m_id; } FeatureID const & GetID() const { return m_id; }
void ParseHeader2(); void ParseHeader2();
void ParseRelations();
void ParseAllBeforeGeometry() { ParseRelations(); }
void ResetGeometry(); void ResetGeometry();
void ParseGeometry(int scale); void ParseGeometry(int scale);
void ParseTriangles(int scale); void ParseTriangles(int scale);
@@ -195,31 +198,41 @@ public:
GeomStat GetOuterTrianglesStats(); GeomStat GetOuterTrianglesStats();
//@} //@}
using RelationIDsV = feature::ShortArray;
RelationIDsV const & GetRelations();
feature::RouteRelationBase ReadRelation(uint32_t id);
private: private:
struct ParsedFlags struct ParsedFlags
{ {
bool m_types : 1; bool m_types : 1;
bool m_common : 1; bool m_common : 1;
bool m_header2 : 1; bool m_header2 : 1;
bool m_relations : 1;
bool m_points : 1; bool m_points : 1;
bool m_triangles : 1; bool m_triangles : 1;
bool m_metadata : 1; bool m_metadata : 1;
bool m_metaIds : 1; bool m_metaIds : 1;
ParsedFlags() { Reset(); } 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 struct Offsets
{ {
uint32_t m_common = 0; uint32_t m_common = 0;
uint32_t m_header2 = 0; uint32_t m_header2 = 0;
uint32_t m_relations = 0;
GeometryOffsets m_pts; GeometryOffsets m_pts;
GeometryOffsets m_trg; GeometryOffsets m_trg;
void Reset() void Reset()
{ {
m_common = m_header2 = 0; m_common = m_header2 = m_relations = 0;
m_pts.clear(); m_pts.clear();
m_trg.clear(); m_trg.clear();
} }
@@ -252,6 +265,9 @@ private:
Offsets m_offsets; Offsets m_offsets;
uint32_t m_ptsSimpMask = 0; uint32_t m_ptsSimpMask = 0;
RelationIDsV m_relationIDs;
bool m_hasRelations = false;
InnerGeomStat m_innerStats; InnerGeomStat m_innerStats;
DISALLOW_COPY_AND_MOVE(FeatureType); DISALLOW_COPY_AND_MOVE(FeatureType);

View File

@@ -19,8 +19,8 @@ FeatureSource::FeatureSource(MwmSet::MwmHandle const & handle) : m_handle(handle
return; return;
auto const & value = *m_handle.GetValue(); auto const & value = *m_handle.GetValue();
m_vector = std::make_unique<FeaturesVector>(value.m_cont, value.GetHeader(), value.m_table.get(), m_vector = std::make_unique<FeaturesVector>(value.m_cont, value.GetHeader(), value.m_ftTable.get(),
value.m_metaDeserializer.get()); value.m_relTable.get(), value.m_metaDeserializer.get());
} }
size_t FeatureSource::GetNumFeatures() const size_t FeatureSource::GetNumFeatures() const

View File

@@ -1,10 +1,7 @@
#include "indexer/features_offsets_table.hpp" #include "indexer/features_offsets_table.hpp"
#include "indexer/dat_section_header.hpp"
#include "indexer/features_vector.hpp" #include "indexer/features_vector.hpp"
#include "platform/local_country_file.hpp"
#include "platform/local_country_file_utils.hpp"
#include "platform/platform.hpp" #include "platform/platform.hpp"
#include "coding/files_container.hpp" #include "coding/files_container.hpp"
@@ -14,11 +11,11 @@
#include "base/logging.hpp" #include "base/logging.hpp"
#include "base/scope_guard.hpp" #include "base/scope_guard.hpp"
namespace feature
{
using namespace platform; using namespace platform;
using namespace std; using namespace std;
namespace feature
{
void FeaturesOffsetsTable::Builder::PushOffset(uint32_t const offset) void FeaturesOffsetsTable::Builder::PushOffset(uint32_t const offset)
{ {
ASSERT(m_offsets.empty() || m_offsets.back() < offset, ()); ASSERT(m_offsets.empty() || m_offsets.back() < offset, ());
@@ -63,14 +60,14 @@ unique_ptr<FeaturesOffsetsTable> FeaturesOffsetsTable::Load(string const & fileP
} }
// static // static
unique_ptr<FeaturesOffsetsTable> FeaturesOffsetsTable::Load(FilesContainerR const & cont) unique_ptr<FeaturesOffsetsTable> FeaturesOffsetsTable::Load(FilesContainerR const & cont, std::string const & tag)
{ {
unique_ptr<FeaturesOffsetsTable> table(new FeaturesOffsetsTable()); unique_ptr<FeaturesOffsetsTable> table(new FeaturesOffsetsTable());
table->m_file.Open(cont.GetFileName()); 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 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<char>()); succinct::mapper::map(table->m_table, table->m_handle.GetData<char>());
return table; return table;
@@ -80,9 +77,7 @@ void FeaturesOffsetsTable::Build(FilesContainerR const & cont, string const & st
{ {
Builder builder; Builder builder;
FeaturesVector::ForEachOffset(cont, [&builder](uint32_t offset) { builder.PushOffset(offset); }); FeaturesVector::ForEachOffset(cont, [&builder](uint32_t offset) { builder.PushOffset(offset); });
Build(builder)->Save(storePath);
unique_ptr<FeaturesOffsetsTable> table(Build(builder));
table->Save(storePath);
} }
void FeaturesOffsetsTable::Save(string const & filePath) void FeaturesOffsetsTable::Save(string const & filePath)
@@ -123,7 +118,7 @@ bool BuildOffsetsTable(string const & filePath)
{ {
try try
{ {
string const destPath = filePath + ".offsets"; string const destPath = filePath + TMP_OFFSETS_EXT;
SCOPE_GUARD(fileDeleter, bind(FileWriter::DeleteFileX, destPath)); SCOPE_GUARD(fileDeleter, bind(FileWriter::DeleteFileX, destPath));
{ {
@@ -140,5 +135,4 @@ bool BuildOffsetsTable(string const & filePath)
return false; return false;
} }
} }
} // namespace feature } // namespace feature

View File

@@ -66,7 +66,7 @@ public:
/// Load table by full path to the table file. /// Load table by full path to the table file.
static std::unique_ptr<FeaturesOffsetsTable> Load(std::string const & filePath); static std::unique_ptr<FeaturesOffsetsTable> Load(std::string const & filePath);
static std::unique_ptr<FeaturesOffsetsTable> Load(FilesContainerR const & cont); static std::unique_ptr<FeaturesOffsetsTable> Load(FilesContainerR const & cont, std::string const & tag);
static void Build(FilesContainerR const & cont, std::string const & storePath); static void Build(FilesContainerR const & cont, std::string const & storePath);
FeaturesOffsetsTable(FeaturesOffsetsTable const &) = delete; FeaturesOffsetsTable(FeaturesOffsetsTable const &) = delete;

View File

@@ -5,10 +5,11 @@
#include "platform/constants.hpp" #include "platform/constants.hpp"
FeaturesVector::FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header, FeaturesVector::FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header,
feature::FeaturesOffsetsTable const * table, feature::FeaturesOffsetsTable const * ftTable,
feature::FeaturesOffsetsTable const * relTable,
indexer::MetadataDeserializer * metaDeserializer) indexer::MetadataDeserializer * metaDeserializer)
: m_loadInfo(cont, header, metaDeserializer) : m_loadInfo(cont, header, relTable, metaDeserializer)
, m_table(table) , m_table(ftTable)
{ {
InitRecordsReader(); InitRecordsReader();
} }
@@ -44,9 +45,12 @@ FeaturesVectorTest::FeaturesVectorTest(std::string const & filePath)
FeaturesVectorTest::FeaturesVectorTest(FilesContainerR const & cont) FeaturesVectorTest::FeaturesVectorTest(FilesContainerR const & cont)
: m_cont(cont) : m_cont(cont)
, m_header(m_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)) if (m_cont.IsExist(METADATA_FILE_TAG))
m_vector.m_loadInfo.m_metaDeserializer = indexer::MetadataDeserializer::Load(m_cont).release(); 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_table;
delete m_vector.m_loadInfo.m_metaDeserializer; delete m_vector.m_loadInfo.m_metaDeserializer;
delete m_vector.m_loadInfo.m_relTable;
} }

View File

@@ -21,7 +21,8 @@ class FeaturesVector
public: public:
FeaturesVector(FilesContainerR const & cont, feature::DataHeader const & header, 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<FeatureType> GetByIndex(uint32_t index) const; std::unique_ptr<FeatureType> GetByIndex(uint32_t index) const;
@@ -55,7 +56,8 @@ public:
private: private:
/// Actually, this ctor is needed only for ForEachOffset call. /// Actually, this ctor is needed only for ForEachOffset call.
/// Didn't find a better solution without big refactoring. /// 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(); InitRecordsReader();
} }

View File

@@ -81,7 +81,7 @@ UNIT_TEST(FeaturesOffsetsTable_ReadWrite)
FeaturesOffsetsTable::Build(baseContainer, indexFile); FeaturesOffsetsTable::Build(baseContainer, indexFile);
unique_ptr<FeaturesOffsetsTable> table(FeaturesOffsetsTable::Load(baseContainer)); unique_ptr<FeaturesOffsetsTable> table(FeaturesOffsetsTable::Load(baseContainer, FEATURE_OFFSETS_FILE_TAG));
TEST(table.get() && table->size() > minFeaturesCount, ()); TEST(table.get() && table->size() > minFeaturesCount, ());
unique_ptr<FeaturesOffsetsTable> loadedTable(FeaturesOffsetsTable::Load(indexFile)); unique_ptr<FeaturesOffsetsTable> loadedTable(FeaturesOffsetsTable::Load(indexFile));

View File

@@ -48,7 +48,8 @@ UNIT_TEST(FeaturesVectorTest_ParseMetadata)
TEST(handle.IsAlive(), ()); TEST(handle.IsAlive(), ());
auto const * value = handle.GetValue(); 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<string, int> actual; map<string, int> actual;
fv.ForEach([&](FeatureType & ft, uint32_t index) fv.ForEach([&](FeatureType & ft, uint32_t index)

View File

@@ -394,12 +394,19 @@ MwmValue::~MwmValue() {}
void MwmValue::SetTable(MwmInfoEx & info) void MwmValue::SetTable(MwmInfoEx & info)
{ {
m_table = info.m_table.lock(); m_ftTable = info.m_ftTable.lock();
if (m_table) if (!m_ftTable)
return; {
m_ftTable = feature::FeaturesOffsetsTable::Load(m_cont, FEATURE_OFFSETS_FILE_TAG);
info.m_ftTable = m_ftTable;
}
m_table = feature::FeaturesOffsetsTable::Load(m_cont); m_relTable = info.m_relTable.lock();
info.m_table = m_table; 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) string DebugPrint(MwmSet::RegResult result)

View File

@@ -115,7 +115,7 @@ private:
// only in MwmValue::SetTable() method, which, in turn, is called // only in MwmValue::SetTable() method, which, in turn, is called
// only in the MwmSet critical section, protected by a lock. So, // only in the MwmSet critical section, protected by a lock. So,
// there's an implicit synchronization on this field. // there's an implicit synchronization on this field.
std::weak_ptr<feature::FeaturesOffsetsTable> m_table; std::weak_ptr<feature::FeaturesOffsetsTable> m_ftTable, m_relTable;
}; };
class MwmValue; class MwmValue;
@@ -387,7 +387,8 @@ private:
feature::DataHeader m_header; feature::DataHeader m_header;
public: public:
std::shared_ptr<feature::FeaturesOffsetsTable> m_table; // m_ftTable should always present, m_relTable maybe nullptr.
std::shared_ptr<feature::FeaturesOffsetsTable> m_ftTable, m_relTable;
std::unique_ptr<indexer::MetadataDeserializer> m_metaDeserializer; std::unique_ptr<indexer::MetadataDeserializer> m_metaDeserializer;
std::unique_ptr<HouseToStreetTable> m_house2street, m_house2place; std::unique_ptr<HouseToStreetTable> m_house2street, m_house2place;

View File

@@ -182,7 +182,7 @@ unique_ptr<RankTable> RankTable::Load(FilesMappingContainer const & mcont, strin
void SearchRankTableBuilder::CalcSearchRanks(FilesContainerR & rcont, vector<uint8_t> & ranks) void SearchRankTableBuilder::CalcSearchRanks(FilesContainerR & rcont, vector<uint8_t> & ranks)
{ {
feature::DataHeader header(rcont); 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)); }); featuresVector.ForEach([&ranks](FeatureType & ft, uint32_t /* index */) { ranks.push_back(CalcSearchRank(ft)); });
} }

View File

@@ -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 <array>
#include <string>
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 <class TSink>
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 <class TSource>
void Read(TSource & src)
{
m_type = static_cast<Type>(ReadPrimitiveFromSource<uint8_t>(src));
uint8_t const flags = ReadPrimitiveFromSource<uint8_t>(src);
if (flags & HasColor)
m_color = dp::Color::FromRGBA(ReadPrimitiveFromSource<uint32_t>(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<std::string, CountIdx> m_params;
dp::Color m_color = kEmptyColor;
Type m_type; // from route or route_master tag
friend class RelationBuilder;
};
using ShortArray = buffer_vector<uint32_t, 2>;
class RouteRelation : public RouteRelationBase
{
public:
enum Flags : uint8_t
{
HasRelationMembers = 0x1,
HasParents = 0x2,
};
RouteRelation() = default;
/// @todo Use RecordReader + buffers?
template <class TSource>
void Read(TSource & src)
{
RouteRelationBase::Read(src);
uint32_t const sz = ReadVarUint<uint32_t>(src);
m_ftMembers.reserve(sz);
uint32_t prev = 0;
for (size_t i = 0; i < sz; ++i)
{
m_ftMembers.push_back(prev + ReadVarUint<uint32_t>(src));
prev = m_ftMembers.back();
}
uint8_t const flags = ReadPrimitiveFromSource<uint8_t>(src);
if (flags & HasRelationMembers)
ReadVarUInt32SortedShortArray(src, m_relMembers);
if (flags & HasParents)
ReadVarUInt32SortedShortArray(src, m_relParents);
}
private:
std::vector<uint32_t> m_ftMembers;
ShortArray m_relMembers;
ShortArray m_relParents;
};
} // namespace feature

View File

@@ -1,15 +1,18 @@
#include "indexer/shared_load_info.hpp" #include "indexer/shared_load_info.hpp"
#include "indexer/feature_impl.hpp" #include "indexer/feature_impl.hpp"
#include "indexer/features_offsets_table.hpp"
#include "defines.hpp" #include "defines.hpp"
namespace feature namespace feature
{ {
SharedLoadInfo::SharedLoadInfo(FilesContainerR const & cont, DataHeader const & header, SharedLoadInfo::SharedLoadInfo(FilesContainerR const & cont, DataHeader const & header,
feature::FeaturesOffsetsTable const * relTable,
indexer::MetadataDeserializer * metaDeserializer) indexer::MetadataDeserializer * metaDeserializer)
: m_cont(cont) : m_cont(cont)
, m_header(header) , m_header(header)
, m_relTable(relTable)
, m_metaDeserializer(metaDeserializer) , m_metaDeserializer(metaDeserializer)
{} {}
@@ -28,4 +31,15 @@ SharedLoadInfo::Reader SharedLoadInfo::GetTrianglesReader(size_t ind) const
return m_cont.GetReader(GetTagForIndex(TRIANGLE_FILE_TAG, ind)); 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 } // namespace feature

View File

@@ -2,6 +2,7 @@
#include "indexer/dat_section_header.hpp" #include "indexer/dat_section_header.hpp"
#include "indexer/data_header.hpp" #include "indexer/data_header.hpp"
#include "indexer/route_relation.hpp"
#include "coding/files_container.hpp" #include "coding/files_container.hpp"
#include "coding/geometry_coding.hpp" #include "coding/geometry_coding.hpp"
@@ -15,6 +16,8 @@ class MetadataDeserializer;
namespace feature namespace feature
{ {
class FeaturesOffsetsTable;
// This info is created once per FeaturesVector. // This info is created once per FeaturesVector.
class SharedLoadInfo class SharedLoadInfo
{ {
@@ -22,12 +25,14 @@ public:
using Reader = FilesContainerR::TReader; using Reader = FilesContainerR::TReader;
SharedLoadInfo(FilesContainerR const & cont, DataHeader const & header, SharedLoadInfo(FilesContainerR const & cont, DataHeader const & header,
indexer::MetadataDeserializer * metaDeserializer); feature::FeaturesOffsetsTable const * relTable, indexer::MetadataDeserializer * metaDeserializer);
Reader GetDataReader() const; Reader GetDataReader() const;
Reader GetGeometryReader(size_t ind) const; Reader GetGeometryReader(size_t ind) const;
Reader GetTrianglesReader(size_t ind) const; Reader GetTrianglesReader(size_t ind) const;
RouteRelationBase ReadRelation(uint32_t id) const;
serial::GeometryCodingParams const & GetDefGeometryCodingParams() const serial::GeometryCodingParams const & GetDefGeometryCodingParams() const
{ {
return m_header.GetDefGeometryCodingParams(); return m_header.GetDefGeometryCodingParams();
@@ -47,6 +52,7 @@ private:
DataHeader const & m_header; DataHeader const & m_header;
public: public:
feature::FeaturesOffsetsTable const * m_relTable;
indexer::MetadataDeserializer * m_metaDeserializer; indexer::MetadataDeserializer * m_metaDeserializer;
feature::DatSectionHeader::Version m_version; feature::DatSectionHeader::Version m_version;

View File

@@ -29,7 +29,8 @@ public:
m_src.ForEachFeature(r, [this](FeatureType & ft) m_src.ForEachFeature(r, [this](FeatureType & ft)
{ {
ft.ParseHeader2(); ft.ParseAllBeforeGeometry();
(void)ft.GetOuterGeometryStats(); (void)ft.GetOuterGeometryStats();
(void)ft.GetOuterTrianglesStats(); (void)ft.GetOuterTrianglesStats();

View File

@@ -42,7 +42,7 @@ void TestConcurrentAccessToFeatures(string const & mwm)
auto const handle = dataSource.GetMwmHandleByCountryFile(countryFile); auto const handle = dataSource.GetMwmHandleByCountryFile(countryFile);
TEST(handle.IsAlive(), (local)); 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. // 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. // 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. // In the both cases 2 threads should be used for this test.

View File

@@ -17,7 +17,8 @@ void CoverRect(m2::RectD const & rect, int scale, covering::Intervals & result)
MwmContext::MwmContext(MwmSet::MwmHandle handle) MwmContext::MwmContext(MwmSet::MwmHandle handle)
: m_handle(std::move(handle)) : m_handle(std::move(handle))
, m_value(*m_handle.GetValue()) , 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_index(m_value.m_cont.GetReader(INDEX_FILE_TAG))
, m_centers(m_value) , m_centers(m_value)
, m_editableSource(m_handle) , m_editableSource(m_handle)

View File

@@ -194,7 +194,8 @@ public:
void Process(FeatureType & f, map<uint32_t, base::GeoObjectId> const & ft2osm) void Process(FeatureType & f, map<uint32_t, base::GeoObjectId> const & ft2osm)
{ {
f.ParseHeader2(); f.ParseAllBeforeGeometry();
string const & category = GetReadableType(f); string const & category = GetReadableType(f);
auto const & meta = f.GetMetadata(); auto const & meta = f.GetMetadata();