blob: 6e0622c2fb242a4f77a9ffe06d4bbedb29dd2463 [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
mtklein533eb782014-08-27 10:39:42 -070020static SkRect random_rect(SkRandom& rand) {
21 SkRect rect = {0,0,0,0};
rileya@google.com1f45e932012-09-05 16:10:59 +000022 while (rect.isEmpty()) {
mtklein533eb782014-08-27 10:39:42 -070023 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);
rileya@google.com1f45e932012-09-05 16:10:59 +000027 rect.sort();
28 }
29 return rect;
30}
31
mtklein6bd41962014-10-02 07:41:56 -070032static void random_data_rects(SkRandom& rand, SkRect out[], int n) {
rileya@google.com1f45e932012-09-05 16:10:59 +000033 for (int i = 0; i < n; ++i) {
mtklein6bd41962014-10-02 07:41:56 -070034 out[i] = random_rect(rand);
rileya@google.com1f45e932012-09-05 16:10:59 +000035 }
36}
37
mtklein6bd41962014-10-02 07:41:56 -070038static bool verify_query(SkRect query, SkRect rects[], SkTDArray<unsigned>& found) {
mtklein533eb782014-08-27 10:39:42 -070039 // TODO(mtklein): no need to do this after everything's SkRects
40 query.roundOut();
41
mtklein6bd41962014-10-02 07:41:56 -070042 SkTDArray<unsigned> expected;
mtklein533eb782014-08-27 10:39:42 -070043
rileya@google.com1f45e932012-09-05 16:10:59 +000044 // manually intersect with every rectangle
bsalomon@google.com373ebc62012-09-26 13:08:56 +000045 for (int i = 0; i < NUM_RECTS; ++i) {
mtklein6bd41962014-10-02 07:41:56 -070046 if (SkRect::Intersects(query, rects[i])) {
47 expected.push(i);
rileya@google.com1f45e932012-09-05 16:10:59 +000048 }
49 }
50
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000051 if (expected.count() != found.count()) {
52 return false;
53 }
54
rileya@google.com1f45e932012-09-05 16:10:59 +000055 if (0 == expected.count()) {
56 return true;
57 }
58
mtklein6bd41962014-10-02 07:41:56 -070059 // skia:2834. RTree doesn't always return results in order.
60 SkTQSort(expected.begin(), expected.end() -1);
61 SkTQSort(found.begin(), found.end() -1);
rileya@google.com1f45e932012-09-05 16:10:59 +000062 return found == expected;
63}
64
mtklein6bd41962014-10-02 07:41:56 -070065static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, SkRect rects[],
rileya@google.com1f45e932012-09-05 16:10:59 +000066 SkRTree& tree) {
robertphillips@google.com178a2672012-09-13 13:25:30 +000067 for (size_t i = 0; i < NUM_QUERIES; ++i) {
mtklein6bd41962014-10-02 07:41:56 -070068 SkTDArray<unsigned> hits;
mtklein533eb782014-08-27 10:39:42 -070069 SkRect query = random_rect(rand);
rileya@google.com1f45e932012-09-05 16:10:59 +000070 tree.search(query, &hits);
71 REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
72 }
73}
74
sglez@google.com8c902122013-08-30 17:27:47 +000075static void rtree_test_main(SkRTree* rtree, skiatest::Reporter* reporter) {
mtklein6bd41962014-10-02 07:41:56 -070076 SkRect rects[NUM_RECTS];
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000077 SkRandom rand;
bsalomon49f085d2014-09-05 13:34:00 -070078 REPORTER_ASSERT(reporter, rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +000079
80 int expectedDepthMin = -1;
81 int expectedDepthMax = -1;
82
83 int tmp = NUM_RECTS;
84 while (tmp > 0) {
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000085 tmp -= static_cast<int>(pow(static_cast<double>(MAX_CHILDREN),
rileya@google.com1f45e932012-09-05 16:10:59 +000086 static_cast<double>(expectedDepthMin + 1)));
87 ++expectedDepthMin;
88 }
89
90 tmp = NUM_RECTS;
91 while (tmp > 0) {
92 tmp -= static_cast<int>(pow(static_cast<double>(MIN_CHILDREN),
93 static_cast<double>(expectedDepthMax + 1)));
94 ++expectedDepthMax;
95 }
96
robertphillips@google.com178a2672012-09-13 13:25:30 +000097 for (size_t i = 0; i < NUM_ITERATIONS; ++i) {
rileya@google.com1f45e932012-09-05 16:10:59 +000098 random_data_rects(rand, rects, NUM_RECTS);
99
100 // First try bulk-loaded inserts
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000101 for (int i = 0; i < NUM_RECTS; ++i) {
mtklein6bd41962014-10-02 07:41:56 -0700102 rtree->insert(i, rects[i], true);
rileya@google.com1f45e932012-09-05 16:10:59 +0000103 }
104 rtree->flushDeferredInserts();
sglez@google.com8c902122013-08-30 17:27:47 +0000105 run_queries(reporter, rand, rects, *rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +0000106 REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
107 REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
108 expectedDepthMax >= rtree->getDepth());
109 rtree->clear();
110 REPORTER_ASSERT(reporter, 0 == rtree->getCount());
111
112 // Then try immediate inserts
bsalomon@google.com373ebc62012-09-26 13:08:56 +0000113 for (int i = 0; i < NUM_RECTS; ++i) {
mtklein6bd41962014-10-02 07:41:56 -0700114 rtree->insert(i, rects[i]);
rileya@google.com1f45e932012-09-05 16:10:59 +0000115 }
sglez@google.com8c902122013-08-30 17:27:47 +0000116 run_queries(reporter, rand, rects, *rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +0000117 REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
118 REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
119 expectedDepthMax >= rtree->getDepth());
120 rtree->clear();
121 REPORTER_ASSERT(reporter, 0 == rtree->getCount());
122
123 // And for good measure try immediate inserts, but in reversed order
124 for (int i = NUM_RECTS - 1; i >= 0; --i) {
mtklein6bd41962014-10-02 07:41:56 -0700125 rtree->insert(i, rects[i]);
rileya@google.com1f45e932012-09-05 16:10:59 +0000126 }
sglez@google.com8c902122013-08-30 17:27:47 +0000127 run_queries(reporter, rand, rects, *rtree);
rileya@google.com1f45e932012-09-05 16:10:59 +0000128 REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
129 REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
130 expectedDepthMax >= rtree->getDepth());
131 rtree->clear();
132 REPORTER_ASSERT(reporter, 0 == rtree->getCount());
133 }
134}
135
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000136DEF_TEST(RTree, reporter) {
sglez@google.com8c902122013-08-30 17:27:47 +0000137 SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN);
138 SkAutoUnref au(rtree);
139 rtree_test_main(rtree, reporter);
140
141 // Rtree that orders input rectangles on deferred insert.
sglez@google.comffb71f22013-08-30 17:43:31 +0000142 SkRTree* unsortedRtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN, 1, false);
143 SkAutoUnref auo(unsortedRtree);
144 rtree_test_main(unsortedRtree, reporter);
sglez@google.com8c902122013-08-30 17:27:47 +0000145}