示例#1
0
  bool LocationIndex::VisitLocationAddresses(const AdminRegion& region,
                                             const Location& location,
                                             AddressVisitor& visitor) const
  {
    FileScanner scanner;
    bool        stopped=false;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      true)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!scanner.SetPos(indexOffset)) {
      return false;
    }

    if (!VisitLocationAddressEntries(scanner,
                                     region,
                                     location,
                                     visitor,
                                     stopped)) {
      return false;
    }

    return !scanner.HasError() && scanner.Close();
  }
示例#2
0
  bool LocationIndex::ResolveAdminRegionHierachie(const AdminRegionRef& adminRegion,
                                                  std::map<FileOffset,AdminRegionRef >& refs) const
  {
    FileScanner scanner;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      true)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!scanner.SetPos(indexOffset)) {
      return false;
    }

    std::list<FileOffset> offsets;

    refs[adminRegion->regionOffset]=adminRegion;

    if (adminRegion->parentRegionOffset!=0) {
      offsets.push_back(adminRegion->parentRegionOffset);
    }

    while (!offsets.empty()) {
      std::list<FileOffset> newOffsets;

      for (const auto& offset : offsets) {
        if (refs.find(offset)!=refs.end()) {
          continue;
        }

        if (!scanner.SetPos(offset)) {
          return false;
        }

        AdminRegion adminRegion;

        if (!LoadAdminRegion(scanner,
                             adminRegion)) {
          return false;
        }

        refs[adminRegion.regionOffset]=std::make_shared<AdminRegion>(adminRegion);

        if (adminRegion.parentRegionOffset!=0) {
          newOffsets.push_back(adminRegion.parentRegionOffset);
        }

      }
      offsets.clear();

      std::swap(offsets,
                newOffsets);
    }

    return !scanner.HasError() && scanner.Close();
  }
示例#3
0
  bool LocationIndex::Load(const std::string& path)
  {
    this->path=path;

    FileScanner scanner;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      true)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!(scanner.Read(bytesForNodeFileOffset) &&
          scanner.Read(bytesForAreaFileOffset) &&
          scanner.Read(bytesForWayFileOffset))) {
      return false;
    }

    uint32_t ignoreTokenCount;

    if (!scanner.ReadNumber(ignoreTokenCount)) {
      return false;
    }

    for (size_t i=0; i<ignoreTokenCount; i++) {
      std::string token;

      if (!scanner.Read(token)) {
        return false;
      }

      regionIgnoreTokens.insert(token);
    }

    if (!scanner.ReadNumber(ignoreTokenCount)) {
      return false;
    }

    for (size_t i=0; i<ignoreTokenCount; i++) {
      std::string token;

      if (!scanner.Read(token)) {
        return false;
      }

      locationIgnoreTokens.insert(token);
    }

    if (!scanner.GetPos(indexOffset)) {
      return false;
    }

    return !scanner.HasError() && scanner.Close();
  }
  bool DebugDatabase::ResolveReferences(const std::string& mapName,
                                        RefType fileType,
                                        const std::set<ObjectOSMRef>& ids,
                                        const std::set<ObjectFileRef>& fileOffsets,
                                        std::map<ObjectOSMRef,ObjectFileRef>& idFileOffsetMap,
                                        std::map<ObjectFileRef,ObjectOSMRef>& fileOffsetIdMap)
  {
    FileScanner scanner;
    uint32_t    entryCount;
    std::string filename=AppendFileToDir(path,mapName);

    if (!scanner.Open(filename,FileScanner::LowMemRandom,false)) {
      std::cerr << "Cannot open file '" << scanner.GetFilename() << "'!" << std::endl;
      return false;
    }

    if (!scanner.Read(entryCount)) {
      return false;
    }

    for (size_t i=1; i<=entryCount; i++) {
      Id         id;
      uint8_t    typeByte;
      OSMRefType osmType;
      FileOffset fileOffset;

      if (!scanner.Read(id)) {
        return false;
      }

      if (!scanner.Read(typeByte)) {
        return false;
      }

      osmType=(OSMRefType)typeByte;

      if (!scanner.ReadFileOffset(fileOffset)) {
        return false;
      }

      ObjectOSMRef  osmRef(id,osmType);
      ObjectFileRef fileRef(fileOffset,fileType);

      if (ids.find(osmRef)!=ids.end() ||
          fileOffsets.find(fileRef)!=fileOffsets.end()) {
        idFileOffsetMap.insert(std::make_pair(osmRef,fileRef));
        fileOffsetIdMap.insert(std::make_pair(fileRef,osmRef));
      }
    }

    return scanner.Close();
  }
