diff --git a/generator/feature_builder.cpp b/generator/feature_builder.cpp new file mode 100644 index 0000000000..37ebf2efc9 --- /dev/null +++ b/generator/feature_builder.cpp @@ -0,0 +1,417 @@ +#include "../base/SRC_FIRST.hpp" + +#include "feature_builder.hpp" + +#include "../indexer/feature_impl.hpp" +#include "../indexer/feature_visibility.hpp" + +#include "../geometry/region2d.hpp" + +#include "../coding/byte_stream.hpp" + +#include "../base/start_mem_debug.hpp" + + +using namespace feature; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FeatureBuilder1 implementation +/////////////////////////////////////////////////////////////////////////////////////////////////// + +bool FeatureBuilder1::IsGeometryClosed() const +{ + return (m_Geometry.size() > 2 && m_Geometry.front() == m_Geometry.back()); +} + +void FeatureBuilder1::SetCenter(m2::PointD const & p) +{ + m_Center = p; + m_Params.SetGeomType(GEOM_POINT); + m_LimitRect.Add(p); +} + +void FeatureBuilder1::AddPoint(m2::PointD const & p) +{ + m_Geometry.push_back(p); + m_LimitRect.Add(p); +} + +void FeatureBuilder1::SetAreaAddHoles(list const & holes) +{ + m_Params.SetGeomType(GEOM_AREA); + m_Holes.clear(); + + if (holes.empty()) return; + + m2::Region rgn(m_Geometry.begin(), m_Geometry.end()); + + for (list::const_iterator i = holes.begin(); i != holes.end(); ++i) + { + ASSERT ( !i->empty(), () ); + + if (rgn.Contains(i->front())) + m_Holes.push_back(*i); + } +} + +FeatureBase FeatureBuilder1::GetFeatureBase() const +{ + CHECK ( CheckValid(), () ); + + FeatureBase f; + f.SetHeader(m_Params.GetHeader()); + + 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_bTypesParsed = f.m_bCommonParsed = true; + + return f; +} + +namespace +{ + bool is_equal(double d1, double d2) + { + //return my::AlmostEqual(d1, d2, 100000000); + return (fabs(d1 - d2) < MercatorBounds::GetCellID2PointAbsEpsilon()); + } + + bool is_equal(m2::PointD const & p1, m2::PointD const & p2) + { + return p1.EqualDxDy(p2, MercatorBounds::GetCellID2PointAbsEpsilon()); + } + + bool is_equal(m2::RectD const & r1, m2::RectD const & r2) + { + return (is_equal(r1.minX(), r2.minX()) && + is_equal(r1.minY(), r2.minY()) && + is_equal(r1.maxX(), r2.maxX()) && + is_equal(r1.maxY(), r2.maxY())); + } + + bool is_equal(vector const & v1, vector const & v2) + { + if (v1.size() != v2.size()) + return false; + + for (size_t i = 0; i < v1.size(); ++i) + if (!is_equal(v1[i], v2[i])) + return false; + + return true; + } +} + +bool FeatureBuilder1::PreSerialize() +{ + if (!m_Params.IsValid()) return false; + + 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(0, m_Params.house.Get()); + + m_Params.ref = string(); + m_Params.house.Clear(); + break; + + case GEOM_LINE: + // We need refs only for road numbers. + if (!feature::IsHighway(m_Params.m_Types)) + m_Params.ref = string(); + + m_Params.rank = 0; + m_Params.house.Clear(); + break; + + case GEOM_AREA: + m_Params.rank = 0; + m_Params.ref = string(); + break; + + default: + return false; + } + + // Clear name for features with invisible texts. + if (!m_Params.name.IsEmpty() && feature::DrawableScaleRangeForText(GetFeatureBase()).first == -1) + m_Params.name.Clear(); + + 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; + + if (!is_equal(m_Geometry, fb.m_Geometry)) + return false; + + if (m_Holes.size() != fb.m_Holes.size()) + return false; + + list::const_iterator i = m_Holes.begin(); + list::const_iterator j = fb.m_Holes.begin(); + for (; i != m_Holes.end(); ++i, ++j) + if (!is_equal(*i, *j)) + return false; + + return true; +} + +bool FeatureBuilder1::CheckValid() const +{ + CHECK(m_Params.CheckValid(), ()); + + EGeomType const type = m_Params.GetGeomType(); + + CHECK(type != GEOM_LINE || m_Geometry.size() >= 2, ()); + + CHECK(type != GEOM_AREA || m_Geometry.size() >= 3, ()); + + CHECK(m_Holes.empty() || type == GEOM_AREA, ()); + + for (list::const_iterator i = m_Holes.begin(); i != m_Holes.end(); ++i) + CHECK(i->size() >= 3, ()); + + return true; +} + +void FeatureBuilder1::SerializeBase(buffer_t & data, serial::CodingParams const & params) const +{ + PushBackByteSink sink(data); + + m_Params.Write(sink); + + if (m_Params.GetGeomType() == GEOM_POINT) + WriteVarUint(sink, EncodeDelta(PointD2PointU(m_Center.x, m_Center.y, params.GetCoordBits()), + params.GetBasePoint())); +} + +void FeatureBuilder1::Serialize(buffer_t & data) const +{ + CHECK ( CheckValid(), () ); + + data.clear(); + + SerializeBase(data, serial::CodingParams()); + + PushBackByteSink sink(data); + + EGeomType const type = m_Params.GetGeomType(); + + if (type != GEOM_POINT) + serial::SaveOuterPath(m_Geometry, serial::CodingParams(), sink); + + if (type == GEOM_AREA) + { + WriteVarUint(sink, uint32_t(m_Holes.size())); + + for (list::const_iterator i = m_Holes.begin(); i != m_Holes.end(); ++i) + serial::SaveOuterPath(*i, serial::CodingParams(), sink); + } + + // check for correct serialization +#ifdef DEBUG + buffer_t tmp(data); + FeatureBuilder1 fb; + fb.Deserialize(tmp); + ASSERT ( fb == *this, () ); +#endif +} + +void FeatureBuilder1::Deserialize(buffer_t & data) +{ + FeatureBase f; + f.Deserialize(data, 0, serial::CodingParams()); + InitFeatureBuilder(f); + + ArrayByteSource src(f.DataPtr() + f.m_Header2Offset); + + EGeomType const type = m_Params.GetGeomType(); + + if (type != GEOM_POINT) + { + serial::LoadOuterPath(src, serial::CodingParams(), m_Geometry); + CalcRect(m_Geometry, m_LimitRect); + } + + if (type == GEOM_AREA) + { + uint32_t const count = ReadVarUint(src); + for (uint32_t i = 0; i < count; ++i) + { + m_Holes.push_back(points_t()); + serial::LoadOuterPath(src, serial::CodingParams(), m_Holes.back()); + } + } + + CHECK ( CheckValid(), () ); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FeatureBuilderGeomRef implementation +/////////////////////////////////////////////////////////////////////////////////////////////////// + +bool FeatureBuilder2::IsDrawableInRange(int lowS, int highS) const +{ + if (!m_Geometry.empty()) + { + FeatureBase const fb = GetFeatureBase(); + + while (lowS <= highS) + if (feature::IsDrawableForIndex(fb, lowS++)) + return true; + } + + return false; +} + +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); + + // we don't need empty features without geometry + return base_type::PreSerialize(); +} + +namespace +{ + template class BitSink + { + TSink & m_sink; + uint8_t m_pos; + uint8_t m_current; + + public: + BitSink(TSink & sink) : m_sink(sink), m_pos(0), m_current(0) {} + + void Finish() + { + if (m_pos > 0) + { + WriteToSink(m_sink, m_current); + m_pos = 0; + m_current = 0; + } + } + + void Write(uint8_t value, uint8_t count) + { + ASSERT_LESS ( count, 9, () ); + ASSERT_EQUAL ( value >> count, 0, () ); + + if (m_pos + count > 8) + Finish(); + + m_current |= (value << m_pos); + m_pos += count; + } + }; +} + +void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams const & params) +{ + data.m_buffer.clear(); + + // header data serialization + SerializeBase(data.m_buffer, params); + + PushBackByteSink sink(data.m_buffer); + + uint8_t const ptsCount = static_cast(data.m_innerPts.size()); + uint8_t trgCount = static_cast(data.m_innerTrg.size()); + if (trgCount > 0) + { + ASSERT_GREATER ( trgCount, 2, () ); + trgCount -= 2; + } + + BitSink< PushBackByteSink > bitSink(sink); + + uint8_t const h = m_Params.GetTypeMask(); + + if (h & HEADER_GEOM_LINE) + { + bitSink.Write(ptsCount, 4); + if (ptsCount == 0) + bitSink.Write(data.m_ptsMask, 4); + } + + if (h & HEADER_GEOM_AREA) + { + bitSink.Write(trgCount, 4); + if (trgCount == 0) + bitSink.Write(data.m_trgMask, 4); + } + + bitSink.Finish(); + + if (h & HEADER_GEOM_LINE) + { + if (ptsCount > 0) + { + if (ptsCount > 2) + { + uint32_t v = data.m_ptsSimpMask; + int const count = (ptsCount - 2 + 3) / 4; + for (int i = 0; i < count; ++i) + { + WriteToSink(sink, static_cast(v)); + v >>= 8; + } + } + + serial::SaveInnerPath(data.m_innerPts, params, sink); + } + else + { + // offsets was pushed from high scale index to low + reverse(data.m_ptsOffset.begin(), data.m_ptsOffset.end()); + serial::WriteVarUintArray(data.m_ptsOffset, sink); + } + } + + if (h & HEADER_GEOM_AREA) + { + if (trgCount > 0) + serial::SaveInnerTriangles(data.m_innerTrg, params, sink); + else + { + // offsets was pushed from high scale index to low + reverse(data.m_trgOffset.begin(), data.m_trgOffset.end()); + serial::WriteVarUintArray(data.m_trgOffset, sink); + } + } +} + +void FeatureBuilder1::InitFeatureBuilder(FeatureBase const & ft) +{ + ft.ParseAll(); + + m_Params = ft.GetFeatureParams(); + + if (ft.GetFeatureType() == GEOM_POINT) + { + SetCenter(ft.GetCenter()); + m_Params.SetGeomType(GEOM_POINT); + } +} diff --git a/generator/feature_builder.hpp b/generator/feature_builder.hpp new file mode 100644 index 0000000000..5c57c5418a --- /dev/null +++ b/generator/feature_builder.hpp @@ -0,0 +1,180 @@ +#pragma once +#include "../indexer/feature.hpp" + + +/// Used for serialization\deserialization of features during --generate_features. +class FeatureBuilder1 +{ +public: + /// @name Geometry manipulating functions. + //@{ + /// Set center (origin) point of feature and set that feature is point. + void SetCenter(m2::PointD const & p); + + /// Add point to geometry. + void AddPoint(m2::PointD const & p); + + /// Set that feature is linear type. + void SetLinear() { m_Params.SetGeomType(feature::GEOM_LINE); } + + /// Set that feature is area and get ownership of holes. + void SetAreaAddHoles(list > const & holes); + //@} + + inline feature::EGeomType GetGeomType() const { return m_Params.GetGeomType(); } + + inline void AddType(uint32_t type) { m_Params.AddType(type); } + inline bool HasType(uint32_t t) const { return m_Params.IsTypeExist(t); } + + typedef vector buffer_t; + + /// @name Serialization. + //@{ + void Serialize(buffer_t & data) const; + void SerializeBase(buffer_t & data, serial::CodingParams const & params) const; + + void Deserialize(buffer_t & data); + //@} + + ///@name Selectors. + //@{ + inline m2::RectD GetLimitRect() const { return m_LimitRect; } + + /// Get common parameters of feature. + FeatureBase GetFeatureBase() const; + + bool IsGeometryClosed() const; + + inline size_t GetPointsCount() const { return m_Geometry.size(); } + + template + void ForEachPointRef(ToDo & toDo) const + { + for_each(m_Geometry.begin(), m_Geometry.end(), bind(ref(toDo), _1)); + } + + // stops processing when functor returns false + template + void ForEachTruePointRef(ToDo & toDo) const + { + if (m_Params.GetGeomType() == feature::GEOM_POINT) + toDo(m_Center); + else + { + for (points_t::const_iterator it = m_Geometry.begin(); it != m_Geometry.end(); ++it) + if (!toDo(*it)) + return; + } + } + //@} + + bool PreSerialize(); + + inline void SetParams(FeatureParams const & params) { m_Params = params; } + +protected: + void InitFeatureBuilder(FeatureBase const & ft); + + /// @name For diagnostic use only. + //@{ + bool operator == (FeatureBuilder1 const &) const; + + bool CheckValid() const; + //@} + + FeatureParams m_Params; + + m2::RectD m_LimitRect; + + /// Can be one of the following: + /// - point in point-feature + /// - origin point of text [future] in line-feature + /// - 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 + points_t m_Geometry; // Check HEADER_IS_LINE + + /// List of holes in area-feature. + list m_Holes; // Check HEADER_IS_AREA +}; + +/// Used for serialization of features during final pass. +class FeatureBuilder2 : public FeatureBuilder1 +{ + typedef FeatureBuilder1 base_type; + + typedef vector offsets_t; + + static void SerializeOffsets(uint32_t mask, offsets_t const & offsets, buffer_t & buffer); + +public: + + struct buffers_holder_t + { + /// @name input + //@{ + offsets_t m_ptsOffset, m_trgOffset; + uint8_t m_ptsMask, m_trgMask; + + uint32_t m_ptsSimpMask; + + points_t m_innerPts, m_innerTrg; + //@} + + /// @name output + base_type::buffer_t m_buffer; + + 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 IsDrawableInRange(int lowS, int highS) const; + + points_t const & GetGeometry() const { return m_Geometry; } + list const & GetHoles() const { return m_Holes; } + + /// @name Overwrite from base_type. + //@{ + bool PreSerialize(buffers_holder_t const & data); + void Serialize(buffers_holder_t & data, serial::CodingParams const & params); + //@} +}; + +namespace feature +{ + /// Read feature from feature source. + template + void ReadFromSourceRowFormat(TSource & src, FeatureBuilder1 & f) + { + uint32_t const sz = ReadVarUint(src); + typename FeatureBuilder1::buffer_t buffer(sz); + src.Read(&buffer[0], sz); + f.Deserialize(buffer); + } + + /// Process features in .dat file. + template + void ForEachFromDatRawFormat(string const & fName, ToDo & toDo) + { + FileReader reader(fName); + ReaderSource src(reader); + + uint64_t currPos = 0; + uint64_t const fSize = reader.Size(); + + // read features one by one + while (currPos < fSize) + { + FeatureBuilder1 f; + ReadFromSourceRowFormat(src, f); + toDo(f, currPos); + currPos = src.Pos(); + } + } +} diff --git a/generator/feature_merger.hpp b/generator/feature_merger.hpp index 45b606c3c7..9012170e15 100644 --- a/generator/feature_merger.hpp +++ b/generator/feature_merger.hpp @@ -1,7 +1,6 @@ #pragma once #include "feature_emitter_iface.hpp" - -#include "../indexer/feature.hpp" +#include "feature_builder.hpp" #include "../std/map.hpp" #include "../std/vector.hpp" diff --git a/generator/feature_sorter.cpp b/generator/feature_sorter.cpp index 81d650bdbf..e96061d997 100644 --- a/generator/feature_sorter.cpp +++ b/generator/feature_sorter.cpp @@ -1,5 +1,6 @@ #include "feature_sorter.hpp" #include "feature_generator.hpp" +#include "feature_builder.hpp" #include "../defines.hpp" diff --git a/generator/generator.pro b/generator/generator.pro index f5956f82bd..aee3bda4e6 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -27,6 +27,7 @@ SOURCES += \ mwm_rect_updater.cpp \ dumper.cpp \ unpack_mwm.cpp \ + feature_builder.cpp HEADERS += \ feature_merger.hpp \ @@ -51,3 +52,4 @@ HEADERS += \ dumper.hpp \ generate_info.hpp \ unpack_mwm.hpp \ + feature_builder.hpp diff --git a/generator/generator_tests/generator_tests.pro b/generator/generator_tests/generator_tests.pro index 3d00b663c2..26cbd7d33d 100644 --- a/generator/generator_tests/generator_tests.pro +++ b/generator/generator_tests/generator_tests.pro @@ -18,11 +18,10 @@ win32 { } HEADERS += \ - ../../indexer/indexer_tests/feature_routine.hpp \ + SOURCES += \ ../../testing/testingmain.cpp \ - ../../indexer/indexer_tests/feature_routine.cpp \ osm_parser_test.cpp \ feature_merger_test.cpp \ osm_type_test.cpp \ diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index 11046006fb..037ee83e0a 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -2,8 +2,8 @@ #include "osm2type.hpp" #include "xml_element.hpp" +#include "feature_builder.hpp" -#include "../indexer/feature.hpp" #include "../indexer/osm_decl.hpp" #include "../indexer/feature_visibility.hpp" diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 2e43fe689c..53e8b94542 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -9,12 +9,12 @@ #include "../defines.hpp" // just for file extensions +#include "../coding/byte_stream.hpp" + #include "../geometry/pointu_to_uint64.hpp" #include "../geometry/rect2d.hpp" #include "../geometry/region2d.hpp" -#include "../coding/byte_stream.hpp" - #include "../base/logging.hpp" #include "../base/stl_add.hpp" @@ -25,405 +25,6 @@ using namespace feature; -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FeatureBuilder1 implementation -/////////////////////////////////////////////////////////////////////////////////////////////////// - -bool FeatureBuilder1::IsGeometryClosed() const -{ - return (m_Geometry.size() > 2 && m_Geometry.front() == m_Geometry.back()); -} - -void FeatureBuilder1::SetCenter(m2::PointD const & p) -{ - m_Center = p; - m_Params.SetGeomType(GEOM_POINT); - m_LimitRect.Add(p); -} - -void FeatureBuilder1::AddPoint(m2::PointD const & p) -{ - m_Geometry.push_back(p); - m_LimitRect.Add(p); -} - -void FeatureBuilder1::SetAreaAddHoles(list const & holes) -{ - m_Params.SetGeomType(GEOM_AREA); - m_Holes.clear(); - - if (holes.empty()) return; - - m2::Region rgn(m_Geometry.begin(), m_Geometry.end()); - - for (list::const_iterator i = holes.begin(); i != holes.end(); ++i) - { - ASSERT ( !i->empty(), () ); - - if (rgn.Contains(i->front())) - m_Holes.push_back(*i); - } -} - -FeatureBase FeatureBuilder1::GetFeatureBase() const -{ - CHECK ( CheckValid(), () ); - - FeatureBase f; - f.SetHeader(m_Params.GetHeader()); - - 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_bTypesParsed = f.m_bCommonParsed = true; - - return f; -} - -namespace -{ - bool is_equal(double d1, double d2) - { - //return my::AlmostEqual(d1, d2, 100000000); - return (fabs(d1 - d2) < MercatorBounds::GetCellID2PointAbsEpsilon()); - } - - bool is_equal(m2::PointD const & p1, m2::PointD const & p2) - { - return p1.EqualDxDy(p2, MercatorBounds::GetCellID2PointAbsEpsilon()); - } - - bool is_equal(m2::RectD const & r1, m2::RectD const & r2) - { - return (is_equal(r1.minX(), r2.minX()) && - is_equal(r1.minY(), r2.minY()) && - is_equal(r1.maxX(), r2.maxX()) && - is_equal(r1.maxY(), r2.maxY())); - } - - bool is_equal(vector const & v1, vector const & v2) - { - if (v1.size() != v2.size()) - return false; - - for (size_t i = 0; i < v1.size(); ++i) - if (!is_equal(v1[i], v2[i])) - return false; - - return true; - } -} - -bool FeatureBuilder1::PreSerialize() -{ - if (!m_Params.IsValid()) return false; - - 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(0, m_Params.house.Get()); - - m_Params.ref = string(); - m_Params.house.Clear(); - break; - - case GEOM_LINE: - // We need refs only for road numbers. - if (!feature::IsHighway(m_Params.m_Types)) - m_Params.ref = string(); - - m_Params.rank = 0; - m_Params.house.Clear(); - break; - - case GEOM_AREA: - m_Params.rank = 0; - m_Params.ref = string(); - break; - - default: - return false; - } - - // Clear name for features with invisible texts. - if (!m_Params.name.IsEmpty() && feature::DrawableScaleRangeForText(GetFeatureBase()).first == -1) - m_Params.name.Clear(); - - 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; - - if (!is_equal(m_Geometry, fb.m_Geometry)) - return false; - - if (m_Holes.size() != fb.m_Holes.size()) - return false; - - list::const_iterator i = m_Holes.begin(); - list::const_iterator j = fb.m_Holes.begin(); - for (; i != m_Holes.end(); ++i, ++j) - if (!is_equal(*i, *j)) - return false; - - return true; -} - -bool FeatureBuilder1::CheckValid() const -{ - CHECK(m_Params.CheckValid(), ()); - - EGeomType const type = m_Params.GetGeomType(); - - CHECK(type != GEOM_LINE || m_Geometry.size() >= 2, ()); - - CHECK(type != GEOM_AREA || m_Geometry.size() >= 3, ()); - - CHECK(m_Holes.empty() || type == GEOM_AREA, ()); - - for (list::const_iterator i = m_Holes.begin(); i != m_Holes.end(); ++i) - CHECK(i->size() >= 3, ()); - - return true; -} - -void FeatureBuilder1::SerializeBase(buffer_t & data, serial::CodingParams const & params) const -{ - PushBackByteSink sink(data); - - m_Params.Write(sink); - - if (m_Params.GetGeomType() == GEOM_POINT) - WriteVarUint(sink, EncodeDelta(PointD2PointU(m_Center.x, m_Center.y, params.GetCoordBits()), - params.GetBasePoint())); -} - -void FeatureBuilder1::Serialize(buffer_t & data) const -{ - CHECK ( CheckValid(), () ); - - data.clear(); - - SerializeBase(data, serial::CodingParams()); - - PushBackByteSink sink(data); - - EGeomType const type = m_Params.GetGeomType(); - - if (type != GEOM_POINT) - serial::SaveOuterPath(m_Geometry, serial::CodingParams(), sink); - - if (type == GEOM_AREA) - { - WriteVarUint(sink, uint32_t(m_Holes.size())); - - for (list::const_iterator i = m_Holes.begin(); i != m_Holes.end(); ++i) - serial::SaveOuterPath(*i, serial::CodingParams(), sink); - } - - // check for correct serialization -#ifdef DEBUG - buffer_t tmp(data); - FeatureBuilder1 fb; - fb.Deserialize(tmp); - ASSERT ( fb == *this, () ); -#endif -} - -namespace -{ - template - void CalcRect(TCont const & points, m2::RectD & rect) - { - for (size_t i = 0; i < points.size(); ++i) - rect.Add(points[i]); - } -} - -void FeatureBuilder1::Deserialize(buffer_t & data) -{ - FeatureBase f; - f.Deserialize(data, 0, serial::CodingParams()); - f.InitFeatureBuilder(*this); - - ArrayByteSource src(f.DataPtr() + f.m_Header2Offset); - - EGeomType const type = m_Params.GetGeomType(); - - if (type != GEOM_POINT) - { - serial::LoadOuterPath(src, serial::CodingParams(), m_Geometry); - CalcRect(m_Geometry, m_LimitRect); - } - - if (type == GEOM_AREA) - { - uint32_t const count = ReadVarUint(src); - for (uint32_t i = 0; i < count; ++i) - { - m_Holes.push_back(points_t()); - serial::LoadOuterPath(src, serial::CodingParams(), m_Holes.back()); - } - } - - CHECK ( CheckValid(), () ); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// FeatureBuilderGeomRef implementation -/////////////////////////////////////////////////////////////////////////////////////////////////// - -bool FeatureBuilder2::IsDrawableInRange(int lowS, int highS) const -{ - if (!m_Geometry.empty()) - { - FeatureBase const fb = GetFeatureBase(); - - while (lowS <= highS) - if (feature::IsDrawableForIndex(fb, lowS++)) - return true; - } - - return false; -} - -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); - - // we don't need empty features without geometry - return base_type::PreSerialize(); -} - -namespace -{ - template class BitSink - { - TSink & m_sink; - uint8_t m_pos; - uint8_t m_current; - - public: - BitSink(TSink & sink) : m_sink(sink), m_pos(0), m_current(0) {} - - void Finish() - { - if (m_pos > 0) - { - WriteToSink(m_sink, m_current); - m_pos = 0; - m_current = 0; - } - } - - void Write(uint8_t value, uint8_t count) - { - ASSERT_LESS ( count, 9, () ); - ASSERT_EQUAL ( value >> count, 0, () ); - - if (m_pos + count > 8) - Finish(); - - m_current |= (value << m_pos); - m_pos += count; - } - }; -} - -void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams const & params) -{ - data.m_buffer.clear(); - - // header data serialization - SerializeBase(data.m_buffer, params); - - PushBackByteSink sink(data.m_buffer); - - uint8_t const ptsCount = static_cast(data.m_innerPts.size()); - uint8_t trgCount = static_cast(data.m_innerTrg.size()); - if (trgCount > 0) - { - ASSERT_GREATER ( trgCount, 2, () ); - trgCount -= 2; - } - - BitSink< PushBackByteSink > bitSink(sink); - - uint8_t const h = m_Params.GetTypeMask(); - - if (h & HEADER_GEOM_LINE) - { - bitSink.Write(ptsCount, 4); - if (ptsCount == 0) - bitSink.Write(data.m_ptsMask, 4); - } - - if (h & HEADER_GEOM_AREA) - { - bitSink.Write(trgCount, 4); - if (trgCount == 0) - bitSink.Write(data.m_trgMask, 4); - } - - bitSink.Finish(); - - if (h & HEADER_GEOM_LINE) - { - if (ptsCount > 0) - { - if (ptsCount > 2) - { - uint32_t v = data.m_ptsSimpMask; - int const count = (ptsCount - 2 + 3) / 4; - for (int i = 0; i < count; ++i) - { - WriteToSink(sink, static_cast(v)); - v >>= 8; - } - } - - serial::SaveInnerPath(data.m_innerPts, params, sink); - } - else - { - // offsets was pushed from high scale index to low - reverse(data.m_ptsOffset.begin(), data.m_ptsOffset.end()); - serial::WriteVarUintArray(data.m_ptsOffset, sink); - } - } - - if (h & HEADER_GEOM_AREA) - { - if (trgCount > 0) - serial::SaveInnerTriangles(data.m_innerTrg, params, sink); - else - { - // offsets was pushed from high scale index to low - reverse(data.m_trgOffset.begin(), data.m_trgOffset.end()); - serial::WriteVarUintArray(data.m_trgOffset, sink); - } - } -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // FeatureBase implementation /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -536,10 +137,8 @@ string FeatureBase::DebugString() const return res; } -void FeatureBase::InitFeatureBuilder(FeatureBuilder1 & fb) const +FeatureParams FeatureBase::GetFeatureParams() const { - ParseAll(); - FeatureParams params(m_Params); params.AssignTypes(m_Types, m_Types + GetTypesCount()); @@ -547,13 +146,7 @@ void FeatureBase::InitFeatureBuilder(FeatureBuilder1 & fb) const if (h & HEADER_GEOM_LINE) params.SetGeomType(GEOM_LINE); if (h & HEADER_GEOM_AREA) params.SetGeomType(GEOM_AREA); - if (GetFeatureType() == GEOM_POINT) - { - fb.SetCenter(m_Center); - params.SetGeomType(GEOM_POINT); - } - - fb.SetParams(params); + return params; } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indexer/feature.hpp b/indexer/feature.hpp index 92d2ceb5cc..49193d8e43 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -17,153 +17,6 @@ class ArrayByteSource; -class FeatureBase; - - -/// Used for serialization\deserialization of features during --generate_features. -class FeatureBuilder1 -{ -public: - /// @name Geometry manipulating functions. - //@{ - /// Set center (origin) point of feature and set that feature is point. - void SetCenter(m2::PointD const & p); - - /// Add point to geometry. - void AddPoint(m2::PointD const & p); - - /// Set that feature is linear type. - void SetLinear() { m_Params.SetGeomType(feature::GEOM_LINE); } - - /// Set that feature is area and get ownership of holes. - void SetAreaAddHoles(list > const & holes); - //@} - - inline feature::EGeomType GetGeomType() const { return m_Params.GetGeomType(); } - - inline void AddType(uint32_t type) { m_Params.AddType(type); } - inline bool HasType(uint32_t t) const { return m_Params.IsTypeExist(t); } - - typedef vector buffer_t; - - /// @name Serialization. - //@{ - void Serialize(buffer_t & data) const; - void SerializeBase(buffer_t & data, serial::CodingParams const & params) const; - - void Deserialize(buffer_t & data); - //@} - - ///@name Selectors. - //@{ - inline m2::RectD GetLimitRect() const { return m_LimitRect; } - - /// Get common parameters of feature. - FeatureBase GetFeatureBase() const; - - bool IsGeometryClosed() const; - - inline size_t GetPointsCount() const { return m_Geometry.size(); } - - template - void ForEachPointRef(ToDo & toDo) const - { - for_each(m_Geometry.begin(), m_Geometry.end(), bind(ref(toDo), _1)); - } - - // stops processing when functor returns false - template - void ForEachTruePointRef(ToDo & toDo) const - { - if (m_Params.GetGeomType() == feature::GEOM_POINT) - toDo(m_Center); - else - { - for (points_t::const_iterator it = m_Geometry.begin(); it != m_Geometry.end(); ++it) - if (!toDo(*it)) - return; - } - } - - inline m2::PointD CenterPoint() const { return m_Center; } - //@} - - bool PreSerialize(); - - inline void SetParams(FeatureParams const & params) { m_Params = params; } - -protected: - - /// @name For diagnostic use only. - //@{ - bool operator == (FeatureBuilder1 const &) const; - - bool CheckValid() const; - //@} - - FeatureParams m_Params; - - m2::RectD m_LimitRect; - - /// Can be one of the following: - /// - point in point-feature - /// - origin point of text [future] in line-feature - /// - 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 - points_t m_Geometry; // Check HEADER_IS_LINE - - /// List of holes in area-feature. - list m_Holes; // Check HEADER_IS_AREA -}; - -/// Used for serialization of features during final pass. -class FeatureBuilder2 : public FeatureBuilder1 -{ - typedef FeatureBuilder1 base_type; - - typedef vector offsets_t; - - static void SerializeOffsets(uint32_t mask, offsets_t const & offsets, buffer_t & buffer); - -public: - - struct buffers_holder_t - { - /// @name input - //@{ - offsets_t m_ptsOffset, m_trgOffset; - uint8_t m_ptsMask, m_trgMask; - - uint32_t m_ptsSimpMask; - - points_t m_innerPts, m_innerTrg; - //@} - - /// @name output - base_type::buffer_t m_buffer; - - 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 IsDrawableInRange(int lowS, int highS) const; - - points_t const & GetGeometry() const { return m_Geometry; } - list const & GetHoles() const { return m_Holes; } - - /// @name Overwrite from base_type. - //@{ - bool PreSerialize(buffers_holder_t const & data); - void Serialize(buffers_holder_t & data, serial::CodingParams const & params); - //@} -}; /// Base feature class for storing common data (without geometry). class FeatureBase @@ -257,13 +110,14 @@ public: f(m_Types[i]); } - void InitFeatureBuilder(FeatureBuilder1 & fb) const; - /// @name Statistic functions. //@{ uint32_t GetTypesSize() const { return m_CommonOffset - m_TypesOffset; } //@} + FeatureParams GetFeatureParams() const; + inline m2::PointD GetCenter() const { return m_Center; } + protected: void Deserialize(buffer_t & data, uint32_t offset, serial::CodingParams const & params); string DebugString() const; diff --git a/indexer/feature_impl.hpp b/indexer/feature_impl.hpp index 75c41bf034..ff5d781c7a 100644 --- a/indexer/feature_impl.hpp +++ b/indexer/feature_impl.hpp @@ -39,4 +39,11 @@ namespace feature str += arrChar[ind]; return str; } + + template + void CalcRect(TCont const & points, m2::RectD & rect) + { + for (size_t i = 0; i < points.size(); ++i) + rect.Add(points[i]); + } } diff --git a/indexer/feature_processor.hpp b/indexer/feature_processor.hpp index c471d73583..f3bdf5d662 100644 --- a/indexer/feature_processor.hpp +++ b/indexer/feature_processor.hpp @@ -23,34 +23,4 @@ namespace feature { ForEachFromDat(new FileReader(fPath), toDo); } - - /// Read feature from feature source. - template - void ReadFromSourceRowFormat(TSource & src, FeatureBuilder1 & f) - { - uint32_t const sz = ReadVarUint(src); - typename FeatureBuilder1::buffer_t buffer(sz); - src.Read(&buffer[0], sz); - f.Deserialize(buffer); - } - - /// Process features in .dat file. - template - void ForEachFromDatRawFormat(string const & fName, ToDo & toDo) - { - FileReader reader(fName); - ReaderSource src(reader); - - uint64_t currPos = 0; - uint64_t const fSize = reader.Size(); - - // read features one by one - while (currPos < fSize) - { - FeatureBuilder1 f; - ReadFromSourceRowFormat(src, f); - toDo(f, currPos); - currPos = src.Pos(); - } - } } diff --git a/indexer/indexer_tests/feature_routine.cpp b/indexer/indexer_tests/feature_routine.cpp deleted file mode 100644 index 519a071bbc..0000000000 --- a/indexer/indexer_tests/feature_routine.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "../../base/SRC_FIRST.hpp" - -#include "feature_routine.hpp" - -#include "../../defines.hpp" // just for file extensions - -#include "../../indexer/geometry_serialization.hpp" - -#include "../../coding/file_writer.hpp" - - -namespace -{ - class feature_source_initializer - { - string m_name; - FeatureType::read_source_t * m_source; - - public: - feature_source_initializer(string const & fName) - : m_name(fName), m_source(0) - { - } - - FeatureType::read_source_t & get_source(vector & buffer) - { - delete m_source; - m_source = new FeatureType::read_source_t(FilesContainerR(m_name)); - m_source->m_data.swap(buffer); - return *m_source; - } - - ~feature_source_initializer() - { - delete m_source; - FileWriter::DeleteFileX(m_name); - } - }; -} - -void FeatureBuilder2Feature(FeatureBuilder2 & fb, FeatureType & f) -{ - string const datFile = "indexer_tests_tmp.dat"; - - FeatureBuilder2::buffers_holder_t buffers; - buffers.m_ptsOffset.push_back(0); - buffers.m_trgOffset.push_back(0); - buffers.m_ptsMask = 1; - fb.Serialize(buffers, serial::CodingParams()); - - { - FilesContainerW writer(datFile); - - { - FileWriter geom = writer.GetWriter(string(GEOMETRY_FILE_TAG) + '0'); - serial::SaveOuterPath(fb.GetGeometry(), serial::CodingParams(), geom); - } - - //{ - // FileWriter trg = writer.GetWriter(string(TRIANGLE_FILE_TAG) + '0'); - // feature::SaveTriangles(fb.GetTriangles(), trg); - //} - - writer.Finish(); - } - - static feature_source_initializer staticInstance(datFile); - f.Deserialize(staticInstance.get_source(buffers.m_buffer)); -} - -void Feature2FeatureBuilder(FeatureType const & f, FeatureBuilder2 & fb) -{ - f.InitFeatureBuilder(fb); -} diff --git a/indexer/indexer_tests/feature_routine.hpp b/indexer/indexer_tests/feature_routine.hpp deleted file mode 100644 index 6d8c939e6f..0000000000 --- a/indexer/indexer_tests/feature_routine.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "../../indexer/feature.hpp" - -void FeatureBuilder2Feature(FeatureBuilder2 & fb, FeatureType & f); -void Feature2FeatureBuilder(FeatureType const & f, FeatureBuilder2 & fb); diff --git a/indexer/indexer_tests/feature_test.cpp b/indexer/indexer_tests/feature_test.cpp deleted file mode 100644 index 53627f6baa..0000000000 --- a/indexer/indexer_tests/feature_test.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "feature_routine.hpp" - -#include "../../testing/testing.hpp" - -#include "../feature.hpp" -#include "../cell_id.hpp" -#include "../classificator.hpp" -#include "../classificator_loader.hpp" - -#include "../../platform/platform.hpp" - -#include "../../geometry/point2d.hpp" - -#include "../../base/stl_add.hpp" - -namespace -{ - double Round(double x) - { - return static_cast(x * 1000 + 0.5) / 1000.0; - } - - struct PointAccumulator - { - vector m_V; - - void operator() (CoordPointT p) - { - m_V.push_back(m2::PointD(Round(p.first), Round(p.second))); - } - - void operator() (m2::PointD a, m2::PointD b, m2::PointD c) - { - m_V.push_back(m2::PointD(Round(a.x), Round(a.y))); - m_V.push_back(m2::PointD(Round(b.x), Round(b.y))); - m_V.push_back(m2::PointD(Round(c.x), Round(c.y))); - } - }; -} - -/* -UNIT_TEST(Feature_Deserialize) -{ - Platform & platform = GetPlatform(); - classificator::Read(platform.GetReader("drawing_rules.bin"), - platform.GetReader("classificator.txt"), - platform.GetReader("visibility.txt")); - - FeatureBuilder2 fb; - - fb.AddName("name"); - - vector points; - { - points.push_back(m2::PointD(1.0, 1.0)); - points.push_back(m2::PointD(0.25, 0.5)); - points.push_back(m2::PointD(0.25, 0.2)); - points.push_back(m2::PointD(1.0, 1.0)); - for (size_t i = 0; i < points.size(); ++i) - fb.AddPoint(points[i]); - fb.SetLinear(); - } - - //vector triangles; - //{ - // triangles.push_back(m2::PointD(0.5, 0.5)); - // triangles.push_back(m2::PointD(0.25, 0.5)); - // triangles.push_back(m2::PointD(1.0, 1.0)); - // for (size_t i = 0; i < triangles.size(); i += 3) - // fb.AddTriangle(triangles[i], triangles[i+1], triangles[i+2]); - //} - - fb.AddLayer(3); - - vector types; - { - vector path; - path.push_back("natural"); - path.push_back("coastline"); - - uint32_t const type = classif().GetTypeByPath(path); - TEST_NOT_EQUAL(type, ftype::GetEmptyValue(), () ); - types.push_back(type); - - fb.AddTypes(types.begin(), types.end()); - } - - FeatureType f; - FeatureBuilder2Feature(fb, f); - - TEST_EQUAL(f.GetFeatureType(), FeatureBase::FEATURE_TYPE_LINE, ()); - - FeatureBase::GetTypesFn getTypes; - f.ForEachTypeRef(getTypes); - TEST_EQUAL(vector(getTypes.m_types, getTypes.m_types + getTypes.m_size), types, ()); - - TEST_EQUAL(f.GetLayer(), 3, ()); - TEST_EQUAL(f.GetName(), "name", ()); - //TEST_EQUAL(f.GetGeometrySize(), 4, ()); - //TEST_EQUAL(f.GetTriangleCount(), 1, ()); - - int const level = 0; - - PointAccumulator featurePoints; - f.ForEachPointRef(featurePoints, level); - TEST_EQUAL(points, featurePoints.m_V, ()); - - //PointAccumulator featureTriangles; - //f.ForEachTriangleRef(featureTriangles, level); - //TEST_EQUAL(triangles, featureTriangles.m_V, ()); - - double const eps = MercatorBounds::GetCellID2PointAbsEpsilon(); - m2::RectD const & rect = f.GetLimitRect(level); - - TEST_LESS(fabs(rect.minX() - 0.25), eps, ()); - TEST_LESS(fabs(rect.minY() - 0.20), eps, ()); - TEST_LESS(fabs(rect.maxX() - 1.00), eps, ()); - TEST_LESS(fabs(rect.maxY() - 1.00), eps, ()); - - //{ - // FeatureBuilder2 fbTest; - // Feature2FeatureBuilder(f, fbTest); - - // FeatureType fTest; - // FeatureBuilder2Feature(fbTest, fTest); - // TEST_EQUAL(f.DebugString(level), fTest.DebugString(level), ()); - //} -} -*/ diff --git a/indexer/indexer_tests/indexer_tests.pro b/indexer/indexer_tests/indexer_tests.pro index 253c046db1..c230eeb797 100644 --- a/indexer/indexer_tests/indexer_tests.pro +++ b/indexer/indexer_tests/indexer_tests.pro @@ -14,7 +14,7 @@ win32:LIBS += -lopengl32 -lShell32 win32-g++:LIBS += -lpthread HEADERS += \ - feature_routine.hpp \ + SOURCES += \ ../../testing/testingmain.cpp \ @@ -28,8 +28,6 @@ SOURCES += \ point_to_int64_test.cpp \ mercator_test.cpp \ sort_and_merge_intervals_test.cpp \ - feature_test.cpp \ geometry_coding_test.cpp \ triangles_tree_coding_test.cpp \ - feature_routine.cpp \ - scales_test.cpp \ + scales_test.cpp \