diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/CarOverlay.java b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/CarOverlay.java new file mode 100644 index 0000000000..ac995a7013 --- /dev/null +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/CarOverlay.java @@ -0,0 +1,290 @@ +package com.mogo.eagle.core.function.smp; + +import android.content.Context; +import android.graphics.BitmapFactory; + +import com.amap.api.maps.AMap; +import com.amap.api.maps.CameraUpdateFactory; +import com.amap.api.maps.TextureMapView; +import com.amap.api.maps.model.BitmapDescriptor; +import com.amap.api.maps.model.BitmapDescriptorFactory; +import com.amap.api.maps.model.CameraPosition; +import com.amap.api.maps.model.LatLng; +import com.amap.api.maps.model.Marker; +import com.amap.api.maps.model.MarkerOptions; +import com.amap.api.maps.model.Polyline; +import com.autonavi.amap.mapcore.IPoint; +import com.mogo.eagle.core.function.map.R; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 包名: com.amap.api.navi.core + *
+ * 创建时间:2018/3/1 + * 项目名称:AndroidNavigationSDK + * + * @author guibao.ggb + * @email guibao.ggb@alibaba-inc.com + *
+ * 类说明:自车位置管理Overlay类 + */ +public class CarOverlay { + + protected static final int CAR_MOVE_ANIMATION_PERIOD = 50; + protected int carMoveAnimationFrameNum = 2; + protected boolean mIsLock = true; + protected IPoint mapAnchorBackup = null; + protected double dXOffStep; + protected double dYOffStep; + protected float dAngleOffStep; + protected int currentFrameIndex; + protected float angleStart = 0; + protected boolean isMoveStarted = false; + protected float newAngle = 0; + protected BitmapDescriptor carDescriptor = null; + protected BitmapDescriptor fourCornersDescriptor = null; + protected Marker carMarker; + protected Marker directionMarker; + protected AMap mAmap = null; + protected TextureMapView mapView; + protected boolean isDirectionVisible = true; + protected LatLng endLatLng = null; + protected Polyline leaderLine = null; + protected final int DISTANCE_OFFSET = 150;// 默认 500 偏差 + + // API 默认 1800 UI 默认 360 + protected int angleModValue = 1800; + + + private ScheduledExecutorService executorService; + + public CarOverlay(Context context, TextureMapView mapView) { + this.mapView = mapView; + + fourCornersDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory + .decodeResource(context.getResources(), + R.drawable.module_small_map_navi_direction)); + + carDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory + .decodeResource(context.getResources(), + R.drawable.module_small_map_view_my_location_logo)); + angleModValue = 1800; + + } + + /** + * 设置自车状态 + * + * @param lock true 锁车 false 非锁车 + */ + public void setLock(boolean lock) { + mIsLock = lock; + if (carMarker == null) { + return; + } + if (mAmap == null) { + return; + } + if (directionMarker == null) { + return; + } + carMarker.setFlat(true); + directionMarker.setGeoPoint(carMarker.getGeoPoint()); + carMarker.setGeoPoint(carMarker.getGeoPoint()); + carMarker.setRotateAngle(carMarker.getRotateAngle()); + if (mIsLock) { + CameraPosition cameraPosition = new CameraPosition.Builder().target(carMarker.getPosition()).bearing(newAngle).tilt(0).zoom(16).build(); + mAmap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); + } + } + + public void reset() { + if (carMarker != null) { + carMarker.remove(); + } + if (directionMarker != null) { + directionMarker.remove(); + } + if (leaderLine != null) { + leaderLine.remove(); + } + leaderLine = null; + carMarker = null; + directionMarker = null; + + if (executorService != null) { + if (!executorService.isShutdown()) { + executorService.shutdown(); + } + isMoveStarted = false; + + executorService = null; + } + } + + /** + * 绘制自车 + * + * @param aMap + * @param mLatLng + * @param bearing + */ + public void draw(AMap aMap, LatLng mLatLng, float bearing) { + if (aMap == null || mLatLng == null || carDescriptor == null) { + return; + } + mAmap = aMap; + try { + if (carMarker == null) { + carMarker = aMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).setFlat(true).icon(carDescriptor).position(mLatLng)); + } + + if (directionMarker == null) { + directionMarker = aMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).setFlat(true).icon(fourCornersDescriptor).position(mLatLng)); + if (isDirectionVisible) { + directionMarker.setVisible(true); + } else { + directionMarker.setVisible(false); + } + } + carMarker.setVisible(true); + newAngle = bearing; + IPoint resultGeoPnt = IPoint.obtain(); + resultGeoPnt = NaviUtil.lonlat2Geo(mLatLng.latitude, mLatLng.longitude, 20); + updateCarPosition(resultGeoPnt); + resultGeoPnt.recycle(); + + } catch (Throwable e) { + e.printStackTrace(); + } + } + + + private void updateCarPosition(IPoint p) { + carMarker.setGeoPoint(p); + carMarker.setFlat(true); + carMarker.setRotateAngle(360 - newAngle); + if (directionMarker != null) { + directionMarker.setGeoPoint(p); + } + + if (mIsLock) { + CameraPosition cameraPosition = new CameraPosition.Builder().target(carMarker.getPosition()).bearing(newAngle).tilt(0).zoom(16).build(); + mAmap.moveCamera(CameraUpdateFactory.changeBearingGeoCenter(newAngle, p)); + } + } + + + public void setEndPoi(LatLng latlng) { + endLatLng = latlng; + } + + /** + * 释放自车资源 + */ + public void destroy() { + if (carMarker != null) { + carMarker.remove(); + carMarker = null; + } + if (directionMarker != null) { + directionMarker.remove(); + directionMarker = null; + } + carDescriptor = null; + + if (executorService != null && !executorService.isShutdown()) { + executorService.shutdown(); + isMoveStarted = false; + + executorService = null; + } + } + + private void calculateCarSmoothMoveOffset(IPoint newCenter, float newAngle) { + if (carMarker == null) { + return; + } + IPoint currentAnchorGeoPoint = carMarker.getGeoPoint(); + if (currentAnchorGeoPoint == null || currentAnchorGeoPoint.x == 0 || currentAnchorGeoPoint.y == 0) { + currentAnchorGeoPoint = newCenter; + } + currentFrameIndex = 0; + mapAnchorBackup = currentAnchorGeoPoint; + dXOffStep = (newCenter.x - currentAnchorGeoPoint.x) / carMoveAnimationFrameNum; + dYOffStep = (newCenter.y - currentAnchorGeoPoint.y) / carMoveAnimationFrameNum; + // 获取当前的旋转角度 + angleStart = carMarker.getRotateAngle(); + boolean isFirst = false; + + if (Float.compare(angleStart, newAngle) == 0) { + isFirst = true; + } else { + angleStart = 360 - angleStart; + } + // 校正旋转角度问题 + float dAngleDelta = newAngle - angleStart; + if (isFirst) { + dAngleDelta = 0; + } + if (dAngleDelta > 180) { + dAngleDelta = dAngleDelta - 360; + } + else if (dAngleDelta < -180) { + dAngleDelta = dAngleDelta + 360; + } + dAngleOffStep = dAngleDelta / carMoveAnimationFrameNum; + isMoveStarted = true; + } + +// protected void startSmoothMoveTimer() { +// if (executorService == null) { +// executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("caroverlay-schedule-pool-%d").daemon(true).build()); +// +// executorService.scheduleAtFixedRate(new Runnable() { +// long currentSeconds; +// @Override +// public void run() { +// try{ +// currentSeconds = System.currentTimeMillis(); +// mapSmoothMoveTimerTick(); +// } catch(Throwable e){ +// e.printStackTrace(); +// } +// } +// }, 0, CAR_MOVE_ANIMATION_PERIOD, TimeUnit.MILLISECONDS); +// } +// } + + private void mapSmoothMoveTimerTick() { + if (!isMoveStarted) { + return; + } + if (carMarker == null) { + return; + } + if (mAmap == null) { + return; + } + try { + IPoint p = carMarker.getGeoPoint(); + double newX = 0, newY = 0; + if (currentFrameIndex++ < carMoveAnimationFrameNum) { + newX = mapAnchorBackup.x + dXOffStep * currentFrameIndex; + newY = mapAnchorBackup.y + dYOffStep * currentFrameIndex; + newAngle = angleStart + dAngleOffStep * currentFrameIndex; + newAngle %= angleModValue; + if (newX != 0 || newY != 0) { + p = new IPoint((int)newX, (int)newY); + } + updateCarPosition(p); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + +} diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/NaviUtil.java b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/NaviUtil.java new file mode 100644 index 0000000000..f009ec97c1 --- /dev/null +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/NaviUtil.java @@ -0,0 +1,121 @@ +package com.mogo.eagle.core.function.smp; + +import com.amap.api.maps.AMapUtils; +import com.amap.api.maps.model.LatLng; +import com.amap.api.navi.model.NaviLatLng; +import com.autonavi.amap.mapcore.IPoint; +import com.autonavi.amap.mapcore.MapProjection; + +/** + * 包名: com.amap.navi.demo.util + *
+ * 创建时间:2018/4/19 + * 项目名称:NaviDemo + * + * @author guibao.ggb + * @email guibao.ggb@alibaba-inc.com + *
+ * 类说明:
+ */
+public class NaviUtil {
+
+ public static float calculateDistance(NaviLatLng start, NaviLatLng end) {
+ double x1 = start.getLongitude();
+ double y1 = start.getLatitude();
+ double x2 = end.getLongitude();
+ double y2 = end.getLatitude();
+ return AMapUtils.calculateLineDistance(new LatLng(y1, x1), new LatLng(y2, x2));
+ }
+
+
+ public static NaviLatLng getPointForDis(NaviLatLng sPt, NaviLatLng ePt, double dis) {
+ double lSegLength = calculateDistance(sPt, ePt);
+ NaviLatLng pt = new NaviLatLng();
+ double preResult = dis / lSegLength;
+ pt.setLatitude(((ePt.getLatitude() - sPt.getLatitude()) * preResult + sPt.getLatitude()));
+ pt.setLongitude(((ePt.getLongitude() - sPt.getLongitude()) * preResult + sPt.getLongitude()));
+ return pt;
+ }
+
+ /**
+ * 根据经纬度计算需要偏转的角度
+ *
+ * @param startPoi
+ * @param secondPoi
+ * @return
+ */
+ public static float getRotate(NaviLatLng startPoi, NaviLatLng secondPoi) {
+ float rotate = 0;
+ try {
+ IPoint point1 = new IPoint();
+ IPoint point2 = new IPoint();
+ MapProjection.lonlat2Geo(startPoi.getLongitude(), startPoi.getLatitude(), point1);
+ MapProjection.lonlat2Geo(secondPoi.getLongitude(), secondPoi.getLatitude(), point2);
+ double x1 = point1.x;
+ double x2 = point2.x;
+ double y1 = point1.y;
+ double y2 = point2.y;
+ rotate = (float) (Math.atan2(y2 - y1, x2 - x1) / Math.PI * 180);
+ rotate = rotate + 90;
+ return rotate;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return rotate;
+ }
+
+
+ public static final int MAXZOOMLEVEL = 20;
+ public static final int PIXELSPERTILE = 256;
+ public static final double MINLATITUDE = -85.0511287798;
+ public static final double MAXLATITUDE = 85.0511287798;
+ public static final double MINLONGITUDE = -180;
+ public static final double MAXLONGITUDE = 180;
+ public static final int EARTHRADIUSINMETERS = 6378137;
+ public static final int TILESPLITLEVEL = 0;
+
+
+ public static final double EarthCircumferenceInMeters = 2 * Math.PI
+ * EARTHRADIUSINMETERS;
+
+
+ public static double clip(double n, double minValue, double maxValue) {
+ return Math.min(Math.max(n, minValue), maxValue);
+ }
+
+ public static IPoint lonlat2Geo(double latitude, double longitude,
+ int levelOfDetail) {
+ IPoint rPnt = new IPoint();
+ latitude = clip(latitude, MINLATITUDE, MAXLATITUDE) * Math.PI / 180;
+ longitude = clip(longitude, MINLONGITUDE, MAXLONGITUDE) * Math.PI / 180;
+ double sinLatitude = Math.sin(latitude);
+ double xMeters = EARTHRADIUSINMETERS * longitude;
+ double lLog = Math.log((1 + sinLatitude) / (1 - sinLatitude));
+ double yMeters = EARTHRADIUSINMETERS / 2 * lLog;
+ long numPixels = (long) PIXELSPERTILE << levelOfDetail;
+ double metersPerPixel = EarthCircumferenceInMeters / numPixels;
+ rPnt.x = (int) clip((EarthCircumferenceInMeters / 2 + xMeters)
+ / metersPerPixel + 0.5, 0, numPixels - 1);
+ long tmp = (long) (EarthCircumferenceInMeters / 2 - yMeters);
+ rPnt.y = (int) clip((double) tmp / metersPerPixel + 0.5, 0,
+ numPixels - 1);
+ return rPnt;
+ }
+
+
+
+ public static String formatKM(int d) {
+ if (d == 0) {
+ return "0米";
+ } else if (d < 100) {
+ return d + "米";
+ } else if ((100 <= d) && (d < 1000)) {
+ return d + "米";
+ } else if ((1000 <= d) && (d < 10000)) {
+ return (d / 10) * 10 / 1000.0D + "公里";
+ } else if ((10000 <= d) && (d < 100000)) {
+ return (d / 100) * 100 / 1000.0D + "公里";
+ }
+ return (d / 1000) + "公里";
+ }
+}
diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/SmallMapDirectionView.java b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/SmallMapDirectionView.java
index 5e0d974a80..c5e962f0e3 100644
--- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/SmallMapDirectionView.java
+++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/smp/SmallMapDirectionView.java
@@ -13,6 +13,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
+import android.widget.TextView;
import androidx.annotation.Nullable;
@@ -38,8 +39,24 @@ import com.amap.api.navi.AMapNaviViewListener;
import com.amap.api.navi.AMapNaviViewOptions;
import com.amap.api.navi.ParallelRoadListener;
import com.amap.api.navi.enums.AMapNaviParallelRoadStatus;
+import com.amap.api.navi.model.AMapCalcRouteResult;
+import com.amap.api.navi.model.AMapLaneInfo;
+import com.amap.api.navi.model.AMapModelCross;
+import com.amap.api.navi.model.AMapNaviCameraInfo;
+import com.amap.api.navi.model.AMapNaviCross;
+import com.amap.api.navi.model.AMapNaviInfo;
+import com.amap.api.navi.model.AMapNaviLocation;
+import com.amap.api.navi.model.AMapNaviPath;
+import com.amap.api.navi.model.AMapNaviRouteNotifyData;
+import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo;
+import com.amap.api.navi.model.AMapServiceAreaInfo;
+import com.amap.api.navi.model.AimLessModeCongestionInfo;
+import com.amap.api.navi.model.AimLessModeStat;
+import com.amap.api.navi.model.NaviInfo;
import com.amap.api.navi.model.NaviLatLng;
import com.amap.api.navi.model.RouteOverlayOptions;
+import com.amap.api.navi.view.RouteOverLay;
+import com.autonavi.tbt.TrafficFacilityInfo;
import com.mogo.cloud.commons.utils.CoordinateUtils;
import com.mogo.eagle.core.data.map.MogoLatLng;
import com.mogo.eagle.core.data.map.MogoLocation;
@@ -63,7 +80,7 @@ import java.util.List;
*/
public class SmallMapDirectionView
extends RelativeLayout
- implements IMoGoMapLocationListener, ISmallMapDirectionView,ParallelRoadListener{
+ implements IMoGoMapLocationListener, ISmallMapDirectionView, AMapNaviListener {
//小地图名称
public static final String TAG = "SmallMapDirectionView";
@@ -72,11 +89,11 @@ public class SmallMapDirectionView
private AMapNaviView mAMapNaviView;
protected AMapNavi mAMapNavi;
private AMap mAMap;
- // private Marker mCarMarker;
-// private Marker mStartMarker;
+ private Marker mCarMarker;
+ // private Marker mStartMarker;
// private Marker mEndMarker;
- protected NaviLatLng mEndLatlng = new NaviLatLng(40.032969, 116.313151);
- protected NaviLatLng mStartLatlng = new NaviLatLng(40.106731, 116.248692);
+ protected NaviLatLng mEndLatlng = new NaviLatLng(26.817455, 112.579649);
+ protected NaviLatLng mStartLatlng = new NaviLatLng(26.818968, 112.571216);
protected final List