示例#5
0
  bool LocationIndex::VisitAdminRegions(AdminRegionVisitor& visitor) const
  {
    FileScanner scanner;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      false)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!scanner.SetPos(indexOffset)) {
      return false;
    }

    uint32_t regionCount;

    if (!scanner.ReadNumber(regionCount)) {
      return false;
    }

    for (size_t i=0; i<regionCount; i++) {
      AdminRegionVisitor::Action action;
      FileOffset                 nextChildOffset;

      if (!scanner.ReadFileOffset(nextChildOffset)) {
        return false;
      }

      action=VisitRegionEntries(scanner,
                                visitor);

      if (action==AdminRegionVisitor::error) {
        return false;
      }
      else if (action==AdminRegionVisitor::stop) {
        return true;
      }
      else if (action==AdminRegionVisitor::skipChildren) {
        if (i+1<regionCount) {
          if (!scanner.SetPos(nextChildOffset)) {
            return false;
          }
        }
      }
    }

    return !scanner.HasError() && scanner.Close();
  }
  /**
   * Load the object variant data from the given file.
   *
   * @param typeConfig
   *    TypeConfig instance
   * @param filename
   *    Name of the file containing the object variant data
   * @return
   *    True on success, else false
   */
  bool ObjectVariantDataFile::Load(const TypeConfig& typeConfig,
                                   const std::string& filename)
  {
    FileScanner scanner;

    data.clear();

    isLoaded=false;
    this->filename=filename;

    try {
      scanner.Open(filename,
                   FileScanner::Sequential,true);

      uint32_t dataCount;

      scanner.Read(dataCount);

      data.resize(dataCount);

      for (size_t i=0; i<dataCount; i++) {
        data[i].Read(typeConfig,
                     scanner);
      }

      scanner.Close();

      isLoaded=true;
    }
    catch (IOException& e) {
      log.Error() << e.GetDescription();
      scanner.CloseFailsafe();
      return false;
    }

    return true;
  }
示例#7
0
  bool Database::Open(const std::string& path)
  {
    assert(!path.empty());

    this->path=path;

    typeConfig=std::make_shared<TypeConfig>();

    if (!typeConfig->LoadFromDataFile(path)) {
      log.Error() << "Cannot load 'types.dat'!";
      return false;
    }

    FileScanner scanner;

    try {
      scanner.Open(AppendFileToDir(path,"bounding.dat"),
                   FileScanner::Normal,
                   false);

      scanner.ReadBox(boundingBox);

      log.Debug() << "BoundingBox: " << boundingBox.GetDisplayText();

      scanner.Close();
    }
    catch (IOException& e) {
      log.Error() << e.GetDescription();
      scanner.CloseFailsafe();
      return false;
    }

    isOpen=true;

    return true;
  }
示例#8
0
  bool Database::Open(const std::string& path)
  {
    assert(!path.empty());

    this->path=path;

    typeConfig=new TypeConfig();

    if (!typeConfig->LoadFromDataFile(path)) {
      log.Error() << "Cannot load 'types.dat'!";
      return false;
    }

    FileScanner scanner;
    std::string file=AppendFileToDir(path,"bounding.dat");

    if (!scanner.Open(file,FileScanner::Normal,true)) {
      log.Error() << "Cannot open '" << scanner.GetFilename() << "'";
      return false;
    }

    if (!scanner.ReadBox(boundingBox)) {
      log.Error() << "Error while reading '" << scanner.GetFilename() << "'";
    }

    log.Debug() << "BoundingBox: " << boundingBox.GetDisplayText();

    if (scanner.HasError() || !scanner.Close()) {
      log.Error() << "Cannot while reading/closing '" << scanner.GetFilename() << "'";
      return false;
    }

    isOpen=true;

    return true;
  }
