/** * Processes the given number of ways. * * @param queryParameters the parameters of the current query. * @param mapDataSink the callback which handles the extracted ways. * @param numberOfWays how many ways should be processed. * @return true if the ways could be processed successfully, false otherwise. */ private boolean processWays( QueryParameters queryParameters, ITileDataSink mapDataSink, int numberOfWays) { Tag[] wayTags = mTileSource.fileInfo.wayTags; MapElement e = mElem; int numTags = 0; int wayDataBlocks; // skip string block int stringsSize = 0; stringOffset = 0; if (mTileSource.experimental) { stringsSize = mReadBuffer.readUnsignedInt(); stringOffset = mReadBuffer.getBufferPosition(); mReadBuffer.skipBytes(stringsSize); } // setTileClipping(queryParameters); for (int elementCounter = numberOfWays; elementCounter != 0; --elementCounter) { if (mDebugFile) { // get and check the way signature mSignatureWay = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_WAY); if (!mSignatureWay.startsWith("---WayStart")) { log.warn("invalid way signature: " + mSignatureWay); log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); return false; } } if (queryParameters.useTileBitmask) { elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask, elementCounter); if (elementCounter == 0) return true; if (elementCounter < 0) return false; if (mTileSource.experimental && mReadBuffer.lastTagPosition > 0) { int pos = mReadBuffer.getBufferPosition(); mReadBuffer.setBufferPosition(mReadBuffer.lastTagPosition); byte numberOfTags = (byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK); if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags)) return false; numTags = numberOfTags; mReadBuffer.setBufferPosition(pos); } } else { int wayDataSize = mReadBuffer.readUnsignedInt(); if (wayDataSize < 0) { log.warn("invalid way data size: " + wayDataSize); if (mDebugFile) { log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); } log.error("BUG way 2"); return false; } /* ignore the way tile bitmask (2 bytes) */ mReadBuffer.skipBytes(2); } /* get the special byte which encodes multiple flags */ byte specialByte = mReadBuffer.readByte(); /* bit 1-4 represent the layer */ byte layer = (byte) ((specialByte & WAY_LAYER_BITMASK) >>> WAY_LAYER_SHIFT); /* bit 5-8 represent the number of tag IDs */ byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK); if (numberOfTags != 0) { if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags)) return false; numTags = numberOfTags; } /* get the feature bitmask (1 byte) */ byte featureByte = mReadBuffer.readByte(); /* bit 1-6 enable optional features */ boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0; boolean hasName = (featureByte & WAY_FEATURE_NAME) != 0; boolean hasHouseNr = (featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0; boolean hasRef = (featureByte & WAY_FEATURE_REF) != 0; e.tags.numTags = numTags; if (mTileSource.experimental) { if (hasName) { int textPos = mReadBuffer.readUnsignedInt(); String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos); e.tags.add(new Tag(Tag.KEY_NAME, str, false)); } if (hasHouseNr) { int textPos = mReadBuffer.readUnsignedInt(); String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos); e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false)); } if (hasRef) { int textPos = mReadBuffer.readUnsignedInt(); String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos); e.tags.add(new Tag(Tag.KEY_REF, str, false)); } } else { if (hasName) { String str = mReadBuffer.readUTF8EncodedString(); e.tags.add(new Tag(Tag.KEY_NAME, str, false)); } if (hasHouseNr) { String str = mReadBuffer.readUTF8EncodedString(); e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false)); } if (hasRef) { String str = mReadBuffer.readUTF8EncodedString(); e.tags.add(new Tag(Tag.KEY_REF, str, false)); } } if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0) // labelPosition = readOptionalLabelPosition(); if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) { wayDataBlocks = mReadBuffer.readUnsignedInt(); if (wayDataBlocks < 1) { log.warn("invalid number of way data blocks: " + wayDataBlocks); logDebugSignatures(); return false; } } else { wayDataBlocks = 1; } /* some guessing if feature is a line or a polygon */ boolean linearFeature = e.tags.containsKey("highway") || e.tags.containsKey("boundary") || e.tags.containsKey("railway"); if (linearFeature) { Tag areaTag = e.tags.get("area"); if (areaTag != null && areaTag.value == Tag.VALUE_YES) linearFeature = false; } for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; wayDataBlock++) { e.clear(); if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature)) return false; /* drop invalid outer ring */ if (e.isPoly() && e.index[0] < 6) { continue; } mTileProjection.project(e); if (!e.tags.containsKey("building")) if (!mTileClipper.clip(e)) { continue; } e.simplify(1, true); e.setLayer(layer); mapDataSink.process(e); } } return true; }
/** * Processes the given number of POIs. * * @param mapDataSink the callback which handles the extracted POIs. * @param numberOfPois how many POIs should be processed. * @return true if the POIs could be processed successfully, false otherwise. */ private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois) { Tag[] poiTags = mTileSource.fileInfo.poiTags; MapElement e = mElem; int numTags = 0; for (int elementCounter = numberOfPois; elementCounter != 0; --elementCounter) { if (mDebugFile) { /* get and check the POI signature */ mSignaturePoi = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI); if (!mSignaturePoi.startsWith("***POIStart")) { log.warn("invalid POI signature: " + mSignaturePoi); log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); return false; } } /* get the POI latitude offset (VBE-S) */ int latitude = mTileLatitude + mReadBuffer.readSignedInt(); /* get the POI longitude offset (VBE-S) */ int longitude = mTileLongitude + mReadBuffer.readSignedInt(); /* get the special byte which encodes multiple flags */ byte specialByte = mReadBuffer.readByte(); /* bit 1-4 represent the layer */ byte layer = (byte) ((specialByte & POI_LAYER_BITMASK) >>> POI_LAYER_SHIFT); /* bit 5-8 represent the number of tag IDs */ byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK); if (numberOfTags != 0) { if (!mReadBuffer.readTags(e.tags, poiTags, numberOfTags)) return false; numTags = numberOfTags; } /* reset to common tag position */ e.tags.numTags = numTags; /* get the feature bitmask (1 byte) */ byte featureByte = mReadBuffer.readByte(); /* bit 1-3 enable optional features * check if the POI has a name */ if ((featureByte & POI_FEATURE_NAME) != 0) { String str = mReadBuffer.readUTF8EncodedString(); e.tags.add(new Tag(Tag.KEY_NAME, str, false)); } /* check if the POI has a house number */ if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) { // mReadBuffer.getPositionAndSkip(); // String str = mReadBuffer.readUTF8EncodedString(); } /* check if the POI has an elevation */ if ((featureByte & POI_FEATURE_ELEVATION) != 0) { mReadBuffer.readSignedInt(); // mReadBuffer.getPositionAndSkip();// tags.add(new // Tag(Tag.TAG_KEY_ELE, // Integer.toString(mReadBuffer.readSignedInt()))); } mTileProjection.projectPoint(latitude, longitude, e); e.setLayer(layer); mapDataSink.process(e); } return true; }
@Override public void query(MapTile tile, ITileDataSink sink) { if (mTileSource.fileHeader == null) { sink.completed(FAILED); return; } if (mIntBuffer == null) mIntBuffer = new int[MAXIMUM_WAY_NODES_SEQUENCE_LENGTH * 2]; try { mTileProjection.setTile(tile); // mTile = tile; /* size of tile in map coordinates; */ double size = 1.0 / (1 << tile.zoomLevel); /* simplification tolerance */ int pixel = (tile.zoomLevel > 11) ? 1 : 2; int simplify = Tile.SIZE / pixel; /* translate screen pixel for tile to latitude and longitude * tolerance for point reduction before projection. */ minDeltaLat = (int) (Math.abs( MercatorProjection.toLatitude(tile.y + size) - MercatorProjection.toLatitude(tile.y)) * 1e6) / simplify; minDeltaLon = (int) (Math.abs( MercatorProjection.toLongitude(tile.x + size) - MercatorProjection.toLongitude(tile.x)) * 1e6) / simplify; QueryParameters queryParameters = new QueryParameters(); queryParameters.queryZoomLevel = mTileSource.fileHeader.getQueryZoomLevel(tile.zoomLevel); /* get and check the sub-file for the query zoom level */ SubFileParameter subFileParameter = mTileSource.fileHeader.getSubFileParameter(queryParameters.queryZoomLevel); if (subFileParameter == null) { log.warn("no sub-file for zoom level: " + queryParameters.queryZoomLevel); sink.completed(FAILED); return; } QueryCalculations.calculateBaseTiles(queryParameters, tile, subFileParameter); QueryCalculations.calculateBlocks(queryParameters, subFileParameter); processBlocks(sink, queryParameters, subFileParameter); } catch (IOException e) { log.error(e.getMessage()); sink.completed(FAILED); return; } sink.completed(SUCCESS); }
private void processBlocks( ITileDataSink mapDataSink, QueryParameters queryParams, SubFileParameter subFileParameter) throws IOException { /* read and process all blocks from top to bottom and from left to right */ for (long row = queryParams.fromBlockY; row <= queryParams.toBlockY; row++) { for (long column = queryParams.fromBlockX; column <= queryParams.toBlockX; column++) { // mCurrentCol = column - queryParameters.fromBlockX; // mCurrentRow = row - queryParameters.fromBlockY; setTileClipping(queryParams, row - queryParams.fromBlockY, column - queryParams.fromBlockX); /* calculate the actual block number of the needed block in the * file */ long blockNumber = row * subFileParameter.blocksWidth + column; /* get the current index entry */ long blockIndexEntry = mTileSource.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber); /* check the water flag of the block in its index entry */ if ((blockIndexEntry & BITMASK_INDEX_WATER) != 0) { MapElement e = mElem; e.clear(); e.tags.clear(); e.tags.add(mWaterTag); e.startPolygon(); e.addPoint(xmin, ymin); e.addPoint(xmax, ymin); e.addPoint(xmax, ymax); e.addPoint(xmin, ymax); mapDataSink.process(e); } /* get and check the current block pointer */ long blockPointer = blockIndexEntry & BITMASK_INDEX_OFFSET; if (blockPointer < 1 || blockPointer > subFileParameter.subFileSize) { log.warn("invalid current block pointer: " + blockPointer); log.warn("subFileSize: " + subFileParameter.subFileSize); return; } 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 = mTileSource.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber + 1); nextBlockPointer &= BITMASK_INDEX_OFFSET; if (nextBlockPointer < 1 || nextBlockPointer > subFileParameter.subFileSize) { log.warn("invalid next block pointer: " + nextBlockPointer); log.warn("sub-file size: " + subFileParameter.subFileSize); return; } } /* calculate the size of the current block */ int blockSize = (int) (nextBlockPointer - blockPointer); if (blockSize < 0) { log.warn("current block size must not be negative: " + blockSize); return; } else if (blockSize == 0) { /* the current block is empty, continue with the next block */ continue; } else if (blockSize > ReadBuffer.MAXIMUM_BUFFER_SIZE) { /* the current block is too large, continue with the next * block */ log.warn("current block size too large: " + blockSize); continue; } else if (blockPointer + blockSize > mFileSize) { log.warn("current block larger than file size: " + blockSize); return; } /* seek to the current block in the map file */ mInputFile.seek(subFileParameter.startAddress + blockPointer); /* read the current block into the buffer */ if (!mReadBuffer.readFromFile(blockSize)) { /* skip the current block */ log.warn("reading current block has failed: " + blockSize); return; } /* calculate the top-left coordinates of the underlying tile */ double tileLatitudeDeg = Projection.tileYToLatitude( subFileParameter.boundaryTileTop + row, subFileParameter.baseZoomLevel); double tileLongitudeDeg = Projection.tileXToLongitude( subFileParameter.boundaryTileLeft + column, subFileParameter.baseZoomLevel); mTileLatitude = (int) (tileLatitudeDeg * 1E6); mTileLongitude = (int) (tileLongitudeDeg * 1E6); processBlock(queryParams, subFileParameter, mapDataSink); } } }
private boolean decodeTileElement(int type) throws IOException { int bytes = decodeVarint32(); short[] index = null; int end = position() + bytes; int indexCnt = 1; boolean fail = false; int coordCnt = 0; if (type == TAG_TILE_POINT) { coordCnt = 1; mElem.index[0] = 2; } mElem.layer = 5; // mElem.height = 0; // mElem.minHeight = 0; while (position() < end) { // read tag and wire type int val = decodeVarint32(); if (val == 0) break; int tag = (val >> 3); switch (tag) { case TAG_ELEM_TAGS: if (!decodeElementTags()) return false; break; case TAG_ELEM_NUM_INDICES: indexCnt = decodeVarint32(); break; case TAG_ELEM_INDEX: coordCnt = decodeWayIndices(indexCnt); break; case TAG_ELEM_COORDS: if (coordCnt == 0) { log.debug(mTile + " no coordinates"); } mElem.ensurePointSize(coordCnt, false); int cnt = decodeInterleavedPoints(mElem, mScale); if (cnt != coordCnt) { log.debug(mTile + " wrong number of coordintes"); fail = true; } break; case TAG_ELEM_LAYER: mElem.layer = decodeVarint32(); break; case TAG_ELEM_HEIGHT: // mElem.height = decodeVarint32(); break; case TAG_ELEM_MIN_HEIGHT: // mElem.minHeight = decodeVarint32(); break; case TAG_ELEM_PRIORITY: // mElem.priority = decodeVarint32(); break; default: log.debug(mTile + " invalid type for way: " + tag); } } if (fail || indexCnt == 0) { log.debug( mTile + " failed reading way: bytes:" + bytes + " index:" + (Arrays.toString(index)) + " tag:" + (mElem.tags.numTags > 0 ? Arrays.deepToString(mElem.tags.tags) : "null") + " " + indexCnt + " " + coordCnt); return false; } switch (type) { case TAG_TILE_LINE: mElem.type = GeometryType.LINE; break; case TAG_TILE_POLY: mElem.type = GeometryType.POLY; break; case TAG_TILE_POINT: mElem.type = GeometryType.POINT; break; } mMapDataSink.process(mElem); return true; }