Ejemplo n.º 1
0
  @Override
  protected void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {

    if (shadow) {
      return;
    }

    final int size = mPoints.size();
    if (size < 2) {
      // nothing to paint
      return;
    }

    final Projection pj = mapView.getProjection();
    // 180° in longitude in pixels, for avoiding lines > 180° in length
    final int halfMapSize = TileSystem.MapSize(mapView.getProjection().getZoomLevel()) / 2;
    // southern Limit of the map in Pixels, for detecting map crossing lines
    final int southLimit = pj.toPixelsFromMercator(0, halfMapSize * 2, null).y - 1;
    final int northLimit = southLimit - halfMapSize * 2 + 1;
    // calculate clipBounds in screen coordinates for removing "invisible" line segments
    final Rect clipBounds = new Rect(0, 0, mapView.getWidth() - 1, mapView.getHeight() - 1);
    // take into account map orientation:
    if (mapView.getMapOrientation() != 0.0f)
      GeometryMath.getBoundingBoxForRotatatedRectangle(
          clipBounds, mapView.getMapOrientation(), clipBounds);

    // area of visible line segments
    Rect pathExtension =
        new Rect(
            clipBounds); // used for decision: canvas.draw (fast) or bitmap draw (slow, avoiding
                         // OpenGLRenderer problem)
    boolean lineVisible = false;

    // precompute new points to the intermediate projection.
    precomputePoints(pj);

    final Point projectedPoint0 = mPoints.get(0); // points from the points list

    final Point screenPoint0 =
        pj.toPixelsFromProjected(projectedPoint0, mTempPoint1); // points on screen
    if (screenPoint0.y < northLimit) screenPoint0.y += 2 * halfMapSize;
    Point projectedPoint1;
    Point screenPoint1;

    mPath.rewind();

    for (int i = 1; i < size; i++) {

      // compute next points
      projectedPoint1 = mPoints.get(i);
      screenPoint1 = pj.toPixelsFromProjected(projectedPoint1, this.mTempPoint2);
      if (screenPoint1.y < northLimit) screenPoint1.y += 2 * halfMapSize;
      if (Math.abs(screenPoint1.x - screenPoint0.x) + Math.abs(screenPoint1.y - screenPoint0.y) <= 1
          && screenPoint0.y != southLimit
          && screenPoint1.y != southLimit) { // do not skip points  crossing maps!
        // skip this point, too close to previous point
        continue;
      }

      // check for lines exceeding 180° in longitude, cut line into two segments
      if ((Math.abs(screenPoint1.x - screenPoint0.x) > halfMapSize)
          // check for lines crossing the southern limit
          || (screenPoint1.y > southLimit) != (screenPoint0.y > southLimit)) {
        // handle x and y coordinates separately
        int x0 = screenPoint0.x;
        int y0 = screenPoint0.y;
        int x1 = screenPoint1.x;
        int y1 = screenPoint1.y;

        // first check x
        if (Math.abs(screenPoint1.x - screenPoint0.x) > halfMapSize) { // x has to be adjusted
          if (screenPoint1.x < mapView.getWidth() / 2) {
            // screenPoint1 is left of screenPoint0
            x1 += halfMapSize * 2; // set x1 360° east of screenPoint1
            x0 -= halfMapSize * 2; // set x0 360° west of screenPoint0
          } else {
            x1 -= halfMapSize * 2;
            x0 += halfMapSize * 2;
          }
        }

        // now check y
        if ((screenPoint1.y > southLimit) != (screenPoint0.y > southLimit)) {
          // line is crossing from one map to the other
          if (screenPoint1.y > southLimit) {
            // screenPoint1 was switched to map below
            y1 -= halfMapSize * 2; // set y1 into northern map
            y0 += halfMapSize * 2; // set y0 into map below
          } else {
            y1 += halfMapSize * 2;
            y0 -= halfMapSize * 2;
          }
        }
        // create rectangle of line segment, ensure top < bottom and right < left  to obtain valid
        // rectangle!
        mLineBounds.set(
            Math.min(screenPoint0.x, x1),
            Math.min(screenPoint0.y, y1),
            Math.max(screenPoint0.x, x1),
            Math.max(screenPoint0.y, y1));
        // check whether this line segment is visible
        if (Rect.intersects(clipBounds, mLineBounds)) {
          mPath.moveTo(screenPoint0.x, screenPoint0.y);
          mPath.lineTo(x1, y1);
          pathExtension.union(
              mLineBounds); // caution! buggy for invalid rectangles (top > bottom or right > left)
                            // !
          lineVisible = true;
        }
        screenPoint0.x = x0;
        screenPoint0.y = y0;
      } // end of line break check

      // check, whether this line segment is visible, ensure top < bottom and right < left  to
      // obtain valid rectangle!
      mLineBounds.set(
          Math.min(screenPoint0.x, screenPoint1.x),
          Math.min(screenPoint0.y, screenPoint1.y),
          Math.max(screenPoint0.x, screenPoint1.x),
          Math.max(screenPoint0.y, screenPoint1.y));
      if (Rect.intersects(clipBounds, mLineBounds)) {
        mPath.moveTo(screenPoint0.x, screenPoint0.y);
        mPath.lineTo(screenPoint1.x, screenPoint1.y);
        pathExtension.union(mLineBounds);
        lineVisible = true;
      }

      // update starting point to next position
      screenPoint0.x = screenPoint1.x;
      screenPoint0.y = screenPoint1.y;
    }

    // send only visible lines to canvas, not segments outside screen area
    if (lineVisible) {

      //  check, whether visible line segments cover less than 2048 pixels rectangle.
      if (Math.max(pathExtension.width(), pathExtension.height()) <= 2048) {
        //  Use fast canvas.drawPath method.
        canvas.drawPath(mPath, mPaint);
      } else {

        // fixing W/OpenGLRenderer(29239): Shape path too large to be rendered into a texture.
        // This will occur, if memory exceeds 2040 pixels => Path will disappear.
        // Draw path into temporary bitmap in screen size, then send bitmap to screen canvas.
        // <application android:hardwareAccelerated="false" > does not fix the OpenGLRenderer
        // problem!
        // Line (80, 80) to (-80, 80) will disappear at zoomLevel 4, Line (90, 90) to (-90, 90) at
        // zoomLevel 3
        final Rect dest = new Rect(0, 0, mapView.getWidth() - 1, mapView.getHeight() - 1);
        //          dest.set(0, 0, mapView.getWidth()-1,  mapView.getHeight()-1);
        //          final Bitmap.Config conf = Bitmap.Config.ARGB_8888; // 8 bit Aplpha, RGB
        if (mBmp == null
            || mBmp.getWidth() != mapView.getWidth()
            || mBmp.getHeight() != mapView.getHeight()) { // create Bitmap only once if needed
          mBmp =
              Bitmap.createBitmap(
                  mapView.getWidth(),
                  mapView.getHeight(),
                  Bitmap.Config.ARGB_8888); // this most time consuming step, app. 30 ms!
        } else
          mBmp.eraseColor(
              Color
                  .TRANSPARENT); // recycle bitmap and erase the old bitmap, much faster 0.6 .. 0.9
                                 // ms
        final Canvas bmpcanvas = new Canvas(mBmp);
        // Draw path to bitmap according to actual screen rotation
        if (mapView.getMapOrientation() != 0.0f)
          bmpcanvas.rotate(
              mapView.getMapOrientation(), mapView.getWidth() / 2, mapView.getHeight() / 2);
        bmpcanvas.drawPath(mPath, mPaint);

        // Draw bitmap according to actual screen rotation, derotate canvas if necessary
        if (mapView.getMapOrientation() != 0.0f)
          canvas.rotate(
              -mapView.getMapOrientation(), mapView.getWidth() / 2, mapView.getHeight() / 2);
        canvas.drawBitmap(mBmp, dest, dest, null);
        // restore canvas rotation if necessary
        if (mapView.getMapOrientation() != 0.0f)
          canvas.rotate(
              mapView.getMapOrientation(), mapView.getWidth() / 2, mapView.getHeight() / 2);
      }
    }
  }