示例#9
0
  bool NodeDataGenerator::Import(const TypeConfigRef& typeConfig,
                                 const ImportParameter& parameter,
                                 Progress& progress)
  {
    uint32_t rawNodeCount=0;
    uint32_t nodesReadCount=0;
    uint32_t nodesWrittenCount=0;

    //
    // Iterator over all raw nodes, hcekc they type, and convert them from raw nodes
    // to nodes if the type is interesting (!=typeIgnore).
    //
    // Count the bounding box by the way...
    //

    progress.SetAction("Generating nodes.tmp");

    FileScanner scanner;
    FileWriter  writer;

    if (!scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                      "rawnodes.dat"),
                      FileScanner::Sequential,
                      parameter.GetRawNodeDataMemoryMaped())) {
      progress.Error("Cannot open 'rawnodes.dat'");
      return false;
    }

    if (!scanner.Read(rawNodeCount)) {
      progress.Error("Error while reading number of data entries in file");
      return false;
    }

    if (!writer.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                     "nodes.tmp"))) {
      progress.Error("Cannot create 'nodes.tmp'");
      return false;
    }

    writer.Write(nodesWrittenCount);

    for (uint32_t n=1; n<=rawNodeCount; n++) {
      progress.SetProgress(n,rawNodeCount);

      RawNode rawNode;
      Node    node;

      if (!rawNode.Read(typeConfig,
                        scanner)) {
        progress.Error(std::string("Error while reading data entry ")+
                       NumberToString(n)+" of "+
                       NumberToString(rawNodeCount)+
                       " in file '"+
                       scanner.GetFilename()+"'");
        return false;
      }

      nodesReadCount++;

      if (!rawNode.GetType()->GetIgnore()) {
        node.SetFeatures(rawNode.GetFeatureValueBuffer());
        node.SetCoords(rawNode.GetCoords());

        FileOffset fileOffset;

        if (!writer.GetPos(fileOffset)) {
          progress.Error(std::string("Error while reading current fileOffset in file '")+
                         writer.GetFilename()+"'");
          return false;
        }

        writer.Write(rawNode.GetId());
        node.Write(typeConfig,
                   writer);

        nodesWrittenCount++;
      }
    }

    if (!scanner.Close()) {
      return false;
    }

    writer.SetPos(0);
    writer.Write(nodesWrittenCount);

    if (!writer.Close()) {
      return false;
    }

    progress.Info(std::string("Read "+NumberToString(nodesReadCount)+" nodes, wrote "+NumberToString(nodesWrittenCount)+" nodes"));

    return true;
  }
