1
// Copyright 2005 Google Inc. All Rights Reserved.
3
#include "s2cellunion.h"
15
#include "base/integral_types.h"
16
#include "base/logging.h"
17
#include "testing/base/public/gunit.h"
21
#include "s2testing.h"
22
#include "s2regioncoverer.h"
24
TEST(S2CellUnion, Basic) {
28
EXPECT_EQ(0, empty.num_cells());
30
S2CellId face1_id = S2CellId::FromFacePosLevel(1, 0, 0);
31
S2CellUnion face1_union;
32
ids.push_back(face1_id);
33
face1_union.Init(ids);
34
EXPECT_EQ(1, face1_union.num_cells());
35
EXPECT_EQ(face1_id, face1_union.cell_id(0));
37
S2CellId face2_id = S2CellId::FromFacePosLevel(2, 0, 0);
38
S2CellUnion face2_union;
39
vector<uint64> cell_ids;
40
cell_ids.push_back(face2_id.id());
41
face2_union.Init(cell_ids);
42
EXPECT_EQ(1, face2_union.num_cells());
43
EXPECT_EQ(face2_id, face2_union.cell_id(0));
45
S2Cell face1_cell(face1_id);
46
S2Cell face2_cell(face2_id);
47
EXPECT_TRUE(face1_union.Contains(face1_cell));
48
EXPECT_TRUE(!face1_union.Contains(face2_cell));
51
static S2Testing::Random& rnd = S2Testing::rnd;
53
static void AddCells(S2CellId const& id, bool selected,
54
vector<S2CellId> *input, vector<S2CellId> *expected) {
55
// Decides whether to add "id" and/or some of its descendants to the
56
// test case. If "selected" is true, then the region covered by "id"
57
// *must* be added to the test case (either by adding "id" itself, or
58
// some combination of its descendants, or both). If cell ids are to
59
// the test case "input", then the corresponding expected result after
60
// simplification is added to "expected".
62
if (id == S2CellId::None()) {
63
// Initial call: decide whether to add cell(s) from each face.
64
for (int face = 0; face < 6; ++face) {
65
AddCells(S2CellId::FromFacePosLevel(face, 0, 0), false, input, expected);
70
// The rnd.OneIn() call below ensures that the parent of a leaf cell
71
// will always be selected (if we make it that far down the hierarchy).
76
// The following code ensures that the probability of selecting a cell
77
// at each level is approximately the same, i.e. we test normalization
78
// of cells at all levels.
79
if (!selected && rnd.OneIn(S2CellId::kMaxLevel - id.level())) {
80
// Once a cell has been selected, the expected output is predetermined.
81
// We then make sure that cells are selected that will normalize to
82
// the desired output.
83
expected->push_back(id);
87
// With the rnd.OneIn() constants below, this function adds an average
88
// of 5/6 * (kMaxLevel - level) cells to "input" where "level" is the
89
// level at which the cell was first selected (level 15 on average).
90
// Therefore the average number of input cells in a test case is about
91
// (5/6 * 15 * 6) = 75. The average number of output cells is about 6.
93
// If a cell is selected, we add it to "input" with probability 5/6.
95
if (selected && !rnd.OneIn(6)) {
100
S2CellId child = id.child_begin();
101
for (int pos = 0; pos < 4; ++pos, child = child.next()) {
102
// If the cell is selected, on average we recurse on 4/12 = 1/3 child.
103
// This intentionally may result in a cell and some of its children
104
// being included in the test case.
106
// If the cell is not selected, on average we recurse on one child.
107
// We also make sure that we do not recurse on all 4 children, since
108
// then we might include all 4 children in the input case by accident
109
// (in which case the expected output would not be correct).
110
if (rnd.OneIn(selected ? 12 : 4) && num_children < 3) {
111
AddCells(child, selected, input, expected);
114
// If this cell was selected but the cell itself was not added, we
115
// must ensure that all 4 children (or some combination of their
116
// descendants) are added.
117
if (selected && !added) AddCells(child, selected, input, expected);
121
TEST(S2CellUnion, Normalize) {
122
// Try a bunch of random test cases, and keep track of average
123
// statistics for normalization (to see if they agree with the
125
S2CellUnion cellunion;
126
double in_sum = 0, out_sum = 0;
127
static int const kIters = 2000;
128
for (int i = 0; i < kIters; ++i) {
129
vector<S2CellId> input, expected;
130
AddCells(S2CellId::None(), false, &input, &expected);
131
in_sum += input.size();
132
out_sum += expected.size();
133
cellunion.Init(input);
134
EXPECT_EQ(expected.size(), cellunion.num_cells());
135
for (int i = 0; i < expected.size(); ++i) {
136
EXPECT_EQ(expected[i], cellunion.cell_id(i));
139
// Test GetCapBound().
140
S2Cap cap = cellunion.GetCapBound();
141
for (int i = 0; i < cellunion.num_cells(); ++i) {
142
EXPECT_TRUE(cap.Contains(S2Cell(cellunion.cell_id(i))));
145
// Test Contains(S2CellId) and Intersects(S2CellId).
146
for (int j = 0; j < input.size(); ++j) {
147
EXPECT_TRUE(cellunion.Contains(input[j]));
148
EXPECT_TRUE(cellunion.Contains(input[j].ToPoint()));
149
EXPECT_TRUE(cellunion.VirtualContainsPoint(input[j].ToPoint()));
150
EXPECT_TRUE(cellunion.Intersects(input[j]));
151
if (!input[j].is_face()) {
152
EXPECT_TRUE(cellunion.Intersects(input[j].parent()));
153
if (input[j].level() > 1) {
154
EXPECT_TRUE(cellunion.Intersects(input[j].parent().parent()));
155
EXPECT_TRUE(cellunion.Intersects(input[j].parent(0)));
158
if (!input[j].is_leaf()) {
159
EXPECT_TRUE(cellunion.Contains(input[j].child_begin()));
160
EXPECT_TRUE(cellunion.Intersects(input[j].child_begin()));
161
EXPECT_TRUE(cellunion.Contains(input[j].child_end().prev()));
162
EXPECT_TRUE(cellunion.Intersects(input[j].child_end().prev()));
163
EXPECT_TRUE(cellunion.Contains(
164
input[j].child_begin(S2CellId::kMaxLevel)));
165
EXPECT_TRUE(cellunion.Intersects(
166
input[j].child_begin(S2CellId::kMaxLevel)));
169
for (int j = 0; j < expected.size(); ++j) {
170
if (!expected[j].is_face()) {
171
EXPECT_TRUE(!cellunion.Contains(expected[j].parent()));
172
EXPECT_TRUE(!cellunion.Contains(expected[j].parent(0)));
176
// Test Contains(S2CellUnion*), Intersects(S2CellUnion*),
177
// GetUnion(), GetIntersection(), and GetDifference().
178
vector<S2CellId> x, y, x_or_y, x_and_y;
179
for (int j = 0; j < input.size(); ++j) {
180
bool in_x = rnd.OneIn(2);
181
bool in_y = rnd.OneIn(2);
182
if (in_x) x.push_back(input[j]);
183
if (in_y) y.push_back(input[j]);
184
if (in_x || in_y) x_or_y.push_back(input[j]);
186
S2CellUnion xcells, ycells, x_or_y_expected, x_and_y_expected;
189
x_or_y_expected.Init(x_or_y);
191
S2CellUnion x_or_y_cells;
192
x_or_y_cells.GetUnion(&xcells, &ycells);
193
EXPECT_TRUE(x_or_y_cells == x_or_y_expected);
195
// Compute the intersection of "x" with each cell of "y",
196
// check that this intersection is correct, and append the
197
// results to x_and_y_expected.
198
for (int j = 0; j < ycells.num_cells(); ++j) {
199
S2CellId yid = ycells.cell_id(j);
201
u.GetIntersection(&xcells, yid);
202
for (int k = 0; k < xcells.num_cells(); ++k) {
203
S2CellId xid = xcells.cell_id(k);
204
if (xid.contains(yid)) {
205
EXPECT_TRUE(u.num_cells() == 1 && u.cell_id(0) == yid);
206
} else if (yid.contains(xid)) {
207
EXPECT_TRUE(u.Contains(xid));
210
for (int k = 0; k < u.num_cells(); ++k) {
211
EXPECT_TRUE(xcells.Contains(u.cell_id(k)));
212
EXPECT_TRUE(yid.contains(u.cell_id(k)));
214
x_and_y.insert(x_and_y.end(), u.cell_ids().begin(), u.cell_ids().end());
216
x_and_y_expected.Init(x_and_y);
218
S2CellUnion x_and_y_cells;
219
x_and_y_cells.GetIntersection(&xcells, &ycells);
220
EXPECT_TRUE(x_and_y_cells == x_and_y_expected);
222
S2CellUnion x_minus_y_cells, y_minus_x_cells;
223
x_minus_y_cells.GetDifference(&xcells, &ycells);
224
y_minus_x_cells.GetDifference(&ycells, &xcells);
225
EXPECT_TRUE(xcells.Contains(&x_minus_y_cells));
226
EXPECT_TRUE(!x_minus_y_cells.Intersects(&ycells));
227
EXPECT_TRUE(ycells.Contains(&y_minus_x_cells));
228
EXPECT_TRUE(!y_minus_x_cells.Intersects(&xcells));
229
EXPECT_TRUE(!x_minus_y_cells.Intersects(&y_minus_x_cells));
230
S2CellUnion diff_union;
231
diff_union.GetUnion(&x_minus_y_cells, &y_minus_x_cells);
232
S2CellUnion diff_intersection_union;
233
diff_intersection_union.GetUnion(&diff_union, &x_and_y_cells);
234
EXPECT_TRUE(diff_intersection_union == x_or_y_cells);
236
vector<S2CellId> test, dummy;
237
AddCells(S2CellId::None(), false, &test, &dummy);
238
for (int j = 0; j < test.size(); ++j) {
239
bool contains = false, intersects = false;
240
for (int k = 0; k < expected.size(); ++k) {
241
if (expected[k].contains(test[j])) contains = true;
242
if (expected[k].intersects(test[j])) intersects = true;
244
EXPECT_EQ(contains, cellunion.Contains(test[j]));
245
EXPECT_EQ(intersects, cellunion.Intersects(test[j]));
249
printf("avg in %.2f, avg out %.2f\n", in_sum / kIters, out_sum / kIters);
252
static double GetMaxAngle(S2CellUnion const& covering, S2Point const& axis) {
253
double max_angle = 0;
254
for (int i = 0; i < covering.num_cells(); ++i) {
255
S2Cell cell(covering.cell_id(i));
256
S2Cap cell_cap = cell.GetCapBound();
257
double angle = axis.Angle(cell_cap.axis()) + cell_cap.angle().radians();
258
max_angle = max(max_angle, angle);
263
TEST(S2CellUnion, Expand) {
264
// This test generates coverings for caps of random sizes, and expands
265
// the coverings by a random radius, and then make sure that the new
266
// covering covers the expanded cap. It also makes sure that the
267
// new covering is not too much larger than expected.
269
S2RegionCoverer coverer;
270
for (int i = 0; i < 1000; ++i) {
271
S2Cap cap = S2Testing::GetRandomCap(
272
S2Cell::AverageArea(S2CellId::kMaxLevel), 4 * M_PI);
274
// Expand the cap by a random factor whose log is uniformly distributed
275
// between 0 and log(1e2).
276
S2Cap expanded_cap = S2Cap::FromAxisHeight(
277
cap.axis(), min(2.0, pow(1e2, rnd.RandDouble()) * cap.height()));
279
double radius = expanded_cap.angle().radians() - cap.angle().radians();
280
int max_level_diff = rnd.Uniform(8);
282
S2CellUnion covering;
283
coverer.set_max_cells(1 + rnd.Skewed(10));
284
coverer.GetCellUnion(cap, &covering);
285
S2Testing::CheckCovering(cap, covering, true);
287
double max_angle = GetMaxAngle(covering, cap.axis());
288
int min_level = S2CellId::kMaxLevel;
289
for (int i = 0; i < covering.num_cells(); ++i) {
290
min_level = min(min_level, covering.cell_id(i).level());
292
covering.Expand(S1Angle::Radians(radius), max_level_diff);
293
S2Testing::CheckCovering(expanded_cap, covering, false);
295
int expand_level = min(min_level + max_level_diff,
296
S2::kMinWidth.GetMaxLevel(radius));
297
double expanded_max_angle = GetMaxAngle(covering, cap.axis());
299
// If the covering includes a tiny cell along the boundary, in theory the
300
// maximum angle of the covering from the cap axis can increase by up to
301
// twice the maximum length of a cell diagonal. We allow for an increase
302
// of slightly more than this because cell bounding caps are not exact.
303
EXPECT_LE(expanded_max_angle - max_angle,
304
2.02 * S2::kMaxDiag.GetValue(expand_level));
305
// TODO(user): This fails for some random seeds,
306
// e.g. initialize the random seed to 3 in s2testing.cc. This
307
// means the assumption above is incorrect and needs to be
312
static void TestInitFromRange(S2CellId const& min_id,
313
S2CellId const& max_id) {
314
S2CellUnion cell_union;
315
cell_union.InitFromRange(min_id, max_id);
316
vector<S2CellId> const& cell_ids = cell_union.cell_ids();
318
EXPECT_GT(cell_ids.size(), 0);
319
EXPECT_EQ(min_id, cell_ids.front().range_min());
320
EXPECT_EQ(max_id, cell_ids.back().range_max());
321
for (int i = 1; i < cell_ids.size(); ++i) {
322
EXPECT_EQ(cell_ids[i].range_min(), cell_ids[i-1].range_max().next());
324
EXPECT_FALSE(cell_union.Normalize());
327
TEST(S2CellUnion, InitFromRange) {
328
// Check the very first leaf cell and face cell.
329
S2CellId face1_id = S2CellId::FromFacePosLevel(0, 0, 0);
330
TestInitFromRange(face1_id.range_min(), face1_id.range_min());
331
TestInitFromRange(face1_id.range_min(), face1_id.range_max());
333
// Check the very last leaf cell and face cell.
334
S2CellId face5_id = S2CellId::FromFacePosLevel(5, 0, 0);
335
TestInitFromRange(face1_id.range_min(), face1_id.range_max());
336
TestInitFromRange(face1_id.range_max(), face1_id.range_max());
338
// Check random ranges of leaf cells.
339
for (int i = 0; i < 100; ++i) {
340
S2CellId x = S2Testing::GetRandomCellId(S2CellId::kMaxLevel);
341
S2CellId y = S2Testing::GetRandomCellId(S2CellId::kMaxLevel);
342
if (x > y) swap(x, y);
343
TestInitFromRange(x, y);
347
TEST(S2CellUnion, Empty) {
348
S2CellUnion empty_cell_union;
349
S2CellId face1_id = S2CellId::FromFacePosLevel(1, 0, 0);
352
empty_cell_union.Normalize();
353
EXPECT_EQ(0, empty_cell_union.num_cells());
356
vector<S2CellId> output;
357
empty_cell_union.Denormalize(0, 2, &output);
358
EXPECT_EQ(0, empty_cell_union.num_cells());
361
empty_cell_union.Pack();
364
EXPECT_FALSE(empty_cell_union.Contains(face1_id));
365
EXPECT_TRUE(empty_cell_union.Contains(&empty_cell_union));
368
EXPECT_FALSE(empty_cell_union.Intersects(face1_id));
369
EXPECT_FALSE(empty_cell_union.Intersects(&empty_cell_union));
372
S2CellUnion cell_union;
373
cell_union.GetUnion(&empty_cell_union, &empty_cell_union);
374
EXPECT_EQ(0, cell_union.num_cells());
376
// GetIntersection(...)
377
S2CellUnion intersection;
378
intersection.GetIntersection(&empty_cell_union, face1_id);
379
EXPECT_EQ(0, intersection.num_cells());
380
intersection.GetIntersection(&empty_cell_union, &empty_cell_union);
381
EXPECT_EQ(0, intersection.num_cells());
383
// GetDifference(...)
384
S2CellUnion difference;
385
difference.GetDifference(&empty_cell_union, &empty_cell_union);
386
EXPECT_EQ(0, difference.num_cells());
389
empty_cell_union.Expand(S1Angle::Radians(1), 20);
390
EXPECT_EQ(0, empty_cell_union.num_cells());
391
empty_cell_union.Expand(10);
392
EXPECT_EQ(0, empty_cell_union.num_cells());
395
TEST(S2CellUnion, Detach) {
396
S2CellId face1_id = S2CellId::FromFacePosLevel(1, 0, 0);
397
S2CellUnion face1_union;
398
vector<S2CellId> ids;
399
ids.push_back(face1_id);
400
face1_union.Init(ids);
401
ASSERT_EQ(1, face1_union.num_cells());
402
EXPECT_EQ(face1_id, face1_union.cell_id(0));
404
vector<S2CellId> retrieve;
405
retrieve.push_back(S2CellId::Sentinel());
406
face1_union.Detach(&retrieve);
407
ASSERT_EQ(1, retrieve.size());
408
EXPECT_EQ(face1_id, retrieve[0]);
409
EXPECT_EQ(0, face1_union.num_cells());
412
TEST(S2CellUnion, LeafCellsCovered) {
413
S2CellUnion cell_union;
416
EXPECT_EQ(0, cell_union.LeafCellsCovered());
419
vector<S2CellId> ids;
420
ids.push_back(S2CellId::FromFacePosLevel(
421
0, (1ULL << ((S2CellId::kMaxLevel << 1) - 1)), S2CellId::kMaxLevel));
422
// One leaf on face 0.
423
cell_union.Init(ids);
424
EXPECT_EQ(1ULL, cell_union.LeafCellsCovered());
427
ids.push_back(S2CellId::FromFacePosLevel(0, 0, 0));
428
cell_union.Init(ids);
429
EXPECT_EQ(1ULL << 60, cell_union.LeafCellsCovered());
431
cell_union.Expand(0);
432
EXPECT_EQ(5ULL << 60, cell_union.LeafCellsCovered());
434
cell_union.Expand(0);
435
EXPECT_EQ(6ULL << 60, cell_union.LeafCellsCovered());
437
// Add some disjoint cells.
438
ids.push_back(S2CellId::FromFacePosLevel(1, 0, 1));
439
ids.push_back(S2CellId::FromFacePosLevel(2, 0, 2));
440
ids.push_back(S2CellId::FromFacePosLevel(2, (1ULL << 60), 2));
441
ids.push_back(S2CellId::FromFacePosLevel(3, 0, 14));
442
ids.push_back(S2CellId::FromFacePosLevel(4, (1ULL << 60), 15));
443
ids.push_back(S2CellId::FromFacePosLevel(4, 0, 27));
444
ids.push_back(S2CellId::FromFacePosLevel(5, 0, 30));
445
cell_union.Init(ids);
446
uint64 expected = 1ULL + (1ULL << 6) + (1ULL << 30) + (1ULL << 32) +
447
(2ULL << 56) + (1ULL << 58) + (1ULL << 60);
448
EXPECT_EQ(expected, cell_union.LeafCellsCovered());