예제 #1
0
  /**
   * 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;
  }
예제 #2
0
  /**
   * 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;
  }
예제 #3
0
  @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);
  }
예제 #4
0
  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);
      }
    }
  }
예제 #5
0
    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;
    }