示例#10
0
  bool MergeAreasGenerator::Import(const TypeConfigRef& typeConfig,
                                   const ImportParameter& parameter,
                                   Progress& progress)
  {
    TypeInfoSet                    mergeTypes;
    FileScanner                    scanner;
    FileWriter                     writer;
    uint32_t                       areasWritten=0;

    for (const auto& type : typeConfig->GetTypes()) {
      if (type->CanBeArea() &&
          type->GetMergeAreas()) {
        mergeTypes.Set(type);
      }
    }

    std::unordered_set<Id> nodeUseMap;

    try {
      scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                   MergeAreaDataGenerator::AREAS_TMP),
                   FileScanner::Sequential,
                   parameter.GetRawWayDataMemoryMaped());

      if (!ScanAreaNodeIds(progress,
                           *typeConfig,
                           scanner,
                           mergeTypes,
                           nodeUseMap)) {
        return false;
      }

      uint32_t nodeCount=nodeUseMap.size();

      progress.Info("Found "+NumberToString(nodeCount)+" nodes as possible connection points for areas");

      /* ------ */

      writer.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                  AREAS2_TMP));

      writer.Write(areasWritten);

      while (true) {
        TypeInfoSet                loadedTypes;
        std::vector<AreaMergeData> mergeJob(typeConfig->GetTypeCount());

        //
        // Load type data
        //

        progress.SetAction("Collecting area data by type");

        if (!GetAreas(parameter,
                      progress,
                      *typeConfig,
                      mergeTypes,
                      loadedTypes,
                      nodeUseMap,
                      scanner,
                      writer,
                      mergeJob,
                      areasWritten)) {
          return false;
        }

        // Merge

        progress.SetAction("Merging areas");

        for (const auto& type : loadedTypes) {
          if (!mergeJob[type->GetIndex()].areas.empty()) {
            progress.Info("Merging areas of type "+type->GetName());
            MergeAreas(progress,
                       nodeUseMap,
                       mergeJob[type->GetIndex()]);
            progress.Info("Reduced areas of '"+type->GetName()+"' from "+NumberToString(mergeJob[type->GetIndex()].areaCount)+" to "+NumberToString(mergeJob[type->GetIndex()].areaCount-mergeJob[type->GetIndex()].mergedAway.size()));

            mergeJob[type->GetIndex()].areas.clear();
          }
        }

        // Store back merge result

        if (!loadedTypes.Empty()) {
          if (!WriteMergeResult(progress,
                                *typeConfig,
                                scanner,
                                writer,
                                loadedTypes,
                                mergeJob,
                                areasWritten)) {
            return false;
          }

          mergeTypes.Remove(loadedTypes);
        }


        if (mergeTypes.Empty()) {
          break;
        }
      }

      scanner.Close();

      writer.GotoBegin();
      writer.Write(areasWritten);
      writer.Close();
    }
    catch (IOException& e) {
      progress.Error(e.GetDescription());

      scanner.CloseFailsafe();
      writer.CloseFailsafe();

      return false;
    }

    return true;
  }
示例#11
0
  bool OptimizeAreaWayIdsGenerator::ScanAreaIds(const ImportParameter& parameter,
                                                Progress& progress,
                                                const TypeConfig& typeConfig,
                                                NodeUseMap& nodeUseMap)
  {
    FileScanner scanner;
    uint32_t    dataCount=0;

    progress.SetAction("Scanning ids from 'areas2.tmp'");

    if (!scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                      "areas2.tmp"),
                      FileScanner::Sequential,
                      parameter.GetAreaDataMemoryMaped())) {
      progress.Error(std::string("Cannot open '")+scanner.GetFilename()+"'");
      return false;
    }

    if (!scanner.Read(dataCount)) {
      progress.Error("Error while reading number of data entries in file");
      return false;
    }

    for (uint32_t current=1; current<=dataCount; current++) {
      uint8_t type;
      Id      id;
      Area    data;

      progress.SetProgress(current,dataCount);

      if (!scanner.Read(type) ||
          !scanner.Read(id) ||
          !data.ReadImport(typeConfig,
                           scanner)) {
        progress.Error(std::string("Error while reading data entry ")+
                       NumberToString(current)+" of "+
                       NumberToString(dataCount)+
                       " in file '"+
                       scanner.GetFilename()+"'");

        return false;
      }

      for (const auto& ring: data.rings) {
        std::unordered_set<Id> nodeIds;

        if (!ring.GetType()->CanRoute()) {
          continue;
        }

        for (const auto id: ring.ids) {
          if (nodeIds.find(id)==nodeIds.end()) {
            nodeUseMap.SetNodeUsed(id);

            nodeIds.insert(id);
          }
        }
      }
    }

    if (!scanner.Close()) {
      progress.Error(std::string("Error while closing file '")+
                     scanner.GetFilename()+"'");
      return false;
    }

    return true;
  }
