From 2400357a3db3f7eaf00e8c75d7603168f441fd80 Mon Sep 17 00:00:00 2001 From: vng Date: Mon, 9 May 2011 01:53:49 +0300 Subject: [PATCH] Refactoring of feature structure: - multilanguage names - separate house numbers - point feature rank - refs for linear features --- docs/feature structure.txt | 10 +- generator/feature_merger.cpp | 5 +- generator/feature_merger.hpp | 5 +- .../generator_tests/feature_bucketer_test.cpp | 1 + generator/osm2type.cpp | 83 +++++-- generator/osm2type.hpp | 9 +- generator/osm_element.hpp | 69 ++---- generator/statistics.cpp | 8 +- generator/statistics.hpp | 2 +- generator/world_map_generator.hpp | 2 +- indexer/feature.cpp | 223 +++++++----------- indexer/feature.hpp | 126 ++++------ indexer/feature_data.cpp | 129 ++++++++++ indexer/feature_data.hpp | 163 +++++++++++++ indexer/feature_visibility.cpp | 4 +- indexer/indexer.pro | 2 + map/framework.cpp | 12 +- qt/searchwindow.cpp | 7 +- 18 files changed, 535 insertions(+), 325 deletions(-) create mode 100644 indexer/feature_data.cpp create mode 100644 indexer/feature_data.hpp diff --git a/docs/feature structure.txt b/docs/feature structure.txt index ff01b23e9f..e882d27e89 100644 --- a/docs/feature structure.txt +++ b/docs/feature structure.txt @@ -2,11 +2,13 @@ 0. кол-во типов (1-8, пишем 0-7, 3 бита) 3. имя 4. слой -5. точка -6. линия -7. площадной +5, 6. - тип геометрии (точка = 00, линия = 01, площадной = 10) +7. бит присутствия дополнительной информации: + - точка - ранг (1 байт как логарифм населения по основанию 1.1); + - линейный - № дороги (строка); + - площадной - № дома (строка, оптимизированная для хранения двузначного числа); -* пишем типы, слой, имя, точку +* пишем типы, имя, слой, дополнительную информацию, точку (для точечного типа) 1 или 2 байта следующего заголовка (только для линейного и\или площадного объекта): * 4 бита кол-ва внутренних точек для линейного объекта: diff --git a/generator/feature_merger.cpp b/generator/feature_merger.cpp index 547ef882c0..5cdb681e73 100644 --- a/generator/feature_merger.cpp +++ b/generator/feature_merger.cpp @@ -17,10 +17,11 @@ bool FeatureBuilder1Merger::ReachedMaxPointsCount() const void FeatureBuilder1Merger::AppendFeature(FeatureBuilder1Merger const & fb) { // check that both features are of linear type - CHECK(fb.m_bLinear && m_bLinear, ("Not linear feature")); + CHECK(fb.m_Params.GetGeomType() == feature::GEOM_LINE && + m_Params.GetGeomType() == feature::GEOM_LINE, ("Not linear feature")); // check that classificator types are the same - CHECK_EQUAL(fb.m_Types, m_Types, ("Not equal types")); + //CHECK_EQUAL(fb.m_Types, m_Types, ("Not equal types")); // check last-first points equality //CHECK_EQUAL(m_Geometry.back(), fb.m_Geometry.front(), ("End and Start point are no equal")); diff --git a/generator/feature_merger.hpp b/generator/feature_merger.hpp index 0bede7358c..0662309097 100644 --- a/generator/feature_merger.hpp +++ b/generator/feature_merger.hpp @@ -16,14 +16,13 @@ public: if (m_Geometry.size() < 3) return false; - m_bArea = true; + m_Params.SetGeomType(feature::GEOM_AREA); return true; } uint32_t KeyType() const { - ASSERT_EQUAL ( m_Types.size(), 1, () ); - return m_Types.front(); + return m_Params.KeyType(); } bool ReachedMaxPointsCount() const; diff --git a/generator/generator_tests/feature_bucketer_test.cpp b/generator/generator_tests/feature_bucketer_test.cpp index 648a83e26e..4cdbf527aa 100644 --- a/generator/generator_tests/feature_bucketer_test.cpp +++ b/generator/generator_tests/feature_bucketer_test.cpp @@ -60,6 +60,7 @@ UNIT_TEST(FeatureBucketerSmokeTest) fb.AddPoint(m2::PointD(10, 10)); fb.AddPoint(m2::PointD(20, 20)); fb.SetType(0); + fb.SetLinear(); bucketer(fb); FeatureType f; diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index 864b2fe876..dc630f81c5 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -450,7 +450,8 @@ namespace ftype { string const & k = p->childs[i].attrs["k"]; string const & v = p->childs[i].attrs["v"]; - if (is_skip_tag(k, v)) continue; + if (k.empty() || is_skip_tag(k, v)) + continue; // this means "no" //if (get_mark_value(k, v) == -1) @@ -485,33 +486,70 @@ namespace ftype { class do_find_name { size_t & m_count; - string & m_name; - string & m_addr; - int32_t & m_layer; + FeatureParams & m_params; + + class get_lang + { + bool m_ok; + string & m_lang; + + public: + get_lang(string & lang) : m_ok(false), m_lang(lang) {} + + void operator() (string const & s) + { + if (m_ok) + m_lang = s; + else if (s == "name") + { + m_ok = true; + m_lang = "def"; + } + } + }; public: typedef bool result_type; - do_find_name(size_t & count, string & name, string & addr, int32_t & layer) - : m_count(count), m_name(name), m_addr(addr), m_layer(layer) + do_find_name(size_t & count, FeatureParams & params) + : m_count(count), m_params(params) { m_count = 0; - m_layer = 0; } bool operator() (string const & k, string const & v) { ++m_count; - // do not call is_name_tag(k), but exactly "name" tag - if (m_name.empty() && k == "name") - m_name = v; + if (v.empty()) return false; - // add house number - if (m_addr.empty() && k == "addr:housenumber") - m_addr = v; + // get names + string lang; + utils::TokenizeString(k, "\t :", get_lang(lang)); + if (!lang.empty()) + m_params.name.AddString(lang, v); - if (k == "layer" && m_layer == 0) - m_layer = atoi(v.c_str()); + // get layer + if (k == "layer" && m_params.layer == 0) + m_params.layer = atoi(v.c_str()); + + // get reference (we process road numbers only) + if (k == "ref") + m_params.ref = v; + + // get house number + if ((m_params.house.IsEmpty() && k == "addr:housenumber") || + (k == "addr:housename")) + { + m_params.house.Set(v); + } + + // get population rank + if (k == "population") + { + int n; + if (utils::to_int(v, n)) + m_params.rank = static_cast(log(double(n)) / log(1.1)); + } return false; } @@ -565,13 +603,10 @@ namespace ftype { return for_each_tag(p, do_find_obj(parent, isKey)); } - size_t find_name_and_count(XMLElement * p, string & name, int32_t & layer) + size_t process_common_params(XMLElement * p, FeatureParams & params) { size_t count; - string addr; - for_each_tag(p, do_find_name(count, name, addr, layer)); - - if (name.empty()) name = addr; + for_each_tag(p, do_find_name(count, params)); return count; } @@ -589,7 +624,7 @@ namespace ftype { // }; //#endif - bool GetNameAndType(XMLElement * p, vector & types, string & name, int32_t & layer) + bool GetNameAndType(XMLElement * p, FeatureParams & params) { //#ifdef DEBUG // // code to set a breakpoint @@ -600,7 +635,7 @@ namespace ftype { //#endif // maybe an empty feature - if (find_name_and_count(p, name, layer) == 0) + if (process_common_params(p, params) == 0) return false; set skipRootKeys; @@ -639,7 +674,7 @@ namespace ftype { // use features only with drawing rules if (feature::IsDrawableAny(t)) - types.push_back(t); + params.AddType(t); } if (pRoot) @@ -652,6 +687,6 @@ namespace ftype { } while (true); - return !types.empty(); + return params.IsValid(); } } diff --git a/generator/osm2type.hpp b/generator/osm2type.hpp index 6a2449c29d..fa399ba6ef 100644 --- a/generator/osm2type.hpp +++ b/generator/osm2type.hpp @@ -1,9 +1,6 @@ #pragma once -#include "../base/base.hpp" - -#include "../std/string.hpp" -#include "../std/vector.hpp" +#include "../indexer/feature_data.hpp" #include "../base/start_mem_debug.hpp" @@ -13,8 +10,8 @@ namespace ftype { void ParseOSMTypes(char const * fPath, int scale); - /// Get the types, name and layer fot feature with the tree of tags. - bool GetNameAndType(XMLElement * p, vector & types, string & name, int32_t & layer); + /// Get the types, name and layer for feature with the tree of tags. + bool GetNameAndType(XMLElement * p, FeatureParams & params); } #include "../base/stop_mem_debug.hpp" diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index 70e34e7e69..06b8b1c25c 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -28,9 +28,6 @@ protected: TEmitter & m_emitter; THolder & m_holder; - /// max possible number of types per feature - static const size_t max_number_of_types = 16; - SecondPassParserBase(TEmitter & emitter, THolder & holder) : m_emitter(emitter), m_holder(holder) { @@ -189,25 +186,6 @@ protected: list > & GetHoles() { return m_holes.m_holes; } }; - /// Feature description struct. - struct value_t - { - typedef vector types_t; - types_t types; ///< 1-n types, not empty - string name; ///< 1-1 name, @todo 1-n names - int32_t layer; ///< layer - - value_t() - { - types.reserve(max_number_of_types); - } - bool IsValid() const { return !types.empty(); } - void Add(value_t const & v) - { - types.insert(types.end(), v.types.begin(), v.types.end()); - } - }; - /// Feature types processor. class type_processor { @@ -229,14 +207,14 @@ protected: uint64_t m_featureID; /// @param[out] Feature value as result. - value_t * m_val; + FeatureParams * m_val; /// Cache: relation id -> feature value (for fast feature parsing) - unordered_map m_typeCache; + unordered_map m_typeCache; public: /// Start process new feature. - void Reset(uint64_t fID, value_t * val) + void Reset(uint64_t fID, FeatureParams * val) { m_featureID = fID; m_val = val; @@ -245,10 +223,10 @@ protected: /// 1. "initial relation" process int operator() (uint64_t id) { - typename unordered_map::const_iterator i = m_typeCache.find(id); + typename unordered_map::const_iterator i = m_typeCache.find(id); if (i != m_typeCache.end()) { - m_val->Add(i->second); + m_val->AddTypes(i->second); return -1; // continue process relations } return 0; // read relation from file (see next operator) @@ -268,14 +246,14 @@ protected: else { // process types of relation and add them to m_val - value_t val; - if (ftype::GetNameAndType(&e, val.types, val.name, val.layer)) + FeatureParams val; + if (ftype::GetNameAndType(&e, val)) { m_typeCache[id] = val; - m_val->Add(val); + m_val->AddTypes(val); } else - m_typeCache[id] = value_t(); + m_typeCache[id] = FeatureParams(); } // continue process relations @@ -294,13 +272,13 @@ protected: ft.SetAreaAddHoles(processor.GetHoles()); } - bool ParseType(XMLElement * p, uint64_t & id, value_t & fValue) + bool ParseType(XMLElement * p, uint64_t & id, FeatureParams & fValue) { VERIFY ( utils::to_uint64(p->attrs["id"], id), ("Unknown element with invalid id : ", p->attrs["id"]) ); // try to get type from element tags - ftype::GetNameAndType(p, fValue.types, fValue.name, fValue.layer); + ftype::GetNameAndType(p, fValue); // try to get type from relations tags m_typeProcessor.Reset(id, &fValue); @@ -316,9 +294,7 @@ protected: m_holder.ForEachRelationByWayCached(id, m_typeProcessor); } - // remove duplicating types - sort(fValue.types.begin(), fValue.types.end()); - fValue.types.erase(unique(fValue.types.begin(), fValue.types.end()), fValue.types.end()); + fValue.FinishAddingTypes(); // unrecognized feature by classificator return fValue.IsValid(); @@ -421,12 +397,12 @@ protected: virtual void EmitElement(XMLElement * p) { uint64_t id; - typename base_type::value_t fValue; + FeatureParams fValue; if (!ParseType(p, id, fValue)) return; // check, if we can make united feature - for (typename base_type::value_t::types_t::iterator i = fValue.types.begin(); i != fValue.types.end(); ++i) + for (typename FeatureParams::types_t::iterator i = fValue.types.begin(); i != fValue.types.end(); ++i) if (feature::NeedUnite(*i)) { typename base_type::feature_builder_t ft; @@ -452,21 +428,18 @@ class SecondPassParserUsual : public SecondPassParserBase { typedef SecondPassParserBase base_type; - typedef typename base_type::value_t type_t; typedef typename base_type::feature_builder_t feature_t; - void InitFeature(type_t const & fValue, feature_t & ft) + void InitFeature(FeatureParams const & fValue, feature_t & ft) { - ft.AddName(fValue.name); - ft.AddTypes(fValue.types.begin(), fValue.types.end()); - ft.AddLayer(fValue.layer); + ft.SetParams(fValue); } protected: virtual void EmitElement(XMLElement * p) { uint64_t id; - type_t fValue; + FeatureParams fValue; if (!ParseType(p, id, fValue)) return; @@ -475,7 +448,7 @@ protected: if (p->name == "node") { - if (!feature::IsDrawableLike(fValue.types, feature::fpoint)) + if (!feature::IsDrawableLike(fValue.m_Types, feature::fpoint)) return; m2::PointD pt; @@ -491,8 +464,8 @@ protected: // __debugbreak(); //#endif - bool const isLine = feature::IsDrawableLike(fValue.types, feature::fline); - bool const isArea = feature::IsDrawableLike(fValue.types, feature::farea); + bool const isLine = feature::IsDrawableLike(fValue.m_Types, feature::fline); + bool const isArea = feature::IsDrawableLike(fValue.m_Types, feature::farea); if (!isLine && !isArea) return; @@ -533,7 +506,7 @@ protected: // __debugbreak(); //#endif - if (!feature::IsDrawableLike(fValue.types, feature::farea)) + if (!feature::IsDrawableLike(fValue.m_Types, feature::farea)) return; // check, if this is our processable relation diff --git a/generator/statistics.cpp b/generator/statistics.cpp index 84c99ea74a..0d9da58ad7 100644 --- a/generator/statistics.cpp +++ b/generator/statistics.cpp @@ -13,6 +13,8 @@ #include "../base/start_mem_debug.hpp" +using namespace feature; + namespace stats { void FileContainerStatistic(string const & fName) @@ -88,12 +90,12 @@ namespace stats cout << prefix << ": size = " << info.m_size << "; count = " << info.m_count << endl; } - string GetKey(FeatureBase::FeatureType type) + string GetKey(EGeomType type) { switch (type) { - case FeatureBase::FEATURE_TYPE_LINE: return "Line"; - case FeatureBase::FEATURE_TYPE_AREA: return "Area"; + case GEOM_LINE: return "Line"; + case GEOM_AREA: return "Area"; default: return "Point"; } } diff --git a/generator/statistics.hpp b/generator/statistics.hpp index a4a73c03c1..2f4956fd20 100644 --- a/generator/statistics.hpp +++ b/generator/statistics.hpp @@ -51,7 +51,7 @@ namespace stats struct MapInfo { - set > m_byGeomType; + set > m_byGeomType; set > m_byClassifType; set > m_byPointsCount, m_byTrgCount; diff --git a/generator/world_map_generator.hpp b/generator/world_map_generator.hpp index 75928828b1..9838de9ec3 100644 --- a/generator/world_map_generator.hpp +++ b/generator/world_map_generator.hpp @@ -194,7 +194,7 @@ public: if (m_maxWorldScale >= minScale) { - if (m_mergeCoastlines && fBase.GetFeatureType() == FeatureBase::FEATURE_TYPE_LINE) + if (m_mergeCoastlines && fBase.GetFeatureType() == feature::GEOM_LINE) { for (size_t i = 0; i < m_MergeTypes.size(); ++i) { diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 8accf58a70..e4fda8ab1a 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -23,15 +23,12 @@ #include "../base/start_mem_debug.hpp" +using namespace feature; + /////////////////////////////////////////////////////////////////////////////////////////////////// // FeatureBuilder1 implementation /////////////////////////////////////////////////////////////////////////////////////////////////// -FeatureBuilder1::FeatureBuilder1() -: m_Layer(0), m_bPoint(false), m_bLinear(false), m_bArea(false) -{ -} - bool FeatureBuilder1::IsGeometryClosed() const { return (m_Geometry.size() > 2 && m_Geometry.front() == m_Geometry.back()); @@ -40,7 +37,7 @@ bool FeatureBuilder1::IsGeometryClosed() const void FeatureBuilder1::SetCenter(m2::PointD const & p) { m_Center = p; - m_bPoint = true; + m_Params.SetGeomType(GEOM_POINT); m_LimitRect.Add(p); } @@ -52,7 +49,7 @@ void FeatureBuilder1::AddPoint(m2::PointD const & p) void FeatureBuilder1::SetAreaAddHoles(list const & holes) { - m_bArea = true; + m_Params.SetGeomType(GEOM_AREA); m_Holes.clear(); if (holes.empty()) return; @@ -68,47 +65,16 @@ void FeatureBuilder1::SetAreaAddHoles(list const & holes) } } -void FeatureBuilder1::AddName(string const & name) -{ - m_Name = name; -} - -bool FeatureBuilder1::IsTypeExist(uint32_t t) const -{ - return (find(m_Types.begin(), m_Types.end(), t) != m_Types.end()); -} - -bool FeatureBuilder1::AssignType_SetDifference(vector const & diffTypes) -{ - vector src; - src.swap(m_Types); - - sort(src.begin(), src.end()); - set_difference(src.begin(), src.end(), diffTypes.begin(), diffTypes.end(), back_inserter(m_Types)); - - return !m_Types.empty(); -} - -void FeatureBuilder1::AddLayer(int32_t layer) -{ - int const bound = 10; - if (layer < -bound) layer = -bound; - else if (layer > bound) layer = bound; - m_Layer = layer; -} - FeatureBase FeatureBuilder1::GetFeatureBase() const { CHECK ( CheckValid(), () ); FeatureBase f; - f.SetHeader(GetHeader()); + f.SetHeader(m_Params.GetHeader()); - f.m_Layer = m_Layer; - for (size_t i = 0; i < m_Types.size(); ++i) - f.m_Types[i] = m_Types[i]; + f.m_Params = m_Params; + memcpy(f.m_Types, &m_Params.m_Types[0], sizeof(uint32_t) * m_Params.m_Types.size()); f.m_LimitRect = m_LimitRect; - f.m_Name = m_Name; f.m_bTypesParsed = f.m_bCommonParsed = true; @@ -149,20 +115,40 @@ namespace } } -bool FeatureBuilder1::operator == (FeatureBuilder1 const & fb) const +bool FeatureBuilder1::PreSerialize() { - if (m_Types != fb.m_Types || - m_Layer != fb.m_Layer || - m_Name != fb.m_Name || - m_bPoint != fb.m_bPoint || - m_bLinear != fb.m_bLinear || - m_bArea != fb.m_bArea) + if (!m_Params.IsValid()) return false; + + switch (m_Params.GetGeomType()) { + case GEOM_POINT: + m_Params.ref = string(); + m_Params.house.Clear(); + break; + case GEOM_LINE: + m_Params.rank = 0; + m_Params.house.Clear(); + break; + case GEOM_AREA: + m_Params.rank = 0; + m_Params.ref = string(); + break; + default: return false; } - if (m_bPoint && !is_equal(m_Center, fb.m_Center)) + return true; +} + +bool FeatureBuilder1::operator == (FeatureBuilder1 const & fb) const +{ + if (!(m_Params == fb.m_Params)) return false; + + if (m_Params.GetGeomType() == GEOM_POINT && + !is_equal(m_Center, fb.m_Center)) + { return false; + } if (!is_equal(m_LimitRect, fb.m_LimitRect)) return false; @@ -184,17 +170,15 @@ bool FeatureBuilder1::operator == (FeatureBuilder1 const & fb) const bool FeatureBuilder1::CheckValid() const { - CHECK(!m_Types.empty() && m_Types.size() <= m_maxTypesCount, ()); + CHECK(m_Params.CheckValid(), ()); - CHECK(m_Layer >= -10 && m_Layer <= 10, ()); + EGeomType const type = m_Params.GetGeomType(); - CHECK(m_bPoint || m_bLinear || m_bArea, ()); + CHECK(type != GEOM_LINE || m_Geometry.size() >= 2, ()); - CHECK(!m_bLinear || m_Geometry.size() >= 2, ()); + CHECK(type != GEOM_AREA || m_Geometry.size() >= 3, ()); - CHECK(!m_bArea || m_Geometry.size() >= 3, ()); - - CHECK(m_Holes.empty() || m_bArea, ()); + CHECK(m_Holes.empty() || type == GEOM_AREA, ()); for (list::const_iterator i = m_Holes.begin(); i != m_Holes.end(); ++i) CHECK(i->size() >= 3, ()); @@ -202,47 +186,13 @@ bool FeatureBuilder1::CheckValid() const return true; } -uint8_t FeatureBuilder1::GetHeader() const -{ - uint8_t header = static_cast(m_Types.size()); - - if (!m_Name.empty()) - header |= FeatureBase::HEADER_HAS_NAME; - - if (m_Layer != 0) - header |= FeatureBase::HEADER_HAS_LAYER; - - if (m_bPoint) - header |= FeatureBase::HEADER_HAS_POINT; - - if (m_bLinear) - header |= FeatureBase::HEADER_IS_LINE; - - if (m_bArea) - header |= FeatureBase::HEADER_IS_AREA; - - return header; -} - void FeatureBuilder1::SerializeBase(buffer_t & data, serial::CodingParams const & params) const { PushBackByteSink sink(data); - WriteToSink(sink, GetHeader()); + m_Params.Write(sink); - for (size_t i = 0; i < m_Types.size(); ++i) - WriteVarUint(sink, m_Types[i]); - - if (m_Layer != 0) - WriteVarInt(sink, m_Layer); - - if (!m_Name.empty()) - { - WriteVarUint(sink, m_Name.size() - 1); - sink.Write(&m_Name[0], m_Name.size()); - } - - if (m_bPoint) + if (m_Params.GetGeomType() == GEOM_POINT) WriteVarUint(sink, EncodeDelta(PointD2PointU(m_Center.x, m_Center.y, params.GetCoordBits()), params.GetBasePoint())); } @@ -257,10 +207,12 @@ void FeatureBuilder1::Serialize(buffer_t & data) const PushBackByteSink sink(data); - if (m_bLinear || m_bArea) + EGeomType const type = m_Params.GetGeomType(); + + if (type != GEOM_POINT) serial::SaveOuterPath(m_Geometry, serial::CodingParams(), sink); - if (m_bArea) + if (type == GEOM_AREA) { WriteVarUint(sink, uint32_t(m_Holes.size())); @@ -295,13 +247,15 @@ void FeatureBuilder1::Deserialize(buffer_t & data) ArrayByteSource src(f.DataPtr() + f.m_Header2Offset); - if (m_bLinear || m_bArea) + EGeomType const type = m_Params.GetGeomType(); + + if (type != GEOM_POINT) { serial::LoadOuterPath(src, serial::CodingParams(), m_Geometry); CalcRect(m_Geometry, m_LimitRect); } - if (m_bArea) + if (type == GEOM_AREA) { uint32_t const count = ReadVarUint(src); for (uint32_t i = 0; i < count; ++i) @@ -336,10 +290,10 @@ bool FeatureBuilder2::PreSerialize(buffers_holder_t const & data) { // make flags actual before header serialization if (data.m_ptsMask == 0 && data.m_innerPts.empty()) - m_bLinear = false; + m_Params.RemoveGeomType(GEOM_LINE); if (data.m_trgMask == 0 && data.m_innerTrg.empty()) - m_bArea = false; + m_Params.RemoveGeomType(GEOM_AREA); // we don't need empty features without geometry return base_type::PreSerialize(); @@ -399,14 +353,16 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co BitSink< PushBackByteSink > bitSink(sink); - if (m_bLinear) + EGeomType const type = m_Params.GetGeomType(); + + if (type == GEOM_LINE) { bitSink.Write(ptsCount, 4); if (ptsCount == 0) bitSink.Write(data.m_ptsMask, 4); } - if (m_bArea) + if (type == GEOM_AREA) { bitSink.Write(trgCount, 4); if (trgCount == 0) @@ -415,7 +371,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co bitSink.Finish(); - if (m_bLinear) + if (type == GEOM_LINE) { if (ptsCount > 0) { @@ -440,7 +396,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co } } - if (m_bArea) + if (type == GEOM_AREA) { if (trgCount > 0) serial::SaveInnerTriangles(data.m_innerTrg, params, sink); @@ -467,8 +423,7 @@ void FeatureBase::Deserialize(buffer_t & data, uint32_t offset, serial::CodingPa m_CommonOffset = m_Header2Offset = 0; m_bTypesParsed = m_bCommonParsed = false; - m_Layer = 0; - m_Name.clear(); + m_Params = FeatureParamsBase(); m_LimitRect = m2::RectD::GetEmptyRect(); } @@ -506,16 +461,11 @@ void FeatureBase::ParseCommon() const uint8_t const h = Header(); - if (h & HEADER_HAS_LAYER) - m_Layer = ReadVarInt(source); + EGeomType const type = GetFeatureType(); - if (h & HEADER_HAS_NAME) - { - m_Name.resize(ReadVarUint(source) + 1); - source.Read(&m_Name[0], m_Name.size()); - } + m_Params.Read(source, h, type); - if (h & HEADER_HAS_POINT) + if (type == GEOM_POINT) { CoordPointT center = PointU2PointD(DecodeDelta(ReadVarUint(source), m_CodingParams.GetBasePoint()), @@ -539,14 +489,13 @@ string FeatureBase::DebugString() const ASSERT(m_bCommonParsed, ()); string res("FEATURE: "); - res += "'" + m_Name + "' "; for (size_t i = 0; i < GetTypesCount(); ++i) res += "Type:" + debug_print(m_Types[i]) + " "; - res += "Layer:" + debug_print(m_Layer) + " "; + res += m_Params.DebugString(); - if (Header() & HEADER_HAS_POINT) + if (GetFeatureType() == GEOM_POINT) res += "Center:" + debug_print(m_Center) + " "; return res; @@ -556,23 +505,14 @@ void FeatureBase::InitFeatureBuilder(FeatureBuilder1 & fb) const { ParseAll(); - fb.AddTypes(m_Types, m_Types + GetTypesCount()); - fb.AddLayer(m_Layer); - fb.AddName(m_Name); + FeatureParams params(m_Params); + params.AssignTypes(m_Types, m_Types + GetTypesCount()); + params.SetGeomType(GetFeatureType()); - uint8_t const h = Header(); + fb.SetParams(params); - if (h & HEADER_HAS_POINT) + if (GetFeatureType() == GEOM_POINT) fb.SetCenter(m_Center); - - if (h & HEADER_IS_LINE) - fb.SetLinear(); - - if (h & HEADER_IS_AREA) - { - list > l; - fb.SetAreaAddHoles(l); - } } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -674,11 +614,9 @@ bool FeatureType::IsEmptyGeometry(int scale) const switch (GetFeatureType()) { - case FEATURE_TYPE_AREA: return m_Triangles.empty(); - case FEATURE_TYPE_LINE: return m_Points.empty(); - default: - ASSERT ( Header() & HEADER_HAS_POINT, () ); - return false; + case GEOM_AREA: return m_Triangles.empty(); + case GEOM_LINE: return m_Points.empty(); + default: return false; } } @@ -686,7 +624,7 @@ m2::RectD FeatureType::GetLimitRect(int scale) const { ParseAll(scale); - if (m_Triangles.empty() && m_Points.empty() && (Header() & HEADER_HAS_POINT) == 0) + if (m_Triangles.empty() && m_Points.empty() && (GetFeatureType() != GEOM_POINT)) { // This function is called during indexing, when we need // to check visibility according to feature sizes. @@ -751,10 +689,11 @@ void FeatureType::ParseHeader2() const uint8_t ptsCount, ptsMask, trgCount, trgMask; - uint8_t const commonH = Header(); BitSource bitSource(DataPtr() + m_Header2Offset); - if (commonH & HEADER_IS_LINE) + EGeomType const type = GetFeatureType(); + + if (type == GEOM_LINE) { ptsCount = bitSource.Read(4); if (ptsCount == 0) @@ -765,7 +704,7 @@ void FeatureType::ParseHeader2() const } } - if (commonH & HEADER_IS_AREA) + if (type == GEOM_AREA) { trgCount = bitSource.Read(4); if (trgCount == 0) @@ -774,7 +713,7 @@ void FeatureType::ParseHeader2() const ArrayByteSource src(bitSource.RoundPtr()); - if (commonH & HEADER_IS_LINE) + if (type == GEOM_LINE) { if (ptsCount > 0) { @@ -797,7 +736,7 @@ void FeatureType::ParseHeader2() const ReadOffsets(src, ptsMask, m_ptsOffsets); } - if (commonH & HEADER_IS_AREA) + if (type == GEOM_AREA) { if (trgCount > 0) { @@ -832,7 +771,7 @@ uint32_t FeatureType::ParseGeometry(int scale) const ParseHeader2(); uint32_t sz = 0; - if (Header() & HEADER_IS_LINE) + if (GetFeatureType() == GEOM_LINE) { if (m_Points.empty()) { @@ -885,7 +824,7 @@ uint32_t FeatureType::ParseTriangles(int scale) const ParseHeader2(); uint32_t sz = 0; - if (Header() & HEADER_IS_AREA) + if (GetFeatureType() == GEOM_AREA) { if (m_Triangles.empty()) { diff --git a/indexer/feature.hpp b/indexer/feature.hpp index e5c99e8ece..f2c7dc4d98 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -2,6 +2,7 @@ #include "cell_id.hpp" #include "data_header.hpp" +#include "feature_data.hpp" #include "../geometry/point2d.hpp" #include "../geometry/rect2d.hpp" @@ -18,12 +19,11 @@ class ArrayByteSource; class FeatureBase; + /// Used for serialization\deserialization of features during --generate_features. class FeatureBuilder1 { public: - FeatureBuilder1(); - /// @name Geometry manipulating functions. //@{ /// Set center (origin) point of feature and set that feature is point. @@ -33,33 +33,25 @@ public: void AddPoint(m2::PointD const & p); /// Set that feature is linear type. - void SetLinear() { m_bLinear = true; } + void SetLinear() { m_Params.SetGeomType(feature::GEOM_LINE); } - /// Set that featue is area and get ownership of holes. + /// Set that feature is area and get ownership of holes. void SetAreaAddHoles(list > const & holes); //@} - void AddName(string const & name); - - static const int m_maxTypesCount = 7; - - template - inline void AddTypes(TIter beg, TIter end) - { - // !WTF! with GCC - int const count = min(static_cast(m_maxTypesCount), static_cast(distance(beg, end))); - m_Types.assign(beg, beg + count); - } inline void SetType(uint32_t type) { - m_Types.clear(); - m_Types.push_back(type); + m_Params.SetType(type); } - bool IsTypeExist(uint32_t t) const; - bool AssignType_SetDifference(vector const & diffTypes); - - void AddLayer(int32_t layer); + inline bool IsTypeExist(uint32_t t) const + { + return m_Params.IsTypeExist(t); + } + inline bool AssignType_SetDifference(vector const & diffTypes) + { + return m_Params.AssignType_SetDifference(diffTypes); + } typedef vector buffer_t; @@ -92,7 +84,7 @@ public: template void ForEachTruePointRef(ToDo & toDo) const { - if (m_bPoint) + if (m_Params.GetGeomType() == feature::GEOM_POINT) toDo(m_Center); else { @@ -102,10 +94,12 @@ public: } } - m2::PointD CenterPoint() const { return m_Center; } + inline m2::PointD CenterPoint() const { return m_Center; } //@} - bool PreSerialize() { return m_bPoint || m_bLinear || m_bArea; } + bool PreSerialize(); + + inline void SetParams(FeatureParams const & params) { m_Params = params; } protected: @@ -116,18 +110,7 @@ protected: bool CheckValid() const; //@} - typedef vector points_t; - - uint8_t GetHeader() const; - - /// Name. Can be empty. Check HEADER_HAS_NAME. - string m_Name; - - /// Feature classificator-types. Can not be empty. - vector m_Types; - - /// Drawable layer of feature. Can be empty, Check HEADER_HAS_LAYER. - int32_t m_Layer; + FeatureParams m_Params; m2::RectD m_LimitRect; @@ -137,6 +120,8 @@ protected: /// - origin point of text or symbol in area-feature m2::PointD m_Center; // Check HEADER_HAS_POINT + typedef vector points_t; + /// Can be one of the following: /// - geometry in line-feature /// - boundary in area-feature @@ -144,13 +129,6 @@ protected: /// List of holes in area-feature. list m_Holes; // Check HEADER_IS_AREA - - /// @name This flags can be combined. - //@{ - bool m_bPoint; ///< this is point feature (also m_Center exists) - bool m_bLinear; ///< this is linear-feature - bool m_bArea; ///< this is area-feature - //@} }; /// Used for serialization of features during final pass. @@ -182,8 +160,8 @@ public: buffers_holder_t() : m_ptsMask(0), m_trgMask(0), m_ptsSimpMask(0) {} }; - bool IsLine() const { return m_bLinear; } - bool IsArea() const { return m_bArea; } + bool IsLine() const { return (m_Params.GetGeomType() == feature::GEOM_LINE); } + bool IsArea() const { return (m_Params.GetGeomType() == feature::GEOM_AREA); } bool IsDrawableInRange(int lowS, int highS) const; points_t const & GetGeometry() const { return m_Geometry; } @@ -201,52 +179,46 @@ class FeatureBase { static const int m_maxTypesCount = 7; public: - enum FeatureType - { - FEATURE_TYPE_POINT = 0, - FEATURE_TYPE_LINE = 1, - FEATURE_TYPE_AREA = 2 - }; - FeatureBase() : m_Offset(0) {} typedef vector buffer_t; - inline FeatureType GetFeatureType() const + inline feature::EGeomType GetFeatureType() const { - uint8_t const h = Header(); - if (h & HEADER_IS_AREA) - return FEATURE_TYPE_AREA; - else if (h & HEADER_IS_LINE) - return FEATURE_TYPE_LINE; + uint8_t const h = Header() & feature::HEADER_GEOTYPE_MASK; + + if (h == feature::HEADER_GEOM_POINT) + return feature::GEOM_POINT; + else if (h == feature::HEADER_GEOM_LINE) + return feature::GEOM_LINE; else { - ASSERT ( h & HEADER_HAS_POINT, () ); - return FEATURE_TYPE_POINT; + ASSERT ( h == feature::HEADER_GEOM_AREA, (h) ); + return feature::GEOM_AREA; } } - inline uint32_t GetTypesCount() const + inline uint8_t GetTypesCount() const { - return Header() & m_maxTypesCount; + return ((Header() & feature::HEADER_TYPE_MASK) + 1); } - inline int32_t GetLayer() const + inline int8_t GetLayer() const { - if (!(Header() & HEADER_HAS_LAYER)) + if (!(Header() & feature::HEADER_HAS_LAYER)) return 0; if (!m_bCommonParsed) ParseCommon(); - return m_Layer; + return m_Params.layer; } - inline string GetName() const + inline bool GetName(char lang, string & utf8s) const { - if (!(Header() & HEADER_HAS_NAME)) - return string(); + if (!(Header() & feature::HEADER_HAS_NAME)) + return false; if (!m_bCommonParsed) ParseCommon(); - return m_Name; + return m_Params.name.GetString(lang, utf8s); } inline m2::RectD GetLimitRect() const @@ -279,15 +251,6 @@ public: f(m_Types[i]); } - enum - { - HEADER_HAS_LAYER = 1U << 7, - HEADER_HAS_NAME = 1U << 6, - HEADER_IS_AREA = 1U << 5, - HEADER_IS_LINE = 1U << 4, - HEADER_HAS_POINT = 1U << 3 - }; - void InitFeatureBuilder(FeatureBuilder1 & fb) const; /// @name Statistic functions. @@ -312,8 +275,9 @@ protected: uint32_t CalcOffset(ArrayByteSource const & source) const; mutable uint32_t m_Types[m_maxTypesCount]; - mutable int32_t m_Layer; - mutable string m_Name; + + mutable FeatureParamsBase m_Params; + mutable m2::PointD m_Center; mutable m2::RectD m_LimitRect; @@ -377,7 +341,7 @@ public: if (m_Points.empty()) { // it's a point feature - if (Header() & HEADER_HAS_POINT) + if (GetFeatureType() == feature::GEOM_POINT) f(CoordPointT(m_Center.x, m_Center.y)); } else diff --git a/indexer/feature_data.cpp b/indexer/feature_data.cpp new file mode 100644 index 0000000000..0a8ca2f511 --- /dev/null +++ b/indexer/feature_data.cpp @@ -0,0 +1,129 @@ +#include "feature_data.hpp" + +#include "../std/algorithm.hpp" + + +using namespace feature; + +bool FeatureParamsBase::operator == (FeatureParamsBase const & rhs) const +{ + return (name == rhs.name && house == rhs.house && ref == rhs.ref && + layer == rhs.layer && rank == rhs.rank); +} + +bool FeatureParamsBase::CheckValid() const +{ + CHECK(layer >= -10 && layer <= 10, ()); + return true; +} + +string FeatureParamsBase::DebugString() const +{ + string utf8name; + name.GetString(0, utf8name); + + return ("'" + utf8name + "' Layer:" + debug_print(layer) + + (rank != 0 ? " Rank:" + debug_print(rank) : "") + + (!house.IsEmpty() ? " House:" + house.Get() : "") + + (!ref.empty() ? " Ref:" + ref : "") + " "); +} + +bool FeatureParams::IsValid() const +{ + return !m_Types.empty(); +} + +uint32_t FeatureParams::KeyType() const +{ + ASSERT_EQUAL ( m_Types.size(), 1, () ); + return m_Types.front(); +} + +void FeatureParams::AddType(uint32_t t) +{ + m_Types.push_back(t); +} + +void FeatureParams::AddTypes(FeatureParams const & v) +{ + m_Types.insert(m_Types.end(), v.m_Types.begin(), v.m_Types.end()); +} + +namespace +{ + size_t GetMaximunTypesCount() { return HEADER_TYPE_MASK + 1; } +} + +void FeatureParams::FinishAddingTypes() +{ + sort(m_Types.begin(), m_Types.end()); + m_Types.erase(unique(m_Types.begin(), m_Types.end()), m_Types.end()); + if (m_Types.size() > GetMaximunTypesCount()) + m_Types.resize(GetMaximunTypesCount()); +} + +void FeatureParams::SetType(uint32_t t) +{ + m_Types.clear(); + m_Types.push_back(t); +} + +bool FeatureParams::IsTypeExist(uint32_t t) const +{ + return (find(m_Types.begin(), m_Types.end(), t) != m_Types.end()); +} + +bool FeatureParams::AssignType_SetDifference(vector const & diffTypes) +{ + vector src; + src.swap(m_Types); + + sort(src.begin(), src.end()); + set_difference(src.begin(), src.end(), diffTypes.begin(), diffTypes.end(), back_inserter(m_Types)); + + return !m_Types.empty(); +} + +bool FeatureParams::operator == (FeatureParams const & rhs) const +{ + return (FeatureParamsBase::operator ==(rhs) && + m_Types == rhs.m_Types && + m_Geom == rhs.m_Geom); +} + +bool FeatureParams::CheckValid() const +{ + CHECK(!m_Types.empty() && m_Types.size() <= GetMaximunTypesCount(), ()); + CHECK(m_Geom != GEOM_UNDEFINED, ()); + + return FeatureParamsBase::CheckValid(); +} + +uint8_t FeatureParams::GetHeader() const +{ + uint8_t header = static_cast(m_Types.size() - 1); + + if (!name.IsEmpty()) + header |= HEADER_HAS_NAME; + + if (layer != 0) + header |= HEADER_HAS_LAYER; + + switch (m_Geom) + { + case GEOM_POINT: + header |= HEADER_GEOM_POINT; + if (rank != 0) header |= HEADER_HAS_ADDINFO; + break; + case GEOM_LINE: + header |= HEADER_GEOM_LINE; + if (!ref.empty()) header |= HEADER_HAS_ADDINFO; + break; + case GEOM_AREA: + header |= HEADER_GEOM_AREA; + if (!house.IsEmpty()) header |= HEADER_HAS_ADDINFO; + break; + } + + return header; +} diff --git a/indexer/feature_data.hpp b/indexer/feature_data.hpp new file mode 100644 index 0000000000..8686666940 --- /dev/null +++ b/indexer/feature_data.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include "../coding/multilang_utf8_string.hpp" +#include "../coding/value_opt_string.hpp" + +#include "../std/string.hpp" +#include "../std/vector.hpp" + + +namespace feature +{ + enum EGeomType + { + GEOM_UNDEFINED = -1, + GEOM_POINT = 0, + GEOM_LINE = 1, + GEOM_AREA = 2 + }; + + enum EHeaderMask + { + HEADER_TYPE_MASK = 7U, + HEADER_HAS_NAME = 1U << 3, + HEADER_HAS_LAYER = 1U << 4, + HEADER_GEOTYPE_MASK = 3U << 5, + HEADER_HAS_ADDINFO = 1U << 7 + }; + + enum EHeaderTypeMask + { + HEADER_GEOM_POINT = 0, + HEADER_GEOM_LINE = 1U << 5, + HEADER_GEOM_AREA = 1U << 6 + }; +} + +/// Feature description struct. +struct FeatureParamsBase +{ + StringUtf8Multilang name; + StringNumericOptimal house; + string ref; + int8_t layer; + uint8_t rank; + + FeatureParamsBase() : layer(0), rank(0) {} + + bool operator == (FeatureParamsBase const & rhs) const; + + bool CheckValid() const; + + string DebugString() const; + + template + void Write(TSink & sink, uint8_t header, feature::EGeomType type) const + { + if (header & HEADER_HAS_NAME) + name.Write(sink); + + if (header & HEADER_HAS_LAYER) + WriteToSink(sink, layer); + + if (header & HEADER_HAS_ADDINFO) + { + switch (type) + { + case GEOM_POINT: + WriteToSink(sink, rank); + break; + case GEOM_LINE: + utils::WriteString(sink, ref); + break; + case GEOM_AREA: + house.Write(sink); + break; + } + } + } + + template + void Read(TSrc & src, uint8_t header, feature::EGeomType type) + { + if (header & HEADER_HAS_NAME) + name.Read(src); + + if (header & HEADER_HAS_LAYER) + layer = ReadPrimitiveFromSource(src); + + if (header & HEADER_HAS_ADDINFO) + { + switch (type) + { + case GEOM_POINT: + rank = ReadPrimitiveFromSource(src); + break; + case GEOM_LINE: + utils::ReadString(src, ref); + break; + case GEOM_AREA: + house.Read(src); + break; + } + } + } +}; + +class FeatureParams : public FeatureParamsBase +{ + feature::EGeomType m_Geom; + +public: + typedef vector types_t; + types_t m_Types; + + FeatureParams(FeatureParamsBase const & rhs) + : FeatureParamsBase(rhs), m_Geom(feature::GEOM_UNDEFINED) + { + } + FeatureParams() : m_Geom(feature::GEOM_UNDEFINED) {} + + bool IsValid() const; + uint32_t KeyType() const; + + inline void SetGeomType(feature::EGeomType t) { m_Geom = t; } + inline void RemoveGeomType(feature::EGeomType t) + { + if (m_Geom == t) m_Geom = feature::GEOM_UNDEFINED; + } + inline feature::EGeomType GetGeomType() const { return m_Geom; } + + void AddType(uint32_t t); + void AddTypes(FeatureParams const & v); + void SetType(uint32_t t); + + void FinishAddingTypes(); + + template + void AssignTypes(TIter b, TIter e) + { + m_Types.assign(b, e); + } + + bool IsTypeExist(uint32_t t) const; + bool AssignType_SetDifference(vector const & diffTypes); + + bool operator == (FeatureParams const & rhs) const; + + bool CheckValid() const; + + uint8_t GetHeader() const; + + template void Write(TSink & sink) const + { + uint8_t const header = GetHeader(); + + WriteToSink(sink, header); + + for (size_t i = 0; i < m_Types.size(); ++i) + WriteVarUint(sink, m_Types[i]); + + FeatureParamsBase::Write(sink, header, m_Geom); + } +}; diff --git a/indexer/feature_visibility.cpp b/indexer/feature_visibility.cpp index eb82ddd846..623d6e739b 100644 --- a/indexer/feature_visibility.cpp +++ b/indexer/feature_visibility.cpp @@ -132,7 +132,7 @@ namespace int GetDrawRule(FeatureBase const & f, int level, vector & keys, string & names) { - FeatureBase::FeatureType const geoType = f.GetFeatureType(); + feature::EGeomType const geoType = f.GetFeatureType(); FeatureBase::GetTypesFn types; f.ForEachTypeRef(types); @@ -211,7 +211,7 @@ bool IsDrawableLike(vector const & types, feature_geo_t ft) bool IsDrawableForIndex(FeatureBase const & f, int level) { - if (f.GetFeatureType() == FeatureBase::FEATURE_TYPE_AREA) + if (f.GetFeatureType() == feature::GEOM_AREA) if (!scales::IsGoodForLevel(level, f.GetLimitRect())) return false; diff --git a/indexer/indexer.pro b/indexer/indexer.pro index 6680c2fb95..379fd3aff6 100644 --- a/indexer/indexer.pro +++ b/indexer/indexer.pro @@ -28,6 +28,7 @@ SOURCES += \ geometry_coding.cpp \ geometry_serialization.cpp \ tesselator.cpp \ + feature_data.cpp \ HEADERS += \ feature.hpp \ @@ -60,3 +61,4 @@ HEADERS += \ point_to_int64.hpp \ tesselator.hpp \ tesselator_decl.hpp \ + feature_data.hpp \ diff --git a/map/framework.cpp b/map/framework.cpp index 3c80975d63..532e567d53 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -21,6 +21,8 @@ #include "../base/start_mem_debug.hpp" +using namespace feature; + namespace fwork { namespace @@ -135,18 +137,20 @@ namespace fwork m_renderState->m_isEmptyModelCurrent = false; - shared_ptr ptr(new di::DrawInfo(f.GetName())); + string utf8name; + f.GetName(0, utf8name); + shared_ptr ptr(new di::DrawInfo(utf8name)); using namespace get_pts; bool isExist = false; switch (type) { - case FeatureBase::FEATURE_TYPE_POINT: + case GEOM_POINT: GET_POINTS(get_pts::one_point, ForEachPointRef, assign_point) break; - case FeatureBase::FEATURE_TYPE_AREA: + case GEOM_AREA: GET_POINTS(filter_screenpts_adapter, ForEachTriangleExRef, assign_area) { // if area feature has any line-drawing-rules, than draw it like line @@ -157,7 +161,7 @@ namespace fwork } draw_line: - case FeatureBase::FEATURE_TYPE_LINE: + case GEOM_LINE: GET_POINTS(filter_screenpts_adapter, ForEachPointRef, assign_path) break; } diff --git a/qt/searchwindow.cpp b/qt/searchwindow.cpp index 7ad497295e..f208678005 100644 --- a/qt/searchwindow.cpp +++ b/qt/searchwindow.cpp @@ -27,9 +27,8 @@ FindTableWnd::FindTableWnd(QWidget * pParent, FindEditorWnd * pEditor, model_t * bool FindTableWnd::AddFeature(FeatureType const & f) { - string name = f.GetName(); - - if (!name.empty()) + string utf8name; + if (f.GetName(0, utf8name) && !utf8name.empty()) { // 200 rows is enough int const r = rowCount(); @@ -38,7 +37,7 @@ bool FindTableWnd::AddFeature(FeatureType const & f) insertRow(r); - QTableWidgetItem * item = new QTableWidgetItem(QString::fromUtf8(name.c_str())); + QTableWidgetItem * item = new QTableWidgetItem(QString::fromUtf8(utf8name.c_str())); item->setFlags(item->flags() ^ Qt::ItemIsEditable); setItem(r, 0, item);