bool AreaAreaIndex::GetOffsets(const TypeConfigRef& typeConfig,
                                 double minlon,
                                 double minlat,
                                 double maxlon,
                                 double maxlat,
                                 size_t maxLevel,
                                 const TypeSet& types,
                                 size_t maxCount,
                                 std::vector<FileOffset>& offsets) const
  {
    std::vector<CellRef>    cellRefs;     // cells to scan in this level
    std::vector<CellRef>    nextCellRefs; // cells to scan for the next level
    std::vector<FileOffset> newOffsets;   // offsets collected in the current level

    minlon+=180;
    maxlon+=180;
    minlat+=90;
    maxlat+=90;

    // Clear result datastructures
    offsets.clear();

    // Make the vector preallocate memory for the expected data size
    // This should void reallocation
    offsets.reserve(std::min(100000u,(uint32_t)maxCount));
    newOffsets.reserve(std::min(100000u,(uint32_t)maxCount));

    cellRefs.reserve(1000);

    nextCellRefs.reserve(1000);

    cellRefs.push_back(CellRef(topLevelOffset,0,0));

    // For all levels:
    // * Take the tiles and offsets of the last level
    // * Calculate the new tiles and offsets that still interfere with given area
    // * Add the new offsets to the list of offsets and finish if we have
    //   reached maxLevel or maxAreaCount.
    // * copy no, ntx, nty to ctx, cty, co and go to next iteration
    bool stopArea=false;
    for (uint32_t level=0;
         !stopArea &&
         level<=this->maxLevel &&
         level<=maxLevel &&
         !cellRefs.empty();
         level++) {
      nextCellRefs.clear();

      newOffsets.clear();

      for (size_t i=0; !stopArea && i<cellRefs.size(); i++) {
        size_t               cx;
        size_t               cy;
        IndexCache::CacheRef cell;

        if (!GetIndexCell(*typeConfig,
                          level,
                          cellRefs[i].offset,
                          cell)) {
          log.Error() << "Cannot find offset " << cellRefs[i].offset << " in level " << level << " in file '" << scanner.GetFilename() << "'";
          return false;
        }

        if (offsets.size()+
            newOffsets.size()+
            cell->value.areas.size()>=maxCount) {
          stopArea=true;
          continue;
        }

        for (const auto entry : cell->value.areas) {
          if (types.IsTypeSet(entry.type)) {
            newOffsets.push_back(entry.offset);
          }
        }

        cx=cellRefs[i].x*2;
        cy=cellRefs[i].y*2;

        if (cell->value.children[0]!=0) {
          // top left
          double x=cx*cellWidth[level+1];
          double y=(cy+1)*cellHeight[level+1];

          if (!(x>maxlon+cellWidth[level+1]/2 ||
                y>maxlat+cellHeight[level+1]/2 ||
                x+cellWidth[level+1]<minlon-cellWidth[level+1]/2 ||
                y+cellHeight[level+1]<minlat-cellHeight[level+1]/2)) {
            nextCellRefs.push_back(CellRef(cell->value.children[0],cx,cy+1));
          }
        }

        if (cell->value.children[1]!=0) {
          // top right
          double x=(cx+1)*cellWidth[level+1];
          double y=(cy+1)*cellHeight[level+1];

          if (!(x>maxlon+cellWidth[level+1]/2 ||
                y>maxlat+cellHeight[level+1]/2 ||
                x+cellWidth[level+1]<minlon-cellWidth[level+1]/2 ||
                y+cellHeight[level+1]<minlat-cellHeight[level+1]/2)) {
            nextCellRefs.push_back(CellRef(cell->value.children[1],cx+1,cy+1));
          }
        }

        if (cell->value.children[2]!=0) {
          // bottom left
          double x=cx*cellWidth[level+1];
          double y=cy*cellHeight[level+1];

          if (!(x>maxlon+cellWidth[level+1]/2 ||
                y>maxlat+cellHeight[level+1]/2 ||
                x+cellWidth[level+1]<minlon-cellWidth[level+1]/2 ||
                y+cellHeight[level+1]<minlat-cellHeight[level+1]/2)) {
            nextCellRefs.push_back(CellRef(cell->value.children[2],cx,cy));
          }
        }

        if (cell->value.children[3]!=0) {
          // bottom right
          double x=(cx+1)*cellWidth[level+1];
          double y=cy*cellHeight[level+1];

          if (!(x>maxlon+cellWidth[level+1]/2 ||
                y>maxlat+cellHeight[level+1]/2 ||
                x+cellWidth[level+1]<minlon-cellWidth[level+1]/2 ||
                y+cellHeight[level+1]<minlat-cellHeight[level+1]/2)) {
            nextCellRefs.push_back(CellRef(cell->value.children[3],cx+1,cy));
          }
        }
      }

      if (!stopArea) {
        offsets.insert(offsets.end(),newOffsets.begin(),newOffsets.end());
      }

      std::swap(cellRefs,nextCellRefs);
    }

    return true;
  }