diff --git a/generator/feature_builder.cpp b/generator/feature_builder.cpp index 404fc25eef..782f8cbb67 100644 --- a/generator/feature_builder.cpp +++ b/generator/feature_builder.cpp @@ -95,24 +95,13 @@ void FeatureBuilder1::AddPolygon(vector & poly) m_Polygons.back().swap(poly); } -void FeatureBuilder1::DoCorrectForType(EGeomType type) -{ - if (m_Params.GetGeomType() == type && - !IsDrawableLike(m_Params.m_Types, static_cast(type))) - { - m_Params.RemoveGeomType(type); - } -} - -bool FeatureBuilder1::DoCorrect() +bool FeatureBuilder1::RemoveInvalidTypes() { if (!m_Params.FinishAddingTypes()) return false; - DoCorrectForType(GEOM_AREA); - DoCorrectForType(GEOM_LINE); - - return (m_Params.GetGeomType() != GEOM_UNDEFINED); + return feature::RemoveNoDrawableTypes(m_Params.m_Types, + static_cast(m_Params.GetGeomType())); } FeatureBase FeatureBuilder1::GetFeatureBase() const @@ -167,27 +156,27 @@ namespace bool FeatureBuilder1::PreSerialize() { - if (!m_Params.IsValid()) return false; - static const int8_t defaultCode = StringUtf8Multilang::GetLangIndex("default"); - static const int8_t intCode = StringUtf8Multilang::GetLangIndex("int_name"); + if (!m_Params.IsValid()) + return false; + + /// @todo Do not use flats info. Maybe in future. + m_Params.flats.clear(); switch (m_Params.GetGeomType()) { case GEOM_POINT: - // If we don't have name and have house number, than replace them. - if (m_Params.name.IsEmpty() && !m_Params.house.IsEmpty()) - m_Params.name.AddString(defaultCode, m_Params.house.Get()); - - // We need refs for motorway's junctions. Try to update name always, not only for junctions. - if (m_Params.name.IsEmpty() && (!m_Params.ref.empty() || m_Params.flats.empty())) + // Store house number like HEADER_GEOM_POINT_EX. + if (!m_Params.house.IsEmpty()) { - m_Params.name.AddString(defaultCode, m_Params.ref); - m_Params.name.AddString(intCode, m_Params.flats); + m_Params.SetGeomTypePointEx(); + m_Params.rank = 0; } - m_Params.house.Clear(); + // Store ref's in name field (used in "highway-motorway_junction"). + if (m_Params.name.IsEmpty() && !m_Params.ref.empty()) + m_Params.name.AddString(0, m_Params.ref); + m_Params.ref.clear(); - m_Params.flats.clear(); break; case GEOM_LINE: @@ -196,7 +185,7 @@ bool FeatureBuilder1::PreSerialize() // We need refs for road's numbers. if (!checkHighway.IsEqualV(m_Params.m_Types)) - m_Params.ref = string(); + m_Params.ref.clear(); m_Params.rank = 0; m_Params.house.Clear(); @@ -269,7 +258,6 @@ bool FeatureBuilder1::CheckValid() const CHECK(m_Params.CheckValid(), (*this)); EGeomType const type = m_Params.GetGeomType(); - CHECK ( type != GEOM_UNDEFINED, (*this) ); points_t const & poly = GetGeometry(); @@ -429,11 +417,17 @@ bool FeatureBuilder2::IsDrawableInRange(int lowS, int highS) const bool FeatureBuilder2::PreSerialize(buffers_holder_t const & data) { // make flags actual before header serialization - if (data.m_ptsMask == 0 && data.m_innerPts.empty()) - m_Params.RemoveGeomType(GEOM_LINE); - - if (data.m_trgMask == 0 && data.m_innerTrg.empty()) - m_Params.RemoveGeomType(GEOM_AREA); + EGeomType const geoType = m_Params.GetGeomType(); + if (geoType == GEOM_LINE) + { + if (data.m_ptsMask == 0 && data.m_innerPts.empty()) + return false; + } + else if (geoType == GEOM_AREA) + { + if (data.m_trgMask == 0 && data.m_innerTrg.empty()) + return false; + } // we don't need empty features without geometry return base_type::PreSerialize(); @@ -495,14 +489,13 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co uint8_t const h = m_Params.GetTypeMask(); - if (h & HEADER_GEOM_LINE) + if (h == HEADER_GEOM_LINE) { bitSink.Write(ptsCount, 4); if (ptsCount == 0) bitSink.Write(data.m_ptsMask, 4); } - - if (h & HEADER_GEOM_AREA) + else if (h == HEADER_GEOM_AREA) { bitSink.Write(trgCount, 4); if (trgCount == 0) @@ -511,7 +504,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co bitSink.Finish(); - if (h & HEADER_GEOM_LINE) + if (h == HEADER_GEOM_LINE) { if (ptsCount > 0) { @@ -540,8 +533,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co serial::WriteVarUintArray(data.m_ptsOffset, sink); } } - - if (h & HEADER_GEOM_AREA) + else if (h == HEADER_GEOM_AREA) { if (trgCount > 0) serial::SaveInnerTriangles(data.m_innerTrg, params, sink); diff --git a/generator/feature_builder.hpp b/generator/feature_builder.hpp index f77c4b6f79..f7ad3160ff 100644 --- a/generator/feature_builder.hpp +++ b/generator/feature_builder.hpp @@ -45,11 +45,10 @@ public: inline bool PopExactType(uint32_t type) { return m_Params.PopExactType(type); } inline void SetType(uint32_t type) { m_Params.SetType(type); } - /// Check for feature visibility according to it's types. - /// If feature is invisible, it's not correct. - /// This fuction is called after it's classificator types manipulating. - void DoCorrectForType(feature::EGeomType type); - bool DoCorrect(); + /// Check classificator types for their compatibility with feature geometry type. + /// Need to call when using any classificator types manipulating. + /// @return false If no any valid types. + bool RemoveInvalidTypes(); /// Clear name if it's not visible in scale range [minS, maxS]. void RemoveNameIfInvisible(int minS = 0, int maxS = 1000); @@ -214,8 +213,8 @@ public: buffers_holder_t() : m_ptsMask(0), m_trgMask(0), m_ptsSimpMask(0) {} }; - bool IsLine() const { return (m_Params.GetTypeMask() & feature::HEADER_GEOM_LINE) != 0; } - bool IsArea() const { return (m_Params.GetTypeMask() & feature::HEADER_GEOM_AREA) != 0; } + bool IsLine() const { return (m_Params.GetTypeMask() == feature::HEADER_GEOM_LINE); } + bool IsArea() const { return (m_Params.GetTypeMask() == feature::HEADER_GEOM_AREA); } bool IsDrawableInRange(int lowS, int highS) const; points_t const & GetOuterPoly() const { return GetGeometry(); } diff --git a/generator/feature_generator.cpp b/generator/feature_generator.cpp index 8813c848e1..d40ebfe78f 100644 --- a/generator/feature_generator.cpp +++ b/generator/feature_generator.cpp @@ -359,10 +359,13 @@ public: fb.PopExactType(Type(NATURAL_LAND)); fb.PopExactType(coastType); } - else if (fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) + else if ((fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) && + fb.GetGeomType() == feature::GEOM_AREA) + { fb.AddType(Type(NATURAL_LAND)); + } - if (fb.DoCorrect()) + if (fb.RemoveInvalidTypes()) { if (m_world) (*m_world)(fb); diff --git a/generator/generator_tests/feature_builder_test.cpp b/generator/generator_tests/feature_builder_test.cpp index 56215c290d..643293233a 100644 --- a/generator/generator_tests/feature_builder_test.cpp +++ b/generator/generator_tests/feature_builder_test.cpp @@ -53,7 +53,7 @@ UNIT_TEST(FBuilder_ManyTypes) fb1.SetParams(params); fb1.SetCenter(m2::PointD(0, 0)); - TEST(fb1.DoCorrect(), ()); + TEST(fb1.RemoveInvalidTypes(), ()); TEST(fb1.CheckValid(), ()); FeatureBuilder1::buffer_t buffer; diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 598e1e7301..bd61df43f2 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -48,16 +48,11 @@ void FeatureBase::ParseCommon() const feature::EGeomType FeatureBase::GetFeatureType() const { - uint8_t const h = (Header() & HEADER_GEOTYPE_MASK); - - if (h & HEADER_GEOM_AREA) - return GEOM_AREA; - else if (h & HEADER_GEOM_LINE) - return GEOM_LINE; - else + switch (Header() & HEADER_GEOTYPE_MASK) { - ASSERT ( h == HEADER_GEOM_POINT, (h) ); - return GEOM_POINT; + case HEADER_GEOM_LINE: return GEOM_LINE; + case HEADER_GEOM_AREA: return GEOM_AREA; + default: return GEOM_POINT; } } @@ -287,7 +282,7 @@ void FeatureType::GetReadableName(string & name) const string FeatureType::GetHouseNumber() const { ParseCommon(); - return (GetFeatureType() == GEOM_AREA ? m_Params.house.Get() : string()); + return m_Params.house.Get(); } bool FeatureType::GetName(int8_t lang, string & name) const diff --git a/indexer/feature_data.cpp b/indexer/feature_data.cpp index fbc98bd3ff..d17ebdf163 100644 --- a/indexer/feature_data.cpp +++ b/indexer/feature_data.cpp @@ -110,7 +110,7 @@ string FeatureParamsBase::DebugString() const void FeatureParamsBase::AddHouseName(string const & s) { - house.Set(house.IsEmpty() ? s : house.Get() + " \"" + s + "\""); + house.Set(house.IsEmpty() ? s : house.Get() + ", " + s); } void FeatureParamsBase::AddHouseNumber(string const & ss) @@ -122,27 +122,42 @@ void FeatureParamsBase::AddHouseNumber(string const & ss) if (strings::to_uint64(s, n)) s = strings::to_string(n); - house.Set(house.IsEmpty() ? s : s + " \"" + house.Get() + "\""); + house.Set(house.IsEmpty() ? s : s + ", " + house.Get()); +} + +void FeatureParams::SetGeomType(feature::EGeomType t) +{ + switch (t) + { + case GEOM_POINT: m_geomType = HEADER_GEOM_POINT; break; + case GEOM_LINE: m_geomType = HEADER_GEOM_LINE; break; + case GEOM_AREA: m_geomType = HEADER_GEOM_AREA; break; + } +} + +void FeatureParams::SetGeomTypePointEx() +{ + ASSERT_EQUAL(m_geomType, HEADER_GEOM_POINT, ()); + ASSERT(!house.IsEmpty(), ()); + + m_geomType = HEADER_GEOM_POINT_EX; } feature::EGeomType FeatureParams::GetGeomType() const { - // Geometry types can be combined. - // We define exact type for priority : starting from GEOM_AREA. - - if (m_geomTypes[GEOM_AREA]) return GEOM_AREA; - if (m_geomTypes[GEOM_LINE]) return GEOM_LINE; - if (m_geomTypes[GEOM_POINT]) return GEOM_POINT; - return GEOM_UNDEFINED; + CHECK_NOT_EQUAL(m_geomType, 0xFF, ()); + switch (m_geomType) + { + case HEADER_GEOM_LINE: return GEOM_LINE; + case HEADER_GEOM_AREA: return GEOM_AREA; + default: return GEOM_POINT; + } } uint8_t FeatureParams::GetTypeMask() const { - uint8_t h = 0; - if (m_geomTypes[GEOM_POINT]) h |= HEADER_GEOM_POINT; - if (m_geomTypes[GEOM_LINE]) h |= HEADER_GEOM_LINE; - if (m_geomTypes[GEOM_AREA]) h |= HEADER_GEOM_AREA; - return h; + CHECK_NOT_EQUAL(m_geomType, 0xFF, ()); + return m_geomType; } void FeatureParams::AddTypes(FeatureParams const & rhs, uint32_t skipType2) @@ -209,7 +224,7 @@ bool FeatureParams::operator == (FeatureParams const & rhs) const bool FeatureParams::CheckValid() const { CHECK(!m_Types.empty() && m_Types.size() <= max_types_count, ()); - CHECK(GetGeomType() != GEOM_UNDEFINED, ()); + CHECK_NOT_EQUAL(m_geomType, 0xFF, ()); return FeatureParamsBase::CheckValid(); } @@ -224,16 +239,17 @@ uint8_t FeatureParams::GetHeader() const if (layer != 0) header |= HEADER_HAS_LAYER; - header |= GetTypeMask(); + uint8_t const typeMask = GetTypeMask(); + header |= typeMask; // Geometry type for additional info is only one. - switch (GetGeomType()) + switch (GetTypeMask()) { - case GEOM_POINT: if (rank != 0) header |= HEADER_HAS_ADDINFO; break; - case GEOM_LINE: if (!ref.empty()) header |= HEADER_HAS_ADDINFO; break; - case GEOM_AREA: if (!house.IsEmpty()) header |= HEADER_HAS_ADDINFO; break; - default: - ASSERT(false, ("Undefined geometry type")); + case HEADER_GEOM_POINT: if (rank != 0) header |= HEADER_HAS_ADDINFO; break; + case HEADER_GEOM_LINE: if (!ref.empty()) header |= HEADER_HAS_ADDINFO; break; + case HEADER_GEOM_AREA: + case HEADER_GEOM_POINT_EX: + if (!house.IsEmpty()) header |= HEADER_HAS_ADDINFO; break; } return header; diff --git a/indexer/feature_data.hpp b/indexer/feature_data.hpp index 26b9e83aa3..9c8e47fe2b 100644 --- a/indexer/feature_data.hpp +++ b/indexer/feature_data.hpp @@ -33,9 +33,11 @@ namespace feature enum EHeaderTypeMask { - HEADER_GEOM_POINT = 0, - HEADER_GEOM_LINE = 1U << 5, - HEADER_GEOM_AREA = 1U << 6 + /// Coding geometry feature type in 2 bits. + HEADER_GEOM_POINT = 0, /// point feature (addinfo = rank) + HEADER_GEOM_LINE = 1U << 5, /// linear feature (addinfo = ref) + HEADER_GEOM_AREA = 1U << 6, /// area feature (addinfo = house) + HEADER_GEOM_POINT_EX = 3U << 5 /// point feature (addinfo = house) }; static const int max_types_count = HEADER_TYPE_MASK + 1; @@ -125,57 +127,59 @@ struct FeatureParamsBase void AddHouseNumber(string const & s); template - void Write(TSink & sink, uint8_t header, feature::EGeomType type) const + void Write(TSink & sink, uint8_t header) const { - if (header & feature::HEADER_HAS_NAME) + using namespace feature; + + if (header & HEADER_HAS_NAME) name.Write(sink); - if (header & feature::HEADER_HAS_LAYER) + if (header & HEADER_HAS_LAYER) WriteToSink(sink, layer); - if (header & feature::HEADER_HAS_ADDINFO) + if (header & HEADER_HAS_ADDINFO) { - switch (type) + switch (header & HEADER_GEOTYPE_MASK) { - case feature::GEOM_POINT: + case HEADER_GEOM_POINT: WriteToSink(sink, rank); break; - case feature::GEOM_LINE: + case HEADER_GEOM_LINE: utils::WriteString(sink, ref); break; - case feature::GEOM_AREA: + case HEADER_GEOM_AREA: + case HEADER_GEOM_POINT_EX: house.Write(sink); break; - default: - ASSERT(false, ("Undefined geometry type")); } } } template - void Read(TSrc & src, uint8_t header, feature::EGeomType type) + void Read(TSrc & src, uint8_t header) { - if (header & feature::HEADER_HAS_NAME) + using namespace feature; + + if (header & HEADER_HAS_NAME) name.Read(src); - if (header & feature::HEADER_HAS_LAYER) + if (header & HEADER_HAS_LAYER) layer = ReadPrimitiveFromSource(src); - if (header & feature::HEADER_HAS_ADDINFO) + if (header & HEADER_HAS_ADDINFO) { - switch (type) + switch (header & HEADER_GEOTYPE_MASK) { - case feature::GEOM_POINT: + case HEADER_GEOM_POINT: rank = ReadPrimitiveFromSource(src); break; - case feature::GEOM_LINE: + case HEADER_GEOM_LINE: utils::ReadString(src, ref); break; - case feature::GEOM_AREA: + case HEADER_GEOM_AREA: + case HEADER_GEOM_POINT_EX: house.Read(src); break; - default: - ASSERT(false, ("Undefined geometry type")); } } } @@ -185,16 +189,13 @@ class FeatureParams : public FeatureParamsBase { typedef FeatureParamsBase BaseT; - bool m_geomTypes[3]; + uint8_t m_geomType; public: typedef vector types_t; types_t m_Types; - FeatureParams() - { - m_geomTypes[0] = m_geomTypes[1] = m_geomTypes[2] = false; - } + FeatureParams() : m_geomType(0xFF) {} /// Assign parameters except geometry type. /// Geometry is independent state and it's set by FeatureType's geometry functions. @@ -206,9 +207,8 @@ public: inline bool IsValid() const { return !m_Types.empty(); } - inline void SetGeomType(feature::EGeomType t) { m_geomTypes[t] = true; } - inline void RemoveGeomType(feature::EGeomType t) { m_geomTypes[t] = false; } - + void SetGeomType(feature::EGeomType t); + void SetGeomTypePointEx(); feature::EGeomType GetGeomType() const; uint8_t GetTypeMask() const; @@ -245,7 +245,7 @@ public: for (size_t i = 0; i < m_Types.size(); ++i) WriteVarUint(sink, GetIndexForType(m_Types[i])); - BaseT::Write(sink, header, GetGeomType()); + BaseT::Write(sink, header); } template void Read(TSrc & src) @@ -253,17 +253,13 @@ public: using namespace feature; uint8_t const header = ReadPrimitiveFromSource(src); - - uint8_t const type = (header & HEADER_GEOTYPE_MASK); - if (type & HEADER_GEOM_LINE) SetGeomType(GEOM_LINE); - if (type & HEADER_GEOM_AREA) SetGeomType(GEOM_AREA); - if (type == HEADER_GEOM_POINT) SetGeomType(GEOM_POINT); + m_geomType = header & HEADER_GEOTYPE_MASK; size_t const count = (header & HEADER_TYPE_MASK) + 1; for (size_t i = 0; i < count; ++i) m_Types.push_back(GetTypeForIndex(ReadVarUint(src))); - BaseT::Read(src, header, GetGeomType()); + BaseT::Read(src, header); } private: diff --git a/indexer/feature_loader.cpp b/indexer/feature_loader.cpp index 6091ef2e8c..b14a997b7d 100644 --- a/indexer/feature_loader.cpp +++ b/indexer/feature_loader.cpp @@ -37,12 +37,9 @@ void LoaderCurrent::ParseCommon() ArrayByteSource source(DataPtr() + m_CommonOffset); uint8_t const h = Header(); + m_pF->m_Params.Read(source, h); - EGeomType const type = m_pF->GetFeatureType(); - - m_pF->m_Params.Read(source, h, type); - - if (type == GEOM_POINT) + if (m_pF->GetFeatureType() == GEOM_POINT) { m_pF->m_Center = serial::LoadPoint(source, GetDefCodingParams()); m_pF->m_LimitRect.Add(m_pF->m_Center); @@ -103,20 +100,16 @@ void LoaderCurrent::ParseHeader2() BitSource bitSource(DataPtr() + m_Header2Offset); - uint8_t const h = (Header() & HEADER_GEOTYPE_MASK); - - if (h & HEADER_GEOM_LINE) + uint8_t const typeMask = Header() & HEADER_GEOTYPE_MASK; + if (typeMask == HEADER_GEOM_LINE) { ptsCount = bitSource.Read(4); if (ptsCount == 0) ptsMask = bitSource.Read(4); else - { ASSERT_GREATER ( ptsCount, 1, () ); - } } - - if (h & HEADER_GEOM_AREA) + else if (typeMask == HEADER_GEOM_AREA) { trgCount = bitSource.Read(4); if (trgCount == 0) @@ -127,7 +120,7 @@ void LoaderCurrent::ParseHeader2() serial::CodingParams const & cp = GetDefCodingParams(); - if (h & HEADER_GEOM_LINE) + if (typeMask == HEADER_GEOM_LINE) { if (ptsCount > 0) { @@ -153,8 +146,7 @@ void LoaderCurrent::ParseHeader2() ReadOffsets(src, ptsMask, m_ptsOffsets); } } - - if (h & HEADER_GEOM_AREA) + else if (typeMask == HEADER_GEOM_AREA) { if (trgCount > 0) { @@ -184,7 +176,7 @@ void LoaderCurrent::ParseHeader2() uint32_t LoaderCurrent::ParseGeometry(int scale) { uint32_t sz = 0; - if (Header() & HEADER_GEOM_LINE) + if ((Header() & HEADER_GEOTYPE_MASK) == HEADER_GEOM_LINE) { size_t const count = m_pF->m_Points.size(); if (count < 2) @@ -236,7 +228,7 @@ uint32_t LoaderCurrent::ParseGeometry(int scale) uint32_t LoaderCurrent::ParseTriangles(int scale) { uint32_t sz = 0; - if (Header() & HEADER_GEOM_AREA) + if ((Header() & HEADER_GEOTYPE_MASK) == HEADER_GEOM_AREA) { if (m_pF->m_Triangles.empty()) { diff --git a/indexer/search_index_builder.cpp b/indexer/search_index_builder.cpp index efce23aaa1..e069ad5821 100644 --- a/indexer/search_index_builder.cpp +++ b/indexer/search_index_builder.cpp @@ -219,10 +219,10 @@ class FeatureInserter SkipIndexing() { // Get features which shoud be skipped in any case. - char const * arrSkip2[][2] = { - { "building", "address" } - }; + char const * arrSkip1[][1] = { { "entrance" } }; + char const * arrSkip2[][2] = { { "building", "address" } }; + FillTypes(arrSkip1, m_skipFeatures); FillTypes(arrSkip2, m_skipFeatures); // Get features which shoud be skipped without names.