Factor out FeatureBuilder to the separate module in 'generator' lib.

This commit is contained in:
vng 2011-08-23 17:17:58 +03:00 committed by Alex Zolotarev
parent 56dda15554
commit 2046a47d56
15 changed files with 619 additions and 808 deletions

View file

@ -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<points_t> const & holes)
{
m_Params.SetGeomType(GEOM_AREA);
m_Holes.clear();
if (holes.empty()) return;
m2::Region<m2::PointD> rgn(m_Geometry.begin(), m_Geometry.end());
for (list<points_t>::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<m2::PointD> const & v1, vector<m2::PointD> 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<points_t>::const_iterator i = m_Holes.begin();
list<points_t>::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<points_t>::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<buffer_t> 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<buffer_t> 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<points_t>::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<uint32_t>(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 TSink> 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<buffer_t> sink(data.m_buffer);
uint8_t const ptsCount = static_cast<uint8_t>(data.m_innerPts.size());
uint8_t trgCount = static_cast<uint8_t>(data.m_innerTrg.size());
if (trgCount > 0)
{
ASSERT_GREATER ( trgCount, 2, () );
trgCount -= 2;
}
BitSink< PushBackByteSink<buffer_t> > 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<uint8_t>(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);
}
}

View file

@ -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<vector<m2::PointD> > 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<char> 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 <class ToDo>
void ForEachPointRef(ToDo & toDo) const
{
for_each(m_Geometry.begin(), m_Geometry.end(), bind<void>(ref(toDo), _1));
}
// stops processing when functor returns false
template <class ToDo>
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<m2::PointD> 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<points_t> m_Holes; // Check HEADER_IS_AREA
};
/// Used for serialization of features during final pass.
class FeatureBuilder2 : public FeatureBuilder1
{
typedef FeatureBuilder1 base_type;
typedef vector<uint32_t> 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<points_t> 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 <class TSource>
void ReadFromSourceRowFormat(TSource & src, FeatureBuilder1 & f)
{
uint32_t const sz = ReadVarUint<uint32_t>(src);
typename FeatureBuilder1::buffer_t buffer(sz);
src.Read(&buffer[0], sz);
f.Deserialize(buffer);
}
/// Process features in .dat file.
template <class ToDo>
void ForEachFromDatRawFormat(string const & fName, ToDo & toDo)
{
FileReader reader(fName);
ReaderSource<FileReader> 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();
}
}
}

View file

@ -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"

View file

@ -1,5 +1,6 @@
#include "feature_sorter.hpp"
#include "feature_generator.hpp"
#include "feature_builder.hpp"
#include "../defines.hpp"

View file

@ -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

View file

@ -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 \

View file

@ -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"

View file

@ -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<points_t> const & holes)
{
m_Params.SetGeomType(GEOM_AREA);
m_Holes.clear();
if (holes.empty()) return;
m2::Region<m2::PointD> rgn(m_Geometry.begin(), m_Geometry.end());
for (list<points_t>::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<m2::PointD> const & v1, vector<m2::PointD> 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<points_t>::const_iterator i = m_Holes.begin();
list<points_t>::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<points_t>::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<buffer_t> 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<buffer_t> 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<points_t>::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 <class TCont>
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<uint32_t>(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 TSink> 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<buffer_t> sink(data.m_buffer);
uint8_t const ptsCount = static_cast<uint8_t>(data.m_innerPts.size());
uint8_t trgCount = static_cast<uint8_t>(data.m_innerTrg.size());
if (trgCount > 0)
{
ASSERT_GREATER ( trgCount, 2, () );
trgCount -= 2;
}
BitSink< PushBackByteSink<buffer_t> > 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<uint8_t>(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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -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<vector<m2::PointD> > 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<char> 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 <class ToDo>
void ForEachPointRef(ToDo & toDo) const
{
for_each(m_Geometry.begin(), m_Geometry.end(), bind<void>(ref(toDo), _1));
}
// stops processing when functor returns false
template <class ToDo>
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<m2::PointD> 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<points_t> m_Holes; // Check HEADER_IS_AREA
};
/// Used for serialization of features during final pass.
class FeatureBuilder2 : public FeatureBuilder1
{
typedef FeatureBuilder1 base_type;
typedef vector<uint32_t> 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<points_t> 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;

View file

@ -39,4 +39,11 @@ namespace feature
str += arrChar[ind];
return str;
}
template <class TCont>
void CalcRect(TCont const & points, m2::RectD & rect)
{
for (size_t i = 0; i < points.size(); ++i)
rect.Add(points[i]);
}
}

View file

@ -23,34 +23,4 @@ namespace feature
{
ForEachFromDat(new FileReader(fPath), toDo);
}
/// Read feature from feature source.
template <class TSource>
void ReadFromSourceRowFormat(TSource & src, FeatureBuilder1 & f)
{
uint32_t const sz = ReadVarUint<uint32_t>(src);
typename FeatureBuilder1::buffer_t buffer(sz);
src.Read(&buffer[0], sz);
f.Deserialize(buffer);
}
/// Process features in .dat file.
template <class ToDo>
void ForEachFromDatRawFormat(string const & fName, ToDo & toDo)
{
FileReader reader(fName);
ReaderSource<FileReader> 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();
}
}
}

View file

@ -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<char> & 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);
}

View file

@ -1,6 +0,0 @@
#pragma once
#include "../../indexer/feature.hpp"
void FeatureBuilder2Feature(FeatureBuilder2 & fb, FeatureType & f);
void Feature2FeatureBuilder(FeatureType const & f, FeatureBuilder2 & fb);

View file

@ -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<int>(x * 1000 + 0.5) / 1000.0;
}
struct PointAccumulator
{
vector<m2::PointD> 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<m2::PointD> 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<m2::PointD> 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<uint32_t> types;
{
vector<string> 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<uint32_t>(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), ());
//}
}
*/

View file

@ -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 \