From fec57ec15746ae9fbc080daf2969ba69fcdd1e9c Mon Sep 17 00:00:00 2001 From: Kirill Zhdanovich Date: Thu, 5 Dec 2013 23:42:18 +0100 Subject: [PATCH] [search] Compare Street names and House numbers --- search/house_detector.cpp | 66 +++++++++++++++++--- search/house_detector.hpp | 41 ++++++++++-- search/search_tests/house_detector_tests.cpp | 53 ++++++++++++++-- 3 files changed, 142 insertions(+), 18 deletions(-) diff --git a/search/house_detector.cpp b/search/house_detector.cpp index 9ee3a5f60f..806bef110e 100644 --- a/search/house_detector.cpp +++ b/search/house_detector.cpp @@ -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 & 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 & 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::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, vectorm_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); diff --git a/search/house_detector.hpp b/search/house_detector.hpp index 2ed85c4054..3033e1098f 100644 --- a/search/house_detector.hpp +++ b/search/house_detector.hpp @@ -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 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 m_points; vector 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 & ids); diff --git a/search/search_tests/house_detector_tests.cpp b/search/search_tests/house_detector_tests.cpp index db078c44f1..1a89ff336a 100644 --- a/search/search_tests/house_detector_tests.cpp +++ b/search/search_tests/house_detector_tests.cpp @@ -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 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 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)), ()); +}