[feature] Store house number in "house" field for point features (entrance, building-address).

This commit is contained in:
vng 2013-12-06 18:49:08 +01:00 committed by Alex Zolotarev
parent 68a506fd5d
commit e06897fa17
9 changed files with 133 additions and 140 deletions

View file

@ -95,24 +95,13 @@ void FeatureBuilder1::AddPolygon(vector<m2::PointD> & poly)
m_Polygons.back().swap(poly);
}
void FeatureBuilder1::DoCorrectForType(EGeomType type)
{
if (m_Params.GetGeomType() == type &&
!IsDrawableLike(m_Params.m_Types, static_cast<FeatureGeoType>(type)))
{
m_Params.RemoveGeomType(type);
}
}
bool FeatureBuilder1::DoCorrect()
bool FeatureBuilder1::RemoveInvalidTypes()
{
if (!m_Params.FinishAddingTypes())
return false;
DoCorrectForType(GEOM_AREA);
DoCorrectForType(GEOM_LINE);
return (m_Params.GetGeomType() != GEOM_UNDEFINED);
return feature::RemoveNoDrawableTypes(m_Params.m_Types,
static_cast<FeatureGeoType>(m_Params.GetGeomType()));
}
FeatureBase FeatureBuilder1::GetFeatureBase() const
@ -167,27 +156,27 @@ namespace
bool FeatureBuilder1::PreSerialize()
{
if (!m_Params.IsValid()) return false;
static const int8_t defaultCode = StringUtf8Multilang::GetLangIndex("default");
static const int8_t intCode = StringUtf8Multilang::GetLangIndex("int_name");
if (!m_Params.IsValid())
return false;
/// @todo Do not use flats info. Maybe in future.
m_Params.flats.clear();
switch (m_Params.GetGeomType())
{
case GEOM_POINT:
// If we don't have name and have house number, than replace them.
if (m_Params.name.IsEmpty() && !m_Params.house.IsEmpty())
m_Params.name.AddString(defaultCode, m_Params.house.Get());
// We need refs for motorway's junctions. Try to update name always, not only for junctions.
if (m_Params.name.IsEmpty() && (!m_Params.ref.empty() || m_Params.flats.empty()))
// Store house number like HEADER_GEOM_POINT_EX.
if (!m_Params.house.IsEmpty())
{
m_Params.name.AddString(defaultCode, m_Params.ref);
m_Params.name.AddString(intCode, m_Params.flats);
m_Params.SetGeomTypePointEx();
m_Params.rank = 0;
}
m_Params.house.Clear();
// Store ref's in name field (used in "highway-motorway_junction").
if (m_Params.name.IsEmpty() && !m_Params.ref.empty())
m_Params.name.AddString(0, m_Params.ref);
m_Params.ref.clear();
m_Params.flats.clear();
break;
case GEOM_LINE:
@ -196,7 +185,7 @@ bool FeatureBuilder1::PreSerialize()
// We need refs for road's numbers.
if (!checkHighway.IsEqualV(m_Params.m_Types))
m_Params.ref = string();
m_Params.ref.clear();
m_Params.rank = 0;
m_Params.house.Clear();
@ -269,7 +258,6 @@ bool FeatureBuilder1::CheckValid() const
CHECK(m_Params.CheckValid(), (*this));
EGeomType const type = m_Params.GetGeomType();
CHECK ( type != GEOM_UNDEFINED, (*this) );
points_t const & poly = GetGeometry();
@ -429,11 +417,17 @@ bool FeatureBuilder2::IsDrawableInRange(int lowS, int highS) const
bool FeatureBuilder2::PreSerialize(buffers_holder_t const & data)
{
// make flags actual before header serialization
if (data.m_ptsMask == 0 && data.m_innerPts.empty())
m_Params.RemoveGeomType(GEOM_LINE);
if (data.m_trgMask == 0 && data.m_innerTrg.empty())
m_Params.RemoveGeomType(GEOM_AREA);
EGeomType const geoType = m_Params.GetGeomType();
if (geoType == GEOM_LINE)
{
if (data.m_ptsMask == 0 && data.m_innerPts.empty())
return false;
}
else if (geoType == GEOM_AREA)
{
if (data.m_trgMask == 0 && data.m_innerTrg.empty())
return false;
}
// we don't need empty features without geometry
return base_type::PreSerialize();
@ -495,14 +489,13 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co
uint8_t const h = m_Params.GetTypeMask();
if (h & HEADER_GEOM_LINE)
if (h == HEADER_GEOM_LINE)
{
bitSink.Write(ptsCount, 4);
if (ptsCount == 0)
bitSink.Write(data.m_ptsMask, 4);
}
if (h & HEADER_GEOM_AREA)
else if (h == HEADER_GEOM_AREA)
{
bitSink.Write(trgCount, 4);
if (trgCount == 0)
@ -511,7 +504,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co
bitSink.Finish();
if (h & HEADER_GEOM_LINE)
if (h == HEADER_GEOM_LINE)
{
if (ptsCount > 0)
{
@ -540,8 +533,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, serial::CodingParams co
serial::WriteVarUintArray(data.m_ptsOffset, sink);
}
}
if (h & HEADER_GEOM_AREA)
else if (h == HEADER_GEOM_AREA)
{
if (trgCount > 0)
serial::SaveInnerTriangles(data.m_innerTrg, params, sink);

View file

@ -45,11 +45,10 @@ public:
inline bool PopExactType(uint32_t type) { return m_Params.PopExactType(type); }
inline void SetType(uint32_t type) { m_Params.SetType(type); }
/// Check for feature visibility according to it's types.
/// If feature is invisible, it's not correct.
/// This fuction is called after it's classificator types manipulating.
void DoCorrectForType(feature::EGeomType type);
bool DoCorrect();
/// Check classificator types for their compatibility with feature geometry type.
/// Need to call when using any classificator types manipulating.
/// @return false If no any valid types.
bool RemoveInvalidTypes();
/// Clear name if it's not visible in scale range [minS, maxS].
void RemoveNameIfInvisible(int minS = 0, int maxS = 1000);
@ -214,8 +213,8 @@ public:
buffers_holder_t() : m_ptsMask(0), m_trgMask(0), m_ptsSimpMask(0) {}
};
bool IsLine() const { return (m_Params.GetTypeMask() & feature::HEADER_GEOM_LINE) != 0; }
bool IsArea() const { return (m_Params.GetTypeMask() & feature::HEADER_GEOM_AREA) != 0; }
bool IsLine() const { return (m_Params.GetTypeMask() == feature::HEADER_GEOM_LINE); }
bool IsArea() const { return (m_Params.GetTypeMask() == feature::HEADER_GEOM_AREA); }
bool IsDrawableInRange(int lowS, int highS) const;
points_t const & GetOuterPoly() const { return GetGeometry(); }

View file

@ -359,10 +359,13 @@ public:
fb.PopExactType(Type(NATURAL_LAND));
fb.PopExactType(coastType);
}
else if (fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET)))
else if ((fb.HasType(Type(PLACE_ISLAND)) || fb.HasType(Type(PLACE_ISLET))) &&
fb.GetGeomType() == feature::GEOM_AREA)
{
fb.AddType(Type(NATURAL_LAND));
}
if (fb.DoCorrect())
if (fb.RemoveInvalidTypes())
{
if (m_world)
(*m_world)(fb);

View file

@ -53,7 +53,7 @@ UNIT_TEST(FBuilder_ManyTypes)
fb1.SetParams(params);
fb1.SetCenter(m2::PointD(0, 0));
TEST(fb1.DoCorrect(), ());
TEST(fb1.RemoveInvalidTypes(), ());
TEST(fb1.CheckValid(), ());
FeatureBuilder1::buffer_t buffer;

View file

@ -48,16 +48,11 @@ void FeatureBase::ParseCommon() const
feature::EGeomType FeatureBase::GetFeatureType() const
{
uint8_t const h = (Header() & HEADER_GEOTYPE_MASK);
if (h & HEADER_GEOM_AREA)
return GEOM_AREA;
else if (h & HEADER_GEOM_LINE)
return GEOM_LINE;
else
switch (Header() & HEADER_GEOTYPE_MASK)
{
ASSERT ( h == HEADER_GEOM_POINT, (h) );
return GEOM_POINT;
case HEADER_GEOM_LINE: return GEOM_LINE;
case HEADER_GEOM_AREA: return GEOM_AREA;
default: return GEOM_POINT;
}
}
@ -287,7 +282,7 @@ void FeatureType::GetReadableName(string & name) const
string FeatureType::GetHouseNumber() const
{
ParseCommon();
return (GetFeatureType() == GEOM_AREA ? m_Params.house.Get() : string());
return m_Params.house.Get();
}
bool FeatureType::GetName(int8_t lang, string & name) const

View file

@ -110,7 +110,7 @@ string FeatureParamsBase::DebugString() const
void FeatureParamsBase::AddHouseName(string const & s)
{
house.Set(house.IsEmpty() ? s : house.Get() + " \"" + s + "\"");
house.Set(house.IsEmpty() ? s : house.Get() + ", " + s);
}
void FeatureParamsBase::AddHouseNumber(string const & ss)
@ -122,27 +122,42 @@ void FeatureParamsBase::AddHouseNumber(string const & ss)
if (strings::to_uint64(s, n))
s = strings::to_string(n);
house.Set(house.IsEmpty() ? s : s + " \"" + house.Get() + "\"");
house.Set(house.IsEmpty() ? s : s + ", " + house.Get());
}
void FeatureParams::SetGeomType(feature::EGeomType t)
{
switch (t)
{
case GEOM_POINT: m_geomType = HEADER_GEOM_POINT; break;
case GEOM_LINE: m_geomType = HEADER_GEOM_LINE; break;
case GEOM_AREA: m_geomType = HEADER_GEOM_AREA; break;
}
}
void FeatureParams::SetGeomTypePointEx()
{
ASSERT_EQUAL(m_geomType, HEADER_GEOM_POINT, ());
ASSERT(!house.IsEmpty(), ());
m_geomType = HEADER_GEOM_POINT_EX;
}
feature::EGeomType FeatureParams::GetGeomType() const
{
// Geometry types can be combined.
// We define exact type for priority : starting from GEOM_AREA.
if (m_geomTypes[GEOM_AREA]) return GEOM_AREA;
if (m_geomTypes[GEOM_LINE]) return GEOM_LINE;
if (m_geomTypes[GEOM_POINT]) return GEOM_POINT;
return GEOM_UNDEFINED;
CHECK_NOT_EQUAL(m_geomType, 0xFF, ());
switch (m_geomType)
{
case HEADER_GEOM_LINE: return GEOM_LINE;
case HEADER_GEOM_AREA: return GEOM_AREA;
default: return GEOM_POINT;
}
}
uint8_t FeatureParams::GetTypeMask() const
{
uint8_t h = 0;
if (m_geomTypes[GEOM_POINT]) h |= HEADER_GEOM_POINT;
if (m_geomTypes[GEOM_LINE]) h |= HEADER_GEOM_LINE;
if (m_geomTypes[GEOM_AREA]) h |= HEADER_GEOM_AREA;
return h;
CHECK_NOT_EQUAL(m_geomType, 0xFF, ());
return m_geomType;
}
void FeatureParams::AddTypes(FeatureParams const & rhs, uint32_t skipType2)
@ -209,7 +224,7 @@ bool FeatureParams::operator == (FeatureParams const & rhs) const
bool FeatureParams::CheckValid() const
{
CHECK(!m_Types.empty() && m_Types.size() <= max_types_count, ());
CHECK(GetGeomType() != GEOM_UNDEFINED, ());
CHECK_NOT_EQUAL(m_geomType, 0xFF, ());
return FeatureParamsBase::CheckValid();
}
@ -224,16 +239,17 @@ uint8_t FeatureParams::GetHeader() const
if (layer != 0)
header |= HEADER_HAS_LAYER;
header |= GetTypeMask();
uint8_t const typeMask = GetTypeMask();
header |= typeMask;
// Geometry type for additional info is only one.
switch (GetGeomType())
switch (GetTypeMask())
{
case GEOM_POINT: if (rank != 0) header |= HEADER_HAS_ADDINFO; break;
case GEOM_LINE: if (!ref.empty()) header |= HEADER_HAS_ADDINFO; break;
case GEOM_AREA: if (!house.IsEmpty()) header |= HEADER_HAS_ADDINFO; break;
default:
ASSERT(false, ("Undefined geometry type"));
case HEADER_GEOM_POINT: if (rank != 0) header |= HEADER_HAS_ADDINFO; break;
case HEADER_GEOM_LINE: if (!ref.empty()) header |= HEADER_HAS_ADDINFO; break;
case HEADER_GEOM_AREA:
case HEADER_GEOM_POINT_EX:
if (!house.IsEmpty()) header |= HEADER_HAS_ADDINFO; break;
}
return header;

View file

@ -33,9 +33,11 @@ namespace feature
enum EHeaderTypeMask
{
HEADER_GEOM_POINT = 0,
HEADER_GEOM_LINE = 1U << 5,
HEADER_GEOM_AREA = 1U << 6
/// Coding geometry feature type in 2 bits.
HEADER_GEOM_POINT = 0, /// point feature (addinfo = rank)
HEADER_GEOM_LINE = 1U << 5, /// linear feature (addinfo = ref)
HEADER_GEOM_AREA = 1U << 6, /// area feature (addinfo = house)
HEADER_GEOM_POINT_EX = 3U << 5 /// point feature (addinfo = house)
};
static const int max_types_count = HEADER_TYPE_MASK + 1;
@ -125,57 +127,59 @@ struct FeatureParamsBase
void AddHouseNumber(string const & s);
template <class TSink>
void Write(TSink & sink, uint8_t header, feature::EGeomType type) const
void Write(TSink & sink, uint8_t header) const
{
if (header & feature::HEADER_HAS_NAME)
using namespace feature;
if (header & HEADER_HAS_NAME)
name.Write(sink);
if (header & feature::HEADER_HAS_LAYER)
if (header & HEADER_HAS_LAYER)
WriteToSink(sink, layer);
if (header & feature::HEADER_HAS_ADDINFO)
if (header & HEADER_HAS_ADDINFO)
{
switch (type)
switch (header & HEADER_GEOTYPE_MASK)
{
case feature::GEOM_POINT:
case HEADER_GEOM_POINT:
WriteToSink(sink, rank);
break;
case feature::GEOM_LINE:
case HEADER_GEOM_LINE:
utils::WriteString(sink, ref);
break;
case feature::GEOM_AREA:
case HEADER_GEOM_AREA:
case HEADER_GEOM_POINT_EX:
house.Write(sink);
break;
default:
ASSERT(false, ("Undefined geometry type"));
}
}
}
template <class TSrc>
void Read(TSrc & src, uint8_t header, feature::EGeomType type)
void Read(TSrc & src, uint8_t header)
{
if (header & feature::HEADER_HAS_NAME)
using namespace feature;
if (header & HEADER_HAS_NAME)
name.Read(src);
if (header & feature::HEADER_HAS_LAYER)
if (header & HEADER_HAS_LAYER)
layer = ReadPrimitiveFromSource<int8_t>(src);
if (header & feature::HEADER_HAS_ADDINFO)
if (header & HEADER_HAS_ADDINFO)
{
switch (type)
switch (header & HEADER_GEOTYPE_MASK)
{
case feature::GEOM_POINT:
case HEADER_GEOM_POINT:
rank = ReadPrimitiveFromSource<uint8_t>(src);
break;
case feature::GEOM_LINE:
case HEADER_GEOM_LINE:
utils::ReadString(src, ref);
break;
case feature::GEOM_AREA:
case HEADER_GEOM_AREA:
case HEADER_GEOM_POINT_EX:
house.Read(src);
break;
default:
ASSERT(false, ("Undefined geometry type"));
}
}
}
@ -185,16 +189,13 @@ class FeatureParams : public FeatureParamsBase
{
typedef FeatureParamsBase BaseT;
bool m_geomTypes[3];
uint8_t m_geomType;
public:
typedef vector<uint32_t> types_t;
types_t m_Types;
FeatureParams()
{
m_geomTypes[0] = m_geomTypes[1] = m_geomTypes[2] = false;
}
FeatureParams() : m_geomType(0xFF) {}
/// Assign parameters except geometry type.
/// Geometry is independent state and it's set by FeatureType's geometry functions.
@ -206,9 +207,8 @@ public:
inline bool IsValid() const { return !m_Types.empty(); }
inline void SetGeomType(feature::EGeomType t) { m_geomTypes[t] = true; }
inline void RemoveGeomType(feature::EGeomType t) { m_geomTypes[t] = false; }
void SetGeomType(feature::EGeomType t);
void SetGeomTypePointEx();
feature::EGeomType GetGeomType() const;
uint8_t GetTypeMask() const;
@ -245,7 +245,7 @@ public:
for (size_t i = 0; i < m_Types.size(); ++i)
WriteVarUint(sink, GetIndexForType(m_Types[i]));
BaseT::Write(sink, header, GetGeomType());
BaseT::Write(sink, header);
}
template <class TSrc> void Read(TSrc & src)
@ -253,17 +253,13 @@ public:
using namespace feature;
uint8_t const header = ReadPrimitiveFromSource<uint8_t>(src);
uint8_t const type = (header & HEADER_GEOTYPE_MASK);
if (type & HEADER_GEOM_LINE) SetGeomType(GEOM_LINE);
if (type & HEADER_GEOM_AREA) SetGeomType(GEOM_AREA);
if (type == HEADER_GEOM_POINT) SetGeomType(GEOM_POINT);
m_geomType = header & HEADER_GEOTYPE_MASK;
size_t const count = (header & HEADER_TYPE_MASK) + 1;
for (size_t i = 0; i < count; ++i)
m_Types.push_back(GetTypeForIndex(ReadVarUint<uint32_t>(src)));
BaseT::Read(src, header, GetGeomType());
BaseT::Read(src, header);
}
private:

