diff --git a/builder/genindex/genindex.pro b/builder/genindex/genindex.pro index a8485f4..0f29e9f 100644 --- a/builder/genindex/genindex.pro +++ b/builder/genindex/genindex.pro @@ -9,13 +9,23 @@ include (../../defines.pri) SOURCES += \ main.cpp \ + +# storage sources +SOURCES += \ ../../storage/storage_builder.cpp \ + ../../storage/storage.cpp \ ../../storage/article_info.cpp \ ../../storage/distance.cpp \ + +# env sources +SOURCES += \ ../../env/file_handle.cpp \ ../../env/assert.cpp \ ../../env/source_address.cpp \ ../../env/logging.cpp \ ../../env/posix.cpp \ ../../env/strings.cpp \ + +# utf8proc +SOURCES += \ ../../3rdparty/utf8proc/utf8proc.c \ diff --git a/storage/article_info.cpp b/storage/article_info.cpp index fdc1ee7..251b73b 100644 --- a/storage/article_info.cpp +++ b/storage/article_info.cpp @@ -113,7 +113,7 @@ void ArticleInfo::Read(rd::Reader & r) namespace { double const DISTANCE_TRASHOLD = 2.0E5; // 200 km -double const METERS_PER_LETTER_FACTOR = 10.0; +double const METERS_PER_LETTER_FACTOR = 1.0; } double ArticleInfo::Score(double currLat, double currLon) const @@ -123,14 +123,14 @@ double ArticleInfo::Score(double currLat, double currLon) const if (IsValidCoordinates() && currLat != EMPTY_COORD && currLon != EMPTY_COORD) { - dist = earth::Distance(m_lat, m_lon, currLat, currLon); + dist = earth::GetDistance(m_lat, m_lon, currLat, currLon); if (dist > DISTANCE_TRASHOLD) dist = inf; } else dist = inf; - return (dist - METERS_PER_LETTER_FACTOR * m_length); + return (dist - METERS_PER_LETTER_FACTOR * sqrt(m_length)); } void ArticleInfo::Swap(ArticleInfo & i) diff --git a/storage/storage_builder.cpp b/storage/storage_builder.cpp index 1c09b93..90a7c58 100644 --- a/storage/storage_builder.cpp +++ b/storage/storage_builder.cpp @@ -210,6 +210,14 @@ void StorageBuilder::Save(string const & path) } } +void StorageBuilder::Load(string const & path) +{ + Storage s; + s.Load(path); + + m_info.assign(s.m_info.begin(), s.m_info.end()); +} + void StorageBuilder::Assign(Storage & storage) { ProcessArticles(); diff --git a/storage/storage_builder.hpp b/storage/storage_builder.hpp index 25ebf0c..a3a41d4 100644 --- a/storage/storage_builder.hpp +++ b/storage/storage_builder.hpp @@ -9,7 +9,11 @@ class ArticleInfoBuilder : public ArticleInfo { public: - ArticleInfoBuilder(string const & title) : ArticleInfo(title) + explicit ArticleInfoBuilder(string const & title) : ArticleInfo(title) + { + } + + ArticleInfoBuilder(ArticleInfo const & info) : ArticleInfo(info) { } @@ -76,6 +80,7 @@ public: void Add(ArticleInfoBuilder const & info); void Save(string const & path); + void Load(string const & path); void Assign(Storage & storage); @@ -87,6 +92,9 @@ public: return (i == m_url2info.end() ? 0 : &m_info[i->second]); } + size_t GetSize() const { return m_info.size(); } + ArticleInfoBuilder const & GetArticle(size_t i) const { return m_info[i]; } + /// For tests only. void InitMock(); }; diff --git a/storage/tests/storage_test.cpp b/storage/tests/storage_test.cpp index 66b94dd..d4580d4 100644 --- a/storage/tests/storage_test.cpp +++ b/storage/tests/storage_test.cpp @@ -30,6 +30,112 @@ TEST(ArticleInfo, PrefixMatch) namespace { +void CheckScore(ArticleInfoBuilder const & i1, + ArticleInfoBuilder const & i2, + double r) +{ + // generic score check for quite far objects + double const dist = earth::GetDistance(i1.Lat(), i1.Lon(), i2.Lat(), i2.Lon()); + if (dist < 50.0) + return; + + r = r * 1000.0; + size_t const count = 4; + double const deltaAzimuth = 2.0 * earth::PI / count; + + for (size_t i = 0; i < count; ++i) + { + // get estimate users position + double lat, lon; + earth::GetOffset(i1.Lat(), i1.Lon(), i * deltaAzimuth, r, lat, lon); + + // do check score if position closer to i1 more than 3 times. + if (earth::GetDistance(lat, lon, i2.Lat(), i2.Lon()) >= 2.0 * r) + { + double const s1 = i1.Score(lat, lon); + double const s2 = i2.Score(lat, lon); + if (s1 > s2) + { + LOG(INFO, ("Scores:", s1, s2)); + LOG(INFO, ("Distance:", dist, r)); + LOG(INFO, (i1.Title(), ";", i2.Title())); + + EXPECT_TRUE(false); + } + } + } +} + +} + +TEST(ArticleInfo, ScoreSmoke) +{ + typedef ArticleInfoBuilder AIB; + AIB arr[] = { + AIB("London", 51.5073219, -0.1276474, 251423), + AIB("Glasgow", 55.86115, -4.24999, 152010), + AIB("Manchester", 53.47910, -2.24457, 132021), + AIB("Aberdeen", 57.14525, -2.09137, 131042), + AIB("Leeds", 53.79737, -1.54376, 118763), + AIB("Birmingham", 52.48136, -1.89807, 115464), + AIB("Bristol", 51.45566, -2.59531, 107102), + AIB("Belfast", 54.59694, -5.93016, 105649), + AIB("Liverpool", 53.40547, -2.98052, 90401), + AIB("Edinburgh", 55.94832, -3.19319, 74188), + AIB("Brighton", 50.82217, -0.13767, 62403) + }; + + // Check that no side effects. + for (size_t i = 0; i < ArraySize(arr); ++i) + { + EXPECT_EQ(arr[i].Score(arr[i].Lat(), arr[i].Lon()), + arr[i].Score(arr[i].Lat(), arr[i].Lon())); + } + + // Check for correct scoring around every city (with the set of approximate radius in km). + double arrLen[] = { 0, 0.5, 1, 2, 5, 10, 15, 20, 30, 50, 100 }; + + size_t const count = ArraySize(arr); + for (size_t len = 0; len < ArraySize(arrLen); ++len) + for (size_t i = 0; i < count; ++i) + for (size_t j = 0; j < count; ++j) + { + if (i != j) + CheckScore(arr[i], arr[j], arrLen[len]); + } +} + +/* +TEST(ArticleInfo, ScoreUK) +{ + StorageBuilder builder; + builder.Load("../../guide_info/index.dat"); + + double arrLen[] = { 0, 0.3, 0.5, 1, 2, 5, 10, 15, 20, 30 }; + + size_t const count = builder.GetSize(); + for (size_t len = 0; len < ArraySize(arrLen); ++len) + for (size_t i = 0; i < count; ++i) + for (size_t j = 0; j < count; ++j) + { + if (i != j) + { + ArticleInfoBuilder const & i1 = builder.GetArticle(i); + ArticleInfoBuilder const & i2 = builder.GetArticle(j); + + if (!i1.IsRedirect() && !i2.IsRedirect() && + i1.IsValidCoordinates() && i2.IsValidCoordinates()) + { + CheckScore(i1, i2, arrLen[len]); + } + } + } +} +*/ + +namespace +{ + class StorageTest : public Storage { public: