skia2/tests/RTreeTest.cpp
mtklein 6bd41969a0 BBHs: void* data -> unsigned data
Now that the old backend's not using BBHs, we can specialize them for
SkRecord's needs.  The only thing we really want to store is op index, which
should always be small enough to fit into an unsigned (unsigned also helps keep
it straight from other ints floating around).

This means we'll need half (32-bit) or a quarter (64-bit) the bytes in SkTileGrid,
because we don't have to store an extra int for ordering.

BUG=skia:2834

Review URL: https://codereview.chromium.org/617393004
2014-10-02 07:41:56 -07:00

146 lines
4.6 KiB
C++

/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkRTree.h"
#include "SkRandom.h"
#include "SkTSort.h"
#include "Test.h"
static const size_t MIN_CHILDREN = 6;
static const size_t MAX_CHILDREN = 11;
static const int NUM_RECTS = 200;
static const size_t NUM_ITERATIONS = 100;
static const size_t NUM_QUERIES = 50;
static SkRect random_rect(SkRandom& rand) {
SkRect rect = {0,0,0,0};
while (rect.isEmpty()) {
rect.fLeft = rand.nextRangeF(0, 1000);
rect.fRight = rand.nextRangeF(0, 1000);
rect.fTop = rand.nextRangeF(0, 1000);
rect.fBottom = rand.nextRangeF(0, 1000);
rect.sort();
}
return rect;
}
static void random_data_rects(SkRandom& rand, SkRect out[], int n) {
for (int i = 0; i < n; ++i) {
out[i] = random_rect(rand);
}
}
static bool verify_query(SkRect query, SkRect rects[], SkTDArray<unsigned>& found) {
// TODO(mtklein): no need to do this after everything's SkRects
query.roundOut();
SkTDArray<unsigned> expected;
// manually intersect with every rectangle
for (int i = 0; i < NUM_RECTS; ++i) {
if (SkRect::Intersects(query, rects[i])) {
expected.push(i);
}
}
if (expected.count() != found.count()) {
return false;
}
if (0 == expected.count()) {
return true;
}
// skia:2834. RTree doesn't always return results in order.
SkTQSort(expected.begin(), expected.end() -1);
SkTQSort(found.begin(), found.end() -1);
return found == expected;
}
static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, SkRect rects[],
SkRTree& tree) {
for (size_t i = 0; i < NUM_QUERIES; ++i) {
SkTDArray<unsigned> hits;
SkRect query = random_rect(rand);
tree.search(query, &hits);
REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
}
}
static void rtree_test_main(SkRTree* rtree, skiatest::Reporter* reporter) {
SkRect rects[NUM_RECTS];
SkRandom rand;
REPORTER_ASSERT(reporter, rtree);
int expectedDepthMin = -1;
int expectedDepthMax = -1;
int tmp = NUM_RECTS;
while (tmp > 0) {
tmp -= static_cast<int>(pow(static_cast<double>(MAX_CHILDREN),
static_cast<double>(expectedDepthMin + 1)));
++expectedDepthMin;
}
tmp = NUM_RECTS;
while (tmp > 0) {
tmp -= static_cast<int>(pow(static_cast<double>(MIN_CHILDREN),
static_cast<double>(expectedDepthMax + 1)));
++expectedDepthMax;
}
for (size_t i = 0; i < NUM_ITERATIONS; ++i) {
random_data_rects(rand, rects, NUM_RECTS);
// First try bulk-loaded inserts
for (int i = 0; i < NUM_RECTS; ++i) {
rtree->insert(i, rects[i], true);
}
rtree->flushDeferredInserts();
run_queries(reporter, rand, rects, *rtree);
REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
expectedDepthMax >= rtree->getDepth());
rtree->clear();
REPORTER_ASSERT(reporter, 0 == rtree->getCount());
// Then try immediate inserts
for (int i = 0; i < NUM_RECTS; ++i) {
rtree->insert(i, rects[i]);
}
run_queries(reporter, rand, rects, *rtree);
REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
expectedDepthMax >= rtree->getDepth());
rtree->clear();
REPORTER_ASSERT(reporter, 0 == rtree->getCount());
// And for good measure try immediate inserts, but in reversed order
for (int i = NUM_RECTS - 1; i >= 0; --i) {
rtree->insert(i, rects[i]);
}
run_queries(reporter, rand, rects, *rtree);
REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount());
REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() &&
expectedDepthMax >= rtree->getDepth());
rtree->clear();
REPORTER_ASSERT(reporter, 0 == rtree->getCount());
}
}
DEF_TEST(RTree, reporter) {
SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN);
SkAutoUnref au(rtree);
rtree_test_main(rtree, reporter);
// Rtree that orders input rectangles on deferred insert.
SkRTree* unsortedRtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN, 1, false);
SkAutoUnref auo(unsortedRtree);
rtree_test_main(unsortedRtree, reporter);
}