Ejemplo n.º 2
0
  protected void drawOld(final Canvas canvas, final MapView mapView, final boolean shadow) {

    if (shadow) {
      return;
    }

    final int size = this.mPoints.size();
    if (size < 2) {
      // nothing to paint
      return;
    }

    final Projection pj = mapView.getProjection();

    // precompute new points to the intermediate projection.
    precomputePoints(pj);

    Point screenPoint0 = null; // points on screen
    Point screenPoint1;
    Point projectedPoint0; // points from the points list
    Point projectedPoint1;

    // clipping rectangle in the intermediate projection, to avoid performing projection.
    BoundingBoxE6 boundingBox = pj.getBoundingBox();
    Point topLeft =
        pj.toProjectedPixels(boundingBox.getLatNorthE6(), boundingBox.getLonWestE6(), null);
    Point bottomRight =
        pj.toProjectedPixels(boundingBox.getLatSouthE6(), boundingBox.getLonEastE6(), null);
    final Rect clipBounds = new Rect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
    // take into account map orientation:
    if (mapView.getMapOrientation() != 0.0f)
      GeometryMath.getBoundingBoxForRotatatedRectangle(
          clipBounds, mapView.getMapOrientation(), clipBounds);

    mPath.rewind();
    projectedPoint0 = this.mPoints.get(size - 1);
    mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);

    for (int i = size - 2; i >= 0; i--) {
      // compute next points
      projectedPoint1 = this.mPoints.get(i);
      mLineBounds.union(projectedPoint1.x, projectedPoint1.y);

      if (!Rect.intersects(clipBounds, mLineBounds)) {
        // skip this line, move to next point
        projectedPoint0 = projectedPoint1;
        screenPoint0 = null;
        continue;
      }

      // the starting point may be not calculated, because previous segment was out of clip
      // bounds
      if (screenPoint0 == null) {
        screenPoint0 = pj.toPixelsFromProjected(projectedPoint0, this.mTempPoint1);
        mPath.moveTo(screenPoint0.x, screenPoint0.y);
      }

      screenPoint1 = pj.toPixelsFromProjected(projectedPoint1, this.mTempPoint2);

      // skip this point, too close to previous point
      if (Math.abs(screenPoint1.x - screenPoint0.x) + Math.abs(screenPoint1.y - screenPoint0.y)
          <= 1) {
        continue;
      }

      mPath.lineTo(screenPoint1.x, screenPoint1.y);

      // update starting point to next position
      projectedPoint0 = projectedPoint1;
      screenPoint0.x = screenPoint1.x;
      screenPoint0.y = screenPoint1.y;
      mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);
    }

    canvas.drawPath(mPath, mPaint);
  }