示例#12
0
  bool OptimizeAreaWayIdsGenerator::CopyWays(const ImportParameter& parameter,
                                             Progress& progress,
                                             const TypeConfig& typeConfig,
                                             NodeUseMap& nodeUseMap)
  {
    FileScanner scanner;
    FileWriter  writer;
    uint32_t    dataCount=0;

    progress.SetAction("Copy data from 'wayway.tmp' to 'ways.tmp'");

    if (!scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                      "wayway.tmp"),
                                      FileScanner::Sequential,
                                      parameter.GetWayDataMemoryMaped())) {
      progress.Error(std::string("Cannot open '")+scanner.GetFilename()+"'");
      return false;
    }

    if (!scanner.Read(dataCount)) {
      progress.Error("Error while reading number of data entries in file");
      return false;
    }

    if (!writer.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                     "ways.tmp"))) {
      progress.Error(std::string("Cannot create '")+writer.GetFilename()+"'");
      return false;
    }

    writer.Write(dataCount);

    for (uint32_t current=1; current<=dataCount; current++) {
      uint8_t type;
      Id      id;
      Way     data;

      progress.SetProgress(current,dataCount);

      if (!scanner.Read(type) ||
          !scanner.Read(id) ||
          !data.Read(typeConfig,
                     scanner)) {
        progress.Error(std::string("Error while reading data entry ")+
                       NumberToString(current)+" of "+
                       NumberToString(dataCount)+
                       " in file '"+
                       scanner.GetFilename()+"'");

        return false;
      }

      for (auto& id : data.ids) {
        if (!nodeUseMap.IsNodeUsedAtLeastTwice(id)) {
          id=0;
        }
      }

      if (!writer.Write(type) ||
          !writer.Write(id) ||
          !data.Write(typeConfig,
                      writer)) {
        progress.Error(std::string("Error while writing data entry to file '")+
                       writer.GetFilename()+"'");

        return false;
      }
    }

    if (!scanner.Close()) {
      progress.Error(std::string("Error while closing file '")+
                     scanner.GetFilename()+"'");
      return false;
    }

    if (!writer.Close()) {
      progress.Error(std::string("Error while closing file '")+
                     writer.GetFilename()+"'");
      return false;
    }

    return true;
  }
