| 1 | // Copyright 2005 Google Inc. All Rights Reserved. |
| 2 | |
| 3 | #include "s2cellunion.h" |
| 4 | |
| 5 | #include <algorithm> |
| 6 | using std::min; |
| 7 | using std::max; |
| 8 | using std::swap; |
| 9 | using std::reverse; |
| 10 | |
| 11 | #include <vector> |
| 12 | using std::vector; |
| 13 | |
| 14 | |
| 15 | #include "base/integral_types.h" |
| 16 | #include "base/logging.h" |
| 17 | #include "s2.h" |
| 18 | #include "s2cap.h" |
| 19 | #include "s2cell.h" |
| 20 | #include "s2cellid.h" |
| 21 | #include "s2latlngrect.h" |
| 22 | |
| 23 | // Returns true if the vector of cell_ids is sorted. Used only in |
| 24 | // DCHECKs. |
| 25 | extern bool IsSorted(vector<S2CellId> const& cell_ids) { |
| 26 | for (int i = 0; i + 1 < cell_ids.size(); ++i) { |
| 27 | if (cell_ids[i + 1] < cell_ids[i]) { |
| 28 | return false; |
| 29 | } |
| 30 | } |
| 31 | return true; |
| 32 | } |
| 33 | |
| 34 | void S2CellUnion::Init(vector<S2CellId> const& cell_ids) { |
| 35 | InitRaw(cell_ids); |
| 36 | Normalize(); |
| 37 | } |
| 38 | |
| 39 | void S2CellUnion::Init(vector<uint64> const& cell_ids) { |
| 40 | InitRaw(cell_ids); |
| 41 | Normalize(); |
| 42 | } |
| 43 | |
| 44 | void S2CellUnion::InitSwap(vector<S2CellId>* cell_ids) { |
| 45 | InitRawSwap(cell_ids); |
| 46 | Normalize(); |
| 47 | } |
| 48 | |
| 49 | void S2CellUnion::InitRaw(vector<S2CellId> const& cell_ids) { |
| 50 | cell_ids_ = cell_ids; |
| 51 | } |
| 52 | |
| 53 | void S2CellUnion::InitRaw(vector<uint64> const& cell_ids) { |
| 54 | cell_ids_.resize(cell_ids.size()); |
| 55 | for (int i = 0; i < num_cells(); ++i) { |
| 56 | cell_ids_[i] = S2CellId(cell_ids[i]); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | void S2CellUnion::InitRawSwap(vector<S2CellId>* cell_ids) { |
| 61 | cell_ids_.swap(*cell_ids); |
| 62 | cell_ids->clear(); |
| 63 | } |
| 64 | |
| 65 | void S2CellUnion::Detach(vector<S2CellId>* cell_ids) { |
| 66 | cell_ids_.swap(*cell_ids); |
| 67 | cell_ids_.clear(); |
| 68 | } |
| 69 | |
| 70 | void S2CellUnion::Pack(int excess) { |
| 71 | if (cell_ids_.capacity() - cell_ids_.size() > excess) { |
| 72 | vector<S2CellId> packed = cell_ids_; |
| 73 | cell_ids_.swap(packed); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | S2CellUnion* S2CellUnion::Clone() const { |
| 78 | S2CellUnion* copy = new S2CellUnion; |
| 79 | copy->InitRaw(cell_ids_); |
| 80 | return copy; |
| 81 | } |
| 82 | |
| 83 | bool S2CellUnion::Normalize() { |
| 84 | // Optimize the representation by looking for cases where all subcells |
| 85 | // of a parent cell are present. |
| 86 | |
| 87 | vector<S2CellId> output; |
| 88 | output.reserve(cell_ids_.size()); |
| 89 | sort(cell_ids_.begin(), cell_ids_.end()); |
| 90 | |
| 91 | for (int i = 0; i < num_cells(); ++i) { |
| 92 | S2CellId id = cell_id(i); |
| 93 | |
| 94 | // Check whether this cell is contained by the previous cell. |
| 95 | if (!output.empty() && output.back().contains(id)) continue; |
| 96 | |
| 97 | // Discard any previous cells contained by this cell. |
| 98 | while (!output.empty() && id.contains(output.back())) { |
| 99 | output.pop_back(); |
| 100 | } |
| 101 | |
| 102 | // Check whether the last 3 elements of "output" plus "id" can be |
| 103 | // collapsed into a single parent cell. |
| 104 | while (output.size() >= 3) { |
| 105 | // A necessary (but not sufficient) condition is that the XOR of the |
| 106 | // four cells must be zero. This is also very fast to test. |
| 107 | if ((output.end()[-3].id() ^ output.end()[-2].id() ^ output.back().id()) |
| 108 | != id.id()) |
| 109 | break; |
| 110 | |
| 111 | // Now we do a slightly more expensive but exact test. First, compute a |
| 112 | // mask that blocks out the two bits that encode the child position of |
| 113 | // "id" with respect to its parent, then check that the other three |
| 114 | // children all agree with "mask. |
| 115 | uint64 mask = id.lsb() << 1; |
| 116 | mask = ~(mask + (mask << 1)); |
| 117 | uint64 id_masked = (id.id() & mask); |
| 118 | if ((output.end()[-3].id() & mask) != id_masked || |
| 119 | (output.end()[-2].id() & mask) != id_masked || |
| 120 | (output.end()[-1].id() & mask) != id_masked || |
| 121 | id.is_face()) |
| 122 | break; |
| 123 | |
| 124 | // Replace four children by their parent cell. |
| 125 | output.erase(output.end() - 3, output.end()); |
| 126 | id = id.parent(); |
| 127 | } |
| 128 | output.push_back(id); |
| 129 | } |
| 130 | if (output.size() < num_cells()) { |
| 131 | InitRawSwap(&output); |
| 132 | return true; |
| 133 | } |
| 134 | return false; |
| 135 | } |
| 136 | |
| 137 | void S2CellUnion::Denormalize(int min_level, int level_mod, |
| 138 | vector<S2CellId>* output) const { |
| 139 | DCHECK_GE(min_level, 0); |
| 140 | DCHECK_LE(min_level, S2CellId::kMaxLevel); |
| 141 | DCHECK_GE(level_mod, 1); |
| 142 | DCHECK_LE(level_mod, 3); |
| 143 | |
| 144 | output->clear(); |
| 145 | output->reserve(num_cells()); |
| 146 | for (int i = 0; i < num_cells(); ++i) { |
| 147 | S2CellId id = cell_id(i); |
| 148 | int level = id.level(); |
| 149 | int new_level = max(min_level, level); |
| 150 | if (level_mod > 1) { |
| 151 | // Round up so that (new_level - min_level) is a multiple of level_mod. |
| 152 | // (Note that S2CellId::kMaxLevel is a multiple of 1, 2, and 3.) |
| 153 | new_level += (S2CellId::kMaxLevel - (new_level - min_level)) % level_mod; |
| 154 | new_level = min(S2CellId::kMaxLevel, new_level); |
| 155 | } |
| 156 | if (new_level == level) { |
| 157 | output->push_back(id); |
| 158 | } else { |
| 159 | S2CellId end = id.child_end(new_level); |
| 160 | for (id = id.child_begin(new_level); id != end; id = id.next()) { |
| 161 | output->push_back(id); |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | S2Cap S2CellUnion::GetCapBound() const { |
| 168 | // Compute the approximate centroid of the region. This won't produce the |
| 169 | // bounding cap of minimal area, but it should be close enough. |
| 170 | if (cell_ids_.empty()) return S2Cap::Empty(); |
| 171 | S2Point centroid(0, 0, 0); |
| 172 | for (int i = 0; i < num_cells(); ++i) { |
| 173 | double area = S2Cell::AverageArea(cell_id(i).level()); |
| 174 | centroid += area * cell_id(i).ToPoint(); |
| 175 | } |
| 176 | if (centroid == S2Point(0, 0, 0)) { |
| 177 | centroid = S2Point(1, 0, 0); |
| 178 | } else { |
| 179 | centroid = centroid.Normalize(); |
| 180 | } |
| 181 | |
| 182 | // Use the centroid as the cap axis, and expand the cap angle so that it |
| 183 | // contains the bounding caps of all the individual cells. Note that it is |
| 184 | // *not* sufficient to just bound all the cell vertices because the bounding |
| 185 | // cap may be concave (i.e. cover more than one hemisphere). |
| 186 | S2Cap cap = S2Cap::FromAxisHeight(centroid, 0); |
| 187 | for (int i = 0; i < num_cells(); ++i) { |
| 188 | cap.AddCap(S2Cell(cell_id(i)).GetCapBound()); |
| 189 | } |
| 190 | return cap; |
| 191 | } |
| 192 | |
| 193 | S2LatLngRect S2CellUnion::GetRectBound() const { |
| 194 | S2LatLngRect bound = S2LatLngRect::Empty(); |
| 195 | for (int i = 0; i < num_cells(); ++i) { |
| 196 | bound = bound.Union(S2Cell(cell_id(i)).GetRectBound()); |
| 197 | } |
| 198 | return bound; |
| 199 | } |
| 200 | |
| 201 | bool S2CellUnion::Contains(S2CellId const& id) const { |
| 202 | // This function requires that Normalize has been called first. |
| 203 | // |
| 204 | // This is an exact test. Each cell occupies a linear span of the S2 |
| 205 | // space-filling curve, and the cell id is simply the position at the center |
| 206 | // of this span. The cell union ids are sorted in increasing order along |
| 207 | // the space-filling curve. So we simply find the pair of cell ids that |
| 208 | // surround the given cell id (using binary search). There is containment |
| 209 | // if and only if one of these two cell ids contains this cell. |
| 210 | |
| 211 | vector<S2CellId>::const_iterator i = |
| 212 | lower_bound(cell_ids_.begin(), cell_ids_.end(), id); |
| 213 | if (i != cell_ids_.end() && i->range_min() <= id) return true; |
| 214 | return i != cell_ids_.begin() && (--i)->range_max() >= id; |
| 215 | } |
| 216 | |
| 217 | bool S2CellUnion::Intersects(S2CellId const& id) const { |
| 218 | // This function requires that Normalize has been called first. |
| 219 | // This is an exact test; see the comments for Contains() above. |
| 220 | |
| 221 | vector<S2CellId>::const_iterator i = |
| 222 | lower_bound(cell_ids_.begin(), cell_ids_.end(), id); |
| 223 | if (i != cell_ids_.end() && i->range_min() <= id.range_max()) return true; |
| 224 | return i != cell_ids_.begin() && (--i)->range_max() >= id.range_min(); |
| 225 | } |
| 226 | |
| 227 | bool S2CellUnion::Contains(S2CellUnion const* y) const { |
| 228 | // TODO: A divide-and-conquer or alternating-skip-search approach may be |
| 229 | // sigificantly faster in both the average and worst case. |
| 230 | |
| 231 | for (int i = 0; i < y->num_cells(); ++i) { |
| 232 | if (!Contains(y->cell_id(i))) return false; |
| 233 | } |
| 234 | return true; |
| 235 | } |
| 236 | |
| 237 | bool S2CellUnion::Intersects(S2CellUnion const* y) const { |
| 238 | // TODO: A divide-and-conquer or alternating-skip-search approach may be |
| 239 | // sigificantly faster in both the average and worst case. |
| 240 | |
| 241 | for (int i = 0; i < y->num_cells(); ++i) { |
| 242 | if (Intersects(y->cell_id(i))) return true; |
| 243 | } |
| 244 | return false; |
| 245 | } |
| 246 | |
| 247 | void S2CellUnion::GetUnion(S2CellUnion const* x, S2CellUnion const* y) { |
| 248 | DCHECK_NE(this, x); |
| 249 | DCHECK_NE(this, y); |
| 250 | cell_ids_.reserve(x->num_cells() + y->num_cells()); |
| 251 | cell_ids_ = x->cell_ids_; |
| 252 | cell_ids_.insert(cell_ids_.end(), y->cell_ids_.begin(), y->cell_ids_.end()); |
| 253 | Normalize(); |
| 254 | } |
| 255 | |
| 256 | void S2CellUnion::GetIntersection(S2CellUnion const* x, S2CellId const& id) { |
| 257 | DCHECK_NE(this, x); |
| 258 | cell_ids_.clear(); |
| 259 | if (x->Contains(id)) { |
| 260 | cell_ids_.push_back(id); |
| 261 | } else { |
| 262 | vector<S2CellId>::const_iterator i = |
| 263 | lower_bound(x->cell_ids_.begin(), x->cell_ids_.end(), id.range_min()); |
| 264 | S2CellId idmax = id.range_max(); |
| 265 | while (i != x->cell_ids_.end() && *i <= idmax) |
| 266 | cell_ids_.push_back(*i++); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | void S2CellUnion::GetIntersection(S2CellUnion const* x, S2CellUnion const* y) { |
| 271 | DCHECK_NE(this, x); |
| 272 | DCHECK_NE(this, y); |
| 273 | |
| 274 | // This is a fairly efficient calculation that uses binary search to skip |
| 275 | // over sections of both input vectors. It takes constant time if all the |
| 276 | // cells of "x" come before or after all the cells of "y" in S2CellId order. |
| 277 | |
| 278 | cell_ids_.clear(); |
| 279 | vector<S2CellId>::const_iterator i = x->cell_ids_.begin(); |
| 280 | vector<S2CellId>::const_iterator j = y->cell_ids_.begin(); |
| 281 | while (i != x->cell_ids_.end() && j != y->cell_ids_.end()) { |
| 282 | S2CellId imin = i->range_min(); |
| 283 | S2CellId jmin = j->range_min(); |
| 284 | if (imin > jmin) { |
| 285 | // Either j->contains(*i) or the two cells are disjoint. |
| 286 | if (*i <= j->range_max()) { |
| 287 | cell_ids_.push_back(*i++); |
| 288 | } else { |
| 289 | // Advance "j" to the first cell possibly contained by *i. |
| 290 | j = lower_bound(j + 1, y->cell_ids_.end(), imin); |
| 291 | // The previous cell *(j-1) may now contain *i. |
| 292 | if (*i <= (j - 1)->range_max()) --j; |
| 293 | } |
| 294 | } else if (jmin > imin) { |
| 295 | // Identical to the code above with "i" and "j" reversed. |
| 296 | if (*j <= i->range_max()) { |
| 297 | cell_ids_.push_back(*j++); |
| 298 | } else { |
| 299 | i = lower_bound(i + 1, x->cell_ids_.end(), jmin); |
| 300 | if (*j <= (i - 1)->range_max()) --i; |
| 301 | } |
| 302 | } else { |
| 303 | // "i" and "j" have the same range_min(), so one contains the other. |
| 304 | if (*i < *j) |
| 305 | cell_ids_.push_back(*i++); |
| 306 | else |
| 307 | cell_ids_.push_back(*j++); |
| 308 | } |
| 309 | } |
| 310 | // The output is generated in sorted order, and there should not be any |
| 311 | // cells that can be merged (provided that both inputs were normalized). |
| 312 | DCHECK(IsSorted(cell_ids_)); |
| 313 | DCHECK(!Normalize()); |
| 314 | } |
| 315 | |
| 316 | static void GetDifferenceInternal(S2CellId cell, |
| 317 | S2CellUnion const* y, |
| 318 | vector<S2CellId>* cell_ids) { |
| 319 | // Add the difference between cell and y to cell_ids. |
| 320 | // If they intersect but the difference is non-empty, divides and conquers. |
| 321 | |
| 322 | if (!y->Intersects(cell)) { |
| 323 | cell_ids->push_back(cell); |
| 324 | } else if (!y->Contains(cell)) { |
| 325 | S2CellId child = cell.child_begin(); |
| 326 | for (int i = 0; ; ++i) { |
| 327 | GetDifferenceInternal(child, y, cell_ids); |
| 328 | if (i == 3) break; // Avoid unnecessary next() computation. |
| 329 | child = child.next(); |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | void S2CellUnion::GetDifference(S2CellUnion const* x, S2CellUnion const* y) { |
| 335 | DCHECK_NE(this, x); |
| 336 | DCHECK_NE(this, y); |
| 337 | // TODO: this is approximately O(N*log(N)), but could probably use similar |
| 338 | // techniques as GetIntersection() to be more efficient. |
| 339 | |
| 340 | cell_ids_.clear(); |
| 341 | for (int i = 0; i < x->num_cells(); ++i) { |
| 342 | GetDifferenceInternal(x->cell_id(i), y, &cell_ids_); |
| 343 | } |
| 344 | // The output is generated in sorted order, and there should not be any |
| 345 | // cells that can be merged (provided that both inputs were normalized). |
| 346 | DCHECK(IsSorted(cell_ids_)); |
| 347 | DCHECK(!Normalize()); |
| 348 | } |
| 349 | |
| 350 | void S2CellUnion::Expand(int level) { |
| 351 | vector<S2CellId> output; |
| 352 | uint64 level_lsb = S2CellId::lsb_for_level(level); |
| 353 | for (int i = num_cells() - 1; i >= 0; --i) { |
| 354 | S2CellId id = cell_id(i); |
| 355 | if (id.lsb() < level_lsb) { |
| 356 | id = id.parent(level); |
| 357 | // Optimization: skip over any cells contained by this one. This is |
| 358 | // especially important when very small regions are being expanded. |
| 359 | while (i > 0 && id.contains(cell_id(i-1))) --i; |
| 360 | } |
| 361 | output.push_back(id); |
| 362 | id.AppendAllNeighbors(level, &output); |
| 363 | } |
| 364 | InitSwap(&output); |
| 365 | } |
| 366 | |
| 367 | void S2CellUnion::Expand(S1Angle const& min_radius, int max_level_diff) { |
| 368 | int min_level = S2CellId::kMaxLevel; |
| 369 | for (int i = 0; i < num_cells(); ++i) { |
| 370 | min_level = min(min_level, cell_id(i).level()); |
| 371 | } |
| 372 | // Find the maximum level such that all cells are at least "min_radius" wide. |
| 373 | int radius_level = S2::kMinWidth.GetMaxLevel(min_radius.radians()); |
| 374 | if (radius_level == 0 && min_radius.radians() > S2::kMinWidth.GetValue(0)) { |
| 375 | // The requested expansion is greater than the width of a face cell. |
| 376 | // The easiest way to handle this is to expand twice. |
| 377 | Expand(0); |
| 378 | } |
| 379 | Expand(min(min_level + max_level_diff, radius_level)); |
| 380 | } |
| 381 | |
| 382 | void S2CellUnion::InitFromRange(S2CellId const& min_id, |
| 383 | S2CellId const& max_id) { |
| 384 | DCHECK(min_id.is_leaf()); |
| 385 | DCHECK(max_id.is_leaf()); |
| 386 | DCHECK_LE(min_id, max_id); |
| 387 | |
| 388 | // We repeatedly add the largest cell we can. |
| 389 | cell_ids_.clear(); |
| 390 | for (S2CellId next_min_id = min_id; next_min_id <= max_id; ) { |
| 391 | DCHECK(next_min_id.is_leaf()); |
| 392 | |
| 393 | // Find the largest cell that starts at "next_min_id" and doesn't extend |
| 394 | // beyond "max_id". |
| 395 | S2CellId next_id = next_min_id; |
| 396 | while (!next_id.is_face() && |
| 397 | next_id.parent().range_min() == next_min_id && |
| 398 | next_id.parent().range_max() <= max_id) { |
| 399 | next_id = next_id.parent(); |
| 400 | } |
| 401 | cell_ids_.push_back(next_id); |
| 402 | next_min_id = next_id.range_max().next(); |
| 403 | } |
| 404 | |
| 405 | // The output is already normalized. |
| 406 | DCHECK(IsSorted(cell_ids_)); |
| 407 | DCHECK(!Normalize()); |
| 408 | } |
| 409 | |
| 410 | uint64 S2CellUnion::LeafCellsCovered() const { |
| 411 | uint64 num_leaves = 0; |
| 412 | for (int i = 0; i < num_cells(); ++i) { |
| 413 | const int inverted_level = |
| 414 | S2CellId::kMaxLevel - cell_id(i).level(); |
| 415 | num_leaves += (1ULL << (inverted_level << 1)); |
| 416 | } |
| 417 | return num_leaves; |
| 418 | } |
| 419 | |
| 420 | double S2CellUnion::AverageBasedArea() const { |
| 421 | return S2Cell::AverageArea(S2CellId::kMaxLevel) * LeafCellsCovered(); |
| 422 | } |
| 423 | |
| 424 | double S2CellUnion::ApproxArea() const { |
| 425 | double area = 0; |
| 426 | for (int i = 0; i < num_cells(); ++i) { |
| 427 | area += S2Cell(cell_id(i)).ApproxArea(); |
| 428 | } |
| 429 | return area; |
| 430 | } |
| 431 | |
| 432 | double S2CellUnion::ExactArea() const { |
| 433 | double area = 0; |
| 434 | for (int i = 0; i < num_cells(); ++i) { |
| 435 | area += S2Cell(cell_id(i)).ExactArea(); |
| 436 | } |
| 437 | return area; |
| 438 | } |
| 439 | |
| 440 | bool operator==(S2CellUnion const& x, S2CellUnion const& y) { |
| 441 | return x.cell_ids() == y.cell_ids(); |
| 442 | } |
| 443 | |
| 444 | bool S2CellUnion::Contains(S2Cell const& cell) const { |
| 445 | return Contains(cell.id()); |
| 446 | } |
| 447 | |
| 448 | bool S2CellUnion::MayIntersect(S2Cell const& cell) const { |
| 449 | return Intersects(cell.id()); |
| 450 | } |
| 451 | |
| 452 | bool S2CellUnion::Contains(S2Point const& p) const { |
| 453 | return Contains(S2CellId::FromPoint(p)); |
| 454 | } |
| 455 | |