//Created by plusminus on 14:00:27 - 30.01.2008
package org.androad.ui.map.overlay;
import java.util.ArrayList;
import java.util.List;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.MapView.Projection;
import org.osmdroid.views.overlay.Overlay;
import org.osmdroid.views.util.constants.MathConstants;
import org.androad.R;
import org.androad.loc.AbstractAndNavLocationProvider;
import org.androad.nav.Navigator;
import org.androad.osm.views.overlay.util.DirectionArrowDescriptor;
import org.androad.preferences.PreferenceConstants;
import org.androad.sys.ors.adt.rs.Route;
import org.androad.sys.ors.adt.rs.RouteInstruction;
import org.androad.ui.map.OpenStreetDDMap;
import org.androad.ui.map.overlay.util.ArrowPathCreator;
import org.androad.ui.map.overlay.util.ManagedLinePath;
import org.androad.util.constants.Constants;
import org.androad.util.constants.GeoConstants;
import org.androad.util.constants.MathematicalConstants;
import org.androad.util.constants.TimeConstants;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import android.util.FloatMath;
import android.util.Log;
public class MapDrivingDirectionsOverlay extends Overlay implements Constants, TimeConstants, MathematicalConstants, PreferenceConstants, GeoConstants {
// ===========================================================
// Final Fields
// ===========================================================
private static final int MIN_ZOOMLEVEL_FOR_ARROWS = 11;
private static final int MARKER_START_HOTSPOT_X = 18;
private static final int MARKER_DESTINATION_HOTSPOT_X = MARKER_START_HOTSPOT_X;
private static final int MARKER_VIA_HOTSPOT_X = 12;
private static final int MARKER_START_HOTSPOT_Y = 47;
private static final int MARKER_DESTINATION_HOTSPOT_Y = MARKER_START_HOTSPOT_Y;
private static final int MARKER_VIA_HOTSPOT_Y = 31;
private static final float RADIUS_NO_ACCURACY = 20;
private final Bitmap MARKER_START;
private final Bitmap MARKER_VIA;
private final Bitmap MARKER_END;
private final Bitmap DIRECTION_ARROW;
private final float DIRECTION_ARROW_HOTSPOT_X;
private final float DIRECTION_ARROW_HOTSPOT_Y;
private final float DIRECTION_ARROW_CENTER_X;
private final float DIRECTION_ARROW_CENTER_Y;
private final int DIRECTION_ARROW_WIDTH;
private final int DIRECTION_ARROW_HEIGHT;
// ===========================================================
// Fields
// ===========================================================
// private int debugDrawSum = 0;
// private int debugDrawCount= 0;
private float mapRotationDegree = 0;
private Route mRoute;
private OpenStreetDDMap myDDMapActivity;
private final Paint mPathDonePaint;
private final Paint mPathUpcomingPaint;
private final Paint mPathCurrentSegmentPaint;
private final Paint mPathTurnSegmentPeakPaint;
private final Paint mPathTurnSegmentPeakOutlinePaint;
private final Paint mPathTurnSegmentPaint;
private final Paint mPathTurnSegmentOutlinePaint;
private final Paint mDirectionRotatorPaint;
private final Paint mMarkerPaint;
private final Paint mAccuracyPaint = new Paint();
private final Matrix mDirectionRotater = new Matrix();
private boolean mRealtimeNav;
private int mStaticNavCurrentTurnPointIndex = 0;
private boolean mShowAccuracy = true;
// ===========================================================
// Constructors
// ===========================================================
public MapDrivingDirectionsOverlay(final OpenStreetDDMap aMapAct, final int aDisplayQuality, final boolean aRealtimeNav, final DirectionArrowDescriptor pDirectionArrowDescriptor) {
super(aMapAct);
this.myDDMapActivity = aMapAct;
this.mRealtimeNav = aRealtimeNav;
{ /* Setup the paints. Needs to be inside of the constructor, as all paints are declared final. */
this.mAccuracyPaint.setStrokeWidth(2);
this.mAccuracyPaint.setColor(Color.BLUE);
this.mAccuracyPaint.setAntiAlias(true);
this.mPathDonePaint = new Paint();
this.mPathDonePaint.setStyle(Paint.Style.STROKE);
this.mPathDonePaint.setStrokeWidth(12);
this.mPathDonePaint.setARGB(255, 252, 113, 105); // red
this.mPathDonePaint.setStrokeCap(Cap.ROUND);
this.mPathUpcomingPaint = new Paint(this.mPathDonePaint);
this.mPathUpcomingPaint.setARGB(255, 113, 105, 252); // blue
this.mPathCurrentSegmentPaint = new Paint(this.mPathDonePaint);
this.mPathCurrentSegmentPaint.setARGB(255, 113, 252, 105); // green
this.mPathTurnSegmentPaint = new Paint(this.mPathDonePaint);
this.mPathTurnSegmentPaint.setARGB(255, 255, 255, 255); // white
this.mPathTurnSegmentPaint.setStrokeWidth(12);
this.mPathTurnSegmentOutlinePaint = new Paint(this.mPathDonePaint);
this.mPathTurnSegmentOutlinePaint.setARGB(255, 0, 0, 0); // black
this.mPathTurnSegmentOutlinePaint.setStrokeWidth(this.mPathTurnSegmentPaint.getStrokeWidth()+4);
this.mPathTurnSegmentPeakPaint = new Paint(this.mPathTurnSegmentPaint);
this.mPathTurnSegmentPeakPaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.mPathTurnSegmentPeakPaint.setStrokeWidth(1);
this.mPathTurnSegmentPeakOutlinePaint = new Paint(this.mPathTurnSegmentOutlinePaint);
this.mPathTurnSegmentPeakOutlinePaint.setStyle(Paint.Style.STROKE);
this.mPathTurnSegmentPeakOutlinePaint.setStrokeWidth(this.mPathTurnSegmentPeakPaint.getStrokeWidth()+4);
this.mDirectionRotatorPaint = new Paint();
this.mMarkerPaint = new Paint();
switch(aDisplayQuality){
case PREF_DISPLAYQUALITY_BEST:
this.mDirectionRotatorPaint.setAntiAlias(true);
this.mPathDonePaint.setAntiAlias(true);
this.mPathUpcomingPaint.setAntiAlias(true);
this.mPathCurrentSegmentPaint.setAntiAlias(true);
this.mPathTurnSegmentPaint.setAntiAlias(true);
this.mPathTurnSegmentOutlinePaint.setAntiAlias(true);
this.mPathTurnSegmentPeakPaint.setAntiAlias(true);
this.mPathTurnSegmentPeakOutlinePaint.setAntiAlias(true);
case PREF_DISPLAYQUALITY_HIGH:
this.mPathDonePaint.setPathEffect(new CornerPathEffect(this.mPathDonePaint.getStrokeWidth() / 2));
this.mPathUpcomingPaint.setPathEffect(new CornerPathEffect(this.mPathUpcomingPaint.getStrokeWidth() / 2));
this.mPathCurrentSegmentPaint.setPathEffect(new CornerPathEffect(this.mPathCurrentSegmentPaint.getStrokeWidth() / 2));
this.mPathTurnSegmentPaint.setPathEffect(new CornerPathEffect(this.mPathTurnSegmentPaint.getStrokeWidth() / 2));
this.mPathTurnSegmentOutlinePaint.setPathEffect(new CornerPathEffect(this.mPathTurnSegmentOutlinePaint.getStrokeWidth() / 2));
this.mPathTurnSegmentPeakPaint.setPathEffect(new CornerPathEffect(this.mPathTurnSegmentPeakPaint.getStrokeWidth() / 2));
this.mPathTurnSegmentPeakOutlinePaint.setPathEffect(new CornerPathEffect(this.mPathTurnSegmentPeakOutlinePaint.getStrokeWidth() / 2));
case PREF_DISPLAYQUALITY_STANDARD:
this.mMarkerPaint.setAlpha(180);
this.mPathCurrentSegmentPaint.setAlpha(210);
this.mPathUpcomingPaint.setAlpha(210);
this.mPathDonePaint.setAlpha(210);
this.mPathTurnSegmentOutlinePaint.setAlpha(225); // A bit less transparent than the others
this.mPathTurnSegmentPeakOutlinePaint.setAlpha(225);
case PREF_DISPLAYQUALITY_LOW:
break;
}
}
this.MARKER_START = BitmapFactory.decodeResource(this.myDDMapActivity.getResources(), R.drawable.flag_start);
this.MARKER_END = BitmapFactory.decodeResource(this.myDDMapActivity.getResources(), R.drawable.flag_destination);
this.MARKER_VIA = BitmapFactory.decodeResource(this.myDDMapActivity.getResources(), R.drawable.flag_via);
this.DIRECTION_ARROW = BitmapFactory.decodeResource(this.myDDMapActivity.getResources(), pDirectionArrowDescriptor.getDrawableID());
this.DIRECTION_ARROW_HEIGHT = this.DIRECTION_ARROW.getHeight();
this.DIRECTION_ARROW_WIDTH = this.DIRECTION_ARROW.getWidth();
this.DIRECTION_ARROW_CENTER_X = this.DIRECTION_ARROW_HEIGHT / 2;
this.DIRECTION_ARROW_CENTER_Y = this.DIRECTION_ARROW_WIDTH / 2;
final Point center = pDirectionArrowDescriptor.getCenter();
this.DIRECTION_ARROW_HOTSPOT_X = (center != null) ? center.x : this.DIRECTION_ARROW_CENTER_X;
this.DIRECTION_ARROW_HOTSPOT_Y = (center != null) ? center.y : this.DIRECTION_ARROW_CENTER_Y;
}
// ===========================================================
// Getter & Setter
// ===========================================================
public void setShowAccuracy(final boolean pShowIt){
this.mShowAccuracy = pShowIt;
}
public void setMapRotationDegree(final float rotationDegree) {
this.mapRotationDegree = rotationDegree;
}
public void setStaticNavCurrentTurnPointIndex(final int aTurnPointIndex){
this.mStaticNavCurrentTurnPointIndex = aTurnPointIndex;
}
public void setRealtimeNav(final boolean pRealtimenav) {
this.mRealtimeNav = pRealtimenav;
}
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
public void release() {
this.mRoute = null;
this.MARKER_START.recycle();
this.MARKER_VIA.recycle();
this.MARKER_END.recycle();
this.DIRECTION_ARROW.recycle();
this.myDDMapActivity = null;
this.myDDMapActivity = null;
}
/** 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);
}
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}