package net.osmand.plus.views; import net.osmand.osm.MapUtils; import net.osmand.plus.OsmandSettings.ApplicationMode; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.RectF; import android.graphics.Paint.Style; import android.location.Location; import android.util.DisplayMetrics; import android.view.WindowManager; public class PointLocationLayer implements OsmandMapLayer { protected final static int RADIUS = 7; protected final static int HEADING_RADIUS = 60; protected final static float HEADING_ANGLE = 60; private Paint location; private Paint bearing; private Paint bearingOver; private Paint area; private Paint headingPaint; private Path pathForDirection; private ApplicationMode appMode = ApplicationMode.DEFAULT; protected Location lastKnownLocation = null; private DisplayMetrics dm; private OsmandMapTileView view; private Float heading = null; private void initUI() { location = new Paint(); location.setColor(Color.BLUE); location.setAlpha(150); location.setAntiAlias(true); area = new Paint(); area.setColor(Color.BLUE); area.setAlpha(40); headingPaint = new Paint(); headingPaint.setColor(Color.BLUE); headingPaint.setAlpha(50); headingPaint.setAntiAlias(true); headingPaint.setStyle(Style.FILL); bearing = new Paint(); bearing.setColor(Color.BLUE); bearing.setAlpha(150); bearing.setAntiAlias(true); bearing.setStyle(Style.FILL); bearingOver = new Paint(); bearingOver.setColor(Color.BLACK); bearingOver.setAntiAlias(true); bearingOver.setStyle(Style.STROKE); pathForDirection = new Path(); } public void initLayer(OsmandMapTileView view) { this.view = view; initUI(); dm = new DisplayMetrics(); WindowManager wmgr = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE); wmgr.getDefaultDisplay().getMetrics(dm); } private RectF getHeadingRect(int locationX, int locationY){ int rad = Math.min(3*view.getWidth()/8, 3*view.getHeight()/8); return new RectF(locationX - rad, locationY - rad, locationX + rad, locationY + rad); } @Override public void onDraw(Canvas canvas, RectF latLonBounds, boolean nightMode) { if (isLocationVisible(lastKnownLocation)) { int locationX = view.getMapXForPoint(lastKnownLocation.getLongitude()); int locationY = view.getMapYForPoint(lastKnownLocation.getLatitude()); int radius = MapUtils.getLengthXFromMeters(view.getZoom(), view.getLatitude(), view.getLongitude(), lastKnownLocation.getAccuracy(), view.getTileSize(), view.getWidth()); if(appMode == ApplicationMode.CAR){ if(!lastKnownLocation.hasBearing()){ canvas.drawCircle(locationX, locationY, RADIUS * 2.5f * dm.density, location); canvas.drawCircle(locationX, locationY, RADIUS * 2.5f * dm.density, bearingOver); } } else { canvas.drawCircle(locationX, locationY, RADIUS * dm.density, location); canvas.drawCircle(locationX, locationY, RADIUS * dm.density, bearingOver); } if (radius > RADIUS) { canvas.drawCircle(locationX, locationY, radius, area); } if(heading != null){ canvas.drawArc(getHeadingRect(locationX, locationY), heading - HEADING_ANGLE/ 2 - 90, HEADING_ANGLE, true, headingPaint); } if(lastKnownLocation.hasBearing()){ float bearing = lastKnownLocation.getBearing(); int radiusBearing = (int) (30 * dm.density); if(lastKnownLocation.hasSpeed() && appMode != ApplicationMode.CAR){ radiusBearing = Math.max(MapUtils.getLengthXFromMeters(view.getZoom(), view.getLatitude(), view.getLongitude(), lastKnownLocation.getSpeed(), view.getTileSize(), view.getWidth()) * 2, radiusBearing); radiusBearing = Math.min(radiusBearing, view.getHeight() / 4); } radiusBearing += RADIUS * dm.density /2; pathForDirection.reset(); pathForDirection.moveTo(0, 0); pathForDirection.lineTo((float) RADIUS, 1f); pathForDirection.lineTo((float) -RADIUS, 1f); pathForDirection.lineTo(0, 0); Matrix m = new Matrix(); m.reset(); if(appMode == ApplicationMode.CAR){ m.postScale(2.5f * dm.density, radiusBearing * 1.5f); m.postTranslate(0, -radiusBearing/2); } else if(appMode == ApplicationMode.BICYCLE){ m.postScale(2 * dm.density, radiusBearing); m.postTranslate(0, -radiusBearing/2); } else { m.postScale(dm.density, radiusBearing * 0.5f); m.postTranslate(0, -radiusBearing); } m.postTranslate(locationX, locationY); m.postRotate(bearing, locationX, locationY); pathForDirection.transform(m); canvas.drawPath(pathForDirection, this.bearing); canvas.drawPath(pathForDirection, this.bearingOver); } } } public boolean isLocationVisible(Location l){ if(l == null || view == null){ return false; } return view.isPointOnTheRotatedMap(l.getLatitude(), l.getLongitude()); } public Location getLastKnownLocation() { return lastKnownLocation; } public void setHeading(Float heading){ this.heading = heading; if(!view.mapIsRefreshing() && isLocationVisible(this.lastKnownLocation)){ view.refreshMap(); } } public Float getHeading() { return heading; } public void setLastKnownLocation(Location lastKnownLocation) { boolean redraw = isLocationVisible(this.lastKnownLocation) || isLocationVisible(lastKnownLocation); this.lastKnownLocation = lastKnownLocation; if (redraw) { view.refreshMap(); } } @Override public void destroyLayer() { } public ApplicationMode getAppMode() { return appMode; } public void setAppMode(ApplicationMode appMode) { this.appMode = appMode; if(this.appMode == ApplicationMode.CAR || this.appMode == ApplicationMode.BICYCLE){ this.bearing.setAlpha(180); } else { this.bearing.setAlpha(150); } } @Override public boolean drawInScreenPixels() { return false; } @Override public boolean onLongPressEvent(PointF point) { return false; } @Override public boolean onTouchEvent(PointF point) { return false; } }