package net.osmand.plus.views; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.Style; import android.graphics.PointF; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.QuadPoint; import net.osmand.data.RotatedTileBox; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper; import net.osmand.plus.TargetPointsHelper.TargetPoint; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.views.ContextMenuLayer.IContextMenuProvider; import java.util.Iterator; import java.util.List; public class PointNavigationLayer extends OsmandMapLayer implements IContextMenuProvider, ContextMenuLayer.IMoveObjectProvider { protected final static int DIST_TO_SHOW = 80; private Paint mPoint; private Paint mBitmapPaint; private OsmandMapTileView mView; private float[] mCalculations = new float[2]; private Bitmap mStartPoint; private Bitmap mTargetPoint; private Bitmap mIntermediatePoint; private Bitmap mArrowToDestination; private Paint mTextPaint; private final MapActivity map; private ContextMenuLayer contextMenuLayer; public PointNavigationLayer(MapActivity map) { this.map = map; } private void initUI() { mPoint = new Paint(); mPoint.setColor(ContextCompat.getColor(map, R.color.nav_point)); mPoint.setAntiAlias(true); mPoint.setStyle(Style.FILL); mBitmapPaint = new Paint(); mBitmapPaint.setDither(true); mBitmapPaint.setAntiAlias(true); mBitmapPaint.setFilterBitmap(true); mTextPaint = new Paint(); float sp = Resources.getSystem().getDisplayMetrics().scaledDensity; mTextPaint.setTextSize(sp * 18); mTextPaint.setTextAlign(Align.CENTER); mTextPaint.setAntiAlias(true); mStartPoint = BitmapFactory.decodeResource(mView.getResources(), R.drawable.map_start_point); mTargetPoint = BitmapFactory.decodeResource(mView.getResources(), R.drawable.map_target_point); mIntermediatePoint = BitmapFactory.decodeResource(mView.getResources(), R.drawable.map_intermediate_point); mArrowToDestination = BitmapFactory.decodeResource(mView.getResources(), R.drawable.map_arrow_to_destination); } @Override public void initLayer(OsmandMapTileView view) { this.mView = view; initUI(); contextMenuLayer = view.getLayerByClass(ContextMenuLayer.class); } @Override public void onDraw(Canvas canvas, RotatedTileBox tb, DrawSettings nightMode) { if (tb.getZoom() < 3) { return; } TargetPointsHelper targetPoints = map.getMyApplication().getTargetPointsHelper(); TargetPoint pointToStart = targetPoints.getPointToStart(); if (pointToStart != null) { if (isLocationVisible(tb, pointToStart)) { int marginX = mStartPoint.getWidth() / 6; int marginY = mStartPoint.getHeight(); float locationX = getPointX(tb, pointToStart); float locationY = getPointY(tb, pointToStart); canvas.rotate(-tb.getRotate(), locationX, locationY); canvas.drawBitmap(mStartPoint, locationX - marginX, locationY - marginY, mBitmapPaint); canvas.rotate(tb.getRotate(), locationX, locationY); } } int index = 0; for (TargetPoint ip : targetPoints.getIntermediatePoints()) { index++; if (isLocationVisible(tb, ip)) { int marginX = mIntermediatePoint.getWidth() / 6; int marginY = mIntermediatePoint.getHeight(); float locationX = getPointX(tb, ip); float locationY = getPointY(tb, ip); canvas.rotate(-tb.getRotate(), locationX, locationY); canvas.drawBitmap(mIntermediatePoint, locationX - marginX, locationY - marginY, mBitmapPaint); marginX = mIntermediatePoint.getWidth() / 3; canvas.drawText(index + "", locationX + marginX, locationY - 3 * marginY / 5, mTextPaint); canvas.rotate(tb.getRotate(), locationX, locationY); } } TargetPoint pointToNavigate = targetPoints.getPointToNavigate(); if (isLocationVisible(tb, pointToNavigate)) { int marginX = mTargetPoint.getWidth() / 6; int marginY = mTargetPoint.getHeight(); float locationX = getPointX(tb, pointToNavigate); float locationY = getPointY(tb, pointToNavigate); canvas.rotate(-tb.getRotate(), locationX, locationY); canvas.drawBitmap(mTargetPoint, locationX - marginX, locationY - marginY, mBitmapPaint); canvas.rotate(tb.getRotate(), locationX, locationY); } Iterator<TargetPoint> it = targetPoints.getIntermediatePoints().iterator(); if (it.hasNext()) { pointToNavigate = it.next(); } if (pointToNavigate != null && !isLocationVisible(tb, pointToNavigate)) { boolean show = !mView.getApplication().getRoutingHelper().isRouteCalculated(); if (mView.getSettings().SHOW_DESTINATION_ARROW.isSet()) { show = mView.getSettings().SHOW_DESTINATION_ARROW.get(); } if (show) { net.osmand.Location.distanceBetween(mView.getLatitude(), mView.getLongitude(), pointToNavigate.getLatitude(), pointToNavigate.getLongitude(), mCalculations); float bearing = mCalculations[1] - 90; float radiusBearing = DIST_TO_SHOW * tb.getDensity(); final QuadPoint cp = tb.getCenterPixelPoint(); canvas.rotate(bearing, cp.x, cp.y); canvas.translate(-24 * tb.getDensity() + radiusBearing, -22 * tb.getDensity()); canvas.drawBitmap(mArrowToDestination, cp.x, cp.y, mBitmapPaint); } } } private float getPointX(RotatedTileBox tileBox, TargetPoint point) { if (contextMenuLayer.getMoveableObject() != null && point == contextMenuLayer.getMoveableObject()) { return contextMenuLayer.getMovableCenterPoint(tileBox).x; } else { return tileBox.getPixXFromLonNoRot(point.getLongitude()); } } private float getPointY(RotatedTileBox tileBox, TargetPoint point) { if (contextMenuLayer.getMoveableObject() != null && point == contextMenuLayer.getMoveableObject()) { return contextMenuLayer.getMovableCenterPoint(tileBox).y; } else { return tileBox.getPixYFromLatNoRot(point.getLatitude()); } } public boolean isLocationVisible(RotatedTileBox tb, TargetPoint p) { if (contextMenuLayer.getMoveableObject() != null && p == contextMenuLayer.getMoveableObject()) { return true; } else if (p == null || tb == null) { return false; } return tb.containsLatLon(p.getLatitude(), p.getLongitude()); } @Override public void destroyLayer() { } @Override public boolean drawInScreenPixels() { return false; } @Override public boolean disableSingleTap() { return false; } @Override public boolean disableLongPressOnMap() { return false; } @Override public boolean isObjectClickable(Object o) { return false; } @Override public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> o) { if (tileBox.getZoom() >= 3) { TargetPointsHelper tg = map.getMyApplication().getTargetPointsHelper(); List<TargetPoint> intermediatePoints = tg.getAllPoints(); int r = getRadiusPoi(tileBox); for (int i = 0; i < intermediatePoints.size(); i++) { TargetPoint tp = intermediatePoints.get(i); LatLon latLon = tp.point; if (latLon != null) { int ex = (int) point.x; int ey = (int) point.y; int x = (int) tileBox.getPixXFromLatLon(latLon.getLatitude(), latLon.getLongitude()); int y = (int) tileBox.getPixYFromLatLon(latLon.getLatitude(), latLon.getLongitude()); if (calculateBelongs(ex, ey, x, y, r)) { o.add(tp); } } } } } private boolean calculateBelongs(int ex, int ey, int objx, int objy, int radius) { return Math.abs(objx - ex) <= radius && (ey - objy) <= radius && (objy - ey) <= 2.5 * radius; } public int getRadiusPoi(RotatedTileBox tb) { int r; final double zoom = tb.getZoom(); if (zoom <= 15) { r = 10; } else if (zoom <= 16) { r = 14; } else if (zoom <= 17) { r = 16; } else { r = 18; } return (int) (r * tb.getDensity()); } @Override public LatLon getObjectLocation(Object o) { if (o instanceof TargetPoint) { return ((TargetPoint) o).point; } return null; } @Override public PointDescription getObjectName(Object o) { if (o instanceof TargetPoint) { return ((TargetPoint) o).getPointDescription(mView.getContext()); } return null; } @Override public boolean isObjectMovable(Object o) { TargetPointsHelper targetPoints = map.getMyApplication().getTargetPointsHelper(); return o == targetPoints.getPointToNavigate(); } @Override public void applyNewObjectPosition(@NonNull Object o, @NonNull LatLon position, @Nullable ContextMenuLayer.ApplyMovedObjectCallback callback) { boolean result = false; TargetPoint newTargetPoint = null; if (o instanceof TargetPoint) { TargetPointsHelper targetPointsHelper = map.getMyApplication().getTargetPointsHelper(); targetPointsHelper.navigateToPoint(position, true, -1, new PointDescription(PointDescription.POINT_TYPE_LOCATION, "")); newTargetPoint = targetPointsHelper.getPointToNavigate(); result = true; } if (callback != null) { callback.onApplyMovedObject(result, newTargetPoint == null ? o : newTargetPoint); } } }