From b00f54d0ccb969c7516449b80fc300786593d07c Mon Sep 17 00:00:00 2001 From: Kirill Zhdanovich Date: Mon, 9 Dec 2013 13:02:11 +0300 Subject: [PATCH] House filtering functions --- search/house_detector.cpp | 264 ++++++++++++++++++- search/house_detector.hpp | 26 +- search/search_tests/house_detector_tests.cpp | 1 - 3 files changed, 274 insertions(+), 17 deletions(-) diff --git a/search/house_detector.cpp b/search/house_detector.cpp index 806bef110e..cd825f70c6 100644 --- a/search/house_detector.cpp +++ b/search/house_detector.cpp @@ -128,6 +128,19 @@ void Street::SetName(string const & name) strings::MakeLowerCase(m_processedName); } +namespace +{ +bool LessDistance(HouseProjection const & p1, HouseProjection const & p2) +{ + return p1.m_streetDistance < p2.m_streetDistance; +} +} + +void Street::SortHousesProjection() +{ + sort(m_houses.begin(), m_houses.end(), &LessDistance); +} + HouseDetector::HouseDetector(Index const * pIndex) : m_loader(pIndex), m_end2st(LessWithEpsilon(&m_epsMercator)), m_streetNum(0) { @@ -158,7 +171,7 @@ void HouseDetector::FillQueue(queue & q, Street const * street, bool i void HouseDetector::Bfs(Street * st) { - queue q; + queue q; q.push(st); st->m_number = m_streetNum; while(!q.empty()) @@ -251,7 +264,7 @@ double GetDistanceMeters(m2::PointD const & p1, m2::PointD const & p2) class ProjectionCalcToStreet { - Street const * m_street; + vector const & m_points; double m_distanceMeters; typedef m2::ProjectionToSection ProjectionT; @@ -259,24 +272,25 @@ class ProjectionCalcToStreet public: ProjectionCalcToStreet(Street const * st, double distanceMeters) - : m_street(st), m_distanceMeters(distanceMeters) + : m_points(st->m_points), m_distanceMeters(distanceMeters) { } - bool GetProjection(m2::PointD const & pt, HouseProjection & proj) + void Initialize() { - if (m_calcs.empty()) + if (m_calcs.empty() && !m_points.empty()) { - for (size_t i = 1; i < m_street->m_points.size(); ++i) + m_calcs.reserve(m_points.size() - 1); + for (size_t i = 1; i < m_points.size(); ++i) { m_calcs.push_back(ProjectionT()); - m_calcs.back().SetBounds(m_street->m_points[i-1], m_street->m_points[i]); + m_calcs.back().SetBounds(m_points[i-1], m_points[i]); } } + } - m2::PointD resPt; - double dist = numeric_limits::max(); - double resDist = numeric_limits::max(); + void CalculateProjectionParameters(m2::PointD const & pt, m2::PointD & resPt, double & dist, double & resDist, size_t & ind) + { for (size_t i = 0; i < m_calcs.size(); ++i) { m2::PointD const proj = m_calcs[i](pt); @@ -285,13 +299,33 @@ public: { resPt = proj; resDist = dist; + ind = i; } } + } + + bool GetProjection(m2::PointD const & pt, HouseProjection & proj) + { + Initialize(); + + m2::PointD resPt; + double dist = numeric_limits::max(); + double resDist = numeric_limits::max(); + size_t ind; + + CalculateProjectionParameters(pt, resPt, dist, resDist, ind); if (resDist <= m_distanceMeters) { proj.m_proj = resPt; - proj.m_distance = dist; + proj.m_distance = resDist; + + proj.m_streetDistance = 0.0; + for (size_t i = 0; i < ind; ++i) + proj.m_streetDistance += m_calcs[i].GetLength(); + + proj.m_streetDistance += m_points[ind].Length(proj.m_proj); + proj.m_projectionSign = m2::GetOrientation(m_points[ind], m_points[ind+1], pt) >= 0; return true; } else @@ -305,7 +339,7 @@ template void HouseDetector::ReadHouse(FeatureType const & f, Street * st, ProjectionCalcT & calc) { static HouseChecker checker; - if (checker.IsHouse(feature::TypesHolder(f))) + if (checker.IsHouse(feature::TypesHolder(f)) && !f.GetHouseNumber().empty()) { map::iterator const it = m_id2house.find(f.GetID()); @@ -342,6 +376,7 @@ void HouseDetector::ReadHouses(Street * st, double offsetMeters) m_loader.ForEachInRect(st->GetLimitRect(offsetMeters), bind(&HouseDetector::ReadHouse, this, _1, st, ref(calcker))); + st->SortHousesProjection(); st->m_housesReaded = true; } @@ -356,9 +391,10 @@ void HouseDetector::MatchAllHouses(string const & houseNumber, vector s; - for (map::iterator it = m_id2st.begin(); it != m_id2st.end();++it) + for (IterM it = m_id2st.begin(); it != m_id2st.end();++it) { Street const * st = it->second; + for (size_t i = 0; i < st->m_houses.size(); ++i) { House const * house = st->m_houses[i].m_house; @@ -371,4 +407,206 @@ void HouseDetector::MatchAllHouses(string const & houseNumber, vector const & houses, + vector & result) +{ + if (houses.size() < 2) + { + result = houses; + return; + } + vector v(houses.size()); + for (size_t i = 0; i < v.size(); ++i) + v[i] = LS(i); + + size_t res = 0; + size_t pos = 0; + for (size_t i = 0; i + 1 < houses.size(); ++i) + { + for (size_t j = i + 1; j < houses.size(); ++j) + { + if (House::LessHouseNumber(*houses[i].m_house, *houses[j].m_house) && v[i].increaseValue + 1 > v[j].increaseValue) + { + v[j].increaseValue = v[i].increaseValue + 1; + v[j].prevIncreasePos = i; + } + if (!House::LessHouseNumber(*houses[i].m_house, *houses[j].m_house) && v[i].decreaseValue + 1 > v[j].decreaseValue) + { + v[j].decreaseValue = v[i].decreaseValue + 1; + v[j].prevDecreasePos = i; + } + size_t m = max(v[j].increaseValue, v[j].decreaseValue); + if (m > res) + { + res = m; + pos = j; + } + } + } + + result.resize(res); + bool increasing = true; + if (v[pos].increaseValue < v[pos].decreaseValue) + increasing = false; + + while (res > 0) + { + result[res - 1] = houses[pos]; + --res; + if (increasing) + pos = v[pos].prevIncreasePos; + else + pos = v[pos].prevDecreasePos; + } +} + + +pair HouseDetector::GetAllStreets() +{ + return pair (m_id2st.begin(), m_id2st.end()); +} + +void AddHouseToMap(search::HouseProjection const & proj, map & m) +{ + map::iterator const it = m.find(*proj.m_house); + if (it != m.end()) + { + if (it->second > proj.m_distance) + { + m.erase(it); + m.insert(std::pair (*proj.m_house, proj.m_distance)); + } + } + else + m.insert(std::pair (*proj.m_house, proj.m_distance)); +} + +/// @ Simple filter. Delete only houses with same house names. If names are equal take house with smaller distance to projection +void HouseDetector::SimpleFilter(string const & houseNumber, vector & res) +{ + map result; + /// @not release version should think about how to return 5 houses for 5 streets. + for (search::HouseDetector::IterM it = m_id2st.begin(); it != m_id2st.end(); ++it) + { + Street * st = it->second; + for (size_t i = 0; i < st->m_houses.size(); ++i) + if (st->m_houses[i].m_house->GetNumber() == houseNumber) + AddHouseToMap(st->m_houses[i], result); + } + for (map::iterator it = result.begin(); it != result.end(); ++it) + res.push_back(it->first); +} + +//filtering house from street + +bool cmpH(search::HouseProjection const & h, bool isOdd) +{ + int x = h.m_house->GetIntNumber(); + if ((x % 2 == 1) && isOdd) + return false; + if (x % 2 == 0 && !isOdd) + return false; + return true; +} + +void createKMLString(map & m) +{ + for (map::iterator it = m.begin(); it != m.end(); ++it) + { + cout << "" + << "" << it->first.GetNumber() << "" << + + "" << + + MercatorBounds::XToLon(it->first.GetPosition().x) << + + "," << + + MercatorBounds::YToLat(it->first.GetPosition().y) << + + "" << + "" << endl; + } +} + +void ProccessHouses(vector & houses, vector & result, bool isOdd, map & m) +{ + houses.erase(remove_if(houses.begin(), houses.end(), bind(&cmpH, _1, isOdd)), houses.end()); + result.clear(); + LongestSubsequence(houses, result); + for_each(result.begin(), result.end(), bind(&AddHouseToMap, _1, ref(m))); +} + +//valid only if only one street in class +void GetAllHousesForStreet(pair range, map & m) +{ + for (search::HouseDetector::IterM it = range.first; it != range.second; ++it) + { + vector left, right; + search::Street * st = it->second; + double r = numeric_limits::max(); + size_t index = numeric_limits::max(); + for (size_t i = 0; i < st->m_houses.size(); ++i) + { + double dist = st->m_houses[i].m_distance; + if (st->m_houses[i].m_projectionSign) + left.push_back(st->m_houses[i]); + else + right.push_back(st->m_houses[i]); + if (r > dist && st->m_houses[i].m_proj != st->m_points.front() && st->m_houses[i].m_proj != st->m_points.back()) + { + index = i; + r = dist; + } + } + + if (index >= st->m_houses.size()) + { + cout << "WARNING!" << endl; + continue; + } + cout << endl; + bool leftOdd, rightOdd; + if (!st->m_houses[index].m_projectionSign) + { + rightOdd = false; + if (st->m_houses[index].m_house->GetIntNumber() % 2 == 1) + rightOdd = true; + leftOdd = !rightOdd; + } + else + { + leftOdd = false; + if (st->m_houses[index].m_house->GetIntNumber() % 2 == 1) + leftOdd = true; + rightOdd = !leftOdd; + } + + vector leftRes, rightRes; + ProccessHouses(right, rightRes, rightOdd, m); + ProccessHouses(left, leftRes, leftOdd, m); + } + //createKMLString(m); +} + } diff --git a/search/house_detector.hpp b/search/house_detector.hpp index 3033e1098f..17ca98725a 100644 --- a/search/house_detector.hpp +++ b/search/house_detector.hpp @@ -37,14 +37,15 @@ class House string m_suffix; void InitHouseNumberAndSuffix(); + public: string const & GetNumber() const { return m_number; } + int GetIntNumber() const { return m_intNumber; } m2::PointD const & GetPosition() const { return m_point; } House(string const & number, m2::PointD const & point) + : m_number(number), m_point(point), m_intNumber(-1) { - m_number = number; - m_point = point; InitHouseNumberAndSuffix(); } @@ -54,6 +55,11 @@ public: return h1.m_suffix < h2.m_suffix; return h1.m_intNumber < h2.m_intNumber; } + + bool operator<(House const & h) const + { + return LessHouseNumber(*this, h); + } }; struct HouseProjection @@ -61,6 +67,10 @@ struct HouseProjection House const * m_house; m2::PointD m_proj; double m_distance; + /// Distance in mercator, from street beginning to projection on street + double m_streetDistance; + /// false - to the left, true - to the right from projection segment + bool m_projectionSign; inline static bool LessDistance(HouseProjection const & r1, HouseProjection const & r2) { @@ -79,13 +89,14 @@ public: string const & GetName() const { return m_name; } vector m_points; - vector m_houses; bool m_housesReaded; int m_number; Street() : m_housesReaded(false), m_number(-1) {} + void SortHousesProjection(); + /// Get limit rect for street with ortho offset to the left and right. m2::RectD GetLimitRect(double offsetMeters) const; @@ -135,6 +146,7 @@ private: void SetMetres2Mercator(double factor); public: + typedef map::iterator IterM; HouseDetector(Index const * pIndex); @@ -146,6 +158,14 @@ public: void ReadAllHouses(double offsetMeters); void MatchAllHouses(string const & houseNumber, vector & res); + vector GetHouseForName(string const & houseName); + + pair GetAllStreets(); + void SimpleFilter(string const & houseNumber, vector & res); }; +void LongestSubsequence(vector const & houses, + vector & result); +void GetAllHousesForStreet(pair range, map & m); + } diff --git a/search/search_tests/house_detector_tests.cpp b/search/search_tests/house_detector_tests.cpp index 1a89ff336a..e3d56c79ef 100644 --- a/search/search_tests/house_detector_tests.cpp +++ b/search/search_tests/house_detector_tests.cpp @@ -12,7 +12,6 @@ #include "../../std/iostream.hpp" - UNIT_TEST(LESS_WITH_EPSILON) { double q = 3.0 * 360.0 / 40.0E06;