View file

@ -37,12 +37,9 @@ void LoaderCurrent::ParseCommon()
ArrayByteSource source(DataPtr() + m_CommonOffset);
uint8_t const h = Header();
m_pF->m_Params.Read(source, h);
EGeomType const type = m_pF->GetFeatureType();
m_pF->m_Params.Read(source, h, type);
if (type == GEOM_POINT)
if (m_pF->GetFeatureType() == GEOM_POINT)
{
m_pF->m_Center = serial::LoadPoint(source, GetDefCodingParams());
m_pF->m_LimitRect.Add(m_pF->m_Center);
@ -103,20 +100,16 @@ void LoaderCurrent::ParseHeader2()
BitSource bitSource(DataPtr() + m_Header2Offset);
uint8_t const h = (Header() & HEADER_GEOTYPE_MASK);
if (h & HEADER_GEOM_LINE)
uint8_t const typeMask = Header() & HEADER_GEOTYPE_MASK;
if (typeMask == HEADER_GEOM_LINE)
{
ptsCount = bitSource.Read(4);
if (ptsCount == 0)
ptsMask = bitSource.Read(4);
else
{
ASSERT_GREATER ( ptsCount, 1, () );
}
}
if (h & HEADER_GEOM_AREA)
else if (typeMask == HEADER_GEOM_AREA)
{
trgCount = bitSource.Read(4);
if (trgCount == 0)
@ -127,7 +120,7 @@ void LoaderCurrent::ParseHeader2()
serial::CodingParams const & cp = GetDefCodingParams();
if (h & HEADER_GEOM_LINE)
if (typeMask == HEADER_GEOM_LINE)
{
if (ptsCount > 0)
{
@ -153,8 +146,7 @@ void LoaderCurrent::ParseHeader2()
ReadOffsets(src, ptsMask, m_ptsOffsets);
}
}
if (h & HEADER_GEOM_AREA)
else if (typeMask == HEADER_GEOM_AREA)
{
if (trgCount > 0)
{
@ -184,7 +176,7 @@ void LoaderCurrent::ParseHeader2()
uint32_t LoaderCurrent::ParseGeometry(int scale)
{
uint32_t sz = 0;
if (Header() & HEADER_GEOM_LINE)
if ((Header() & HEADER_GEOTYPE_MASK) == HEADER_GEOM_LINE)
{
size_t const count = m_pF->m_Points.size();
if (count < 2)
@ -236,7 +228,7 @@ uint32_t LoaderCurrent::ParseGeometry(int scale)
uint32_t LoaderCurrent::ParseTriangles(int scale)
{
uint32_t sz = 0;
if (Header() & HEADER_GEOM_AREA)
if ((Header() & HEADER_GEOTYPE_MASK) == HEADER_GEOM_AREA)
{
if (m_pF->m_Triangles.empty())
{

View file

@ -219,10 +219,10 @@ class FeatureInserter
SkipIndexing()
{
// Get features which shoud be skipped in any case.
char const * arrSkip2[][2] = {
{ "building", "address" }
};
char const * arrSkip1[][1] = { { "entrance" } };
char const * arrSkip2[][2] = { { "building", "address" } };
FillTypes(arrSkip1, m_skipFeatures);
FillTypes(arrSkip2, m_skipFeatures);
// Get features which shoud be skipped without names.