protected void drawMyLocation(
      final Canvas canvas,
      final MapView mapView,
      final Location lastFix,
      final GeoPoint myLocation) {

    final Projection pj = mapView.getProjection();
    pj.toMapPixels(mMyLocation, mMapCoords);

    if (mDrawAccuracyEnabled) {
      final float radius = pj.metersToEquatorPixels(lastFix.getAccuracy());

      mCirclePaint.setAlpha(50);
      mCirclePaint.setStyle(Style.FILL);
      canvas.drawCircle(mMapCoords.x, mMapCoords.y, radius, mCirclePaint);

      mCirclePaint.setAlpha(150);
      mCirclePaint.setStyle(Style.STROKE);
      canvas.drawCircle(mMapCoords.x, mMapCoords.y, radius, mCirclePaint);
    }

    canvas.getMatrix(mMatrix);
    mMatrix.getValues(mMatrixValues);

    if (DEBUGMODE) {
      final float tx = (-mMatrixValues[Matrix.MTRANS_X] + 20) / mMatrixValues[Matrix.MSCALE_X];
      final float ty = (-mMatrixValues[Matrix.MTRANS_Y] + 90) / mMatrixValues[Matrix.MSCALE_Y];
      canvas.drawText("Lat: " + lastFix.getLatitude(), tx, ty + 5, mPaint);
      canvas.drawText("Lon: " + lastFix.getLongitude(), tx, ty + 20, mPaint);
      canvas.drawText("Cog: " + lastFix.getBearing(), tx, ty + 35, mPaint);
      canvas.drawText("Acc: " + lastFix.getAccuracy(), tx, ty + 50, mPaint);
      canvas.drawText("Kts: " + lastFix.getSpeed() / 1.94384449, tx, ty + 65, mPaint);
    }

    // TODO: read from compass if available for bearing
    if (lastFix.hasBearing()) {
      /*
       * Rotate the direction-Arrow according to the bearing we are driving. And draw it
       * to the canvas.
       */
      directionRotater.setRotate(
          lastFix.getBearing(), DIRECTION_ARROW_CENTER_X, DIRECTION_ARROW_CENTER_Y);

      directionRotater.postTranslate(-DIRECTION_ARROW_CENTER_X, -DIRECTION_ARROW_CENTER_Y);
      directionRotater.postScale(
          1 / mMatrixValues[Matrix.MSCALE_X], 1 / mMatrixValues[Matrix.MSCALE_Y]);
      directionRotater.postTranslate(mMapCoords.x, mMapCoords.y);
      canvas.drawBitmap(DIRECTION_ARROW, directionRotater, mPaint);
    } else {
      directionRotater.setTranslate(-NULLDIRECTION_ICON_CENTER_X, -NULLDIRECTION_ICON_CENTER_Y);
      directionRotater.postScale(
          1 / mMatrixValues[Matrix.MSCALE_X], 1 / mMatrixValues[Matrix.MSCALE_Y]);
      directionRotater.postTranslate(mMapCoords.x, mMapCoords.y);
      canvas.drawBitmap(NULLDIRECTION_ICON, directionRotater, mPaint);
    }
  }
 public boolean onSnapToItem(
     final int x, final int y, final Point snapPoint, final MapView mapView) {
   if (this.mLocation != null) {
     final Projection pj = mapView.getProjection();
     pj.toMapPixels(new GeoPoint(mLocation), mMapCoords);
     snapPoint.x = mMapCoords.x;
     snapPoint.y = mMapCoords.y;
     final double xDiff = x - mMapCoords.x;
     final double yDiff = y - mMapCoords.y;
     final boolean snap = xDiff * xDiff + yDiff * yDiff < 64;
     if (DEBUGMODE) {
       logger.debug("snap=" + snap);
     }
     return snap;
   } else {
     return false;
   }
 }
  /** This function does some fancy drawing, could be shortened a lot. */
  @Override
  public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
    try {
      /* DEBUG Output */
      //		final long startMs = System.currentTimeMillis();
      //		long routedrawStartMs = 0, routedrawEndMs = 0;
      /* END DEBUG Output */

      /* Get the width/height of the underlying MapView.*/
      final int mapViewWidth = this.myDDMapActivity.getMapViewWidth();
      final int mapViewHeight = this.myDDMapActivity.getMapViewHeight();
      //		final GeoPoint curMapCenter = mapView.getMapCenter();

      /* Will hold various screen-coordinates. */
      final Point screenCoords = new Point();

      final Navigator nav = this.myDDMapActivity.getNavigator();

      /* Method in our custom map view
       * to return the DrivingDirection object. */
      this.mRoute = this.myDDMapActivity.getRoute();
      if (this.mRoute != null && this.mStaticNavCurrentTurnPointIndex != Constants.NOT_SET) {
        final int currentZoomLevel = this.myDDMapActivity.getZoomLevel();

        final int nextRouteIndex;
        final int nextTurnPointIndex;
        final int nextTurnIndexInRoute;
        final int turnAngle;

        final GeoPoint myProjectedLocationGeoPoint;

        final List<RouteInstruction> turnPointsRaw = this.mRoute.getRouteInstructions();
        if (!this.mRealtimeNav) {
          final RouteInstruction currentRouteInstruction =
              turnPointsRaw.get(this.mStaticNavCurrentTurnPointIndex);
          final GeoPoint liteVersionCurrentTurnPoint = currentRouteInstruction.getTurnPoint();
          nextRouteIndex = currentRouteInstruction.getFirstMotherPolylineIndex();

          nextTurnPointIndex =
              Math.min(this.mStaticNavCurrentTurnPointIndex + 1, turnPointsRaw.size() - 1);
          final RouteInstruction nextTurnPoint = turnPointsRaw.get(nextTurnPointIndex);
          nextTurnIndexInRoute = nextTurnPoint.getFirstMotherPolylineIndex();

          myProjectedLocationGeoPoint = liteVersionCurrentTurnPoint;

          turnAngle = (int) nextTurnPoint.getAngle();
        } else {
          nextRouteIndex = nav.getNextRoutePointIndex();
          nextTurnPointIndex = nav.getNextTurnPointIndex();
          nextTurnIndexInRoute = Math.max(0, nav.getNextTurnPointIndexInRoute());

          turnAngle = (int) nav.getTurnAngle();

          myProjectedLocationGeoPoint = nav.getLastKnownLocationProjectedGeoPoint();
        }

        final GeoPoint myCurrentLocationGeoPoint =
            this.myDDMapActivity.getLastKnownLocationAsGeoPoint(true);

        /* First get Start end End Point of the route. */
        final GeoPoint startPoint = this.mRoute.getStart();
        final GeoPoint endPoint = this.mRoute.getDestination();

        final Projection pj = mapView.getProjection();

        final ManagedLinePath pathDone = new ManagedLinePath();
        final ManagedLinePath pathCurrentSegment = new ManagedLinePath();
        final ArrayList<Path> pathTurnSegments = new ArrayList<Path>();
        final ArrayList<Path> pathTurnSegmentsPeaks = new ArrayList<Path>();
        final ManagedLinePath pathUpcoming = new ManagedLinePath();

        /* DEBUG Output */
        {
          //				routedrawStartMs = routedrawEndMs = System.currentTimeMillis();
        }
        /* END DEBUG Output */

        /* Check to see if the route is too long. */
        if (nav.isReady()) {
          /* Retrieve all (Map)Points of the route Found. */
          final List<GeoPoint> polyLine = this.mRoute.getPolyLine();

          //				final long startTransform = System.currentTimeMillis();

          //				canvas.drawText("nri: " + nextRouteIndex, 2, 40, this.pathDonePaint);
          //				canvas.drawText("nti: " + nextTurnPointIndex, 2, 50, this.pathDonePaint);
          //				canvas.drawText("ntiir: " + nextTurnIndexInRoute, 2, 60, this.pathDonePaint);

          if (nextRouteIndex != Constants.NOT_SET && polyLine != null) {
            /* Loop through all MapPoints returned. */

            final int increment = (int) (Math.max(1, Math.pow(2, 14 - currentZoomLevel)));

            final int lastIndexPathDone =
                Math.max(
                    0,
                    (myProjectedLocationGeoPoint != null)
                        ? nextRouteIndex - 1
                        : nextRouteIndex); // -1 when there is the projection in between
            final int firstIndexPathDone = Math.max(0, lastIndexPathDone - 100 * increment);

            final int firstIndexPathCurrent = nextRouteIndex;
            final int lastIndexPathCurrent = nextTurnIndexInRoute;

            final int firstIndexPathUpcoming = lastIndexPathCurrent;
            final int lastIndexPathUPcoming =
                Math.min(firstIndexPathUpcoming + 100 * increment, polyLine.size() - 1);

            if (firstIndexPathDone != lastIndexPathDone) {
              for (int i = firstIndexPathDone; i <= lastIndexPathDone; i += increment) {
                pathDone.lineTo(pj.toMapPixels(polyLine.get(i), screenCoords));
              }
            }
            pathDone.lineTo(
                pj.toMapPixels(
                    polyLine.get(lastIndexPathDone),
                    screenCoords)); // Ensures, that the this path and the next are connected.

            if (myProjectedLocationGeoPoint != null) {
              pj.toMapPixels(myProjectedLocationGeoPoint, screenCoords);
              pathDone.lineTo(screenCoords);
              pathCurrentSegment.lineTo(screenCoords);
            }

            if (firstIndexPathCurrent != lastIndexPathCurrent) {
              for (int i = firstIndexPathCurrent; i <= lastIndexPathCurrent; i += increment) {
                pathCurrentSegment.lineTo(pj.toMapPixels(polyLine.get(i), screenCoords));
              }
            }
            pathCurrentSegment.lineTo(
                pj.toMapPixels(
                    polyLine.get(lastIndexPathCurrent),
                    screenCoords)); // Ensures, that the this path and the next are connected.

            if (firstIndexPathUpcoming != lastIndexPathUPcoming) {
              for (int i = firstIndexPathUpcoming; i <= lastIndexPathUPcoming; i += increment) {
                pathUpcoming.lineTo(pj.toMapPixels(polyLine.get(i), screenCoords));
              }
            }

            //				final long endTransform = System.currentTimeMillis();
            //
            //				Log.d(Constants.DEBUGTAG, "Transform: " + (endTransform - startTransform) + "
            // ms");

            /* Used for transforming all paths. */
            final float scaleFactor =
                (this.mapRotationDegree == Constants.NOT_SET)
                    ? 1.0f
                    : FloatMath.sqrt(mapViewHeight * mapViewHeight + mapViewWidth * mapViewWidth)
                        / Math.min(mapViewHeight, mapViewWidth);

            /* Calculate the turn-segment-arrow. */
            if (currentZoomLevel >= MIN_ZOOMLEVEL_FOR_ARROWS) {
              {
                  /* next Arrow */
                final Path arrowPath = new Path();
                final Path arrowPeakPath = new Path();
                try {
                  ArrowPathCreator.createArrowOverIndex(
                      pj,
                      nextTurnIndexInRoute,
                      polyLine,
                      arrowPath,
                      arrowPeakPath,
                      scaleFactor,
                      currentZoomLevel,
                      turnAngle);
                  pathTurnSegments.add(arrowPath);
                  pathTurnSegmentsPeaks.add(arrowPeakPath);
                } catch (final IndexOutOfBoundsException ioobe) {
                  //							Log.e(DEBUGTAG, "Error drawing arrow. index=" + nextTurnIndexInRoute + "
                  // polyline length = " + polyLine.size());
                }

                { // TODO Remove on release
                  //							final int ARROW_RENDER_ZOOMLEVEL = 15;
                  //
                  //							Projection pj2 = mapView.new Projection(ARROW_RENDER_ZOOMLEVEL, 0, 0);
                  //
                  //							final Path arrowPathDummy = new Path();
                  //							final Path arrowPeakPathDummy = new Path();
                  //							ArrowPathCreator.createArrowOverIndex(pj2, nextTurnIndexInRoute,
                  // polyLine, arrowPathDummy, arrowPeakPathDummy, 1, ARROW_RENDER_ZOOMLEVEL,
                  // turnAngle);
                  //
                  //							final Bitmap b = ArrowPathCreator.drawToBitmap(arrowPathDummy,
                  // arrowPeakPathDummy);
                  //							canvas.drawBitmap(b, 250,250, new Paint());
                }
              }

              final int between = nav.getDistanceBetweenNextAndUpperNextTurnPoint();
              if (between < 1500 && nextTurnPointIndex != Constants.NOT_SET) {
                  /* upperNext Arrow */
                final int upperNextTurnPointIndex = nextTurnPointIndex + 1;
                if (upperNextTurnPointIndex > 0
                    && upperNextTurnPointIndex < this.mRoute.getRouteInstructions().size()) {
                  final Path arrowPath = new Path();
                  final Path arrowPeakPath = new Path();

                  final RouteInstruction upperNextTurnPoint =
                      turnPointsRaw.get(upperNextTurnPointIndex);
                  final float upperNextTurnAngle = upperNextTurnPoint.getAngle();
                  final int upperNextTurnIndexInRoute =
                      upperNextTurnPoint.getFirstMotherPolylineIndex();

                  try {
                    ArrowPathCreator.createArrowOverIndex(
                        pj,
                        upperNextTurnIndexInRoute,
                        polyLine,
                        arrowPath,
                        arrowPeakPath,
                        scaleFactor,
                        currentZoomLevel,
                        upperNextTurnAngle);
                    pathTurnSegments.add(arrowPath);
                    pathTurnSegmentsPeaks.add(arrowPeakPath);
                  } catch (final IndexOutOfBoundsException ioobe) {
                    //							Log.e(DEBUGTAG, "Error drawing arrow. index=" +
                    // upperNextTurnIndexInRoute + " polyline length = " + polyLine.size());
                  }
                }
              }
            }
          }

          /* Draw the already driven route to the canvas. */
          //				if(!canvas.quickReject(pathDone, EdgeType.BW))
          canvas.drawPath(pathDone, this.mPathDonePaint);

          /* Draw the rest Route to the canvas. */
          //				if(!canvas.quickReject(pathUpcoming, EdgeType.BW))
          canvas.drawPath(pathUpcoming, this.mPathUpcomingPaint);

          /* Draw the current Route Segment to the canvas. */
          //				if(!canvas.quickReject(pathCurrentSegment, EdgeType.AA))
          canvas.drawPath(pathCurrentSegment, this.mPathCurrentSegmentPaint);

          /* Draw the Turn Segment to the canvas. */
          for (int j = pathTurnSegments.size() - 1; j >= 0; j--) {
            canvas.drawPath(pathTurnSegments.get(j), this.mPathTurnSegmentOutlinePaint);
            canvas.drawPath(pathTurnSegments.get(j), this.mPathTurnSegmentPaint);

            canvas.drawPath(pathTurnSegmentsPeaks.get(j), this.mPathTurnSegmentPeakOutlinePaint);
            canvas.drawPath(pathTurnSegmentsPeaks.get(j), this.mPathTurnSegmentPeakPaint);
          }

          // DEBUG Output
          {
            //					int minLatitude =
            // this.mRoute.getLatitudeMinSpans()[nav.getNextRoutePointIndex()];
            //					int maxLatitude =
            // this.mRoute.getLatitudeMaxSpans()[nav.getNextRoutePointIndex()];
            //					int minLongitude =
            // this.mRoute.getLongitudeMinSpans()[nav.getNextRoutePointIndex()];
            //					int maxLongitude =
            // this.mRoute.getLongitudeMaxSpans()[nav.getNextRoutePointIndex()];
            //
            ////					Log.d(DEBUGTAG, "nextRoutePointIndex=" + nav.getNextRoutePointIndex());
            //
            //					int myLat = myCurrentLocationMapPoint.getLatitude();
            //					int myLon = myCurrentLocationMapPoint.getLongitude();
            //
            //					maxLatitude = Math.max(myLat, maxLatitude);
            //					minLatitude = Math.min(myLat, minLatitude);
            //					maxLongitude = Math.max(myLon, maxLongitude);
            //					minLongitude = Math.min(myLon, minLongitude);
            //
            //					int x1, x2, y1, y2;
            //					pj.toMapPixels(new GeoPoint(minLatitude, minLongitude), screenCoords);
            //					x1 = screenCoords.x;
            //					y1 = screenCoords.y;
            //
            //					pj.toMapPixels(new GeoPoint(maxLatitude, maxLongitude), screenCoords);
            //					x2 = screenCoords.x;
            //					y2 = screenCoords.y;
            ////					Log.d(DEBUGTAG, "x1=" + x1 + ", y1=" + y1 + ", x2=" + x2 + ", y2="+ y2);
            //					Paint p = new Paint();
            //					p.setStrokeWidth(3);
            //					p.setARGB(255,255,0,0);
            //					p.setStyle(Style.STROKE);
            //					canvas.drawRect(new Rect(x1,y1,x2,y2), p);
          }
          // END DEBUG Output

          {
              /* Print Pin-MArkers. */
            /* Finally draw a fancy PIN to mark the end... */
            pj.toMapPixels(endPoint, screenCoords);

            canvas.drawBitmap(
                this.MARKER_END,
                screenCoords.x - MARKER_DESTINATION_HOTSPOT_X,
                screenCoords.y - MARKER_DESTINATION_HOTSPOT_Y,
                this.mMarkerPaint);

            /* ...for all via-points. */
            final List<GeoPoint> vias = this.mRoute.getVias();
            for (final GeoPoint mpVia : vias) {
              pj.toMapPixels(mpVia, screenCoords);

              canvas.drawBitmap(
                  this.MARKER_VIA,
                  screenCoords.x - MARKER_VIA_HOTSPOT_X,
                  screenCoords.y - MARKER_VIA_HOTSPOT_Y,
                  this.mMarkerPaint);
            }

            /* ...and the start of the route.*/
            pj.toMapPixels(startPoint, screenCoords);

            canvas.drawBitmap(
                this.MARKER_START,
                screenCoords.x - MARKER_START_HOTSPOT_X,
                screenCoords.y - MARKER_START_HOTSPOT_Y,
                this.mMarkerPaint);
          }

          {
            /* DEBUG Output */
            //					routedrawEndMs = System.currentTimeMillis();
          } /* END DEBUG Output */
        }

        final AbstractAndNavLocationProvider andNavLocationProvider =
            this.myDDMapActivity.getAndNavLocationProvider();

        if (myCurrentLocationGeoPoint != null) {
          /* Draw ourself to our real location. */
          pj.toMapPixels(myCurrentLocationGeoPoint, screenCoords);

          /* Draw the HorizontalPositioningError if we have a location. */
          if (this.mShowAccuracy) {

            final float accuracyRadius =
                (andNavLocationProvider.hasHorizontalPositioningError())
                    ? pj.metersToEquatorPixels(
                        andNavLocationProvider.getHorizontalPositioningError())
                    : RADIUS_NO_ACCURACY;

            /* Only draw if the DirectionArrow doesn't cover it. */
            if (accuracyRadius > 8) {
              /* Draw the inner shadow. */
              this.mAccuracyPaint.setAntiAlias(false);
              this.mAccuracyPaint.setAlpha(30);
              this.mAccuracyPaint.setStyle(Style.FILL);
              canvas.drawCircle(
                  screenCoords.x, screenCoords.y, accuracyRadius, this.mAccuracyPaint);

              /* Draw the edge. */
              this.mAccuracyPaint.setAntiAlias(true);
              this.mAccuracyPaint.setAlpha(150);
              this.mAccuracyPaint.setStyle(Style.STROKE);
              canvas.drawCircle(
                  screenCoords.x, screenCoords.y, accuracyRadius, this.mAccuracyPaint);
            }
          }

          /* Get the bearing if available. */
          final boolean hasBearing = andNavLocationProvider.hasBearing();
          final float directionBearing = (hasBearing) ? andNavLocationProvider.getBearing() : 0;

          /* Rotate the direction-Arrow according to the bearing we are driving. And draw it to the canvas. */
          this.mDirectionRotater.setRotate(
              directionBearing, this.DIRECTION_ARROW_CENTER_X, this.DIRECTION_ARROW_CENTER_Y);
          final Bitmap rotatedDirection =
              Bitmap.createBitmap(
                  this.DIRECTION_ARROW,
                  0,
                  0,
                  this.DIRECTION_ARROW_WIDTH,
                  this.DIRECTION_ARROW_HEIGHT,
                  this.mDirectionRotater,
                  true);

          /* Calculate the deltas needed after the rotation, to paint the hotspot of the directionarrow on the actual location. */
          final float py = this.DIRECTION_ARROW_HOTSPOT_Y - this.DIRECTION_ARROW_CENTER_Y;

          final float dx;
          final float dy;

          if (py < 0.001 || py > 0.001) {
            final float alpha = MathConstants.DEG2RAD * (-directionBearing + 90f);
            dx = FloatMath.cos(alpha) * py;
            dy = FloatMath.sin(alpha) * py;
          } else {
            dx = 0;
            dy = 0;
          }
          canvas.drawBitmap(
              rotatedDirection,
              screenCoords.x - rotatedDirection.getWidth() / 2 + dx,
              screenCoords.y - rotatedDirection.getHeight() / 2 - dy,
              this.mDirectionRotatorPaint);
        }

        {
          /* DEBUG Output */
          //				long endMs = System.currentTimeMillis();
          //
          //				this.debugDrawSum +=  endMs - startMs;
          //				this.debugDrawCount++;
          //				Log.d(DEBUGTAG, "GUI: " + (endMs - startMs) + " ms  [Avg: " + (this.debugDrawSum /
          // this.debugDrawCount) + " ms]"
          //						+ "    [Route: " + (routedrawEndMs - routedrawStartMs) + " ms]");
        } /* END DEBUG Output */
      }
    } catch (final Exception e) {
      Log.e(Constants.DEBUGTAG, "Error in directionsOverlay", e);
      //			Exceptor.e("Error in directionsOverlay", e, this.myDDMapActivity);
    }
  }