예제 #1
0
  void DataTileCache::ResolveAreasFromParent(Tile& tile,
                                              const Tile& parentTile,
                                              const GeoBox& boundingBox,
                                              const TypeInfoSet& areaTypes)
  {
    if (areaTypes.Intersects(parentTile.GetAreaData().GetTypes())) {
      TypeInfoSet subset(areaTypes);

      subset.Intersection(parentTile.GetAreaData().GetTypes());

      std::vector<AreaRef> data;

      data.reserve(parentTile.GetAreaData().GetDataSize());

      parentTile.GetAreaData().CopyData([&](const AreaRef& area) {
        if (areaTypes.IsSet(area->GetType())) {
          GeoBox areaBoundingBox;

          area->GetBoundingBox(areaBoundingBox);

          if (areaBoundingBox.Intersects(boundingBox)) {
            data.push_back(area);
          }
        }
      });

      tile.GetAreaData().SetPrefillData(subset,
                                        data);
    }
  }
예제 #2
0
  void DataTileCache::ResolveWaysFromParent(Tile& tile,
                                             const Tile& parentTile,
                                             const GeoBox& boundingBox,
                                             const TypeInfoSet& wayTypes)
  {
    if (wayTypes.Intersects(parentTile.GetWayData().GetTypes())) {
      TypeInfoSet subset(wayTypes);

      subset.Intersection(parentTile.GetWayData().GetTypes());

      std::vector<WayRef> data;

      data.reserve(parentTile.GetWayData().GetDataSize());

      parentTile.GetWayData().CopyData([&](const WayRef& way) {
        if (wayTypes.IsSet(way->GetType())) {
          GeoBox wayBoundingBox;

          way->GetBoundingBox(wayBoundingBox);

          if (wayBoundingBox.Intersects(boundingBox)) {
            data.push_back(way);
          }
        }
      });

      tile.GetWayData().SetPrefillData(subset,
                                       data);
    }
  }
예제 #3
0
  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;
  }
예제 #4
0
  void DataTileCache::ResolveNodesFromParent(Tile& tile,
                                              const Tile& parentTile,
                                              const GeoBox& boundingBox,
                                              const TypeInfoSet& nodeTypes)
  {
    if (nodeTypes.Intersects(parentTile.GetNodeData().GetTypes())) {
      TypeInfoSet subset(nodeTypes);

      subset.Intersection(parentTile.GetNodeData().GetTypes());

      std::vector<NodeRef> data;

      data.reserve(parentTile.GetNodeData().GetDataSize());

      parentTile.GetNodeData().CopyData([&](const NodeRef& node) {
        if (nodeTypes.IsSet(node->GetType())) {
          if (boundingBox.Includes(node->GetCoords())) {
            data.push_back(node);
          }
        }
      });

      tile.GetNodeData().SetPrefillData(subset,
                                        data);
    }
  }
예제 #5
0
  bool TileProjection::GetDimensions(GeoBox& boundingBox) const
  {
    assert(valid);

    boundingBox.Set(GeoCoord(latMin,lonMin),
                    GeoCoord(latMax,lonMax));

    return true;
  }
예제 #6
0
  /**
   * 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;
  }
예제 #7
0
파일: Area.cpp 프로젝트: jojva/libosmscout
  void Area::GetBoundingBox(GeoBox& boundingBox) const
  {
    boundingBox.Invalidate();

    for (const auto& role : rings) {
      if (role.ring==Area::outerRingId) {
        if (!boundingBox.IsValid()) {
          role.GetBoundingBox(boundingBox);
        }
        else {
          GeoBox ringBoundingBox;

          role.GetBoundingBox(ringBoundingBox);

          boundingBox.Include(ringBoundingBox);
        }
      }
    }
  }
예제 #8
0
  /**
   * 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;
  }
예제 #9
0
  /**
   * 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;
  }
예제 #10
0
  /**
   * 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)));
      }
    }
  }
예제 #11
0
파일: Area.cpp 프로젝트: jojva/libosmscout
  void Area::Ring::GetBoundingBox(GeoBox& boundingBox) const
  {
    assert(!nodes.empty());

    double minLon=nodes[0].GetLon();
    double maxLon=minLon;
    double minLat=nodes[0].GetLat();
    double maxLat=minLat;

    for (size_t i=1; i<nodes.size(); i++) {
      minLon=std::min(minLon,nodes[i].GetLon());
      maxLon=std::max(maxLon,nodes[i].GetLon());
      minLat=std::min(minLat,nodes[i].GetLat());
      maxLat=std::max(maxLat,nodes[i].GetLat());
    }

    boundingBox.Set(GeoCoord(minLat,minLon),
                    GeoCoord(maxLat,maxLon));
  }
  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++;
    }
  }
예제 #14
0
  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();
  }
예제 #15
0
  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();
  }