/// <summary> /// Reads all map data for the area covered by the given tile at the tile zoom level. /// </summary> /// <param name="tile"> /// defines area and zoom level of read map data. </param> /// <returns> the read map data. </returns> public override MapReadResult ReadMapData(Tile tile) { lock (this) { try { QueryParameters queryParameters = new QueryParameters(); queryParameters.queryZoomLevel = this.mapFileHeader.GetQueryZoomLevel(tile.ZoomLevel); // get and check the sub-file for the query zoom level SubFileParameter subFileParameter = this.mapFileHeader.GetSubFileParameter(queryParameters.queryZoomLevel); if (subFileParameter == null) { LOGGER.Warn("no sub-file for zoom level: " + queryParameters.queryZoomLevel); return(null); } queryParameters.CalculateBaseTiles(tile, subFileParameter); queryParameters.CalculateBlocks(subFileParameter); // we enlarge the bounding box for the tile slightly in order to retain any data that // lies right on the border, some of this data needs to be drawn as the graphics will // overlap onto this tile. return(ProcessBlocks(queryParameters, subFileParameter, tile.BoundingBox)); } catch (IOException e) { LOGGER.Log(LogLevel.Fatal, e.Message, e); return(null); } } }
/// <summary> /// Reads all map data for the area covered by the given tile at the tile zoom level. /// </summary> /// <param name="tile"> /// defines area and zoom level of read map data. </param> /// <returns> the read map data. </returns> public MapReadResult ReadMapData(TileInfo tileInfo) { lock (sync) { try { QueryParameters queryParameters = new QueryParameters(); queryParameters.queryZoomLevel = this.mapFileHeader.GetQueryZoomLevel(sbyte.Parse(tileInfo.Index.Level)); // get and check the sub-file for the query zoom level SubFileParameter subFileParameter = this.mapFileHeader.GetSubFileParameter(queryParameters.queryZoomLevel); if (subFileParameter == null) { Logger.Log(LogLevel.Warning, "no sub-file for zoom level: " + queryParameters.queryZoomLevel); return(null); } queryParameters.CalculateBaseTiles(tileInfo, subFileParameter); queryParameters.CalculateBlocks(subFileParameter); // we enlarge the bounding box for the tile slightly in order to retain any data that // lies right on the border, some of this data needs to be drawn as the graphics will // overlap onto this tile. return(ProcessBlocks(queryParameters, subFileParameter, tileInfo.Extent.ToBoundingBox())); } catch (IOException e) { Logger.Log(LogLevel.Error, e.Message, e); return(null); } } }
public virtual void CalculateBaseTiles(Tile tile, SubFileParameter subFileParameter) { if (tile.ZoomLevel < subFileParameter.BaseZoomLevel) { // calculate the XY numbers of the upper left and lower right sub-tiles int zoomLevelDifference = subFileParameter.BaseZoomLevel - tile.ZoomLevel; this.fromBaseTileX = tile.TileX << zoomLevelDifference; this.fromBaseTileY = tile.TileY << zoomLevelDifference; this.toBaseTileX = this.fromBaseTileX + (1 << zoomLevelDifference) - 1; this.toBaseTileY = this.fromBaseTileY + (1 << zoomLevelDifference) - 1; this.useTileBitmask = false; } else if (tile.ZoomLevel > subFileParameter.BaseZoomLevel) { // calculate the XY numbers of the parent base tile int zoomLevelDifference = tile.ZoomLevel - subFileParameter.BaseZoomLevel; this.fromBaseTileX = (int)((uint)tile.TileX >> zoomLevelDifference); this.fromBaseTileY = (int)((uint)tile.TileY >> zoomLevelDifference); this.toBaseTileX = this.fromBaseTileX; this.toBaseTileY = this.fromBaseTileY; this.useTileBitmask = true; this.queryTileBitmask = QueryCalculations.CalculateTileBitmask(tile, zoomLevelDifference); } else { // use the tile XY numbers of the requested tile this.fromBaseTileX = tile.TileX; this.fromBaseTileY = tile.TileY; this.toBaseTileX = this.fromBaseTileX; this.toBaseTileY = this.fromBaseTileY; this.useTileBitmask = false; } }
private void ReadSubFileParameters(ReadBuffer readBuffer, long fileSize, MapFileInfoBuilder mapFileInfoBuilder) { sbyte numberOfSubFiles = readBuffer.ReadByte(); mapFileInfoBuilder.numberOfSubFiles = numberOfSubFiles; var tempSubFileParameters = new SubFileParameter[numberOfSubFiles]; zoomLevelMinimum = sbyte.MaxValue; zoomLevelMaximum = sbyte.MinValue; for (sbyte currentSubFile = 0; currentSubFile < numberOfSubFiles; ++currentSubFile) { var subFileParameterBuilder = new SubFileParameterBuilder(); sbyte baseZoomLevel = readBuffer.ReadByte(); subFileParameterBuilder.BaseZoomLevel = baseZoomLevel; sbyte zoomLevelMin = readBuffer.ReadByte(); subFileParameterBuilder.ZoomLevelMin = zoomLevelMin; sbyte zoomLevelMax = readBuffer.ReadByte(); subFileParameterBuilder.ZoomLevelMax = zoomLevelMax; long startAddress = readBuffer.ReadLong(); subFileParameterBuilder.StartAddress = startAddress; long indexStartAddress = startAddress; subFileParameterBuilder.IndexStartAddress = indexStartAddress; long subFileSize = readBuffer.ReadLong(); subFileParameterBuilder.SubFileSize = subFileSize; subFileParameterBuilder.BoundingBox = mapFileInfoBuilder.boundingBox; tempSubFileParameters[currentSubFile] = subFileParameterBuilder.Build(); if (zoomLevelMinimum > tempSubFileParameters[currentSubFile].ZoomLevelMin) { zoomLevelMinimum = tempSubFileParameters[currentSubFile].ZoomLevelMin; mapFileInfoBuilder.zoomLevelMin = zoomLevelMinimum; } if (zoomLevelMaximum < tempSubFileParameters[currentSubFile].ZoomLevelMax) { zoomLevelMaximum = tempSubFileParameters[currentSubFile].ZoomLevelMax; mapFileInfoBuilder.zoomLevelMax = zoomLevelMaximum; } } subFileParameters = new SubFileParameter[zoomLevelMaximum + 1]; for (int currentMapFile = 0; currentMapFile < numberOfSubFiles; ++currentMapFile) { var subFileParameter = tempSubFileParameters[currentMapFile]; for (sbyte zoomLevel = subFileParameter.ZoomLevelMin; zoomLevel <= subFileParameter.ZoomLevelMax; ++zoomLevel) { subFileParameters[zoomLevel] = subFileParameter; } } }
public static void calculateBlocks(QueryParameters queryParameters, SubFileParameter subFileParameter) { // calculate the blocks in the file which need to be read queryParameters.fromBlockX = Math.Max(queryParameters.fromBaseTileX - subFileParameter.BoundaryTileLeft, 0); queryParameters.fromBlockY = Math.Max(queryParameters.fromBaseTileY - subFileParameter.BoundaryTileTop, 0); queryParameters.toBlockX = Math.Min(queryParameters.toBaseTileX - subFileParameter.BoundaryTileLeft, subFileParameter.BlocksWidth - 1); queryParameters.toBlockY = Math.Min(queryParameters.toBaseTileY - subFileParameter.BoundaryTileTop, subFileParameter.BlocksHeight - 1); }
public virtual void CalculateBlocks(SubFileParameter subFileParameter) { // calculate the blocks in the file which need to be read this.fromBlockX = Math.Max(this.fromBaseTileX - subFileParameter.BoundaryTileLeft, 0); this.fromBlockY = Math.Max(this.fromBaseTileY - subFileParameter.BoundaryTileTop, 0); this.toBlockX = Math.Min(this.toBaseTileX - subFileParameter.BoundaryTileLeft, subFileParameter.BlocksWidth - 1); this.toBlockY = Math.Min(this.toBaseTileY - subFileParameter.BoundaryTileTop, subFileParameter.BlocksHeight - 1); }
private PoiWayBundle ProcessBlock(QueryParameters queryParameters, SubFileParameter subFileParameter, BoundingBox boundingBox, double tileLatitude, double tileLongitude, ReadBuffer readBuffer) { if (!ProcessBlockSignature(readBuffer)) { return(null); } int[][] zoomTable = ReadZoomTable(subFileParameter, readBuffer); int zoomTableRow = queryParameters.queryZoomLevel - subFileParameter.ZoomLevelMin; int poisOnQueryZoomLevel = zoomTable[zoomTableRow][0]; int waysOnQueryZoomLevel = zoomTable[zoomTableRow][1]; // get the relative offset to the first stored way in the block int firstWayOffset = readBuffer.ReadUnsignedInt(); if (firstWayOffset < 0) { Logger.Log(LogLevel.Warning, INVALID_FIRST_WAY_OFFSET + firstWayOffset); return(null); } // add the current buffer position to the relative first way offset firstWayOffset += readBuffer.BufferPosition; if (firstWayOffset > readBuffer.BufferSize) { Logger.Log(LogLevel.Warning, INVALID_FIRST_WAY_OFFSET + firstWayOffset); return(null); } bool filterRequired = queryParameters.queryZoomLevel > subFileParameter.BaseZoomLevel; IList <PointOfInterest> pois = ProcessPOIs(tileLatitude, tileLongitude, poisOnQueryZoomLevel, boundingBox, filterRequired, readBuffer); if (pois == null) { return(null); } // finished reading POIs, check if the current buffer position is valid if (readBuffer.BufferPosition > firstWayOffset) { Logger.Log(LogLevel.Warning, "invalid buffer position: " + readBuffer.BufferPosition); return(null); } // move the pointer to the first way readBuffer.BufferPosition = firstWayOffset; IList <Way> ways = ProcessWays(queryParameters, waysOnQueryZoomLevel, boundingBox, filterRequired, tileLatitude, tileLongitude, readBuffer); if (ways == null) { return(null); } return(new PoiWayBundle(pois, ways)); }
private NodeWayBundle ProcessBlock(QueryParameters queryParameters, SubFileParameter subFileParameter) { if (!processBlockSignature()) { return(null); } ZoomTable zoomTable = readZoomTable(subFileParameter); if (zoomTable == null) { return(null); } int zoomTableRow = queryParameters.queryZoomLevel - subFileParameter.ZoomLevelMin; int nodesOnQueryZoomLevel = zoomTable[zoomTableRow].NodesCount; int waysOnQueryZoomLevel = zoomTable[zoomTableRow].WaysCount; // get the relative offset to the first stored way in the block long firstWayOffset = this.readBuffer.ReadUnsignedInt(); if (firstWayOffset < 0) { return(null); } // add the current buffer position to the relative first way offset firstWayOffset += this.readBuffer.Position; if (firstWayOffset > this.readBuffer.Length) { return(null); } List <Node> nodes = processNodes(nodesOnQueryZoomLevel); if (nodes == null) { return(null); } // finished reading nodes, check if the current buffer position is valid if (this.readBuffer.Position > firstWayOffset) { return(null); } // move the pointer to the first way this.readBuffer.Position = firstWayOffset; List <Way> ways = processWays(queryParameters, waysOnQueryZoomLevel); if (ways == null) { return(null); } return(new NodeWayBundle(this.tile, nodes, ways)); }
/// <summary> /// Returns the index entry of a block in the given map file. If the required index entry is not cached, it will be /// read from the map file index and put in the cache. /// </summary> /// <param name="subFileParameter"> /// the parameters of the map file for which the index entry is needed. </param> /// <param name="blockNumber"> /// the number of the block in the map file. </param> /// <returns> the index entry. </returns> /// <exception cref="IOException"> /// if an I/O error occurs during reading. </exception> internal virtual long GetIndexEntry(SubFileParameter subFileParameter, long blockNumber) { // check if the block number is out of bounds if (blockNumber >= subFileParameter.NumberOfBlocks) { throw new IOException("invalid block number: " + blockNumber); } // calculate the index block number long indexBlockNumber = blockNumber / INDEX_ENTRIES_PER_BLOCK; // create the cache entry key for this request IndexCacheEntryKey indexCacheEntryKey = new IndexCacheEntryKey(subFileParameter, indexBlockNumber); // check for cached index block byte[] indexBlock = this.map.Get(indexCacheEntryKey); if (indexBlock == null) { // cache miss, seek to the correct index block in the file and read it long indexBlockPosition = subFileParameter.IndexStartAddress + indexBlockNumber * SIZE_OF_INDEX_BLOCK; int remainingIndexSize = (int)(subFileParameter.IndexEndAddress - indexBlockPosition); int indexBlockSize = Math.Min(SIZE_OF_INDEX_BLOCK, remainingIndexSize); indexBlock = new byte[indexBlockSize]; lock (sync) { this.randomAccessFile.Seek(indexBlockPosition, SeekOrigin.Begin); if (this.randomAccessFile.Read(indexBlock, 0, indexBlockSize) != indexBlockSize) { throw new IOException("could not read index block with size: " + indexBlockSize); } } // put the index block in the map this.map.Add(indexCacheEntryKey, indexBlock); } // calculate the address of the index entry inside the index block long indexEntryInBlock = blockNumber % INDEX_ENTRIES_PER_BLOCK; int addressInIndexBlock = (int)(indexEntryInBlock * SubFileParameter.BYTES_PER_INDEX_ENTRY); // return the real index entry return(Deserializer.GetFiveBytesLong((sbyte[])(Array)indexBlock, addressInIndexBlock)); }
/** * Returns the index entry of a block in the given map file. If the required index entry is not cached, it will be * read from the map file index and put in the cache. * * @param subFileParameter * the parameters of the map file for which the index entry is needed. * @param blockNumber * the number of the block in the map file. * @return the index entry. * @throws IOException * if an I/O error occurs during reading. */ public long getIndexEntry(SubFileParameter subFileParameter, long blockNumber) { // check if the block number is out of bounds if (blockNumber >= subFileParameter.NumberOfBlocks) { throw new IOException("invalid block number: " + blockNumber); } // calculate the index block number long indexBlockNumber = blockNumber / INDEX_ENTRIES_PER_BLOCK; // create the cache entry key for this request IndexCacheEntryKey indexCacheEntryKey = new IndexCacheEntryKey(subFileParameter, indexBlockNumber); // check for cached index block byte[] indexBlock; if (!this.map.TryGetValue(indexCacheEntryKey, out indexBlock)) { // cache miss, seek to the correct index block in the file and read it long indexBlockPosition = subFileParameter.IndexStartAddress + indexBlockNumber * SIZE_OF_INDEX_BLOCK; int remainingIndexSize = (int)(subFileParameter.IndexEndAddress - indexBlockPosition); int indexBlockSize = Math.Min(SIZE_OF_INDEX_BLOCK, remainingIndexSize); indexBlock = new byte[indexBlockSize]; this.Stream.Seek(indexBlockPosition, SeekOrigin.Begin); if (this.Stream.Read(indexBlock, 0, indexBlockSize) != indexBlockSize) { throw new IOException("could not read index block with size: " + indexBlockSize); } // put the index block in the map this.map.Add(indexCacheEntryKey, indexBlock); } // calculate the address of the index entry inside the index block long indexEntryInBlock = blockNumber % INDEX_ENTRIES_PER_BLOCK; int addressInIndexBlock = (int)(indexEntryInBlock * SubFileParameter.BytesPerIndexEntry); // return the real index entry return(Deserializer.GetLong(indexBlock, addressInIndexBlock, SubFileParameter.BytesPerIndexEntry)); }
private int[][] ReadZoomTable(SubFileParameter subFileParameter) { int rows = subFileParameter.ZoomLevelMax - subFileParameter.ZoomLevelMin + 1; //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: int[][] zoomTable = new int[rows][2]; int[][] zoomTable = RectangularArrays.ReturnRectangularIntArray(rows, 2); int cumulatedNumberOfPois = 0; int cumulatedNumberOfWays = 0; for (int row = 0; row < rows; ++row) { cumulatedNumberOfPois += this.readBuffer.ReadUnsignedInt(); cumulatedNumberOfWays += this.readBuffer.ReadUnsignedInt(); zoomTable[row][0] = cumulatedNumberOfPois; zoomTable[row][1] = cumulatedNumberOfWays; } return(zoomTable); }
/** * Reads all map data for the area covered by the given tile at the tile zoom level. * * @param tile * defines area and zoom level of read map data. * @return the read map data. */ public IMapReadResult ReadMapData(Tile tile) { try { prepareExecution(); QueryParameters queryParameters = new QueryParameters(); queryParameters.queryZoomLevel = this.mapFileHeader.getQueryZoomLevel(tile.ZoomFactor); // get and check the sub-file for the query zoom level SubFileParameter subFileParameter = this.mapFileHeader.getSubFileParameter(queryParameters.queryZoomLevel); if (subFileParameter == null) { return(null); } QueryCalculations.calculateBaseTiles(queryParameters, tile, subFileParameter); QueryCalculations.calculateBlocks(queryParameters, subFileParameter); return(processBlocks(queryParameters, subFileParameter)); } catch (IOException e) { return(null); } }
private ZoomTable readZoomTable(SubFileParameter subFileParameter) { int rows = subFileParameter.ZoomLevelMax - subFileParameter.ZoomLevelMin + 1; ZoomTable zoomTable = new ZoomTable(rows); int cumulatedNumberOfnodes = 0; int cumulatedNumberOfWays = 0; for (int row = 0; row < rows; ++row) { cumulatedNumberOfnodes += this.readBuffer.ReadUnsignedInt(); cumulatedNumberOfWays += this.readBuffer.ReadUnsignedInt(); if (cumulatedNumberOfnodes < 0 || cumulatedNumberOfnodes > MAXIMUM_ZOOM_TABLE_OBJECTS) { System.Diagnostics.Debug.WriteLine("invalid cumulated number of nodes in row " + row + ' ' + cumulatedNumberOfnodes); if (this.mapFileHeader.MapFileInfo.DebugFile) { System.Diagnostics.Debug.WriteLine(DEBUG_SIGNATURE_BLOCK + this.signatureBlock); } return(null); } else if (cumulatedNumberOfWays < 0 || cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) { System.Diagnostics.Debug.WriteLine("invalid cumulated number of ways in row " + row + ' ' + cumulatedNumberOfWays); if (this.mapFileHeader.MapFileInfo.DebugFile) { System.Diagnostics.Debug.WriteLine(DEBUG_SIGNATURE_BLOCK + this.signatureBlock); } return(null); } zoomTable[row] = new ZoomTable.ZoomTableEntry(cumulatedNumberOfnodes, cumulatedNumberOfWays); } return(zoomTable); }
private int[][] ReadZoomTable(SubFileParameter subFileParameter, ReadBuffer readBuffer) { int rows = subFileParameter.ZoomLevelMax - subFileParameter.ZoomLevelMin + 1; int[][] zoomTable = new int[rows][]; for (int array1 = 0; array1 < rows; array1++) { zoomTable[array1] = new int[2]; } int cumulatedNumberOfPois = 0; int cumulatedNumberOfWays = 0; for (int row = 0; row < rows; ++row) { cumulatedNumberOfPois += readBuffer.ReadUnsignedInt(); cumulatedNumberOfWays += readBuffer.ReadUnsignedInt(); zoomTable[row][0] = cumulatedNumberOfPois; zoomTable[row][1] = cumulatedNumberOfWays; } return(zoomTable); }
private void ReadSubFileParameters(ReadBuffer readBuffer, long fileSize, MapFileInfoBuilder mapFileInfoBuilder) { // get and check the number of sub-files (1 byte) sbyte numberOfSubFiles = readBuffer.ReadByte(); if (numberOfSubFiles < 1) { throw new MapFileException("invalid number of sub-files: " + numberOfSubFiles); } mapFileInfoBuilder.numberOfSubFiles = numberOfSubFiles; SubFileParameter[] tempSubFileParameters = new SubFileParameter[numberOfSubFiles]; this.zoomLevelMinimum = sbyte.MaxValue; this.zoomLevelMaximum = sbyte.MinValue; // get and check the information for each sub-file for (sbyte currentSubFile = 0; currentSubFile < numberOfSubFiles; ++currentSubFile) { SubFileParameterBuilder subFileParameterBuilder = new SubFileParameterBuilder(); // get and check the base zoom level (1 byte) sbyte baseZoomLevel = readBuffer.ReadByte(); if (baseZoomLevel < 0 || baseZoomLevel > BASE_ZOOM_LEVEL_MAX) { throw new MapFileException("invalid base zoom level: " + baseZoomLevel); } subFileParameterBuilder.BaseZoomLevel = baseZoomLevel; // get and check the minimum zoom level (1 byte) sbyte zoomLevelMin = readBuffer.ReadByte(); if (zoomLevelMin < 0 || zoomLevelMin > 22) { throw new MapFileException("invalid minimum zoom level: " + zoomLevelMin); } subFileParameterBuilder.ZoomLevelMin = zoomLevelMin; // get and check the maximum zoom level (1 byte) sbyte zoomLevelMax = readBuffer.ReadByte(); if (zoomLevelMax < 0 || zoomLevelMax > 22) { throw new MapFileException("invalid maximum zoom level: " + zoomLevelMax); } subFileParameterBuilder.ZoomLevelMax = zoomLevelMax; // check for valid zoom level range if (zoomLevelMin > zoomLevelMax) { throw new MapFileException("invalid zoom level range: " + zoomLevelMin + SPACE + zoomLevelMax); } // get and check the start address of the sub-file (8 bytes) long startAddress = readBuffer.ReadLong(); if (startAddress < HEADER_SIZE_MIN || startAddress >= fileSize) { throw new MapFileException("invalid start address: " + startAddress); } subFileParameterBuilder.StartAddress = startAddress; long indexStartAddress = startAddress; if (mapFileInfoBuilder.optionalFields.IsDebugFile) { // the sub-file has an index signature before the index indexStartAddress += SIGNATURE_LENGTH_INDEX; } subFileParameterBuilder.IndexStartAddress = indexStartAddress; // get and check the size of the sub-file (8 bytes) long subFileSize = readBuffer.ReadLong(); if (subFileSize < 1) { throw new MapFileException("invalid sub-file size: " + subFileSize); } subFileParameterBuilder.SubFileSize = subFileSize; subFileParameterBuilder.BoundingBox = mapFileInfoBuilder.boundingBox; // add the current sub-file to the list of sub-files tempSubFileParameters[currentSubFile] = subFileParameterBuilder.Build(); // update the global minimum and maximum zoom level information if (this.zoomLevelMinimum > tempSubFileParameters[currentSubFile].ZoomLevelMin) { this.zoomLevelMinimum = tempSubFileParameters[currentSubFile].ZoomLevelMin; mapFileInfoBuilder.zoomLevelMin = this.zoomLevelMinimum; } if (this.zoomLevelMaximum < tempSubFileParameters[currentSubFile].ZoomLevelMax) { this.zoomLevelMaximum = tempSubFileParameters[currentSubFile].ZoomLevelMax; mapFileInfoBuilder.zoomLevelMax = this.zoomLevelMaximum; } } // create and fill the lookup table for the sub-files this.subFileParameters = new SubFileParameter[this.zoomLevelMaximum + 1]; for (int currentMapFile = 0; currentMapFile < numberOfSubFiles; ++currentMapFile) { SubFileParameter subFileParameter = tempSubFileParameters[currentMapFile]; for (sbyte zoomLevel = subFileParameter.ZoomLevelMin; zoomLevel <= subFileParameter.ZoomLevelMax; ++zoomLevel) { this.subFileParameters[zoomLevel] = subFileParameter; } } }
/// <summary> /// Creates an immutable key to be stored in a map. /// </summary> /// <param name="subFileParameter"> /// the parameters of the map file. </param> /// <param name="indexBlockNumber"> /// the number of the index block. </param> internal IndexCacheEntryKey(SubFileParameter subFileParameter, long indexBlockNumber) { this.subFileParameter = subFileParameter; this.indexBlockNumber = indexBlockNumber; this.hashCodeValue = CalculateHashCode(); }
private MapReadResult processBlocks(QueryParameters queryParameters, SubFileParameter subFileParameter) { bool queryIsWater = true; bool queryReadWaterInfo = false; MapReadResultBuilder mapReadResultBuilder = new MapReadResultBuilder(); // read and process all blocks from top to bottom and from left to right for (long row = queryParameters.fromBlockY; row <= queryParameters.toBlockY; ++row) { for (long column = queryParameters.fromBlockX; column <= queryParameters.toBlockX; ++column) { // calculate the actual block number of the needed block in the file long blockNumber = row * subFileParameter.BlocksWidth + column; // get the current index entry long currentBlockIndexEntry = this.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber); // check if the current query would still return a water tile if (queryIsWater) { // check the water flag of the current block in its index entry queryIsWater &= (currentBlockIndexEntry & BITMASK_INDEX_WATER) != 0; queryReadWaterInfo = true; } // get and check the current block pointer long currentBlockpointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET; if (currentBlockpointer < 1 || currentBlockpointer > subFileParameter.SubFileSize) { System.Diagnostics.Debug.WriteLine("invalid current block pointer: " + currentBlockpointer); System.Diagnostics.Debug.WriteLine("subFileSize: " + subFileParameter.SubFileSize); return(null); } long nextBlockpointer; // check if the current block is the last block in the file if (blockNumber + 1 == subFileParameter.NumberOfBlocks) { // set the next block pointer to the end of the file nextBlockpointer = subFileParameter.SubFileSize; } else { // get and check the next block pointer nextBlockpointer = this.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber + 1) & BITMASK_INDEX_OFFSET; if (nextBlockpointer > subFileParameter.SubFileSize) { System.Diagnostics.Debug.WriteLine("invalid next block pointer: " + nextBlockpointer); System.Diagnostics.Debug.WriteLine("sub-file size: " + subFileParameter.SubFileSize); return(null); } } // calculate the size of the current block int currentBlockSize = (int)(nextBlockpointer - currentBlockpointer); if (currentBlockSize < 0) { System.Diagnostics.Debug.WriteLine("current block size must not be negative: " + currentBlockSize); return(null); } else if (currentBlockSize == 0) { // the current block is empty, continue with the next block continue; } else if (currentBlockSize > BufferStream.MAXIMUM_BUFFER_SIZE) { // the current block is too large, continue with the next block System.Diagnostics.Debug.WriteLine("current block size too large: " + currentBlockSize); continue; } else if (currentBlockpointer + currentBlockSize > this.fileSize) { System.Diagnostics.Debug.WriteLine("current block largher than file size: " + currentBlockSize); return(null); } // seek to the current block in the map file this.inputFile.Seek(subFileParameter.StartAddress + currentBlockpointer, SeekOrigin.Begin); // read the current block into the buffer if (!this.readBuffer.ReadFromFile(currentBlockSize)) { // skip the current block System.Diagnostics.Debug.WriteLine("reading current block has failed: " + currentBlockSize); return(null); } // calculate the top-left coordinates of the underlying tile this.tile = new Tile( subFileParameter.BoundaryTileLeft + column, subFileParameter.BoundaryTileTop + row, subFileParameter.BaseZoomLevel, Projection.TileSize ); this.tilePosition = Projection.MappointToGeoPoint(tile.MapPoint1); try { NodeWayBundle nodeWayBundle = ProcessBlock(queryParameters, subFileParameter); mapReadResultBuilder.Add(nodeWayBundle); } catch (IndexOutOfRangeException e) { System.Diagnostics.Debug.WriteLine(e.Message); } } } // the query is finished, was the water flag set for all blocks? if (queryIsWater && queryReadWaterInfo) { mapReadResultBuilder.isWater = true; } return(mapReadResultBuilder.build()); }
private MapReadResult ProcessBlocks(QueryParameters queryParameters, SubFileParameter subFileParameter, BoundingBox boundingBox) { bool queryIsWater = true; bool queryReadWaterInfo = false; MapReadResult mapFileReadResult = new MapReadResult(); // read and process all blocks from top to bottom and from left to right for (long row = queryParameters.fromBlockY; row <= queryParameters.toBlockY; ++row) { for (long column = queryParameters.fromBlockX; column <= queryParameters.toBlockX; ++column) { // calculate the actual block number of the needed block in the file long blockNumber = row * subFileParameter.BlocksWidth + column; // get the current index entry long currentBlockIndexEntry = this.databaseIndexCache.GetIndexEntry(subFileParameter, blockNumber); // check if the current query would still return a water tile if (queryIsWater) { // check the water flag of the current block in its index entry queryIsWater &= (currentBlockIndexEntry & BITMASK_INDEX_WATER) != 0; queryReadWaterInfo = true; } // get and check the current block pointer long currentBlockPointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET; if (currentBlockPointer < 1 || currentBlockPointer > subFileParameter.SubFileSize) { Logger.Log(LogLevel.Warning, "invalid current block pointer: " + currentBlockPointer); Logger.Log(LogLevel.Warning, "subFileSize: " + subFileParameter.SubFileSize); return(null); } long nextBlockPointer; // check if the current block is the last block in the file if (blockNumber + 1 == subFileParameter.NumberOfBlocks) { // set the next block pointer to the end of the file nextBlockPointer = subFileParameter.SubFileSize; } else { // get and check the next block pointer nextBlockPointer = this.databaseIndexCache.GetIndexEntry(subFileParameter, blockNumber + 1) & BITMASK_INDEX_OFFSET; if (nextBlockPointer > subFileParameter.SubFileSize) { Logger.Log(LogLevel.Warning, "invalid next block pointer: " + nextBlockPointer); Logger.Log(LogLevel.Warning, "sub-file size: " + subFileParameter.SubFileSize); return(null); } } // calculate the size of the current block int currentBlockSize = (int)(nextBlockPointer - currentBlockPointer); if (currentBlockSize < 0) { Logger.Log(LogLevel.Warning, "current block size must not be negative: " + currentBlockSize); return(null); } else if (currentBlockSize == 0) { // the current block is empty, continue with the next block continue; } else if (currentBlockSize > ReadBuffer.MaximumBufferSize) { // the current block is too large, continue with the next block Logger.Log(LogLevel.Warning, "current block size too large: " + currentBlockSize); continue; } else if (currentBlockPointer + currentBlockSize > this.fileSize) { Logger.Log(LogLevel.Warning, "current block largher than file size: " + currentBlockSize); return(null); } // read the current block into the buffer ReadBuffer readBuffer = new ReadBuffer(inputStream); if (!readBuffer.ReadFromStream(subFileParameter.StartAddress + currentBlockPointer, currentBlockSize)) { // skip the current block Logger.Log(LogLevel.Warning, "reading current block has failed: " + currentBlockSize); return(null); } // calculate the top-left coordinates of the underlying tile double tileLatitude = MercatorProjection.TileYToLatitude(subFileParameter.BoundaryTileTop + row, subFileParameter.BaseZoomLevel); double tileLongitude = MercatorProjection.TileXToLongitude(subFileParameter.BoundaryTileLeft + column, subFileParameter.BaseZoomLevel); try { PoiWayBundle poiWayBundle = ProcessBlock(queryParameters, subFileParameter, boundingBox, tileLatitude, tileLongitude, readBuffer); if (poiWayBundle != null) { mapFileReadResult.Add(poiWayBundle); } } catch (System.IndexOutOfRangeException e) { Logger.Log(LogLevel.Error, e.Message, e); } } } // the query is finished, was the water flag set for all blocks? if (queryIsWater && queryReadWaterInfo) { // Deprecate water tiles rendering // mapFileReadResult.IsWater = true; } return(mapFileReadResult); }
public static void calculateBaseTiles(QueryParameters queryParameters, Tile tile, SubFileParameter subFileParameter) { if (tile.ZoomFactor < subFileParameter.BaseZoomLevel) { // calculate the XY numbers of the upper left and lower right sub-tiles int zoomLevelDifference = subFileParameter.BaseZoomLevel - tile.ZoomFactor; queryParameters.fromBaseTileX = tile.TileX << zoomLevelDifference; queryParameters.fromBaseTileY = tile.TileY << zoomLevelDifference; queryParameters.toBaseTileX = queryParameters.fromBaseTileX + (1 << zoomLevelDifference) - 1; queryParameters.toBaseTileY = queryParameters.fromBaseTileY + (1 << zoomLevelDifference) - 1; queryParameters.useTileBitmask = false; } else if (tile.ZoomFactor > subFileParameter.BaseZoomLevel) { // calculate the XY numbers of the parent base tile int zoomLevelDifference = tile.ZoomFactor - subFileParameter.BaseZoomLevel; queryParameters.fromBaseTileX = tile.TileX >> zoomLevelDifference; queryParameters.fromBaseTileY = tile.TileY >> zoomLevelDifference; queryParameters.toBaseTileX = queryParameters.fromBaseTileX; queryParameters.toBaseTileY = queryParameters.fromBaseTileY; queryParameters.useTileBitmask = true; queryParameters.queryTileBitmask = calculateTileBitmask(tile, zoomLevelDifference); } else { // use the tile XY numbers of the requested tile queryParameters.fromBaseTileX = tile.TileX; queryParameters.fromBaseTileY = tile.TileY; queryParameters.toBaseTileX = queryParameters.fromBaseTileX; queryParameters.toBaseTileY = queryParameters.fromBaseTileY; queryParameters.useTileBitmask = false; } }