bool WaterIndex::GetRegions(const GeoBox& boundingBox, const Magnification& magnification, std::list<GroundTile>& tiles) const { try { uint32_t cx1,cx2,cy1,cy2; uint32_t idx=magnification.GetLevel(); tiles.clear(); if (levels.empty()) { return true; } idx+=4; idx=std::max(waterIndexMinMag,idx); idx=std::min(waterIndexMaxMag,idx); idx-=waterIndexMinMag; cx1=(uint32_t)floor((boundingBox.GetMinLon()+180.0)/levels[idx].cellWidth); cx2=(uint32_t)floor((boundingBox.GetMaxLon()+180.0)/levels[idx].cellWidth); cy1=(uint32_t)floor((boundingBox.GetMinLat()+90.0)/levels[idx].cellHeight); cy2=(uint32_t)floor((boundingBox.GetMaxLat()+90.0)/levels[idx].cellHeight); const Level &level=levels[idx]; if (level.hasCellData) { GetGroundTileFromData(level, cx1, cx2, cy1, cy2, tiles); } else { GetGroundTileByDefault(level, cx1, cx2, cy1, cy2, tiles); } } catch (IOException& e) { log.Error() << e.GetDescription(); return false; } return true; }
/** * Return all ways in the given bounding box with the given type * @param boundingBox * Bounding box, objects must be in * @param types * The resulting ways must be of one of these types * @param nodes * Result of the query, in case the query succeeded. In case of errors * the result is empty. * @return * True, if success, else false */ bool POIService::GetWaysInArea(const GeoBox& boundingBox, const TypeSet& types, std::vector<WayRef>& ways) const { AreaWayIndexRef areaWayIndex=database->GetAreaWayIndex(); WayDataFileRef wayDataFile=database->GetWayDataFile(); ways.clear(); if (!areaWayIndex || !wayDataFile) { return false; } std::vector<TypeSet> wayTypes; std::vector<FileOffset> wayWayOffsets; wayTypes.push_back(types); if (!areaWayIndex->GetOffsets(boundingBox.GetMinLon(), boundingBox.GetMinLat(), boundingBox.GetMaxLon(), boundingBox.GetMaxLat(), wayTypes, std::numeric_limits<size_t>::max(), wayWayOffsets)) { log.Error() << "Error getting ways and relations from area way index!"; return false; } std::sort(wayWayOffsets.begin(),wayWayOffsets.end()); if (!wayDataFile->GetByOffset(wayWayOffsets, ways)) { log.Error() << "Error reading ways in area!"; return true; } return true; }
/** * Return all areas in the given bounding box with the given type * @param boundingBox * Bounding box, objects must be in * @param types * The resulting areas must be of one of these types * @param nodes * Result of the query, in case the query succeeded. In case of errors * the result is empty. * @return * True, if success, else false */ bool POIService::GetAreasInArea(const GeoBox& boundingBox, const TypeSet& types, std::vector<AreaRef>& areas) const { AreaAreaIndexRef areaAreaIndex=database->GetAreaAreaIndex(); AreaDataFileRef areaDataFile=database->GetAreaDataFile(); areas.clear(); if (!areaAreaIndex || !areaDataFile) { return false; } std::vector<FileOffset> wayAreaOffsets; if (!areaAreaIndex->GetOffsets(database->GetTypeConfig(), boundingBox.GetMinLon(), boundingBox.GetMinLat(), boundingBox.GetMaxLon(), boundingBox.GetMaxLat(), std::numeric_limits<size_t>::max(), types, std::numeric_limits<size_t>::max(), wayAreaOffsets)) { log.Error() << "Error getting ways and relations from area index!"; return false; } std::sort(wayAreaOffsets.begin(),wayAreaOffsets.end()); if (!areaDataFile->GetByOffset(wayAreaOffsets, areas)) { log.Error() << "Error reading areas in area!"; return false; } return true; }
/** * Return all nodes in the given bounding box with the given type * @param boundingBox * Bounding box, objects must be in * @param types * The resulting nodes must be of one of these types * @param nodes * Result of the query, in case the query succeeded. In case of errors * the result is empty. * @return * True, if success, else false */ bool POIService::GetNodesInArea(const GeoBox& boundingBox, const TypeSet& types, std::vector<NodeRef>& nodes) const { AreaNodeIndexRef areaNodeIndex=database->GetAreaNodeIndex(); NodeDataFileRef nodeDataFile=database->GetNodeDataFile(); nodes.clear(); if (!areaNodeIndex || !nodeDataFile) { return false; } std::vector<FileOffset> nodeOffsets; if (!areaNodeIndex->GetOffsets(boundingBox.GetMinLon(), boundingBox.GetMinLat(), boundingBox.GetMaxLon(), boundingBox.GetMaxLat(), types, std::numeric_limits<size_t>::max(), nodeOffsets)) { log.Error() << "Error getting nodes from area node index!"; return false; } std::sort(nodeOffsets.begin(), nodeOffsets.end()); if (!nodeDataFile->GetByOffset(nodeOffsets, nodes)) { log.Error() << "Error reading nodes in area!"; return false; } return true; }
/** * Return all tile necessary for covering the given boundingbox using the given magnification. */ void DataTileCache::GetTilesForBoundingBox(const Magnification& magnification, const GeoBox& boundingBox, std::list<TileRef>& tiles) const { tiles.clear(); //log.Debug() << "Creating tile data for level " << level << " and bounding box " << boundingBox.GetDisplayText(); uint32_t level=magnification.GetLevel(); uint32_t cx1=(uint32_t)floor((boundingBox.GetMinLon()+180.0)/cellDimension[level].width); uint32_t cy1=(uint32_t)floor((boundingBox.GetMinLat()+90.0)/cellDimension[level].height); uint32_t cx2=(uint32_t)floor((boundingBox.GetMaxLon()+180.0)/cellDimension[level].width); uint32_t cy2=(uint32_t)floor((boundingBox.GetMaxLat()+90.0)/cellDimension[level].height); //std::cout << "Tile bounding box: " << cx1 << "," << cy1 << " - " << cx2 << "," << cy2 << std::endl; for (size_t y=cy1; y<=cy2; y++) { for (size_t x=cx1; x<=cx2; x++) { tiles.push_back(GetTile(TileId(magnification,x,y))); } } }
bool OptimizeAreasLowZoomGenerator::WriteAreaBitmap(Progress& progress, FileWriter& writer, const std::list<AreaRef>& areas, const FileOffsetFileOffsetMap& offsets, TypeData& data) { // We do not write a bitmap, if there is not data to map if (areas.empty()) { return true; } double cellWidth=cellDimension[data.indexLevel].width; double cellHeight=cellDimension[data.indexLevel].height; std::map<Pixel,std::list<FileOffset> > cellOffsets; for (const auto& area : areas) { GeoBox boundingBox; FileOffsetFileOffsetMap::const_iterator offset=offsets.find(area->GetFileOffset()); if (offset==offsets.end()) { continue; } area->GetBoundingBox(boundingBox); // // Calculate minimum and maximum tile ids that are covered // by the way // Renormated coordinate space (everything is >=0) // uint32_t minxc=(uint32_t)floor((boundingBox.GetMinLon()+180.0)/cellWidth); uint32_t maxxc=(uint32_t)floor((boundingBox.GetMaxLon()+180.0)/cellWidth); uint32_t minyc=(uint32_t)floor((boundingBox.GetMinLat()+90.0)/cellHeight); uint32_t maxyc=(uint32_t)floor((boundingBox.GetMaxLat()+90.0)/cellHeight); for (uint32_t y=minyc; y<=maxyc; y++) { for (uint32_t x=minxc; x<=maxxc; x++) { cellOffsets[Pixel(x,y)].push_back(offset->second); } } } size_t indexEntries=0; size_t dataSize=0; char buffer[10]; for (std::map<Pixel,std::list<FileOffset> >::const_iterator cell=cellOffsets.begin(); cell!=cellOffsets.end(); ++cell) { indexEntries+=cell->second.size(); dataSize+=EncodeNumber(cell->second.size(),buffer); FileOffset previousOffset=0; for (std::list<FileOffset>::const_iterator offset=cell->second.begin(); offset!=cell->second.end(); ++offset) { FileOffset data=*offset-previousOffset; dataSize+=EncodeNumber(data,buffer); previousOffset=*offset; } } data.dataOffsetBytes=BytesNeededToEncodeNumber(dataSize); progress.Info("Writing map for level "+ NumberToString(data.optLevel)+", index level "+ NumberToString(data.indexLevel)+", "+ NumberToString(cellOffsets.size())+" cells, "+ NumberToString(indexEntries)+" entries, "+ ByteSizeToString(1.0*data.cellXCount*data.cellYCount*data.dataOffsetBytes+dataSize)); data.bitmapOffset=writer.GetPos(); // Write the bitmap with offsets for each cell // We prefill with zero and only overrite cells that have data // So zero means "no data for this cell" for (size_t i=0; i<data.cellXCount*data.cellYCount; i++) { FileOffset cellOffset=0; writer.WriteFileOffset(cellOffset, data.dataOffsetBytes); } FileOffset dataStartOffset; dataStartOffset=writer.GetPos(); // Now write the list of offsets of objects for every cell with content for (std::map<Pixel,std::list<FileOffset> >::const_iterator cell=cellOffsets.begin(); cell!=cellOffsets.end(); ++cell) { FileOffset bitmapCellOffset=data.bitmapOffset+ ((cell->first.y-data.cellYStart)*data.cellXCount+ cell->first.x-data.cellXStart)*data.dataOffsetBytes; FileOffset previousOffset=0; FileOffset cellOffset; cellOffset=writer.GetPos(); writer.SetPos(bitmapCellOffset); writer.WriteFileOffset(cellOffset-dataStartOffset, data.dataOffsetBytes); writer.SetPos(cellOffset); writer.WriteNumber((uint32_t)cell->second.size()); for (std::list<FileOffset>::const_iterator offset=cell->second.begin(); offset!=cell->second.end(); ++offset) { writer.WriteNumber((FileOffset)(*offset-previousOffset)); previousOffset=*offset; } } return true; }
void OptimizeAreasLowZoomGenerator::GetAreaIndexLevel(const ImportParameter& parameter, const std::list<AreaRef>& areas, TypeData& typeData) { size_t level=5;//parameter.GetOptimizationMinMag(); while (true) { std::map<Pixel,size_t> cellFillCount; for (const auto& area : areas) { GeoBox boundingBox; area->GetBoundingBox(boundingBox); // // Calculate minimum and maximum tile ids that are covered // by the way // Renormated coordinate space (everything is >=0) // uint32_t minxc=(uint32_t)floor((boundingBox.GetMinLon()+180.0)/cellDimension[level].width); uint32_t maxxc=(uint32_t)floor((boundingBox.GetMaxLon()+180.0)/cellDimension[level].width); uint32_t minyc=(uint32_t)floor((boundingBox.GetMinLat()+90.0)/cellDimension[level].height); uint32_t maxyc=(uint32_t)floor((boundingBox.GetMaxLat()+90.0)/cellDimension[level].height); for (uint32_t y=minyc; y<=maxyc; y++) { for (uint32_t x=minxc; x<=maxxc; x++) { cellFillCount[Pixel(x,y)]++; } } } // Check if cell fill for current type is in defined limits size_t entryCount=0; size_t max=0; for (std::map<Pixel,size_t>::const_iterator cell=cellFillCount.begin(); cell!=cellFillCount.end(); ++cell) { entryCount+=cell->second; max=std::max(max,cell->second); } double average=entryCount*1.0/cellFillCount.size(); if (!(max>parameter.GetOptimizationCellSizeMax() || average>parameter.GetOptimizationCellSizeAverage())) { typeData.indexLevel=(uint32_t)level; typeData.indexCells=cellFillCount.size(); typeData.indexEntries=0; if (!cellFillCount.empty()) { typeData.cellXStart=cellFillCount.begin()->first.x; typeData.cellYStart=cellFillCount.begin()->first.y; typeData.cellXEnd=typeData.cellXStart; typeData.cellYEnd=typeData.cellYStart; for (std::map<Pixel,size_t>::const_iterator cell=cellFillCount.begin(); cell!=cellFillCount.end(); ++cell) { typeData.indexEntries+=cell->second; typeData.cellXStart=std::min(typeData.cellXStart,cell->first.x); typeData.cellXEnd=std::max(typeData.cellXEnd,cell->first.x); typeData.cellYStart=std::min(typeData.cellYStart,cell->first.y); typeData.cellYEnd=std::max(typeData.cellYEnd,cell->first.y); } } typeData.cellXCount=typeData.cellXEnd-typeData.cellXStart+1; typeData.cellYCount=typeData.cellYEnd-typeData.cellYStart+1; return; } level++; } }
bool AreaWayIndexGenerator::Import(const TypeConfigRef& typeConfig, const ImportParameter& parameter, Progress& progress) { FileScanner wayScanner; FileWriter writer; std::vector<TypeData> wayTypeData; size_t maxLevel; progress.Info("Minimum magnification: "+NumberToString(parameter.GetAreaWayMinMag())); // // Scanning distribution // progress.SetAction("Scanning level distribution of way types"); if (!CalculateDistribution(typeConfig, parameter, progress, wayTypeData, maxLevel)) { return false; } // Calculate number of types which have data uint32_t indexEntries=0; for (const auto& type : typeConfig->GetWayTypes()) { if (wayTypeData[type->GetIndex()].HasEntries()) { indexEntries++; } } // // Writing index file // progress.SetAction("Generating 'areaway.idx'"); if (!writer.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "areaway.idx"))) { progress.Error("Cannot create 'areaway.idx'"); return false; } writer.Write(indexEntries); for (const auto &type : typeConfig->GetWayTypes()) { size_t i=type->GetIndex(); if (wayTypeData[i].HasEntries()) { uint8_t dataOffsetBytes=0; FileOffset bitmapOffset=0; writer.WriteTypeId(type->GetWayId(), typeConfig->GetWayTypeIdBytes()); writer.GetPos(wayTypeData[i].indexOffset); writer.WriteFileOffset(bitmapOffset); writer.Write(dataOffsetBytes); writer.WriteNumber(wayTypeData[i].indexLevel); writer.WriteNumber(wayTypeData[i].cellXStart); writer.WriteNumber(wayTypeData[i].cellXEnd); writer.WriteNumber(wayTypeData[i].cellYStart); writer.WriteNumber(wayTypeData[i].cellYEnd); } } if (!wayScanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "ways.dat"), FileScanner::Sequential, parameter.GetWayDataMemoryMaped())) { progress.Error("Cannot open 'ways.dat'"); return false; } for (size_t l=parameter.GetAreaWayMinMag(); l<=maxLevel; l++) { TypeInfoSet indexTypes(*typeConfig); uint32_t wayCount; double cellWidth=360.0/pow(2.0,(int)l); double cellHeight=180.0/pow(2.0,(int)l); wayScanner.GotoBegin(); for (const auto &type : typeConfig->GetWayTypes()) { if (wayTypeData[type->GetIndex()].HasEntries() && wayTypeData[type->GetIndex()].indexLevel==l) { indexTypes.Set(type); } } if (indexTypes.Empty()) { continue; } progress.Info("Scanning ways for index level "+NumberToString(l)); std::vector<CoordOffsetsMap> typeCellOffsets(typeConfig->GetTypeCount()); if (!wayScanner.Read(wayCount)) { progress.Error("Error while reading number of data entries in file"); return false; } Way way; for (uint32_t w=1; w<=wayCount; w++) { progress.SetProgress(w,wayCount); FileOffset offset; wayScanner.GetPos(offset); if (!way.Read(*typeConfig, wayScanner)) { progress.Error(std::string("Error while reading data entry ")+ NumberToString(w)+" of "+ NumberToString(wayCount)+ " in file '"+ wayScanner.GetFilename()+"'"); return false; } if (!indexTypes.IsSet(way.GetType())) { continue; } GeoBox boundingBox; way.GetBoundingBox(boundingBox); // // Calculate minimum and maximum tile ids that are covered // by the way // Renormalized coordinate space (everything is >=0) // uint32_t minxc=(uint32_t)floor((boundingBox.GetMinLon()+180.0)/cellWidth); uint32_t maxxc=(uint32_t)floor((boundingBox.GetMaxLon()+180.0)/cellWidth); uint32_t minyc=(uint32_t)floor((boundingBox.GetMinLat()+90.0)/cellHeight); uint32_t maxyc=(uint32_t)floor((boundingBox.GetMaxLat()+90.0)/cellHeight); for (uint32_t y=minyc; y<=maxyc; y++) { for (uint32_t x=minxc; x<=maxxc; x++) { typeCellOffsets[way.GetType()->GetIndex()][Pixel(x,y)].push_back(offset); } } } for (const auto &type : indexTypes) { size_t index=type->GetIndex(); if (!WriteBitmap(progress, writer, *typeConfig->GetTypeInfo(index), wayTypeData[index], typeCellOffsets[index])) { return false; } } } return !writer.HasError() && writer.Close(); }
bool AreaWayIndexGenerator::CalculateDistribution(const TypeConfigRef& typeConfig, const ImportParameter& parameter, Progress& progress, std::vector<TypeData>& wayTypeData, size_t& maxLevel) const { FileScanner wayScanner; TypeInfoSet remainingWayTypes; size_t level; maxLevel=0; wayTypeData.resize(typeConfig->GetTypeCount()); if (!wayScanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "ways.dat"), FileScanner::Sequential, parameter.GetWayDataMemoryMaped())) { progress.Error("Cannot open 'ways.dat'"); return false; } remainingWayTypes.Set(typeConfig->GetWayTypes()); level=parameter.GetAreaWayMinMag(); while (!remainingWayTypes.Empty()) { uint32_t wayCount=0; TypeInfoSet currentWayTypes(remainingWayTypes); double cellWidth=360.0/pow(2.0,(int)level); double cellHeight=180.0/pow(2.0,(int)level); std::vector<CoordCountMap> cellFillCount(typeConfig->GetTypeCount()); progress.Info("Scanning Level "+NumberToString(level)+" ("+NumberToString(remainingWayTypes.Size())+" types remaining)"); wayScanner.GotoBegin(); if (!wayScanner.Read(wayCount)) { progress.Error("Error while reading number of data entries in file"); return false; } Way way; for (uint32_t w=1; w<=wayCount; w++) { progress.SetProgress(w,wayCount); if (!way.Read(*typeConfig, wayScanner)) { progress.Error(std::string("Error while reading data entry ")+ NumberToString(w)+" of "+ NumberToString(wayCount)+ " in file '"+ wayScanner.GetFilename()+"'"); return false; } // Count number of entries per current type and coordinate if (!currentWayTypes.IsSet(way.GetType())) { continue; } GeoBox boundingBox; way.GetBoundingBox(boundingBox); // // Calculate minimum and maximum tile ids that are covered // by the way // Renormalized coordinate space (everything is >=0) // uint32_t minxc=(uint32_t)floor((boundingBox.GetMinLon()+180.0)/cellWidth); uint32_t maxxc=(uint32_t)floor((boundingBox.GetMaxLon()+180.0)/cellWidth); uint32_t minyc=(uint32_t)floor((boundingBox.GetMinLat()+90.0)/cellHeight); uint32_t maxyc=(uint32_t)floor((boundingBox.GetMaxLat()+90.0)/cellHeight); for (uint32_t y=minyc; y<=maxyc; y++) { for (uint32_t x=minxc; x<=maxxc; x++) { cellFillCount[way.GetType()->GetIndex()][Pixel(x,y)]++; } } } // Check if cell fill for current type is in defined limits for (auto &type : currentWayTypes) { size_t i=type->GetIndex(); CalculateStatistics(level, wayTypeData[i], cellFillCount[i]); if (!FitsIndexCriteria(parameter, progress, *typeConfig->GetTypeInfo(i), wayTypeData[i], cellFillCount[i])) { currentWayTypes.Remove(type); } } for (const auto &type : currentWayTypes) { maxLevel=std::max(maxLevel,level); progress.Info("Type "+type->GetName()+", "+NumberToString(wayTypeData[type->GetIndex()].indexCells)+" cells, "+NumberToString(wayTypeData[type->GetIndex()].indexEntries)+" objects"); remainingWayTypes.Remove(type); } level++; } return !wayScanner.HasError() && wayScanner.Close(); }