All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osmdroid.views.overlay.MyLocationOverlay Maven / Gradle / Ivy

There is a newer version: 6.1.20
Show newest version
// Created by plusminus on 22:01:11 - 29.09.2008
package org.osmdroid.views.overlay;

import java.util.LinkedList;

import microsoft.mappoint.TileSystem;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.LocationListenerProxy;
import org.osmdroid.ResourceProxy;
import org.osmdroid.SensorEventListenerProxy;
import org.osmdroid.api.IMapView;
import org.osmdroid.api.IMyLocationOverlay;
import org.osmdroid.api.IProjection;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.util.LocationUtils;
import org.osmdroid.util.NetworkLocationIgnorer;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.MapView.Projection;
import org.osmdroid.views.overlay.Overlay.Snappable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.WindowManager;

/**
 *
 * @author Manuel Stahl
 *
 */
public class MyLocationOverlay extends Overlay implements IMyLocationOverlay, IOverlayMenuProvider,
		SensorEventListener, LocationListener, Snappable {

	private static final Logger logger = LoggerFactory.getLogger(MyLocationOverlay.class);

	// ===========================================================
	// Constants
	// ===========================================================

	// ===========================================================
	// Fields
	// ===========================================================

	protected final Paint mPaint = new Paint();
	protected final Paint mCirclePaint = new Paint();

	protected final Bitmap PERSON_ICON;
	protected final Bitmap DIRECTION_ARROW;

	protected final MapView mMapView;

	private final MapController mMapController;
	private final LocationManager mLocationManager;
	private final SensorManager mSensorManager;
	private final Display mDisplay;

	public LocationListenerProxy mLocationListener = null;
	public SensorEventListenerProxy mSensorListener = null;

	private final LinkedList mRunOnFirstFix = new LinkedList();
	private final Point mMapCoords = new Point();

	private Location mLocation;
	private long mLocationUpdateMinTime = 0;
	private float mLocationUpdateMinDistance = 0.0f;
	protected boolean mFollow = false; // follow location updates
	protected boolean mDrawAccuracyEnabled = true;
	private final NetworkLocationIgnorer mIgnorer = new NetworkLocationIgnorer();

	private final Matrix directionRotater = new Matrix();

	/** Coordinates the feet of the person are located scaled for display density. */
	protected final PointF PERSON_HOTSPOT;

	protected final float DIRECTION_ARROW_CENTER_X;
	protected final float DIRECTION_ARROW_CENTER_Y;

	protected final Picture mCompassFrame = new Picture();
	protected final Picture mCompassRose = new Picture();
	private final Matrix mCompassMatrix = new Matrix();

	/**
	 * The bearing, in degrees east of north, or NaN if none has been set.
	 */
	private float mAzimuth = Float.NaN;

	private float mCompassCenterX = 35.0f;
	private float mCompassCenterY = 35.0f;
	private final float mCompassRadius = 20.0f;

	protected final float COMPASS_FRAME_CENTER_X;
	protected final float COMPASS_FRAME_CENTER_Y;
	protected final float COMPASS_ROSE_CENTER_X;
	protected final float COMPASS_ROSE_CENTER_Y;

	public static final int MENU_MY_LOCATION = getSafeMenuId();
	public static final int MENU_COMPASS = getSafeMenuId();

	private boolean mOptionsMenuEnabled = true;

	// to avoid allocations during onDraw
	private final float[] mMatrixValues = new float[9];
	private final GeoPoint mMyLocation = new GeoPoint(0, 0);
	private final Matrix mMatrix = new Matrix();

	// ===========================================================
	// Constructors
	// ===========================================================

	public MyLocationOverlay(final Context ctx, final MapView mapView) {
		this(ctx, mapView, new DefaultResourceProxyImpl(ctx));
	}

	public MyLocationOverlay(final Context ctx, final MapView mapView,
			final ResourceProxy pResourceProxy) {
		super(pResourceProxy);
		mMapView = mapView;
		mLocationManager = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
		mSensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
		final WindowManager windowManager = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
		mDisplay = windowManager.getDefaultDisplay();

		mMapController = mapView.getController();
		mCirclePaint.setARGB(0, 100, 100, 255);
		mCirclePaint.setAntiAlias(true);

		PERSON_ICON = mResourceProxy.getBitmap(ResourceProxy.bitmap.person);
		DIRECTION_ARROW = mResourceProxy.getBitmap(ResourceProxy.bitmap.direction_arrow);

		DIRECTION_ARROW_CENTER_X = DIRECTION_ARROW.getWidth() / 2 - 0.5f;
		DIRECTION_ARROW_CENTER_Y = DIRECTION_ARROW.getHeight() / 2 - 0.5f;

		// Calculate position of person icon's feet, scaled to screen density
		PERSON_HOTSPOT = new PointF(24.0f * mScale + 0.5f, 39.0f * mScale + 0.5f);

		createCompassFramePicture();
		createCompassRosePicture();

		COMPASS_FRAME_CENTER_X = mCompassFrame.getWidth() / 2 - 0.5f;
		COMPASS_FRAME_CENTER_Y = mCompassFrame.getHeight() / 2 - 0.5f;
		COMPASS_ROSE_CENTER_X = mCompassRose.getWidth() / 2 - 0.5f;
		COMPASS_ROSE_CENTER_Y = mCompassRose.getHeight() / 2 - 0.5f;
	}

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	public long getLocationUpdateMinTime() {
		return mLocationUpdateMinTime;
	}

	/**
	 * Set the minimum interval for location updates.
	 * See {@link LocationManager.requestLocationUpdates(String, long, float, LocationListener)}.
	 * Note that you should call this before calling {@link enableMyLocation()}.
	 *
	 * @param milliSeconds
	 */
	public void setLocationUpdateMinTime(final long milliSeconds) {
		mLocationUpdateMinTime = milliSeconds;
	}

	public float getLocationUpdateMinDistance() {
		return mLocationUpdateMinDistance;
	}

	/**
	 * Set the minimum distance for location updates.
	 * See {@link LocationManager.requestLocationUpdates}.
	 * Note that you should call this before calling {@link enableMyLocation()}.
	 *
	 * @param meters
	 */
	public void setLocationUpdateMinDistance(final float meters) {
		mLocationUpdateMinDistance = meters;
	}

	public void setCompassCenter(final float x, final float y) {
		mCompassCenterX = x;
		mCompassCenterY = y;
	}

	/**
	 * If enabled, an accuracy circle will be drawn around your current position.
	 *
	 * @param drawAccuracyEnabled
	 *            whether the accuracy circle will be enabled
	 */
	public void setDrawAccuracyEnabled(final boolean drawAccuracyEnabled) {
		mDrawAccuracyEnabled = drawAccuracyEnabled;
	}

	/**
	 * If enabled, an accuracy circle will be drawn around your current position.
	 *
	 * @return true if enabled, false otherwise
	 */
	public boolean isDrawAccuracyEnabled() {
		return mDrawAccuracyEnabled;
	}

	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 = lastFix.getAccuracy() / (float) TileSystem.GroundResolution(lastFix.getLatitude(), mapView.getZoomLevel());

			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("Alt: " + lastFix.getAltitude(), tx, ty + 35, mPaint);
			canvas.drawText("Acc: " + lastFix.getAccuracy(), tx, ty + 50, mPaint);
		}

		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(-PERSON_HOTSPOT.x, -PERSON_HOTSPOT.y);
			directionRotater.postScale(
					1 / mMatrixValues[Matrix.MSCALE_X],
					1 / mMatrixValues[Matrix.MSCALE_Y]);
			directionRotater.postTranslate(mMapCoords.x, mMapCoords.y);
			canvas.drawBitmap(PERSON_ICON, directionRotater, mPaint);
		}
	}

	protected void drawCompass(final Canvas canvas, final float bearing) {
		final float centerX = mCompassCenterX * mScale;
		final float centerY = mCompassCenterY * mScale + (canvas.getHeight() - mMapView.getHeight());

		mCompassMatrix.setTranslate(-COMPASS_FRAME_CENTER_X, -COMPASS_FRAME_CENTER_Y);
		mCompassMatrix.postTranslate(centerX, centerY);

		canvas.save();
		canvas.setMatrix(mCompassMatrix);
		canvas.drawPicture(mCompassFrame);

		mCompassMatrix.setRotate(-bearing, COMPASS_ROSE_CENTER_X, COMPASS_ROSE_CENTER_Y);
		mCompassMatrix.postTranslate(-COMPASS_ROSE_CENTER_X, -COMPASS_ROSE_CENTER_Y);
		mCompassMatrix.postTranslate(centerX, centerY);

		canvas.setMatrix(mCompassMatrix);
		canvas.drawPicture(mCompassRose);
		canvas.restore();
	}

	// ===========================================================
	// Methods from SuperClass/Interfaces
	// ===========================================================

	@Override
	public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {

		if (shadow) {
			return;
		}

		if (mLocation != null) {

			mMyLocation.setCoordsE6(
					(int) (mLocation.getLatitude() * 1E6),
					(int) (mLocation.getLongitude() * 1E6));

			drawMyLocation(canvas, mapView, mLocation, mMyLocation);
		}

		if (isCompassEnabled() && !Float.isNaN(mAzimuth)) {
			drawCompass(canvas, mAzimuth + getDisplayOrientation());
		}
	}

	@Override
	public void onLocationChanged(final Location location) {
		if (DEBUGMODE) {
			logger.debug("onLocationChanged(" + location + ")");
		}

		// ignore temporary non-gps fix
		if (mIgnorer.shouldIgnore(location.getProvider(), System.currentTimeMillis())) {
			logger.debug("Ignore temporary non-gps location");
			return;
		}

		mLocation = location;
		if (mFollow) {
			mMapController.animateTo(location.getLatitude(), location.getLongitude());
		} else {
			mMapView.postInvalidate(); // redraw the my location icon
		}

		for (final Runnable runnable : mRunOnFirstFix) {
			new Thread(runnable).start();
		}
		mRunOnFirstFix.clear();
	}

	@Override
	public void onProviderDisabled(final String provider) {
	}

	@Override
	public void onProviderEnabled(final String provider) {
	}

	@Override
	public void onStatusChanged(final String provider, final int status, final Bundle extras) {
	}

	@Override
	public boolean onSnapToItem(final int x, final int y, final Point snapPoint,
			final IMapView mapView) {
		if (this.mLocation != null) {
			final IProjection pj = mapView.getProjection();
			pj.toPixels(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;
		}
	}

	@Override
	public boolean onTouchEvent(final MotionEvent event, final MapView mapView) {
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			disableFollowLocation();
		}

		return super.onTouchEvent(event, mapView);
	}

	@Override
	public void onAccuracyChanged(final Sensor arg0, final int arg1) {
		// This is not interesting for us at the moment
	}

	@Override
	public void onSensorChanged(final SensorEvent event) {
		if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
			if (event.values != null) {
				mAzimuth = event.values[0];
				mMapView.postInvalidate();
			}
		}
	}

	// ===========================================================
	// Menu handling methods
	// ===========================================================

	@Override
	public void setOptionsMenuEnabled(final boolean pOptionsMenuEnabled) {
		this.mOptionsMenuEnabled = pOptionsMenuEnabled;
	}

	@Override
	public boolean isOptionsMenuEnabled() {
		return this.mOptionsMenuEnabled;
	}

	@Override
	public boolean onCreateOptionsMenu(final Menu pMenu, final int pMenuIdOffset,
			final MapView pMapView) {
		pMenu.add(0, MENU_MY_LOCATION + pMenuIdOffset, Menu.NONE,
				mResourceProxy.getString(ResourceProxy.string.my_location)).setIcon(
				mResourceProxy.getDrawable(ResourceProxy.bitmap.ic_menu_mylocation));

		pMenu.add(0, MENU_COMPASS + pMenuIdOffset, Menu.NONE,
				mResourceProxy.getString(ResourceProxy.string.compass)).setIcon(
				mResourceProxy.getDrawable(ResourceProxy.bitmap.ic_menu_compass));

		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(final Menu pMenu, final int pMenuIdOffset,
			final MapView pMapView) {
		return false;
	}

	@Override
	public boolean onOptionsItemSelected(final MenuItem pItem, final int pMenuIdOffset,
			final MapView pMapView) {
		final int menuId = pItem.getItemId() - pMenuIdOffset;
		if (menuId == MENU_MY_LOCATION) {
			if (this.isMyLocationEnabled()) {
				this.disableFollowLocation();
				this.disableMyLocation();
			} else {
				this.enableFollowLocation();
				this.enableMyLocation();
			}
			return true;
		} else if (menuId == MENU_COMPASS) {
			if (this.isCompassEnabled()) {
				this.disableCompass();
			} else {
				this.enableCompass();
			}
			return true;
		} else {
			return false;
		}
	}

	// ===========================================================
	// Methods
	// ===========================================================

	/**
	 * Return a GeoPoint of the last known location, or null if not known.
	 */
	public GeoPoint getMyLocation() {
		if (mLocation == null) {
			return null;
		} else {
			return new GeoPoint(mLocation);
		}
	}

	@Override
	public Location getLastFix() {
		return mLocation;
	}

	/**
	 * @deprecated use {@link enableFollowLocation()} and {@link disableFollowLocation()} instead.
	 * @param follow
	 */
	@Deprecated
	public void followLocation(final boolean follow) {
		if (follow) {
			enableFollowLocation();
		} else {
			disableFollowLocation();
		}
	}

	/**
	 * Enables "follow" functionality. The map will center on your current location and
	 * automatically scroll as you move. Scrolling the map in the UI will disable.
	 */
	public void enableFollowLocation() {
		mFollow = true;

		// set initial location when enabled
		if (isMyLocationEnabled()) {
			mLocation = LocationUtils.getLastKnownLocation(mLocationManager);
			if (mLocation != null) {
				mMapController.animateTo(new GeoPoint(mLocation));
			}
		}

		// Update the screen to see changes take effect
		if (mMapView != null) {
			mMapView.postInvalidate();
		}
	}

	/**
	 * Disables "follow" functionality.
	 */
	public void disableFollowLocation() {
		mFollow = false;
	}

	/**
	 * If enabled, the map will center on your current location and automatically scroll as you
	 * move. Scrolling the map in the UI will disable.
	 *
	 * @return true if enabled, false otherwise
	 */
	public boolean isFollowLocationEnabled() {
		return mFollow;
	}

	/**
	 * Enable location updates and show your current location on the map. By default this will
	 * request location updates as frequently as possible, but you can change the frequency and/or
	 * distance by calling {@link setLocationUpdateMinTime(long)} and/or {@link
	 * setLocationUpdateMinDistance(float)} before calling this method. You will want to call
	 * enableMyLocation() probably from your Activity's Activity.onResume() method, to enable the
	 * features of this overlay. Remember to call the corresponding disableMyLocation() in your
	 * Activity's Activity.onPause() method to turn off updates when in the background.
	 */
	@Override
	public boolean enableMyLocation() {
		boolean result = true;

		if (mLocationListener == null) {
			mLocationListener = new LocationListenerProxy(mLocationManager);
			result = mLocationListener.startListening(this, mLocationUpdateMinTime,
					mLocationUpdateMinDistance);
		}

		// set initial location when enabled
		if (isFollowLocationEnabled()) {
			mLocation = LocationUtils.getLastKnownLocation(mLocationManager);
			if (mLocation != null) {
				mMapController.animateTo(new GeoPoint(mLocation));
			}
		}

		// Update the screen to see changes take effect
		if (mMapView != null) {
			mMapView.postInvalidate();
		}

		return result;
	}

	/**
	 * Disable location updates
	 */
	@Override
	public void disableMyLocation() {
		if (mLocationListener != null) {
			mLocationListener.stopListening();
		}

		mLocationListener = null;

		// Update the screen to see changes take effect
		if (mMapView != null) {
			mMapView.postInvalidate();
		}
	}

	/**
	 * If enabled, the map is receiving location updates and drawing your location on the map.
	 *
	 * @return true if enabled, false otherwise
	 */
	@Override
	public boolean isMyLocationEnabled() {
		return mLocationListener != null;
	}

	/**
	 * Enable orientation sensor (compass) updates and show a compass on the map. You will want to
	 * call enableCompass() probably from your Activity's Activity.onResume() method, to enable the
	 * features of this overlay. Remember to call the corresponding disableCompass() in your
	 * Activity's Activity.onPause() method to turn off updates when in the background.
	 */
	@Override
	public boolean enableCompass() {
		boolean result = true;
		if (mSensorListener == null) {
			mSensorListener = new SensorEventListenerProxy(mSensorManager);
			result = mSensorListener.startListening(this, Sensor.TYPE_ORIENTATION,
					SensorManager.SENSOR_DELAY_UI);
		}

		// Update the screen to see changes take effect
		if (mMapView != null) {
			mMapView.postInvalidate();
		}

		return result;
	}

	/**
	 * Disable orientation updates
	 */
	@Override
	public void disableCompass() {
		if (mSensorListener != null) {
			mSensorListener.stopListening();
		}

		// Reset values
		mSensorListener = null;
		mAzimuth = Float.NaN;

		// Update the screen to see changes take effect
		if (mMapView != null) {
			mMapView.postInvalidate();
		}
	}

	/**
	 * If enabled, the map is receiving orientation updates and drawing your location on the map.
	 *
	 * @return true if enabled, false otherwise
	 */
	@Override
	public boolean isCompassEnabled() {
		return mSensorListener != null;
	}

	@Override
	public float getOrientation() {
		return mAzimuth;
	}

	@Override
	public boolean runOnFirstFix(final Runnable runnable) {
		if (mLocationListener != null && mLocation != null) {
			new Thread(runnable).start();
			return true;
		} else {
			mRunOnFirstFix.addLast(runnable);
			return false;
		}
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================

	private Point calculatePointOnCircle(final float centerX, final float centerY,
			final float radius, final float degrees) {
		// for trigonometry, 0 is pointing east, so subtract 90
		// compass degrees are the wrong way round
		final double dblRadians = Math.toRadians(-degrees + 90);

		final int intX = (int) (radius * Math.cos(dblRadians));
		final int intY = (int) (radius * Math.sin(dblRadians));

		return new Point((int) centerX + intX, (int) centerY - intY);
	}

	private void drawTriangle(final Canvas canvas, final float x, final float y,
			final float radius, final float degrees, final Paint paint) {
		canvas.save();
		final Point point = this.calculatePointOnCircle(x, y, radius, degrees);
		canvas.rotate(degrees, point.x, point.y);
		final Path p = new Path();
		p.moveTo(point.x - 2 * mScale, point.y);
		p.lineTo(point.x + 2 * mScale, point.y);
		p.lineTo(point.x, point.y - 5 * mScale);
		p.close();
		canvas.drawPath(p, paint);
		canvas.restore();
	}

	private int getDisplayOrientation() {
		switch (mDisplay.getOrientation()) {
		case Surface.ROTATION_90: return 90;
		case Surface.ROTATION_180: return 180;
		case Surface.ROTATION_270: return 270;
		default: return 0;
		}
	}

	private void createCompassFramePicture() {
		// The inside of the compass is white and transparent
		final Paint innerPaint = new Paint();
		innerPaint.setColor(Color.WHITE);
		innerPaint.setAntiAlias(true);
		innerPaint.setStyle(Style.FILL);
		innerPaint.setAlpha(200);

		// The outer part (circle and little triangles) is gray and transparent
		final Paint outerPaint = new Paint();
		outerPaint.setColor(Color.GRAY);
		outerPaint.setAntiAlias(true);
		outerPaint.setStyle(Style.STROKE);
		outerPaint.setStrokeWidth(2.0f);
		outerPaint.setAlpha(200);

		final int picBorderWidthAndHeight = (int) ((mCompassRadius + 5) * 2);
		final int center = picBorderWidthAndHeight / 2;

		final Canvas canvas = mCompassFrame.beginRecording(picBorderWidthAndHeight,
				picBorderWidthAndHeight);

		// draw compass inner circle and border
		canvas.drawCircle(center, center, mCompassRadius * mScale, innerPaint);
		canvas.drawCircle(center, center, mCompassRadius * mScale, outerPaint);

		// Draw little triangles north, south, west and east (don't move)
		// to make those move use "-bearing + 0" etc. (Note: that would mean to draw the triangles
		// in the onDraw() method)
		drawTriangle(canvas, center, center, mCompassRadius * mScale, 0, outerPaint);
		drawTriangle(canvas, center, center, mCompassRadius * mScale, 90, outerPaint);
		drawTriangle(canvas, center, center, mCompassRadius * mScale, 180, outerPaint);
		drawTriangle(canvas, center, center, mCompassRadius * mScale, 270, outerPaint);

		mCompassFrame.endRecording();
	}

	private void createCompassRosePicture() {
		// Paint design of north triangle (it's common to paint north in red color)
		final Paint northPaint = new Paint();
		northPaint.setColor(0xFFA00000);
		northPaint.setAntiAlias(true);
		northPaint.setStyle(Style.FILL);
		northPaint.setAlpha(220);

		// Paint design of south triangle (black)
		final Paint southPaint = new Paint();
		southPaint.setColor(Color.BLACK);
		southPaint.setAntiAlias(true);
		southPaint.setStyle(Style.FILL);
		southPaint.setAlpha(220);

		// Create a little white dot in the middle of the compass rose
		final Paint centerPaint = new Paint();
		centerPaint.setColor(Color.WHITE);
		centerPaint.setAntiAlias(true);
		centerPaint.setStyle(Style.FILL);
		centerPaint.setAlpha(220);

		// final int picBorderWidthAndHeight = (int) ((mCompassRadius + 5) * 2 * mScale);
		final int picBorderWidthAndHeight = (int) ((mCompassRadius + 5) * 2);
		final int center = picBorderWidthAndHeight / 2;

		final Canvas canvas = mCompassRose.beginRecording(picBorderWidthAndHeight,
				picBorderWidthAndHeight);

		// Blue triangle pointing north
		final Path pathNorth = new Path();
		pathNorth.moveTo(center, center - (mCompassRadius - 3) * mScale);
		pathNorth.lineTo(center + 4 * mScale, center);
		pathNorth.lineTo(center - 4 * mScale, center);
		pathNorth.lineTo(center, center - (mCompassRadius - 3) * mScale);
		pathNorth.close();
		canvas.drawPath(pathNorth, northPaint);

		// Red triangle pointing south
		final Path pathSouth = new Path();
		pathSouth.moveTo(center, center + (mCompassRadius - 3) * mScale);
		pathSouth.lineTo(center + 4 * mScale, center);
		pathSouth.lineTo(center - 4 * mScale, center);
		pathSouth.lineTo(center, center + (mCompassRadius - 3) * mScale);
		pathSouth.close();
		canvas.drawPath(pathSouth, southPaint);

		// Draw a little white dot in the middle
		canvas.drawCircle(center, center, 2, centerPaint);

		mCompassRose.endRecording();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy