package com.mogo.map; import static com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_300; import static com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_CROSS; import static com.mogo.map.uicontroller.VisualAngleMode.MAP_STYLE_VR_ANGLE_TOP; import static com.mogo.map.uicontroller.VisualAngleMode.MODE_CLOSE_SIGHT; import static com.mogo.map.uicontroller.VisualAngleMode.MODE_LONG_SIGHT; import static com.mogo.map.uicontroller.VisualAngleMode.MODE_MEDIUM_SIGHT; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.location.Location; import android.os.Bundle; import android.os.Trace; import android.util.Log; import android.view.MotionEvent; import android.view.View; import com.mogo.commons.constants.SharedPrefsConstants; import com.mogo.commons.debug.DebugConfig; import com.mogo.eagle.core.data.config.HdMapBuildConfig; import com.mogo.eagle.core.data.map.MogoLatLng; import com.mogo.eagle.core.data.map.MogoLocation; import com.mogo.eagle.core.function.call.map.CallerMapDataCollectorManager; import com.mogo.eagle.core.function.call.map.CallerMapLocationListenerManager; import com.mogo.eagle.core.function.call.map.CallerMapStyleListenerManager; import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager; import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr; import com.mogo.eagle.core.utilcode.mogo.toast.TipToast; import com.mogo.eagle.core.utilcode.util.GsonUtils; import com.mogo.eagle.core.utilcode.util.UiThreadHandler; import com.mogo.map.listener.MogoMapListenerHandler; import com.mogo.map.navi.MogoCarLocationChangedListenerRegister; import com.mogo.map.uicontroller.CarCursorOption; import com.mogo.map.uicontroller.EnumMapUI; import com.mogo.map.uicontroller.IMogoMapUIController; import com.mogo.map.uicontroller.MapCameraPosition; import com.mogo.map.uicontroller.MapControlResult; import com.mogo.map.uicontroller.VisualAngleMode; import com.mogo.map.utils.MogoMapUtils; import com.mogo.map.utils.ObjectUtils; import com.mogo.map.utils.PointInterpolatorUtil; import com.mogo.map.utils.ResIdCache; import com.zhidaoauto.map.sdk.open.MapAutoApi; import com.zhidaoauto.map.sdk.open.abs.MapStatusListener; import com.zhidaoauto.map.sdk.open.abs.OnCameraChangeListener; import com.zhidaoauto.map.sdk.open.abs.OnMapClickListener; import com.zhidaoauto.map.sdk.open.abs.OnMapLoadedListener; import com.zhidaoauto.map.sdk.open.abs.OnMapStyleListener; import com.zhidaoauto.map.sdk.open.abs.OnMapTouchListener; import com.zhidaoauto.map.sdk.open.abs.OnMapViewVisualAngleChangeListener; import com.zhidaoauto.map.sdk.open.camera.CameraPosition; import com.zhidaoauto.map.sdk.open.camera.CameraUpdateFactory; import com.zhidaoauto.map.sdk.open.camera.LatLngBounds; import com.zhidaoauto.map.sdk.open.data.MapDataApi; import com.zhidaoauto.map.sdk.open.data.SinglePointRoadInfo; import com.zhidaoauto.map.sdk.open.location.LocationListener; import com.zhidaoauto.map.sdk.open.location.MyLocationStyle; import com.zhidaoauto.map.sdk.open.location.RTKAutopilotLocationBean; import com.zhidaoauto.map.sdk.open.marker.BitmapDescriptorFactory; import com.zhidaoauto.map.sdk.open.marker.Marker; import com.zhidaoauto.map.sdk.open.marker.OnMarkClickListener; import com.zhidaoauto.map.sdk.open.query.LonLatPoint; import com.zhidaoauto.map.sdk.open.tools.MapTools; import com.zhidaoauto.map.sdk.open.view.MapAutoView; import com.zhidaoauto.map.sdk.open.view.MapAutoViewHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import mogo.telematics.pad.MessagePad; public class AMapViewWrapper implements IMogoMapView, IMogoMapUIController, LocationListener, OnMapLoadedListener, MapStatusListener, OnCameraChangeListener, OnMapClickListener, OnMapTouchListener, OnMarkClickListener, OnMapStyleListener, MapStyleController.IMapStyleAutoChangedListener, OnMapViewVisualAngleChangeListener { private static final String TAG = "AMapViewWrapper"; private final MapAutoView mMapView; private final IMogoMap mIMap; private AMapMarkerClickHandler mMarkerClickHandler; private final CarCursorOption DEFAULT_OPTION = new CarCursorOption.Builder() .carCursorRes(R.drawable.map_api_ic_current_location2) .naviCursorRes(R.drawable.ic_amap_navi_cursor) .build(); private CarCursorOption mCarCursorOption = DEFAULT_OPTION; private EnumMapUI mCurrentCarUIMode; private EnumMapUI mCurrentUI; private VisualAngleMode mVisualAngleMode = MODE_MEDIUM_SIGHT; private int mLockZoom = 16; private long startTime; private float mDefaultZoomLevel = 16.0f; private boolean mIsCarLocked = false; private boolean mIsLightStyle = false; private boolean mMapLoaded = false; private boolean mIsFirstLocated = true; private boolean mIsDelayed = false; public AMapViewWrapper(MapAutoView mMapView) { startTime = System.currentTimeMillis(); CallerLogger.INSTANCE.i(TAG, "autoop--AMapViewWrapper: init"); this.mMapView = mMapView; initViews(); initListeners(); this.mIMap = new AMapWrapper(this.mMapView.getMapAutoViewHelper(), this.mMapView, this); } private void initViews() { } private void initMapView() { if (mMapView == null) { return; } MapAutoViewHelper options = mMapView.getMapAutoViewHelper(); if (options != null) { //设置手势是否可以缩放 isCanZoom true 可缩放 false 不可缩放 options.setZoomGesturesEnabled(true); options.setScaleVRMode(true); if (options.getMyLocationStyle() != null) { options.getMyLocationStyle().setDisplayAnimEnable(false); } //修改自车模型,未来需区分车的类型 options.setMyLocationStyle(options.getMyLocationStyle().myLocationIcon(HdMapBuildConfig.currentCarVrIconRes, true)); // MapAutoApi.INSTANCE.getMyLocationStyle().myLocationIcon(HdMapBuildConfig.currentCarVrIconRes, true); } } private void initListeners() { mMapView.setOnMarkClickListener(this); mMarkerClickHandler = AMapMarkerClickHandler.getInstance(); mMapView.setOnMapLoadedListener(this); mMapView.setOnMapTouchListener(this); mMapView.setOnMapClickListener(this); mMapView.getLocationClient().registerListener(this); mMapView.registerListener(this, MapAutoApi.LISTENER_TYPE_ZOOM); mMapView.registerListener(this, MapAutoApi.LISTENER_TYPE_ROTATE); mMapView.registerListener(this, MapAutoApi.LISTENER_TYPE_3D); mMapView.setOnCameraChangeListener(this); mMapView.setOnMapStyleListener(this); mMapView.setOnMapViewVisualAngleChangeListener(this); CallerLogger.INSTANCE.d(TAG, "styleop - initListeners - setOnMapStyleListener - view " + mMapView); } private Context getContext() { return mMapView.getContext(); } @Override public View getMapView() { return mMapView; } @Override public IMogoMap getMap() { return mIMap; } @Override public void onCreate(Bundle bundle) { if (mMapView != null) { mMapView.onCreate(bundle); CallerLogger.INSTANCE.d(TAG, "map onCreate"); } } @Override public void onResume() { if (mMapView != null) { mMapView.onResume(); CallerLogger.INSTANCE.d(TAG, "map onResume"); } } @Override public void onPause() { if (mMapView != null) { mMapView.onPause(); CallerLogger.INSTANCE.d(TAG, "map onPause"); } } @Override public void onDestroy() { if (mMapView != null) { mMapView.onDestroy(); mMapView.setOnMarkClickListener(null); mMapView.setOnMapLoadedListener(null); mMapView.setOnMapTouchListener(null); mMapView.setOnMapClickListener(null); mMapView.getLocationClient().unRegisterListener(this); mMapView.setOnCameraChangeListener(null); CallerLogger.INSTANCE.d(TAG, "map onDestroy"); } } @Override public void onSaveInstanceState(Bundle outState) { if (mMapView != null) { mMapView.onSaveInstanceState(outState); CallerLogger.INSTANCE.d(TAG, "map onSaveInstanceState"); } } @Override public void onLowMemory() { } @Override public void setTrafficEnabled(boolean visible) { if (checkAMapView()) { // mMapView.getMapAutoViewHelper().setTraffic( visible ); } } @Override public MapControlResult changeZoom(boolean zoom) { if (checkAMapView()) { mDefaultZoomLevel = (getMap().getZoomLevel() + 0.5f); if (zoom) { if (mDefaultZoomLevel >= 20f) { return MapControlResult.TARGET; } } else { if (mDefaultZoomLevel <= 7f) { return MapControlResult.TARGET; } } if (zoom) { mDefaultZoomLevel += 1f; if (mDefaultZoomLevel > 19f) { mDefaultZoomLevel = 19f; } } else { mDefaultZoomLevel -= 1f; if (mDefaultZoomLevel < 8f) { mDefaultZoomLevel = 8f; } } changeZoom(mDefaultZoomLevel); } return MapControlResult.SUCCESS; } @Override public MapControlResult changeZoom(float zoom) { if (mCurrentUI == EnumMapUI.Type_VR) { return MapControlResult.ERROR; } CallerLogger.INSTANCE.d(TAG, "changeZoom : " + zoom); if (DebugConfig.isDebug()) { CallerLogger.INSTANCE.d(TAG, Log.getStackTraceString(new Throwable())); } getMap().changeZoom(zoom); return MapControlResult.SUCCESS; } @Override public void changeMapMode(EnumMapUI ui) { if (ui == null) { return; } CallerLogger.INSTANCE.d(TAG, "设置的样式 :" + ui); if (checkAMapView()) { mMapView.getMapAutoViewHelper().setScaleVRMode(true); mMapView.getMapAutoViewHelper().setMapStyle(MapAutoApi.MAP_STYLE_VR); // TODO 这里临时修改关闭2D // switch (ui) { // case CarUp_2D: // case CarUp_3D: // case NorthUP_2D: // setUIMode(ui); // break; // case Type_VR: // mMapView.getMapAutoViewHelper().setScaleVRMode(true); // mMapView.getMapAutoViewHelper().setMapStyle(MapAutoApi.MAP_STYLE_VR); // return; // case Type_Light: // mMapView.getMapAutoViewHelper().setAutoSwitchStyle(false); // mMapView.getMapAutoViewHelper().setMapStyle(MapAutoApi.MAP_STYLE_DAY); // mIsLightStyle = true; // break; // case Type_Night: // mMapView.getMapAutoViewHelper().setAutoSwitchStyle(false); // mMapView.getMapAutoViewHelper().setMapStyle(MapAutoApi.MAP_STYLE_NIGHT); // mIsLightStyle = false; // break; // case Type_AUTO_LIGHT_Night: // mMapView.getMapAutoViewHelper().setAutoSwitchStyle(true); // break; // } } } @Override public void changeMapVisualAngle(VisualAngleMode angelMode, MogoLatLng mogoLatLng) { MapAutoViewHelper mapAutoViewHelper = mMapView.getMapAutoViewHelper(); if (mapAutoViewHelper != null) { mVisualAngleMode = angelMode; if (angelMode == MODE_CLOSE_SIGHT) { if (mogoLatLng == null) { CallerLogger.INSTANCE.e(TAG, "切换地图近景需要传入要移动的经纬度数据"); return; } // 近景传入经纬度为点击地图上静态marker经纬度数据,为GPS坐标点。 mapAutoViewHelper.setNearViewAnglePosition(new LonLatPoint(mogoLatLng.lon, mogoLatLng.lat), true); } else { mapAutoViewHelper.setMapViewVisualAngle(angelMode.getCode()); } } } @Override public VisualAngleMode getCurrentMapVisualAngle() { return mVisualAngleMode; } @Override public void moveToCenter(MogoLatLng latLng) { moveToCenter(latLng, true); } private boolean checkAMapView() { if (mMapView == null || mMapView.getMapAutoViewHelper() == null) { CallerLogger.INSTANCE.e(TAG, "自研mapView实例为空,请检查"); return false; } return true; } @Override public void moveToCenter(MogoLatLng latLng, boolean animate) { CallerLogger.INSTANCE.d(TAG, "move to center " + latLng); if (latLng == null || latLng.lat == 0.0d || latLng.lon == 0.0d) { CallerLogger.INSTANCE.e(TAG, "latlng = null or is illegal"); return; } if (DebugConfig.isDebug()) { CallerLogger.INSTANCE.d(TAG, Log.getStackTraceString(new Throwable())); } loseLockMode(); mMapView.getMapAutoViewHelper().animateCamera(new LonLatPoint(latLng.lon, latLng.lat)); } @Override public void showMyLocation(boolean visible) { CallerLogger.INSTANCE.d(TAG, "showMyLocation1 " + visible); // 如果是VR模式 if (mCurrentUI == EnumMapUI.Type_VR) { return; } // 不是VR模式情况强制刷新下 if (checkAMapView()) { MyLocationStyle style = mMapView.getMapAutoViewHelper().getMyLocationStyle(); if (visible) { // 强制刷新一遍车标 style.myLocationIcon(mCarCursorOption.getCarCursorRes()); } mMapView.getMapAutoViewHelper().setMyLocationStyle(style); } } @Override public void showMyLocation(View view) { if (DebugConfig.isDebug()) { CallerLogger.INSTANCE.d(TAG, Log.getStackTraceString(new Throwable())); } if (checkAMapView()) { MyLocationStyle style = mMapView.getMapAutoViewHelper().getMyLocationStyle(); style.myLocationIcon(BitmapDescriptorFactory.INSTANCE.convertViewToBitmap(view)); mMapView.getMapAutoViewHelper().setMyLocationStyle(style); } } public void initMyLocation() { if (checkAMapView()) { mMapView.getMapAutoViewHelper().setMyLocationEnabled(true); MyLocationStyle style = mMapView.getMapAutoViewHelper().getMyLocationStyle(); style.setLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER); style.interval(1000); // style.anchor( 0.5F, 0.5F ); // style.strokeColor( Color.TRANSPARENT ); // style.strokeWidth( 0 ); // style.radiusFillColor( Color.TRANSPARENT ); mMapView.getMapAutoViewHelper().setMyLocationStyle(style); } } @Override public void recoverLockMode() { if (checkAMapView()) { if (mCurrentUI == EnumMapUI.Type_VR) { return; } CallerLogger.INSTANCE.d(TAG, "锁车"); mMapView.getMapAutoViewHelper().setLockMode(true); mIsCarLocked = true; } } @Override public void loseLockMode() { if (mCurrentUI == EnumMapUI.Type_VR) { return; } CallerLogger.INSTANCE.d(TAG, "解锁锁车"); mMapView.getMapAutoViewHelper().setLockMode(false); mIsCarLocked = false; } @Override public void setLockZoom(int var1) { mLockZoom = var1; } @Override public void displayOverview(Rect bounds) { } @Override public float getScalePerPixel() { return getMap().getScalePerPixel(); } @Override public float getZoomLevel() { return getMap().getZoomLevel(); } @Override public float getRoadWidth(double lon, double lat, float angle, boolean isGpsLocation, boolean isRTK) { return getMap().getRoadWidth(lon, lat, angle, isGpsLocation, isRTK); } @Override public MogoLatLng getCameraNorthEastPosition() { return ObjectUtils.fromAMap(MapTools.INSTANCE.getVisibleRegion().getRightTopPoint()); } @Override public MogoLatLng getCameraSouthWestPosition() { try { return ObjectUtils.fromAMap(MapTools.INSTANCE.getVisibleRegion().getLeftBottomPoint()); } catch (Exception e) { e.printStackTrace(); } return null; } @Override public MogoLatLng getWindowCenterLocation() { try { return ObjectUtils.fromAMap(mMapView.getMapAutoViewHelper().getCenter()); } catch (Exception e) { e.printStackTrace(); } return null; } @Override public void setPointToCenter(double mapCenterX, double mapCenterY) { if (checkAMapView()) { if (mCurrentUI == EnumMapUI.Type_VR) { return; } CallerLogger.INSTANCE.d(TAG, "setPointToCenter x : " + mapCenterX + " y : " + mapCenterY); mMapView.getMapAutoViewHelper().setPointToCenter((float) mapCenterX, (float) mapCenterY); } } @Override public Point getLocationPointInScreen(MogoLatLng latLng) { if (checkAMapView()) { try { return MapTools.INSTANCE.toScreenLocation(ObjectUtils.fromMogo(latLng)); } catch (Exception e) { e.printStackTrace(); return null; } } return null; } @Override public MogoLatLng getLocationMogoLatLngInScreen(Point point) { if (checkAMapView()) { try { return ObjectUtils.fromAMap( MapTools.INSTANCE.fromScreenLocation(point)); } catch (Exception e) { e.printStackTrace(); return null; } } return null; } @Override public void setRenderFps(int fps) { if (checkAMapView()) { if (mMapView.getMapAutoViewHelper() != null) { mMapView.getMapAutoViewHelper().setRenderFps(fps); CallerLogger.INSTANCE.d(TAG, "设置刷新帧率 fps = " + fps); } } } @Override public void showBounds(String tag, MogoLatLng carPosition, List lonLats, Rect bound, boolean lockCarPosition) { if (!checkAMapView()) { return; } if (mCurrentUI == EnumMapUI.Type_VR) { CallerLogger.INSTANCE.w(TAG, "vr 模式下忽略该设置"); return; } CallerLogger.INSTANCE.i(TAG, "showBounds : " + tag + " , " + carPosition.toString() + " , " + bound.toShortString() + " , " + lockCarPosition); try { LatLngBounds latLngBounds = MogoMapUtils.getLatLngBounds(carPosition, lonLats, lockCarPosition); if (!lockCarPosition) { loseLockMode(); } mMapView.getMapAutoViewHelper().setCenter(ObjectUtils.fromMogo(carPosition)); mMapView.getMapAutoViewHelper().moveCamera(CameraUpdateFactory.INSTANCE.newLatLngBounds(latLngBounds, bound.left, bound.right, bound.top, bound.bottom)); } catch (Exception e) { CallerLogger.INSTANCE.e(TAG, "tag : " + tag + " error : " + e); } } @Override public void forceRender() { if (checkAMapView()) { mMapView.getMapAutoViewHelper().runOnDrawFrame(); } } @Override public float calculateLineDistance(MogoLatLng p1, MogoLatLng p2) throws Exception { if (p1 == null || p2 == null) { throw new Exception("计算距离的点不能为 null"); } return MogoMapUtils.calculateLineDistance(ObjectUtils.fromMogo(p1), ObjectUtils.fromMogo(p2)); } @Override public EnumMapUI getCurrentUiMode() { return mCurrentCarUIMode; } @Override public void changeMyLocation(Location location) { } @Override public synchronized boolean isCarLocked() { return mMapView.getMapAutoViewHelper().getLockMode(); } @Override public void setCarCursorOption(CarCursorOption option) { if (mCurrentUI == EnumMapUI.Type_VR) { return; } if (mCarCursorOption != null && mCarCursorOption != DEFAULT_OPTION) { mCarCursorOption.destroy(); } if (option != null) { try { mCarCursorOption = option.clone(); } catch (Exception e) { mCarCursorOption = DEFAULT_OPTION; } } else { mCarCursorOption = DEFAULT_OPTION; } if (!checkAMapView()) { return; } if (mMapView.getMapAutoViewHelper() == null) { return; } MyLocationStyle style = mMapView.getMapAutoViewHelper().getMyLocationStyle(); if (mCarCursorOption.getCarCursorBmp() != null && !mCarCursorOption.getCarCursorBmp().isRecycled()) { style.myLocationIcon(mCarCursorOption.getCarCursorBmp()); } else { if (mCarCursorOption.getCarCursorRes() != 0) { style.myLocationIcon(mCarCursorOption.getCarCursorRes()); } } mMapView.getMapAutoViewHelper().setMyLocationStyle(style); } @Override public MapCameraPosition getMapCameraPosition() { if (checkAMapView()) { CameraPosition cameraPosition = mMapView.getMapAutoViewHelper().getCameraPosition(); return ObjectUtils.fromAMap(cameraPosition); } return null; } @Override public void changeBearing(float bearing) { if (checkAMapView()) { mMapView.getMapAutoViewHelper().setMapViewRotation(bearing); } } @Override public void changeMapViewAngle(int type) { if (checkAMapView()) { //mMapView.getMapAutoViewHelper().testMapViewAngle(type); } } @Override public void changeCurrentIcon(int iconId) { if (checkAMapView()) { mMapView.getMapAutoViewHelper().getMyLocationStyle().myLocationIcon(iconId, true); } } @Override public long getTileId(double lon, double lat) { return getMap().getUIController().getTileId(lon, lat); } @Override public int getSpeedLimmit(double lon, double lat, float angle) { return MapDataApi.INSTANCE.getLimitSpeed(lon, lat, angle); } @Override public void onLocationChanged(@NotNull com.zhidaoauto.map.sdk.open.location.MogoLocation location) { MogoLocation mLastLocation = ObjectUtils.fromLocation(location); UiThreadHandler.post(() -> CallerMapLocationListenerManager.INSTANCE.invokeMapLocationChangeListener(mLastLocation)); Location sysLocation = new Location(location.getProvider()); sysLocation.setAltitude(location.getAltitude()); sysLocation.setLatitude(location.getLat()); sysLocation.setLongitude(location.getLon()); sysLocation.setProvider(location.getProvider()); sysLocation.setAccuracy(location.getAcceleration()); sysLocation.setTime(location.getDuration()); sysLocation.setBearing((float) location.getHeading()); sysLocation.setSpeed(location.getSpeed()); // 将有效经纬度暂存本地,提供给下一次的Http-DNS使用,防止首次请求位置获取不到 if (location.getLat() > 0) { SharedPrefsMgr.getInstance(mMapView.getContext()) .putString(SharedPrefsConstants.LOCATION_CITY_CODE, location.getCityCode()); SharedPrefsMgr.getInstance(mMapView.getContext()) .putString(SharedPrefsConstants.LOCATION_LATITUDE, String.valueOf(location.getLat())); SharedPrefsMgr.getInstance(mMapView.getContext()) .putString(SharedPrefsConstants.LOCATION_LONGITUDE, String.valueOf(location.getLon())); } if (MogoCarLocationChangedListenerRegister.getInstance().getListener() != null) { MogoCarLocationChangedListenerRegister.getInstance().getListener().onCarLocationChanged2(sysLocation); } if (checkAMapView() && mMapLoaded) { // 地图初始化完成后,每隔5s自动判断当前地图的模式 if (mIsFirstLocated) { if (!mIsDelayed) { mIsDelayed = true; UiThreadHandler.postDelayed(() -> { //CallerLogger.INSTANCE.d(TAG, "倒计时结束"); mIsFirstLocated = false; }, 5_000L); } } else { mIsFirstLocated = true; mIsDelayed = false; CallerLogger.INSTANCE.d(TAG, "同步定位:" + GsonUtils.toJson(location)); MapStyleController.getInstance().onLocationChanged(location, this); } } } @Override public void onMapClick(@Nullable LonLatPoint lonLatPoint) { MogoMapListenerHandler.getInstance().onMapClick(ObjectUtils.fromAMap(lonLatPoint)); } @Override public void onMapInit() { CallerLogger.INSTANCE.i(TAG, "autoop--onMapInit: "); MogoMapListenerHandler.getInstance().onMapLoaded(); } @Override public void onMapLoaded() { CallerLogger.INSTANCE.i(TAG, "autoop--onMapLoaded: "); mMapLoaded = true; CameraPosition cameraPosition = mMapView.getMapAutoViewHelper().getCameraPosition(); Trace.beginSection("timer.onCameraChangeFinish"); MogoMapListenerHandler.getInstance().onMapChanged(ObjectUtils.fromAMap(cameraPosition.getTarget()), cameraPosition.getZoom(), cameraPosition.getTilt(), cameraPosition.getBearing()); Trace.endSection(); initMapView(); initMyLocation(); } @Override public boolean onTouch(@Nullable MotionEvent motionEvent) { MogoMapListenerHandler.getInstance().onTouch(motionEvent); return false; } @Override public void onMarkClick(@NotNull Marker markerInfo) { mMarkerClickHandler.handleMarkerClicked(markerInfo); } @Override public void onRoadLoaded(@Nullable String s) { CallerLogger.INSTANCE.i(TAG, "autoop--onMapLoaded: "); } @Override public void onMapStatusChanged(int type, int value) { //CallerLogger.INSTANCE.i(TAG, "mapop--onMapStatusChanged-: " + type + "," + value); } @Override public void onMapViewVisualAngleChange(int i) { CallerLogger.INSTANCE.d(TAG, " 地图自动更改视距 currentThread : " + Thread.currentThread().getName()); mVisualAngleMode = getVisualAngleMode(i); MogoMapListenerHandler.getInstance().onMapVisualAngleChanged(mVisualAngleMode); } private VisualAngleMode getVisualAngleMode(int mode) { switch (mode) { case 0: return MODE_CLOSE_SIGHT; case 1: return MODE_MEDIUM_SIGHT; case 2: return MODE_LONG_SIGHT; case 3: return MAP_STYLE_VR_ANGLE_300; case 4: return MAP_STYLE_VR_ANGLE_TOP; case 5: return MAP_STYLE_VR_ANGLE_CROSS; default: throw new IllegalStateException("mode is unCorrect"); } } @Override public void onCameraChange(int type, int value) { //CallerLogger.INSTANCE.i(TAG, "mapop--onCameraChange-: " + type + "," + value); } @Override public void onCameraChangeFinish(@Nullable CameraPosition cameraPosition) { // CallerLogger.INSTANCE.i( TAG, "mapop--onCameraChangeFinish-: " + cameraPosition + "cost:" + ( System.currentTimeMillis() - startTime ) ); if (cameraPosition != null) { Trace.beginSection("timer.onCameraChangeFinish"); MogoMapListenerHandler.getInstance().onMapChanged(ObjectUtils.fromAMap(cameraPosition.getTarget()), cameraPosition.getZoom(), cameraPosition.getTilt(), cameraPosition.getBearing()); Trace.endSection(); } } @Override public void emphasizeMyLocation() { } @Override public void onChangeMapStyle(int styleId) { EnumMapUI last = mCurrentUI; CallerLogger.INSTANCE.d(TAG, "currentMapStyle = " + styleId); if (styleId == MapAutoApi.MAP_STYLE_DAY || styleId == MapAutoApi.MAP_STYLE_DAY_NAV) { mCurrentUI = EnumMapUI.Type_Light; } else if (styleId == MapAutoApi.MAP_STYLE_NIGHT || styleId == MapAutoApi.MAP_STYLE_NIGHT_NAV) { mCurrentUI = EnumMapUI.Type_Night; } else if (styleId == MapAutoApi.MAP_STYLE_VR) { mCurrentUI = EnumMapUI.Type_VR; // 进入vr模式的时候自动切换到车头朝上 change2CarUp(); } if (last == mCurrentUI) { CallerLogger.INSTANCE.d(TAG, "currentUI is same as last = " + mCurrentUI); return; } // vr 模式切换到普通模式下,保持之前的白天模式 wtf. if (last == EnumMapUI.Type_VR && mCurrentUI != EnumMapUI.Type_Light) { if (mIsLightStyle) { changeMapMode(EnumMapUI.Type_Light); return; } } CallerLogger.INSTANCE.d(TAG, Log.getStackTraceString(new Throwable())); if (mCurrentUI != null) { UiThreadHandler.post(() -> { try { CallerLogger.INSTANCE.d(TAG, "currentUI = " + mCurrentUI); MogoMapListenerHandler.getInstance().onMapModeChanged(mCurrentUI); CallerMapStyleListenerManager.INSTANCE.invokeMapStyleChange(styleId); } catch (Exception e) { e.printStackTrace(); } }); } } /** * 切换到车头朝上 */ private void change2CarUp() { mMapView.getMapAutoViewHelper().setMapViewPerspective(MapAutoApi.MAP_PERSPECTIVE_UP_CAR); } @Override public void onStyleAutoChanged(boolean isVrMode) { if (isVrMode) { if (mCurrentUI != EnumMapUI.Type_VR) { CallerLogger.INSTANCE.d(TAG, "自动切换为vr模式"); changeMapMode(EnumMapUI.Type_VR); } } else { if (mCurrentUI == EnumMapUI.Type_VR) { CallerLogger.INSTANCE.d(TAG, "自动切换为2D模式"); if (mIsLightStyle) { changeMapMode(EnumMapUI.Type_Light); } else { changeMapMode(EnumMapUI.Type_Night); } } } } private boolean mRtkEnable = false; @Override public void rtkEnable(boolean enable) { try { mRtkEnable = !mRtkEnable; TipToast.shortTip(mRtkEnable ? "已开启rtk道路匹配" : "已开启gps道路匹配"); mMapView.getLocationClient().rtkEnable(mRtkEnable); } catch (Exception e) { CallerLogger.INSTANCE.e(TAG, "rtkEnable has exception : " + e); } } @Override public void syncLocation2Map(JSONObject data) { if (!checkAMapView()) { return; } if (data == null) { CallerLogger.INSTANCE.d(TAG, "停止使用rtk定位数据"); return; } double lon = data.optDouble("lon", -1); double lat = data.optDouble("lat", -1); double alt = data.optDouble("alt", -1); double heading = data.optDouble("heading", -1); double acceleration = data.optDouble("acceleration", -1); double yawRate = data.optDouble("yawRate", -1); double speed = data.optDouble("speed", -1); long systemTime = data.optLong("systemTime"); long satelliteTime = data.optLong("satelliteTime"); if (lon == -1) { return; } RTKAutopilotLocationBean bean = new RTKAutopilotLocationBean(); bean.setYaw_rate(yawRate); bean.setHeading(heading); bean.setAcceleration(acceleration); bean.setAlt(alt); bean.setSystemTime(systemTime); bean.setSatelliteTime(satelliteTime); bean.setLon(lon); bean.setGnss_speed(((float) speed)); bean.setLat(lat); // 使用外部定位数据修改自车位置 mMapView.getLocationClient().updateRTKAutoPilotLocation(bean); CallerMapUIServiceManager.INSTANCE.getSingletonLocationClient(getContext()).updateLocation(bean); CallerMapDataCollectorManager.INSTANCE.setIsInit(); } @Override public void syncLocation2Map(MessagePad.GnssInfo gnssInfo) { if (!checkAMapView()) { return; } if (gnssInfo.getLongitude() == -1) { return; } RTKAutopilotLocationBean bean = new RTKAutopilotLocationBean(); bean.setYaw_rate(gnssInfo.getYawRate()); bean.setHeading(gnssInfo.getHeading()); bean.setAcceleration(gnssInfo.getAcceleration()); bean.setAlt(gnssInfo.getAltitude()); bean.setSystemTime(Double.valueOf(gnssInfo.getSystemTime()).longValue()); bean.setSatelliteTime(Double.valueOf(gnssInfo.getSatelliteTime()).longValue()); bean.setLon(gnssInfo.getLongitude()); bean.setLat(gnssInfo.getLatitude()); bean.setGnss_speed(((float) gnssInfo.getGnssSpeed())); // 使用外部定位数据修改自车位置 mMapView.getLocationClient().updateRTKAutoPilotLocation(bean); CallerMapUIServiceManager.INSTANCE.getSingletonLocationClient(getContext()).updateLocation(bean); CallerMapDataCollectorManager.INSTANCE.setIsInit(); } @Override public void openVrMode(boolean zoomGestureEnable) { try { mMapView.getMapAutoViewHelper().setZoomGesturesEnabled(zoomGestureEnable); mMapView.getMapAutoViewHelper().setMapStyle(MapAutoApi.MAP_STYLE_VR); } catch (Exception e) { e.printStackTrace(); } } Map roadCacheMap = new ConcurrentHashMap<>(); private final RoadCacheWrapper noCache = new RoadCacheWrapper(null); @Override public void clearRoadCacheById(String id) { roadCacheMap.remove(id); } @Override public double[] matchRoad(String id, double lon, double lat, double angle, boolean isGpsLocation, boolean isRTK) { return matchRoad(id, lon, lat, angle, isGpsLocation, isRTK, true); } /** * 带缓存的道路匹配算法 *

* 使用{@link MapDataApi#INSTANCE#getSinglePointMatchRoad()}这个方法获取道路数据会存在一定耗时,目前是4-10ms,因为请求频繁,为了 * 减小这部分耗时,使用一个ConcurrentHashMap{@link #roadCacheMap}缓存道路数据,此缓存是以目标车id为key,道路数据为value,以此减少 * 道路数据获取次数。 *

* 当出现道路改变的情况,需要重新获取道路数据,采用递归的方式重获道路数据以及添加缓存,为了避免一直获取不到道路数据,一直递归,增加useCache参数跳出递归。 *

* 道路改变的情况主要分为: * 1. 目标车距离道路中心线距离超过阈值 matchThreshold(取路宽的1/4为阈值); * 2. 目标车到道路中心线的映射点不在道路上(此判断在{@link PointInterpolatorUtil#mergeToRoad(double, double, List)}),也就是说已经驶出了这条道路 * * @param id 目标车唯一标识 * @param lon 目标车经度 * @param lat 目标车纬度 * @param angle 目标车角度 * @param isGpsLocation true-使用gps定位数据 * @param isRTK true-使用rtk数据 * @param usdCache true-使用道路缓存 false-不使用道路缓存 * @return double[]{匹配后经度,匹配后纬度,目标车距离车道中心线距离},若匹配后经纬度值为-1,则没有匹配成功 */ private double[] matchRoad(String id, double lon, double lat, double angle, boolean isGpsLocation, boolean isRTK, boolean usdCache) { double[] wgs = new double[]{lon, lat}; long start = System.currentTimeMillis(); RoadCacheWrapper roadCache = roadCacheMap.get(id); double matchThreshold = -1; if (roadCache == null || roadCache == noCache) { SinglePointRoadInfo singlePointRoadInfo = MapDataApi.INSTANCE.getSinglePointMatchRoad(((float) wgs[0]), ((float) wgs[1]), ((float) angle), isGpsLocation, isRTK); if (singlePointRoadInfo != null && singlePointRoadInfo.getCoords() != null && !singlePointRoadInfo.getCoords().isEmpty()) { roadCache = new RoadCacheWrapper(singlePointRoadInfo.getCoords()); roadCache.setLaneWidth(singlePointRoadInfo.getLaneWidth()); } } if (roadCache != null && roadCache.getRoad() != null && !roadCache.getRoad().isEmpty()) { // 未获取到道路中心线数据 start = System.currentTimeMillis(); matchThreshold = roadCache.getLaneWidth() / 4; double[] matchedPoint = PointInterpolatorUtil.mergeToRoad(wgs[0], wgs[1], roadCache.getRoad()); if (matchThreshold > 0 && matchedPoint[2] > 0 && matchedPoint[2] <= matchThreshold) { // 目标车在阈值范围内 roadCacheMap.put(id, roadCache); // CallerLogger.INSTANCE.i("timer-matchRoad-3", "cost " + (System.currentTimeMillis() - start) + "ms"); return matchedPoint; // CallerLogger.INSTANCE.i("timer-matchRoad-2", "cost " + (System.currentTimeMillis() - start) + "ms roadId: "+roadCache.getLastLat()); } else if (matchedPoint[2] > matchThreshold && matchedPoint[2] < 1.5) { // 目标车在阈值范围外,也就是说距离道路中心线太远了,就不吸附了 return null; } else { // 目标车到道路中心线的映射点不在道路上,也就是已经使出了缓存的那条道路,需要重新获取一条道路,用useCache这个参数来避免重复递归 roadCacheMap.put(id, noCache); // CallerLogger.INSTANCE.i("timer-matchRoad-2", "cost " + (System.currentTimeMillis() - start) + "ms roadId: " + roadCache.getLastLat()); if (usdCache) { return matchRoad(id, lon, lat, angle, isGpsLocation, isRTK, false); } else { return null; } } } roadCacheMap.put(id, noCache); return null; } @Override public String getMarkerInfoResName(String speedVal) { return ResIdCache.getVal(speedVal); } @Override public void setMarkerInfoResName(String speedVal, String val) { ResIdCache.putVal(speedVal, val); } @Override public void setMapDAngle(float angle) { mMapView.getMapAutoViewHelper().setMapDAngle(angle); } }