blob: ae8c005170e5f1c61565122b5377d59f843db755 [file] [log] [blame]
rileya@google.com1f45e932012-09-05 16:10:59 +00001/*
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
rileya@google.com1f45e932012-09-05 16:10:59 +00008#include "SkRTree.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +00009#include "SkRandom.h"
rileya@google.com1f45e932012-09-05 16:10:59 +000010#include "SkTSort.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "Test.h"
rileya@google.com1f45e932012-09-05 16:10:59 +000012
13static const size_t MIN_CHILDREN = 6;
14static const size_t MAX_CHILDREN = 11;
15
bsalomon@google.com373ebc62012-09-26 13:08:56 +000016static const int NUM_RECTS = 200;
rileya@google.com1f45e932012-09-05 16:10:59 +000017static const size_t NUM_ITERATIONS = 100;
18static const size_t NUM_QUERIES = 50;
19
20struct DataRect {
21 SkIRect rect;
22 void* data;
23};
24
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000025static SkIRect random_rect(SkRandom& rand) {
rileya@google.com1f45e932012-09-05 16:10:59 +000026 SkIRect rect = {0,0,0,0};
27 while (rect.isEmpty()) {
28 rect.fLeft = rand.nextS() % 1000;
29 rect.fRight = rand.nextS() % 1000;
30 rect.fTop = rand.nextS() % 1000;
31 rect.fBottom = rand.nextS() % 1000;
32 rect.sort();
33 }
34 return rect;
35}
36
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000037static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
rileya@google.com1f45e932012-09-05 16:10:59 +000038 for (int i = 0; i < n; ++i) {
39 out[i].rect = random_rect(rand);
40 out[i].data = reinterpret_cast<void*>(i);
41 }
42}
43
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000044static bool verify_query(SkIRect query, DataRect rects[],
rileya@google.com1f45e932012-09-05 16:10:59 +000045 SkTDArray<void*>& found) {
46 SkTDArray<void*> expected;
47 // manually intersect with every rectangle
bsalomon@google.com373ebc62012-09-26 13:08:56 +000048 for (int i = 0; i < NUM_RECTS; ++i) {
rileya@google.com1f45e932012-09-05 16:10:59 +000049 if (SkIRect::IntersectsNoEmptyCheck(query, rects[i].rect)) {
50 expected.push(rects[i].data);
51 }
52 }
53
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000054 if (expected.count() != found.count()) {
55 return false;
56 }
57
rileya@google.com1f45e932012-09-05 16:10:59 +000058 if (0 == expected.count()) {
59 return true;
60 }
61
62 // Just cast to long since sorting by the value of the void*'s was being problematic...
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000063 SkTQSort(reinterpret_cast<long*>(expected.begin()),
rileya@google.com1f45e932012-09-05 16:10:59 +000064 reinterpret_cast<long*>(expected.end() - 1));
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000065 SkTQSort(reinterpret_cast<long*>(found.begin()),
rileya@google.com1f45e932012-09-05 16:10:59 +000066 reinterpret_cast<long*>(found.end() - 1));
67 return found == expected;
68}
69
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000070static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect rects[],
rileya@google.com1f45e932012-09-05 16:10:59 +000071 SkRTree& tree) {
robertphillips@google.com178a2672012-09-13 13:25:30 +000072 for (size_t i = 0; i < NUM_QUERIES; ++i) {
rileya@google.com1f45e932012-09-05 16:10:59 +000073 SkTDArray<void*> hits;
74 SkIRect query = random_rect(rand);
75 tree.search(query, &hits);
76 REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
77 }
78}
79
sglez@google.com8c902122013-08-30 17:27:47 +000080static void rtree_test_main(SkRTree* rtree, skiatest::Reporter* reporter) {
rileya@google.com1f45e932012-09-05 16:10:59 +000081 DataRect rects[NUM_RECTS];
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000082 SkRandom rand;
rileya@google.com1f45e932012-09-05 16:10:59 +000083 REPORTER_ASSERT(reporter, NULL != rtree);
84
85 int expectedDepthMin = -1;
86 int expectedDepthMax = -1;
87
88 int tmp = NUM_RECTS;
89 while (tmp > 0) {
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000090 tmp -= static_cast<int>(pow(static_cast<double>(MAX_CHILDREN),
rileya@google.com1f45e932012-09-05 16:10:59 +000091 static_cast<double>(expectedDepthMin + 1)));
92 ++expectedDepthMin;
93 }
94
95 tmp = NUM_RECTS;
96 while (tmp > 0) {
97 tmp -= static_cast<int>(pow(static_cast<double>(MIN_CHILDREN),
98 static_cast<double>(expectedDepthMax + 1)));
99 ++expectedDepthMax;
100 }
101
robertphillips@google.com178a2672012-09-13 13:25:30 +0000102 for (size_t i = 0; i < NUM_ITERATIONS; ++i) {
rileya@google.com1f45e932012-09-05 16:10:59 +0000103 random_data_rects(rand, rects, NUM_RECTS);
104
105 // First try bulk-loaded inserts
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000106 for (int i = 0; i < NUM_RECTS; ++i) {
rileya@google.com1f45e932012-09-05 16:10:59 +0000107 rtree->insert(rects[i].data, rects[i].rect, true);
108 }
109 rtree->flushDeferredInserts();
sglez@google.com8c902122013-08-30 17:27:47 +0000110 run_queries(reporter, rand, rects, *rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +0000111 REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
112 REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
113 expectedDepthMax >= rtree->getDepth());
114 rtree->clear();
115 REPORTER_ASSERT(reporter, 0 == rtree->getCount());
116
117 // Then try immediate inserts
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000118 for (int i = 0; i < NUM_RECTS; ++i) {
rileya@google.com1f45e932012-09-05 16:10:59 +0000119 rtree->insert(rects[i].data, rects[i].rect);
120 }
sglez@google.com8c902122013-08-30 17:27:47 +0000121 run_queries(reporter, rand, rects, *rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +0000122 REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
123 REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
124 expectedDepthMax >= rtree->getDepth());
125 rtree->clear();
126 REPORTER_ASSERT(reporter, 0 == rtree->getCount());
127
128 // And for good measure try immediate inserts, but in reversed order
129 for (int i = NUM_RECTS - 1; i >= 0; --i) {
130 rtree->insert(rects[i].data, rects[i].rect);
131 }
sglez@google.com8c902122013-08-30 17:27:47 +0000132 run_queries(reporter, rand, rects, *rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +0000133 REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
134 REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
135 expectedDepthMax >= rtree->getDepth());
136 rtree->clear();
137 REPORTER_ASSERT(reporter, 0 == rtree->getCount());
138 }
139}
140
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000141DEF_TEST(RTree, reporter) {
sglez@google.com8c902122013-08-30 17:27:47 +0000142 SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN);
143 SkAutoUnref au(rtree);
144 rtree_test_main(rtree, reporter);
145
146 // Rtree that orders input rectangles on deferred insert.
sglez@google.comffb71f22013-08-30 17:43:31 +0000147 SkRTree* unsortedRtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN, 1, false);
148 SkAutoUnref auo(unsortedRtree);
149 rtree_test_main(unsortedRtree, reporter);
sglez@google.com8c902122013-08-30 17:27:47 +0000150}