示例#13
0
  bool OptimizeAreaWayIdsGenerator::ScanWayIds(const ImportParameter& parameter,
                                               Progress& progress,
                                               const TypeConfig& typeConfig,
                                               NodeUseMap& nodeUseMap)
  {
    FileScanner scanner;
    uint32_t    dataCount=0;

    progress.SetAction("Scanning ids from 'wayway.tmp'");

    if (!scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                      "wayway.tmp"),
                                      FileScanner::Sequential,
                                      parameter.GetWayDataMemoryMaped())) {
      progress.Error(std::string("Cannot open '")+scanner.GetFilename()+"'");
      return false;
    }

    if (!scanner.Read(dataCount)) {
      progress.Error("Error while reading number of data entries in file");
      return false;
    }

    for (uint32_t current=1; current<=dataCount; current++) {
      uint8_t type;
      Id      id;
      Way     data;

      progress.SetProgress(current,dataCount);

      if (!scanner.Read(type) ||
          !scanner.Read(id) ||
          !data.Read(typeConfig,
                     scanner)) {
        progress.Error(std::string("Error while reading data entry ")+
                       NumberToString(current)+" of "+
                       NumberToString(dataCount)+
                       " in file '"+
                       scanner.GetFilename()+"'");

        return false;
      }

      if (!data.GetType()->CanRoute()) {
        continue;
      }

      std::unordered_set<Id> nodeIds;

      for (const auto& id : data.ids) {
        if (nodeIds.find(id)==nodeIds.end()) {
          nodeUseMap.SetNodeUsed(id);

          nodeIds.insert(id);
        }
      }

      // If we have a circular way, we "fake" a double usage,
      // to make sure, that the node id of the first node
      // is not dropped later on, and we cannot detect
      // circular ways anymore
      if (data.ids.front()==data.ids.back()) {
        nodeUseMap.SetNodeUsed(data.ids.back());
      }
    }

    if (!scanner.Close()) {
      progress.Error(std::string("Error while closing file '")+
                     scanner.GetFilename()+"'");
      return false;
    }

    return true;
  }
  bool OptimizeAreasLowZoomGenerator::HandleAreas(const ImportParameter& parameter,
                                                  Progress& progress,
                                                  const TypeConfig& typeConfig,
                                                  FileWriter& writer,
                                                  const TypeInfoSet& types,
                                                  std::list<TypeData>& typesData)
  {
    FileScanner scanner;
    // Everything smaller than 2mm should get dropped. Width, height and DPI come from the Nexus 4
    double dpi=320.0;
    double pixel=2.0/* mm */ * dpi / 25.4 /* inch */;

    progress.Info("Minimum visible size in pixel: "+NumberToString((unsigned long)pixel));

    try {
      scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(),
                                   AreaDataFile::AREAS_DAT),
                   FileScanner::Sequential,
                   parameter.GetWayDataMemoryMaped());

      TypeInfoSet                      typesToProcess(types);
      std::vector<std::list<AreaRef> > allAreas(typeConfig.GetTypeCount());

      while (true) {
        //
        // Load type data
        //

        TypeInfoSet loadedTypes;

        if (!GetAreas(typeConfig,
                      parameter,
                      progress,
                      scanner,
                      typesToProcess,
                      allAreas,
                      loadedTypes)) {
          return false;
        }

        typesToProcess.Remove(loadedTypes);

        for (const auto& type : loadedTypes) {
          progress.SetAction("Optimizing type "+ type->GetName());

          for (uint32_t level=parameter.GetOptimizationMinMag();
               level<=parameter.GetOptimizationMaxMag();
               level++) {
            Magnification      magnification; // Magnification, we optimize for
            std::list<AreaRef> optimizedAreas;

            magnification.SetLevel(level);

            OptimizeAreas(allAreas[type->GetIndex()],
                          optimizedAreas,
                          1280,768,
                          dpi,
                          pixel,
                          magnification,
                          parameter.GetOptimizationWayMethod());

            if (optimizedAreas.empty()) {
              progress.Debug("Empty optimization result for level "+NumberToString(level)+", no index generated");

              TypeData typeData;

              typeData.type=type;
              typeData.optLevel=level;

              typesData.push_back(typeData);

              continue;
            }

            progress.Info("Optimized from "+NumberToString(allAreas[type->GetIndex()].size())+" to "+NumberToString(optimizedAreas.size())+" areas");

            /*
            size_t optAreas=optimizedAreas.size();
            size_t optRoles=0;
            size_t optNodes=0;

            for (std::list<AreaRef>::const_iterator a=optimizedAreas.begin();
                a!=optimizedAreas.end();
                ++a) {
              AreaRef area=*a;

              optRoles+=area->rings.size();

              for (size_t r=0; r<area->rings.size(); r++) {
                optNodes+=area->rings[r].nodes.size();
              }
            }*/

            /*
            std::cout << "Areas: " << origAreas << " => " << optAreas << std::endl;
            std::cout << "Roles: " << origRoles << " => " << optRoles << std::endl;
            std::cout << "Nodes: " << origNodes << " => " << optNodes << std::endl;*/

            TypeData typeData;

            typeData.type=type;
            typeData.optLevel=level;

            GetAreaIndexLevel(parameter,
                              optimizedAreas,
                              typeData);

            //std::cout << "Resulting index level: " << typeData.indexLevel << ", " << typeData.indexCells << ", " << typeData.indexEntries << std::endl;

            FileOffsetFileOffsetMap offsets;

            WriteAreas(typeConfig,
                       writer,
                       optimizedAreas,
                       offsets);

            if (!WriteAreaBitmap(progress,
                                 writer,
                                 optimizedAreas,
                                 offsets,
                                 typeData)) {
              return false;
            }

            typesData.push_back(typeData);
          }

          allAreas[type->GetIndex()].clear();
        }

        if (typesToProcess.Empty()) {
          break;
        }
      }

      scanner.Close();
    }
    catch (IOException& e) {
      progress.Error(e.GetDescription());
      return false;
    }

    return true;
  }
  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();
  }