[search] Compare Street names and House numbers
This commit is contained in:
parent
d18a824355
commit
fec57ec157
3 changed files with 142 additions and 18 deletions
|
@ -7,7 +7,6 @@
|
|||
#include "../geometry/distance.hpp"
|
||||
#include "../geometry/distance_on_sphere.hpp"
|
||||
|
||||
#include "../std/iostream.hpp"
|
||||
#include "../std/set.hpp"
|
||||
#include "../std/bind.hpp"
|
||||
|
||||
|
@ -15,9 +14,55 @@
|
|||
namespace search
|
||||
{
|
||||
|
||||
string affics1[] =
|
||||
{
|
||||
"аллея", "бульвар", "набережная",
|
||||
"переулок", "площадь", "проезд",
|
||||
"проспект", "шоссе", "тупик", "улица"
|
||||
};
|
||||
|
||||
string affics2[] =
|
||||
{
|
||||
"ал.", "бул.", "наб.", "пер.",
|
||||
"пл.", "пр.", "просп.", "ш.",
|
||||
"туп.", "ул."
|
||||
};
|
||||
|
||||
void GetStreetName(strings::SimpleTokenizer iter, string & streetName)
|
||||
{
|
||||
while(iter)
|
||||
{
|
||||
bool flag = true;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(affics2); ++i)
|
||||
{
|
||||
if (*iter == affics2[i] || *iter == affics1[i])
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
streetName += *iter;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
int const BUILDING_PROCESS_SCALE = 15;
|
||||
double const STREET_CONNECTION_LENGTH_M = 25.0;
|
||||
|
||||
void House::InitHouseNumberAndSuffix()
|
||||
{
|
||||
m_suffix = "";
|
||||
m_intNumber = 0;
|
||||
for (int i = 0; i < m_number.size(); ++i)
|
||||
if (m_number[i] < '0' || m_number[i] > '9')
|
||||
{
|
||||
strings::to_int(m_number.substr(0, i), m_intNumber);
|
||||
m_suffix = m_number.substr(i, m_number.size() - i);
|
||||
return;
|
||||
}
|
||||
strings::to_int(m_number, m_intNumber);
|
||||
}
|
||||
|
||||
struct StreetCreator
|
||||
{
|
||||
|
@ -75,6 +120,13 @@ m2::RectD Street::GetLimitRect(double offsetMeters) const
|
|||
return rect;
|
||||
}
|
||||
|
||||
void Street::SetName(string const & name)
|
||||
{
|
||||
m_name = name;
|
||||
strings::SimpleTokenizer iter(name, " -");
|
||||
GetStreetName(iter, m_processedName);
|
||||
strings::MakeLowerCase(m_processedName);
|
||||
}
|
||||
|
||||
HouseDetector::HouseDetector(Index const * pIndex)
|
||||
: m_loader(pIndex), m_end2st(LessWithEpsilon(&m_epsMercator)), m_streetNum(0)
|
||||
|
@ -96,7 +148,7 @@ void HouseDetector::FillQueue(queue<Street *> & q, Street const * street, bool i
|
|||
for (IterT it = range.first; it != range.second; ++it)
|
||||
{
|
||||
/// @todo create clever street names compare functions
|
||||
if (it->second->m_number == -1 && street->m_name == it->second->m_name)
|
||||
if (it->second->m_number == -1 && street->GetName() == it->second->GetName())
|
||||
{
|
||||
it->second->m_number = m_streetNum;
|
||||
q.push(it->second);
|
||||
|
@ -137,7 +189,7 @@ void HouseDetector::LoadStreets(vector<FeatureID> & ids)
|
|||
continue;
|
||||
|
||||
Street * st = new Street();
|
||||
st->m_name = name;
|
||||
st->SetName(name);
|
||||
f.ForEachPoint(StreetCreator(st), FeatureType::BEST_GEOMETRY);
|
||||
|
||||
m_id2st[ids[i]] = st;
|
||||
|
@ -258,7 +310,7 @@ void HouseDetector::ReadHouse(FeatureType const & f, Street * st, ProjectionCalc
|
|||
map<FeatureID, House *>::iterator const it = m_id2house.find(f.GetID());
|
||||
|
||||
m2::PointD const pt = (it == m_id2house.end()) ?
|
||||
f.GetLimitRect(BUILDING_PROCESS_SCALE).Center() : it->second->m_point;
|
||||
f.GetLimitRect(BUILDING_PROCESS_SCALE).Center() : it->second->GetPosition();
|
||||
|
||||
HouseProjection pr;
|
||||
if (calc.GetProjection(pt, pr))
|
||||
|
@ -266,9 +318,7 @@ void HouseDetector::ReadHouse(FeatureType const & f, Street * st, ProjectionCalc
|
|||
House * p;
|
||||
if (it == m_id2house.end())
|
||||
{
|
||||
p = new House();
|
||||
p->m_point = pt;
|
||||
p->m_number = f.GetHouseNumber();
|
||||
p = new House(f.GetHouseNumber(), pt);
|
||||
m_id2house[f.GetID()] = p;
|
||||
}
|
||||
else
|
||||
|
@ -312,7 +362,7 @@ void HouseDetector::MatchAllHouses(string const & houseNumber, vector<HouseProje
|
|||
for (size_t i = 0; i < st->m_houses.size(); ++i)
|
||||
{
|
||||
House const * house = st->m_houses[i].m_house;
|
||||
if (house->m_number == houseNumber && s.count(house) == 0)
|
||||
if (house->GetNumber() == houseNumber && s.count(house) == 0)
|
||||
{
|
||||
res.push_back(st->m_houses[i]);
|
||||
s.insert(house);
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
#include "../std/string.hpp"
|
||||
#include "../std/queue.hpp"
|
||||
#include "../std/iostream.hpp"
|
||||
|
||||
|
||||
namespace search
|
||||
{
|
||||
|
||||
class FeatureLoader
|
||||
{
|
||||
Index const * m_pIndex;
|
||||
|
@ -29,10 +29,31 @@ public:
|
|||
template <class ToDo> void ForEachInRect(m2::RectD const & rect, ToDo toDo);
|
||||
};
|
||||
|
||||
struct House
|
||||
class House
|
||||
{
|
||||
string m_number;
|
||||
m2::PointD m_point;
|
||||
int m_intNumber;
|
||||
string m_suffix;
|
||||
|
||||
void InitHouseNumberAndSuffix();
|
||||
public:
|
||||
string const & GetNumber() const { return m_number; }
|
||||
m2::PointD const & GetPosition() const { return m_point; }
|
||||
|
||||
House(string const & number, m2::PointD const & point)
|
||||
{
|
||||
m_number = number;
|
||||
m_point = point;
|
||||
InitHouseNumberAndSuffix();
|
||||
}
|
||||
|
||||
inline static bool LessHouseNumber(House const & h1, House const & h2)
|
||||
{
|
||||
if (h1.m_intNumber == h2.m_intNumber)
|
||||
return h1.m_suffix < h2.m_suffix;
|
||||
return h1.m_intNumber < h2.m_intNumber;
|
||||
}
|
||||
};
|
||||
|
||||
struct HouseProjection
|
||||
|
@ -41,16 +62,22 @@ struct HouseProjection
|
|||
m2::PointD m_proj;
|
||||
double m_distance;
|
||||
|
||||
static bool LessDistance(HouseProjection const & r1, HouseProjection const & r2)
|
||||
inline static bool LessDistance(HouseProjection const & r1, HouseProjection const & r2)
|
||||
{
|
||||
return r1.m_distance < r2.m_distance;
|
||||
}
|
||||
};
|
||||
|
||||
// many features combines to street
|
||||
struct Street
|
||||
class Street
|
||||
{
|
||||
string m_name;
|
||||
string m_processedName;
|
||||
|
||||
public:
|
||||
void SetName(string const & name);
|
||||
string const & GetName() const { return m_name; }
|
||||
|
||||
vector<m2::PointD> m_points;
|
||||
|
||||
vector<HouseProjection> m_houses;
|
||||
|
@ -61,6 +88,11 @@ struct Street
|
|||
|
||||
/// Get limit rect for street with ortho offset to the left and right.
|
||||
m2::RectD GetLimitRect(double offsetMeters) const;
|
||||
|
||||
inline static bool IsSameStreets(Street const & s1, Street const & s2)
|
||||
{
|
||||
return s1.m_processedName == s2.m_processedName;
|
||||
}
|
||||
};
|
||||
|
||||
class HouseDetector
|
||||
|
@ -103,6 +135,7 @@ private:
|
|||
void SetMetres2Mercator(double factor);
|
||||
|
||||
public:
|
||||
|
||||
HouseDetector(Index const * pIndex);
|
||||
|
||||
void LoadStreets(vector<FeatureID> & ids);
|
||||
|
|
|
@ -180,8 +180,8 @@ UNIT_TEST(SEARCH_HOUSE_NUMBER_SMOKE_TEST)
|
|||
string houseName = "7";
|
||||
GetCanditates(index, streetName, houseName, res, 100);
|
||||
TEST_EQUAL(res.size(), 1, ());
|
||||
TEST_ALMOST_EQUAL(res[0].m_house->m_point, m2::PointD(27.539850827603416406, 64.222406776416349317), ());
|
||||
TEST_EQUAL(res[0].m_house->m_number, houseName, ());
|
||||
TEST_ALMOST_EQUAL(res[0].m_house->GetPosition(), m2::PointD(27.539850827603416406, 64.222406776416349317), ());
|
||||
TEST_EQUAL(res[0].m_house->GetNumber(), houseName, ());
|
||||
}
|
||||
{
|
||||
vector <string> streetName(1, "проспект Независимости");
|
||||
|
@ -189,8 +189,8 @@ UNIT_TEST(SEARCH_HOUSE_NUMBER_SMOKE_TEST)
|
|||
string houseName = "10";
|
||||
GetCanditates(index, streetName, houseName, res, 40);
|
||||
TEST_EQUAL(res.size(), 1, ());
|
||||
TEST_ALMOST_EQUAL(res[0].m_house->m_point, m2::PointD(27.551358845467561309, 64.234708728154814139), ());
|
||||
TEST_EQUAL(res[0].m_house->m_number, houseName, ());
|
||||
TEST_ALMOST_EQUAL(res[0].m_house->GetPosition(), m2::PointD(27.551358845467561309, 64.234708728154814139), ());
|
||||
TEST_EQUAL(res[0].m_house->GetNumber(), houseName, ());
|
||||
}
|
||||
{
|
||||
vector <string> streetName(1, "улица Ленина");
|
||||
|
@ -198,7 +198,48 @@ UNIT_TEST(SEARCH_HOUSE_NUMBER_SMOKE_TEST)
|
|||
string houseName = "9";
|
||||
GetCanditates(index, streetName, houseName, res, 50);
|
||||
TEST_EQUAL(res.size(), 1, ());
|
||||
TEST_ALMOST_EQUAL(res[0].m_house->m_point, m2::PointD(27.560341563525355468, 64.240918042070561), ());
|
||||
TEST_EQUAL(res[0].m_house->m_number, houseName, ());
|
||||
TEST_ALMOST_EQUAL(res[0].m_house->GetPosition(), m2::PointD(27.560341563525355468, 64.240918042070561), ());
|
||||
TEST_EQUAL(res[0].m_house->GetNumber(), houseName, ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UNIT_TEST(STREET_COMPARE_TEST)
|
||||
{
|
||||
search::Street A, B;
|
||||
TEST(search::Street::IsSameStreets(A, B), ());
|
||||
string str[8][2] = { {"Московская", "Московская"},
|
||||
{"ул. Московская", "Московская ул."},
|
||||
{"ул. Московская", "Московская улица"},
|
||||
{"ул. Московская", "улица Московская"},
|
||||
{"ул. Московская", "площадь Московская"},
|
||||
{"ул. мОСКОВСКАЯ", "Московская улица"},
|
||||
{"Московская", "площадь Московская"},
|
||||
{"Московская ", "аллея Московская"}
|
||||
};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(str); ++i)
|
||||
{
|
||||
A.SetName(str[i][0]);
|
||||
B.SetName(str[i][0]);
|
||||
TEST(search::Street::IsSameStreets(A, B), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(HOUSE_COMPARE_TEST)
|
||||
{
|
||||
m2::PointD p(1,1);
|
||||
TEST(search::House::LessHouseNumber(search::House("1", p), search::House("2", p)), ());
|
||||
TEST(search::House::LessHouseNumber(search::House("123", p), search::House("123-3", p)), ());
|
||||
TEST(search::House::LessHouseNumber(search::House("18a", p), search::House("18b", p)), ());
|
||||
TEST(search::House::LessHouseNumber(search::House("120 1A", p), search::House("120 7A", p)), ());
|
||||
TEST(search::House::LessHouseNumber(search::House("120 1A", p), search::House("120 7B", p)), ());
|
||||
|
||||
TEST(!search::House::LessHouseNumber(search::House("4", p), search::House("4", p)), ());
|
||||
TEST(!search::House::LessHouseNumber(search::House("95", p), search::House("82-b", p)), ());
|
||||
|
||||
TEST(!search::House::LessHouseNumber(search::House("2", p), search::House("1", p)), ());
|
||||
TEST(!search::House::LessHouseNumber(search::House("123-3", p), search::House("123", p)), ());
|
||||
TEST(!search::House::LessHouseNumber(search::House("18b", p), search::House("18a", p)), ());
|
||||
TEST(!search::House::LessHouseNumber(search::House("120 7A", p), search::House("120 1A", p)), ());
|
||||
TEST(!search::House::LessHouseNumber(search::House("120 7B", p), search::House("120 1A", p)), ());
|
||||
}
|
||||
|
|
Reference in a new issue