diff options
author | vng <viktor.govako@gmail.com> | 2013-06-24 19:53:50 +0400 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 01:56:49 +0300 |
commit | 8a6201deadd0affd932dae545b5200857d79758f (patch) | |
tree | 6b51bb1374640d756bf9381edca64c699158274c /map/mwm_tests | |
parent | d2d74c74413ef496b946ea87a2d50517fd2ab320 (diff) |
Move "heavy" tests to separate executable mwm_tests.
Diffstat (limited to 'map/mwm_tests')
-rw-r--r-- | map/mwm_tests/multithread_mwm_test.cpp | 89 | ||||
-rw-r--r-- | map/mwm_tests/mwm_foreach_test.cpp | 330 | ||||
-rw-r--r-- | map/mwm_tests/mwm_tests.pro | 25 |
3 files changed, 444 insertions, 0 deletions
diff --git a/map/mwm_tests/multithread_mwm_test.cpp b/map/mwm_tests/multithread_mwm_test.cpp new file mode 100644 index 0000000000..ff2df972ab --- /dev/null +++ b/map/mwm_tests/multithread_mwm_test.cpp @@ -0,0 +1,89 @@ +#include "../../testing/testing.hpp" + +#include "../../map/feature_vec_model.hpp" + +#include "../../base/thread.hpp" + + +namespace +{ + typedef model::FeaturesFetcher SourceT; + + class FeaturesLoader : public threads::IRoutine + { + SourceT const & m_src; + int m_scale; + + // Get random rect inside m_src. + m2::RectD GetRandomRect() const + { + int const count = max(1, rand() % 50); + + int const x = rand() % count; + int const y = rand() % count; + + m2::RectD const r = m_src.GetWorldRect(); + double const sizeX = r.SizeX() / count; + double const sizeY = r.SizeY() / count; + + double const minX = r.minX() + x * sizeX; + double const minY = r.minY() + y * sizeY; + + return m2::RectD(minX, minY, minX + sizeX, minY + sizeY); + } + + public: + FeaturesLoader(SourceT const & src) : m_src(src) {} + + virtual void Do() + { + size_t const count = 2000; + + for (size_t i = 0; i < count; ++i) + { + m2::RectD const r = GetRandomRect(); + m_scale = scales::GetScaleLevel(r); + + m_src.ForEachFeature_TileDrawing(r, *this, m_scale); + } + } + + void operator() (FeatureType const & f) + { + // Force load feature. + // We check asserts here. There is no any other constrains here. + (void)f.IsEmptyGeometry(m_scale); + } + }; + + void RunTest(string const & file) + { + SourceT src; + src.InitClassificator(); + src.AddMap(file + DATA_FILE_EXTENSION); + + // Check that country rect is valid and not infinity. + m2::RectD const r = src.GetWorldRect(); + TEST ( r.IsValid(), () ); + + m2::RectD world(MercatorBounds::FullRect()); + world.Inflate(-10.0, -10.0); + + TEST ( world.IsRectInside(r), () ); + + srand(666); + + size_t const count = 20; + threads::ThreadPool pool(count); + + for (size_t i = 0; i < count; ++i) + pool.Add(new FeaturesLoader(src)); + + pool.Join(); + } +} + +UNIT_TEST(Threading_ForEachFeature) +{ + RunTest("minsk-pass"); +} diff --git a/map/mwm_tests/mwm_foreach_test.cpp b/map/mwm_tests/mwm_foreach_test.cpp new file mode 100644 index 0000000000..bbab151564 --- /dev/null +++ b/map/mwm_tests/mwm_foreach_test.cpp @@ -0,0 +1,330 @@ +#include "../../testing/testing.hpp" + +#include "../../platform/platform.hpp" + +#include "../../map/feature_vec_model.hpp" + +#include "../../indexer/data_header.hpp" +#include "../../indexer/scales.hpp" +#include "../../indexer/feature_visibility.hpp" +#include "../../indexer/feature_processor.hpp" +#include "../../indexer/classificator.hpp" + +#include "../../geometry/rect_intersect.hpp" +#include "../../geometry/robust_orientation.hpp" + +#include "../../base/logging.hpp" + +#include "../../std/string.hpp" +#include "../../std/algorithm.hpp" +#include "../../std/iostream.hpp" + + +typedef vector<pair<FeatureType, string> > feature_cont_t; + +class AccumulatorBase +{ + mutable string m_dbgString; + feature_cont_t & m_cont; + +protected: + int m_scale; + + bool is_drawable(FeatureType const & f) const + { + m_dbgString = f.DebugString(m_scale); + CHECK(m_dbgString == f.DebugString(m_scale), ()); + + // Feature that doesn't have any geometry for m_scale returns empty DebugString(). + return (!f.IsEmptyGeometry(m_scale) && feature::IsDrawableForIndex(f, m_scale)); + } + + void add(FeatureType const & f) const + { + m_cont.push_back(make_pair(f, m_dbgString)); + } + +public: + AccumulatorBase(m2::RectD const & r, feature_cont_t & cont) + : m_cont(cont) + { + m_scale = scales::GetScaleLevel(r); + } + + void operator() (FeatureType const & f) const + { + if (is_drawable(f)) + add(f); + } +}; + +class IntersectCheck +{ + m2::RectD m_rect; + + m2::PointD m_prev; + bool m_isPrev, m_intersect; + +public: + IntersectCheck(m2::RectD const & r) + : m_rect(r), m_isPrev(false), m_intersect(false) + { + } + + void TestPoint(m2::PointD const & p) + { + m_intersect = m_rect.IsPointInside(p); + } + + void operator() (CoordPointT const & p) + { + if (m_intersect) return; + + m2::PointD pt(p.first, p.second); + if (m_isPrev) + { + m2::PointD d1 = m_prev; + m2::PointD d2 = pt; + m_intersect = m2::Intersect(m_rect, d1, d2); + } + else + m_isPrev = true; + + m_prev = pt; + } + + void operator() (m2::PointD const & p1, m2::PointD const & p2, m2::PointD const & p3) + { + if (m_intersect) return; + + m2::PointD arrP[] = { p1, p2, p3 }; + + // make right-oriented triangle + if (m2::robust::OrientedS(arrP[0], arrP[1], arrP[2]) < 0.0) + swap(arrP[1], arrP[2]); + + bool isInside = true; + m2::PointD const pt = m_rect.LeftTop(); + + for (size_t i = 0; i < 3; ++i) + { + // intersect edge with rect + m_intersect = m2::Intersect(m_rect, arrP[i], arrP[(i + 1) % 3]); + if (m_intersect) + break; + + if (isInside) + { + // or check if rect inside triangle (any point of rect) + double const s = m2::robust::OrientedS(arrP[i], arrP[(i + 1) % 3], pt); + isInside = (s >= 0.0); + } + } + + m_intersect = m_intersect || isInside; + } + + bool IsIntersect() const { return m_intersect; } +}; + +class AccumulatorEtalon : public AccumulatorBase +{ + typedef AccumulatorBase base_type; + + m2::RectD m_rect; + + bool is_intersect(FeatureType const & f) const + { + IntersectCheck check(m_rect); + + using namespace feature; + switch (f.GetFeatureType()) + { + case GEOM_POINT: check.TestPoint(f.GetCenter()); break; + case GEOM_LINE: f.ForEachPointRef(check, m_scale); break; + case GEOM_AREA: f.ForEachTriangleRef(check, m_scale); break; + default: + CHECK ( false, () ); + } + + return check.IsIntersect(); + } + +public: + AccumulatorEtalon(m2::RectD const & r, feature_cont_t & cont) + : base_type(r, cont), m_rect(r) + { + } + + void operator() (FeatureType const & f, uint64_t /*offset*/) const + { + if (is_drawable(f) && is_intersect(f)) + add(f); + } +}; + +// invoke this comparator to ensure that "sort" and "compare_sequence" use equal criterion +struct compare_strings +{ + int compare(string const & r1, string const & r2) const + { + if (r1 < r2) + return -1; + if (r2 < r1) + return 1; + return 0; + } + template <class T> + int compare(T const & r1, T const & r2) const + { + return compare(r1.second, r2.second); + } + template <class T> + bool operator() (T const & r1, T const & r2) const + { + return (compare(r1, r2) == -1); + } +}; + +template <class TAccumulator, class TSource> +void for_each_in_rect(TSource & src, feature_cont_t & cont, m2::RectD const & rect) +{ + cont.clear(); + TAccumulator acc(rect, cont); + src.ForEachFeature(rect, acc); + sort(cont.begin(), cont.end(), compare_strings()); +} + +class file_source_t +{ + ModelReaderPtr m_file; +public: + file_source_t(ModelReaderPtr const & file) : m_file(file) {} + + template <class ToDo> + void ForEachFeature(m2::RectD const & /*rect*/, ToDo toDo) + { + feature::ForEachFromDat(m_file, toDo); + } +}; + +/// "test" should contain all elements from etalon +template <class TCont, class TCompare> +bool compare_sequence(TCont const & etalon, TCont const & test, TCompare comp, size_t & errInd) +{ + if (test.size() < etalon.size()) + return false; + + typedef typename TCont::const_iterator iter_t; + + iter_t i1 = etalon.begin(); + iter_t i2 = test.begin(); + while (i1 != etalon.end() && i2 != test.end()) + { + switch (comp.compare(*i1, *i2)) + { + case 0: + ++i1; + ++i2; + break; + case -1: + { + errInd = distance(etalon.begin(), i1); + return false; + } + case 1: + ++i2; + break; + } + } + + return true; +} + +namespace +{ + class FindOffset + { + int m_level; + pair<FeatureType, string> const & m_test; + + public: + FindOffset(int level, pair<FeatureType, string> const & test) + : m_level(level), m_test(test) + {} + + void operator() (FeatureType const & f, uint64_t offset) + { + string const s = f.DebugString(m_level); + if (s == m_test.second) + { + cout << s << endl << "Feature offset = " << offset << endl; + + cout << "Feature classificator types:\n"; + + feature::TypesHolder types(f); + for (size_t i = 0; i < types.Size(); ++i) + cout << classif().GetFullObjectName(types[i]) << endl; + } + } + }; + + void RunTest(string const & file) + { + model::FeaturesFetcher src1; + src1.InitClassificator(); + src1.AddMap(file); + + vector<m2::RectD> rects; + rects.push_back(src1.GetWorldRect()); + + ModelReaderPtr reader = GetPlatform().GetReader(file); + + while (!rects.empty()) + { + m2::RectD r = rects.back(); + rects.pop_back(); + + feature_cont_t v1, v2; + for_each_in_rect<AccumulatorBase>(src1, v1, r); + + file_source_t src2(reader); + for_each_in_rect<AccumulatorEtalon>(src2, v2, r); + + int const level = scales::GetScaleLevel(r); + + size_t const emptyInd = size_t(-1); + size_t errInd = emptyInd; + if (!compare_sequence(v2, v1, compare_strings(), errInd)) + { + if (errInd != emptyInd) + src2.ForEachFeature(r, FindOffset(level, v2[errInd])); + + TEST(false, ("Failed for rect: ", r, "; Scale level = ", level, ". Etalon size = ", v2.size(), ". Index size = ", v1.size())); + } + + if (!v2.empty() && (level < scales::GetUpperScale())) + { + m2::RectD r1, r2; + r.DivideByGreaterSize(r1, r2); + rects.push_back(r1); + rects.push_back(r2); + } + } + } + + void RunTestForChoice(string const & fName) + { +// cout << "Run " << fName << "? (y/n)\n"; +// char c; +// cin >> c; +// if (c == 'y') + RunTest(fName + DATA_FILE_EXTENSION); + } +} + +UNIT_TEST(ForEach_QueryResults) +{ + RunTestForChoice("minsk-pass"); + //RunTestForChoice("london-center"); +} diff --git a/map/mwm_tests/mwm_tests.pro b/map/mwm_tests/mwm_tests.pro new file mode 100644 index 0000000000..5b4beb6c16 --- /dev/null +++ b/map/mwm_tests/mwm_tests.pro @@ -0,0 +1,25 @@ +# Map library tests. + +TARGET = mwm_tests +CONFIG += console +CONFIG -= app_bundle +TEMPLATE = app + +ROOT_DIR = ../.. +DEPENDENCIES = map gui search storage graphics indexer platform anim geometry coding base \ + freetype fribidi expat protobuf tomcrypt jansson zlib + +include($$ROOT_DIR/common.pri) + +QT *= core opengl + +win32* { + LIBS *= -lShell32 -lOpengl32 + win32-g++: LIBS *= -lpthread +} +macx*: LIBS *= "-framework Foundation" "-framework IOKit" + +SOURCES += \ + ../../testing/testingmain.cpp \ + mwm_foreach_test.cpp \ + multithread_mwm_test.cpp \ |