RTreeTest.cpp revision 4477c3c0e6eb064772aefe8737425cd1c2ce557f
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkRTree.h"
9#include "SkRandom.h"
10#include "SkTSort.h"
11#include "Test.h"
12
13static const size_t MIN_CHILDREN = 6;
14static const size_t MAX_CHILDREN = 11;
15
16static const int NUM_RECTS = 200;
17static const size_t NUM_ITERATIONS = 100;
18static const size_t NUM_QUERIES = 50;
19
20static SkRect random_rect(SkRandom& rand) {
21    SkRect rect = {0,0,0,0};
22    while (rect.isEmpty()) {
23        rect.fLeft   = rand.nextRangeF(0, 1000);
24        rect.fRight  = rand.nextRangeF(0, 1000);
25        rect.fTop    = rand.nextRangeF(0, 1000);
26        rect.fBottom = rand.nextRangeF(0, 1000);
27        rect.sort();
28    }
29    return rect;
30}
31
32static bool verify_query(SkRect query, SkRect rects[], SkTDArray<unsigned>& found) {
33    // TODO(mtklein): no need to do this after everything's SkRects
34    query.roundOut();
35
36    SkTDArray<unsigned> expected;
37
38    // manually intersect with every rectangle
39    for (int i = 0; i < NUM_RECTS; ++i) {
40        if (SkRect::Intersects(query, rects[i])) {
41            expected.push(i);
42        }
43    }
44
45    if (expected.count() != found.count()) {
46        return false;
47    }
48
49    if (0 == expected.count()) {
50        return true;
51    }
52
53    // skia:2834.  RTree doesn't always return results in order.
54    SkTQSort(expected.begin(), expected.end() -1);
55    SkTQSort(found.begin(), found.end() -1);
56    return found == expected;
57}
58
59static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, SkRect rects[],
60                       SkRTree& tree) {
61    for (size_t i = 0; i < NUM_QUERIES; ++i) {
62        SkTDArray<unsigned> hits;
63        SkRect query = random_rect(rand);
64        tree.search(query, &hits);
65        REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
66    }
67}
68
69static void rtree_test_main(SkRTree* rtree, skiatest::Reporter* reporter) {
70    SkASSERT(rtree);
71
72    int expectedDepthMin = -1;
73    int expectedDepthMax = -1;
74
75    int tmp = NUM_RECTS;
76    while (tmp > 0) {
77        tmp -= static_cast<int>(pow(static_cast<double>(MAX_CHILDREN),
78                                static_cast<double>(expectedDepthMin + 1)));
79        ++expectedDepthMin;
80    }
81
82    tmp = NUM_RECTS;
83    while (tmp > 0) {
84        tmp -= static_cast<int>(pow(static_cast<double>(MIN_CHILDREN),
85                                static_cast<double>(expectedDepthMax + 1)));
86        ++expectedDepthMax;
87    }
88
89    SkRandom rand;
90    SkAutoTMalloc<SkRect> rects(NUM_RECTS);
91    for (size_t i = 0; i < NUM_ITERATIONS; ++i) {
92        rtree->clear();
93        REPORTER_ASSERT(reporter, 0 == rtree->getCount());
94
95        for (int j = 0; j < NUM_RECTS; j++) {
96            rects[j] = random_rect(rand);
97        }
98
99        rtree->insert(&rects, NUM_RECTS);
100        SkASSERT(rects);  // SkRTree doesn't take ownership of rects.
101
102        run_queries(reporter, rand, rects, *rtree);
103        REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
104        REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
105                                  expectedDepthMax >= rtree->getDepth());
106    }
107}
108
109DEF_TEST(RTree, reporter) {
110    SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN);
111    SkAutoUnref au(rtree);
112    rtree_test_main(rtree, reporter);
113
114    // Rtree that orders input rectangles on deferred insert.
115    SkRTree* unsortedRtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN, 1, false);
116    SkAutoUnref auo(unsortedRtree);
117    rtree_test_main(unsortedRtree, reporter);
118}
119