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; }