bool AreaAreaIndexGenerator::Import(const TypeConfigRef& typeConfig, const ImportParameter& parameter, Progress& progress) { FileScanner scanner; size_t areas=0; // Number of areas found size_t areasConsumed=0; // Number of areas consumed std::vector<double> cellWidth; std::vector<double> cellHeight; std::map<Pixel,AreaLeaf> leafs; std::map<Pixel,AreaLeaf> newAreaLeafs; cellWidth.resize(parameter.GetAreaAreaIndexMaxMag()+1); cellHeight.resize(parameter.GetAreaAreaIndexMaxMag()+1); for (size_t i=0; i<cellWidth.size(); i++) { cellWidth[i]=360.0/pow(2.0,(int)i); } for (size_t i=0; i<cellHeight.size(); i++) { cellHeight[i]=180.0/pow(2.0,(int)i); } // // Writing index file // progress.SetAction("Generating 'areaarea.idx'"); FileWriter writer; FileOffset topLevelOffset=0; FileOffset topLevelOffsetOffset; // Offset of the toplevel entry if (!writer.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "areaarea.idx"))) { progress.Error("Cannot create 'areaarea.idx'"); return false; } if (!scanner.Open(AppendFileToDir(parameter.GetDestinationDirectory(), "areas.dat"), FileScanner::Sequential, parameter.GetWayDataMemoryMaped())) { progress.Error("Cannot open 'areas.dat'"); return false; } writer.WriteNumber((uint32_t)parameter.GetAreaAreaIndexMaxMag()); // MaxMag if (!writer.GetPos(topLevelOffsetOffset)) { progress.Error("Cannot read current file position"); return false; } if (!writer.WriteFileOffset(topLevelOffset)) { progress.Error("Cannot write top level entry offset"); return false; } int l=parameter.GetAreaAreaIndexMaxMag(); while (l>=0) { size_t areaLevelEntries=0; progress.Info(std::string("Storing level ")+NumberToString(l)+"..."); newAreaLeafs.clear(); SetOffsetOfChildren(leafs,newAreaLeafs); leafs=newAreaLeafs; // Areas if (areas==0 || (areas>0 && areas>areasConsumed)) { uint32_t areaCount=0; progress.Info(std::string("Scanning areas.dat for areas of index level ")+NumberToString(l)+"..."); if (!scanner.GotoBegin()) { progress.Error("Cannot go to begin of way file"); } if (!scanner.Read(areaCount)) { progress.Error("Error while reading number of data entries in file"); return false; } areas=0; for (uint32_t a=1; a<=areaCount; a++) { progress.SetProgress(a,areaCount); FileOffset offset; Area area; scanner.GetPos(offset); if (!area.Read(typeConfig, scanner)) { progress.Error(std::string("Error while reading data entry ")+ NumberToString(a)+" of "+ NumberToString(areaCount)+ " in file '"+ scanner.GetFilename()+"'"); return false; } areas++; double minLon; double maxLon; double minLat; double maxLat; area.GetBoundingBox(minLon,maxLon,minLat,maxLat); // // Calculate highest level where the bounding box completely // fits in the cell size and assign area to the tiles that // hold the geometric center of the tile. // int level=parameter.GetAreaAreaIndexMaxMag(); while (level>=0) { if (maxLon-minLon<=cellWidth[level] && maxLat-minLat<=cellHeight[level]) { break; } level--; } if (level==l) { // // Renormated coordinate space (everything is >=0) // minLon+=180; maxLon+=180; minLat+=90; maxLat+=90; // // Calculate minimum and maximum tile ids that are covered // by the area // uint32_t minyc=(uint32_t)floor(minLat/cellHeight[level]); uint32_t maxyc=(uint32_t)ceil(maxLat/cellHeight[level]); uint32_t minxc=(uint32_t)floor(minLon/cellWidth[level]); uint32_t maxxc=(uint32_t)ceil(maxLon/cellWidth[level]); Entry entry; entry.type=area.GetType()->GetId(); entry.offset=offset; // Add this area to the tile where the center of the area lies in. leafs[Pixel((minxc+maxxc)/2,(minyc+maxyc)/2)].areas.push_back(entry); areaLevelEntries++; areasConsumed++; } } } progress.Debug(std::string("Writing ")+NumberToString(leafs.size())+" leafs ("+ NumberToString(areaLevelEntries)+") "+ "to index of level "+NumberToString(l)+"..."); // Remember the offset of one cell in level '0' if (l==0) { if (!writer.GetPos(topLevelOffset)) { progress.Error("Cannot read top level entry offset"); return false; } } /* uint32_t minX=std::numeric_limits<uint32_t>::max(); uint32_t minY=std::numeric_limits<uint32_t>::max(); uint32_t maxX=std::numeric_limits<uint32_t>::min(); uint32_t maxY=std::numeric_limits<uint32_t>::min(); std::map<TypeId,size_t> useMap; for (std::map<Pixel,AreaLeaf>::const_iterator leaf=leafs.begin(); leaf!=leafs.end(); ++leaf) { minX=std::min(minX,leaf->first.x); maxX=std::max(maxX,leaf->first.x); minY=std::min(minY,leaf->first.y); maxY=std::max(maxY,leaf->first.y); for (std::list<Entry>::const_iterator entry=leaf->second.areas.begin(); entry!=leaf->second.areas.end(); entry++) { std::map<TypeId,size_t>::iterator u=useMap.find(entry->type); if (u==useMap.end()) { useMap[entry->type]=1; } else { u->second++; } } }*/ /* std::cout << "[" << minX << "-" << maxX << "]x[" << minY << "-" << maxY << "] => " << leafs.size() << "/" << (maxX-minX+1)*(maxY-minY+1) << " " << (int)BytesNeededToAddressFileData(leafs.size()) << " " << ByteSizeToString(BytesNeededToAddressFileData(leafs.size())*(maxX-minX+1)*(maxY-minY+1)) << std::endl; for (std::map<TypeId,size_t>::const_iterator u=useMap.begin(); u!=useMap.end(); ++u) { std::cout << "* " << u->first << " " << typeConfig.GetTypeInfo(u->first).GetName() << " " << u->second << std::endl; }*/ if (!WriteIndexLevel(parameter, writer, (int)l, leafs)) { return false; } l--; } writer.SetPos(topLevelOffsetOffset); writer.WriteFileOffset(topLevelOffset); return !writer.HasError() && writer.Close(); }
bool WayNodeReductionProcessorFilter::RemoveDuplicateNodes(Progress& progress, const FileOffset& offset, Way& way, bool& save) { unsigned char buffers[2][coordByteSize]; bool reduced=false; if (way.nodes.size()>=2) { size_t lastIndex=0; size_t currentIndex=1; nodeBuffer.clear(); idBuffer.clear(); // Prefill with the first coordinate way.nodes[0].EncodeToBuffer(buffers[0]); nodeBuffer.push_back(way.nodes[0]); if (!way.ids.empty()) { idBuffer.push_back(way.ids[0]); } for (size_t n=1; n<way.nodes.size(); n++) { way.nodes[n].EncodeToBuffer(buffers[currentIndex]); if (IsEqual(buffers[lastIndex], buffers[currentIndex])) { if (n>=way.ids.size() || way.ids[n]==0) { duplicateCount++; reduced=true; } else if ((n-1)>=way.ids.size() || way.ids[n-1]==0) { way.ids[n-1]=way.ids[n]; duplicateCount++; reduced=true; } else { nodeBuffer.push_back(way.nodes[n]); if (n<way.ids.size()) { idBuffer.push_back(way.ids[n]); } lastIndex=currentIndex; currentIndex=(lastIndex+1)%2; } } else { nodeBuffer.push_back(way.nodes[n]); if (n<way.ids.size()) { idBuffer.push_back(way.ids[n]); } lastIndex=currentIndex; currentIndex=(lastIndex+1)%2; } } } if (reduced) { if (nodeBuffer.size()<2) { progress.Debug("Way " + NumberToString(offset) + " empty/invalid after node reduction"); save=false; return true; } else { way.nodes=nodeBuffer; way.ids=idBuffer; } } 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; }