Refactoring of feature structure:

- multilanguage names
- separate house numbers
- point feature rank
- refs for linear features
This commit is contained in:
vng 2011-05-09 01:53:49 +03:00 committed by Alex Zolotarev
parent 4ec7dff6c7
commit 2400357a3d
18 changed files with 535 additions and 325 deletions

View file

@ -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 бита кол-ва внутренних точек для линейного объекта:

View file

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

View file

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

View file

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

View file

@ -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<uint8_t>(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<uint32_t> & 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<string> 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();
}
}

View file

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

View file

@ -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<vector<m2::PointD> > & GetHoles() { return m_holes.m_holes; }
};
/// Feature description struct.
struct value_t
{
typedef vector<uint32_t> 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<uint64_t, value_t> m_typeCache;
unordered_map<uint64_t, FeatureParams> 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<uint64_t, value_t>::const_iterator i = m_typeCache.find(id);
typename unordered_map<uint64_t, FeatureParams>::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<TEmitter, THolder>
{
typedef SecondPassParserBase<TEmitter, THolder> 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

View file

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

View file

@ -51,7 +51,7 @@ namespace stats
struct MapInfo
{
set<GeneralInfoKey<FeatureBase::FeatureType> > m_byGeomType;
set<GeneralInfoKey<feature::EGeomType> > m_byGeomType;
set<GeneralInfoKey<TypeTag> > m_byClassifType;
set<GeneralInfoKey<uint32_t> > m_byPointsCount, m_byTrgCount;

View file

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

View file

@ -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<points_t> 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<points_t> 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<uint32_t> const & diffTypes)
{
vector<uint32_t> 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<points_t>::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<uint8_t>(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<buffer_t> 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<buffer_t> 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<uint32_t>(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<buffer_t> > 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<int32_t>(source);
EGeomType const type = GetFeatureType();
if (h & HEADER_HAS_NAME)
{
m_Name.resize(ReadVarUint<uint32_t>(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<uint64_t>(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<vector<m2::PointD> > 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())
{

View file

@ -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<vector<m2::PointD> > const & holes);
//@}
void AddName(string const & name);
static const int m_maxTypesCount = 7;
template <class TIter>
inline void AddTypes(TIter beg, TIter end)
{
// !WTF! with GCC
int const count = min(static_cast<int>(m_maxTypesCount), static_cast<int>(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<uint32_t> const & diffTypes);
void AddLayer(int32_t layer);
inline bool IsTypeExist(uint32_t t) const
{
return m_Params.IsTypeExist(t);
}
inline bool AssignType_SetDifference(vector<uint32_t> const & diffTypes)
{
return m_Params.AssignType_SetDifference(diffTypes);
}
typedef vector<char> buffer_t;
@ -92,7 +84,7 @@ public:
template <class ToDo>
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<m2::PointD> 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<uint32_t> 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<m2::PointD> 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<points_t> 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<char> 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

129
indexer/feature_data.cpp Normal file
View file

@ -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<uint32_t> const & diffTypes)
{
vector<uint32_t> 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<uint8_t>(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;
}

163
indexer/feature_data.hpp Normal file
View file

@ -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 <class TSink>
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 <class TSrc>
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<int8_t>(src);
if (header & HEADER_HAS_ADDINFO)
{
switch (type)
{
case GEOM_POINT:
rank = ReadPrimitiveFromSource<uint8_t>(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<uint32_t> 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 <class TIter>
void AssignTypes(TIter b, TIter e)
{
m_Types.assign(b, e);
}
bool IsTypeExist(uint32_t t) const;
bool AssignType_SetDifference(vector<uint32_t> const & diffTypes);
bool operator == (FeatureParams const & rhs) const;
bool CheckValid() const;
uint8_t GetHeader() const;
template <class TSink> 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);
}
};

View file

@ -132,7 +132,7 @@ namespace
int GetDrawRule(FeatureBase const & f, int level, vector<drule::Key> & 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<uint32_t> 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;

View file

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

View file

@ -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<di::DrawInfo> ptr(new di::DrawInfo(f.GetName()));
string utf8name;
f.GetName(0, utf8name);
shared_ptr<di::DrawInfo> 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<area_tess_points>, 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<path_points>, ForEachPointRef, assign_path)
break;
}

View file

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