diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/MainMoGoApplication.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/MainMoGoApplication.java index d67b55b7c7..36e777c379 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/MainMoGoApplication.java +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/main/MainMoGoApplication.java @@ -27,7 +27,7 @@ import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsUpgradeListene import com.mogo.eagle.core.function.call.hmi.CallerHmiManager; import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager; import com.mogo.eagle.core.function.msgbox.db.MsgBoxDb; -import com.mogo.eagle.core.function.overview.OverviewDb; +import com.mogo.eagle.core.function.overview.db.OverviewDb; import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils; import com.mogo.eagle.core.utilcode.mogo.AppLaunchTimeUtils; import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverViewDataManager.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverViewDataManager.kt new file mode 100644 index 0000000000..1bd7910759 --- /dev/null +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverViewDataManager.kt @@ -0,0 +1,143 @@ +package com.mogo.eagle.core.function.overview + +import androidx.lifecycle.* +import com.mogo.commons.AbsMogoApplication +import com.mogo.commons.constants.HostConst +import com.mogo.eagle.core.data.map.Infrastructure +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager +import com.mogo.eagle.core.function.overview.db.OverviewDb +import com.mogo.eagle.core.function.overview.remote.OverViewServiceApi +import com.mogo.eagle.core.function.overview.remote.V2XEvent +import com.mogo.eagle.core.network.MoGoRetrofitFactory +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.launch +import java.util.concurrent.TimeUnit + +object OverViewDataManager { + + const val TAG = "OverViewDataManager" + + private val overviewDao by lazy { + OverviewDb.getDb(AbsMogoApplication.getApp()).overviewDao() + } + + private val _infStructures = MutableLiveData>() + private val _V2XEvents = MutableLiveData>() + private var disposable: Disposable? = null + + val infStructures + get() = _infStructures + + private val _infStructuresMap = _infStructures + .switchMap { infStructures -> + liveData { + val map = HashMap>() + infStructures.forEach { + val geoHash = it.geoHash + if (geoHash == null) { + return@forEach + } else { + if (!map.containsKey(geoHash)) { + val list = ArrayList() + list.add(it) + map[geoHash] = list + } else { + map[geoHash]?.add(it) + } + } + } + emit(map) + } + } + val infStructuresMap + get() = _infStructuresMap + + fun fetchInfStructures() { + ProcessLifecycleOwner.get().lifecycleScope.launch { + val data = try { + // 只查找摄像头 + overviewDao.listInfStructures(0) +// overviewDao.listAllInfStructures() + } catch (e: Exception) { + e.printStackTrace() + null + } + data?.let { + _infStructures.value = it + } + } + } + + fun updateGeoHash(id: Int, geoHash: String) { + ProcessLifecycleOwner.get().lifecycleScope.launch { + try { + overviewDao.updateGeoHash(id, geoHash) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + fun getAllV2XEventsByLineId(sn: String) { + if (disposable != null && !disposable!!.isDisposed) { + disposable!!.dispose() + } + + // 1分钟查询一次 + disposable = Observable.interval(2000, 60000, TimeUnit.MILLISECONDS) + .flatMap { + val lineId = getLineId() + if (lineId > 0) { + MoGoRetrofitFactory.getInstance(HostConst.getHost()) + .create(OverViewServiceApi::class.java) + .queryAllV2XEventsByLineId(lineId.toString(), sn) + .map { + if (it.code == 200 || it.code == 0) { + CallerLogger.d(SceneConstant.M_MAP + TAG, "请求成功,size为:${it.result?.v2XEventList?.size}") + return@map it.result?.v2XEventList + } else { + CallerLogger.d(SceneConstant.M_MAP + TAG, "请求失败,code为:${it.code}") + return@map ArrayList() + } + } + } else { + Observable.just(ArrayList()) + } + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + it?.apply { + _V2XEvents.value = this + } + } + } + + fun getV2XEventLiveData() = _V2XEvents + + fun stopQueryV2XEvents() { + disposable?.dispose() + } + + private fun getLineId(): Long { + var lineId: Long = -1 + val parameter = CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo() + .autopilotControlParameters + if (parameter != null) { + if (parameter.autoPilotLine != null) { + lineId = parameter.autoPilotLine!!.lineId + CallerLogger.d(SceneConstant.M_MAP + TAG, "lineId为:$lineId") + } else { + CallerLogger.d(SceneConstant.M_MAP + TAG, "parameter.autoPilotLine为null") + } + } else { + CallerLogger.d(SceneConstant.M_MAP + TAG, "parameter为null") + } + return lineId + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/ViewModelFactory.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/ViewModelFactory.kt index d6dd931290..0418a667e6 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/ViewModelFactory.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/ViewModelFactory.kt @@ -5,6 +5,8 @@ import android.app.Application import androidx.annotation.VisibleForTesting import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.mogo.eagle.core.function.overview.db.OverviewDao +import com.mogo.eagle.core.function.overview.db.OverviewDb import com.mogo.eagle.core.function.overview.vm.OverViewModel class ViewModelFactory private constructor( diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverviewDao.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/db/OverviewDao.kt similarity index 91% rename from core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverviewDao.kt rename to core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/db/OverviewDao.kt index 3bc147766c..4398041c9e 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverviewDao.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/db/OverviewDao.kt @@ -1,4 +1,4 @@ -package com.mogo.eagle.core.function.overview +package com.mogo.eagle.core.function.overview.db import androidx.room.Dao import androidx.room.Query diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverviewDb.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/db/OverviewDb.kt similarity index 96% rename from core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverviewDb.kt rename to core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/db/OverviewDb.kt index 555fd59913..596c282697 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/OverviewDb.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/db/OverviewDb.kt @@ -1,4 +1,4 @@ -package com.mogo.eagle.core.function.overview +package com.mogo.eagle.core.function.overview.db import android.content.Context import androidx.room.Database diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/view/OverMapView.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/view/OverMapView.kt new file mode 100644 index 0000000000..ddc6423415 --- /dev/null +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/view/OverMapView.kt @@ -0,0 +1,580 @@ +package com.mogo.eagle.core.function.overview.view + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.os.Bundle +import android.util.AttributeSet +import android.util.Log +import android.view.LayoutInflater +import android.view.MotionEvent +import android.widget.RelativeLayout +import android.widget.TextView +import ch.hsr.geohash.GeoHash +import com.amap.api.maps.AMap +import com.amap.api.maps.CameraUpdate +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.TextureMapView +import com.amap.api.maps.model.* +import com.mogo.cloud.passport.MoGoAiCloudClientConfig +import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.data.map.Infrastructure +import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener +import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager.getGlobalPath +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ20ListenerManager +import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager +import com.mogo.eagle.core.function.call.hmi.CallerHmiManager.showVideoDialog +import com.mogo.eagle.core.function.map.R +import com.mogo.eagle.core.function.overview.InfStructureManager +import com.mogo.eagle.core.function.overview.InfStructureManager.getData +import com.mogo.eagle.core.function.overview.OverViewDataManager +import com.mogo.eagle.core.function.overview.remote.V2XEvent +import com.mogo.eagle.core.function.smp.MakerWithCount +import com.mogo.eagle.core.function.smp.MarkerDrawerManager +import com.mogo.eagle.core.function.smp.MarkerDrawerManager.callback +import com.mogo.eagle.core.function.smp.MarkerDrawerManager.coordinateConverterWgsToGcj +import com.mogo.eagle.core.function.smp.MarkerDrawerManager.lonLat +import com.mogo.eagle.core.function.smp.MarkerDrawerManager.planningPoints +import com.mogo.eagle.core.function.smp.MarkerDrawerManager.startLoopCalCarLocation +import com.mogo.eagle.core.function.smp.MarkerDrawerManager.updateRoutePoints +import com.mogo.eagle.core.function.smp.V2XMarkerView +import com.mogo.eagle.core.utilcode.kotlin.lifecycleOwner +import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils.isTaxi +import com.mogo.eagle.core.utilcode.mogo.MapAssetStyleUtils +import com.mogo.eagle.core.utilcode.util.UiThreadHandler +import me.jessyan.autosize.utils.AutoSizeUtils +import mogo.telematics.pad.MessagePad + +/** + * 全览地图View + * + * @author chenfufeng + */ +class OverMapView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : RelativeLayout(context, attrs, defStyleAttr), IMoGoChassisLocationGCJ02Listener { + private var mMapView: TextureMapView? = null + private var mAMap: AMap? = null + private val zoomLevel = 15 + private var mCameraUpdate: CameraUpdate? = null + private var mContext: Context? = null + private val mTilt = 60f + private var overLayerView: TextView? = null + + // 全局路径规划中的GeoHash网格 + private val pathMap: MutableMap?> = HashMap() + private val posInfMap: MutableMap?> = HashMap() + + // =============绘制轨迹线相关============= + private var mCarMarker: Marker? = null + private var mCompassMarker: Marker? = null + private var mStartMarker: Marker? = null + private var mEndMarker: Marker? = null + private var mBottomPolyline: Polyline? = null + private var mCoveredPolyline: Polyline? = null + + // 计算索引并设置对应的Bitmap + var arrivedBitmap: BitmapDescriptor? = null + var unArrivedBitmap: BitmapDescriptor? = null + + // 绘制轨迹线的集合 + private val textureList: MutableList = ArrayList() + private val texIndexList: MutableList = ArrayList() + private var mLocation: MessagePad.GnssInfo? = null + private var isFirstLocation = true + var mCustomMapStyleOptions: CustomMapStyleOptions? = null + var currMarkerList: ArrayList? = null + + companion object { + const val TAG = "OverMapView" + } + + init { + try { + initView(context) + } catch (e: Exception) { + e.printStackTrace() + } + } + + // =================必须通知高德地图生命周期的变化================= + fun onCreateView(savedInstanceState: Bundle?) { + if (mMapView != null) { + mMapView!!.onCreate(savedInstanceState) + } + } + + fun onResume() { + if (mMapView != null) { + mMapView!!.onResume() + } + } + + fun onPause() { + if (mMapView != null) { + mMapView!!.onPause() + } + } + + fun onDestroy() { + if (mMapView != null) { + mMapView!!.onDestroy() + } + if (mMapView != null) { + mMapView!!.onDestroy() + } + } + // =================必须通知高德地图生命周期的变化================= + + private fun initView(context: Context) { + mContext = context + val smpView = LayoutInflater.from(context).inflate(R.layout.module_overview_map_view, this) + mMapView = smpView.findViewById(R.id.aMapView) + overLayerView = findViewById(R.id.overLayer) + if (isTaxi(FunctionBuildConfig.appIdentityMode)) { + overLayerView?.background = resources.getDrawable(R.drawable.amap_reset) + arrivedBitmap = BitmapDescriptorFactory.fromResource(R.drawable.taxi_map_arrow_arrived) + unArrivedBitmap = + BitmapDescriptorFactory.fromResource(R.drawable.taxi_map_arrow_un_arrive) + } else { + overLayerView?.background = resources.getDrawable(R.drawable.amap_reset_bus) + arrivedBitmap = BitmapDescriptorFactory.fromResource(R.drawable.arrow_arrived_img) + unArrivedBitmap = BitmapDescriptorFactory.fromResource(R.drawable.amap_bus_smooth_route) + } + CallerPlanningRottingListenerManager.addListener(TAG, moGoAutopilotPlanningListener) + initAMapView(context) + // 注册定位监听 + CallerChassisLocationGCJ20ListenerManager.addListener(TAG, this) + //设置全览模式 + overLayerView?.setOnClickListener { displayCustomOverView() } + } + + private fun initAMapView(context: Context) { + Log.d(TAG, "initAMapView") + mCameraUpdate = CameraUpdateFactory.zoomTo(zoomLevel.toFloat()) + mAMap = mMapView!!.map + mCustomMapStyleOptions = CustomMapStyleOptions() + if (isTaxi(FunctionBuildConfig.appIdentityMode)) { + mCustomMapStyleOptions!!.styleData = + MapAssetStyleUtils.getAssetsStyle(getContext(), "over_view_style.data") + mCustomMapStyleOptions!!.styleExtraData = + MapAssetStyleUtils.getAssetsExtraStyle(getContext(), "over_view_style_extra.data") + } else { + mCustomMapStyleOptions!!.styleData = + MapAssetStyleUtils.getAssetsStyle(getContext(), "over_view_style_bus.data") + mCustomMapStyleOptions!!.styleExtraData = + MapAssetStyleUtils.getAssetsExtraStyle( + getContext(), + "over_view_style_extra_bus.data" + ) + } + mAMap?.setOnMapLoadedListener { + Log.d(TAG, "---onMapLoaded---") + if (mCustomMapStyleOptions != null) { + // 加载自定义样式 + mCustomMapStyleOptions!!.isEnable = true + // 设置自定义样式 + mAMap?.setCustomMapStyle(mCustomMapStyleOptions) + } + // 实时路况图层关闭,必须添加在loaded结束之后,其他位置不生效 + mAMap?.isTrafficEnabled = false + } + setUpMap() + customOptions() + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + OverViewDataManager.infStructuresMap.observe(lifecycleOwner) { list -> + InfStructureManager.saveData(list) + } + // 查询本地数据库中的摄像头数据 + OverViewDataManager.fetchInfStructures() + // 主动查一次全局路径规划的数据 + getGlobalPath() + // 定时查询V2X事件 + OverViewDataManager.getV2XEventLiveData().observe(lifecycleOwner) { + showV2XEventMarkers(it) + } + OverViewDataManager.getAllV2XEventsByLineId(MoGoAiCloudClientConfig.getInstance().sn) + } + + private fun setUpMap() { + // 地图文字标注 + mAMap!!.showMapText(true) + //设置希望展示的地图缩放级别 + mAMap!!.moveCamera(mCameraUpdate) + //设置地图的样式 + val uiSettings = mAMap!!.uiSettings + //地图缩放级别的交换按钮 + uiSettings.isZoomControlsEnabled = false + //所有手势 + uiSettings.setAllGesturesEnabled(true) + //隐藏指南针 + uiSettings.isCompassEnabled = false + //设置倾斜手势是否可用。 + uiSettings.isTiltGesturesEnabled = true + //隐藏默认的定位按钮 + uiSettings.isMyLocationButtonEnabled = false + //设置Logo下边界距离屏幕底部的边距,设置为负值即可 + uiSettings.setLogoBottomMargin(-150) + Log.d(TAG, "before onMapLoaded") + } + + /** + * 自定义导航View和路况状态 + */ + private fun customOptions() { + if (isTaxi(FunctionBuildConfig.appIdentityMode)) { + mCarMarker = mAMap!!.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_car_icon)) + .anchor(0.5f, 0.5f) + ) + mCompassMarker = mAMap!!.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.amap_custom_corner)) + .anchor(0.5f, 0.5f) + ) + } else { + mCarMarker = mAMap!!.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_bus_icon)) + .anchor(0.5f, 0.5f) + ) + mCompassMarker = mAMap!!.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.amap_bus_corner)) + .anchor(0.5f, 0.5f) + ) + } + mStartMarker = mAMap!!.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.module_small_map_view_dir_start)) + ) + mEndMarker = mAMap!!.addMarker( + MarkerOptions() + .icon(BitmapDescriptorFactory.fromResource(R.drawable.module_small_map_view_dir_end)) + ) + } + + private val moGoAutopilotPlanningListener: IMoGoPlanningRottingListener = + object : IMoGoPlanningRottingListener { + /** + * 根据全路径获取起始点和经停点进行导航路线绘制 + * 自动驾驶启动后获得数据,获取全路径的具体时间要进行路测 + * 室内某个bag包自动驾驶启动8s后返回 + */ + override fun onAutopilotRotting(globalPathResp: MessagePad.GlobalPathResp?) { + Log.d(TAG, "onAutopilotRotting") + handlePlanningData(globalPathResp!!.wayPointsList) + } + } + + fun handlePlanningData(locationList: List) { + val list: List = locationList + // 转成高德坐标系并存储 + updateRoutePoints(list, mContext!!) + val planningPointList: List = planningPoints + UiThreadHandler.post { + displayCustomOverView() + drawStartAndEndMarker(planningPointList) + } + callback = object : MarkerDrawerManager.Callback { + override fun onLocationChanged(planningPoints: List, locIndex: Int) { + // 每1s刷新一下轨迹线 + UiThreadHandler.post { + if (planningPoints.isNotEmpty()) { + drawPolyline(planningPoints, locIndex) + } + } + } + } + startLoopCalCarLocation() + UiThreadHandler.post { drawInfrastructureMarkers(locationList) } + } + + /** + * 显示V2X事件的Marker + */ + fun showV2XEventMarkers(v2XEvents: List?) { + if (v2XEvents == null || v2XEvents.isEmpty()) return + clearV2XMarkers() + val markerOptionsList = ArrayList() + for ((_, _, _, center, _, _, poiType, coordinateType) in v2XEvents) { + if (center != null) { + center.lon + val markerOption = MarkerOptions() + var latLng: LatLng = if (coordinateType == null || coordinateType == 0) { + LatLng(center.lat, center.lon) + } else { + // wgs84坐标系需转成高德坐标系 + coordinateConverterWgsToGcj(mContext!!, center.lat, center.lon) + } + markerOption.position(latLng) + markerOption.anchor(0.13f, 1f) + markerOption.icon( + BitmapDescriptorFactory.fromBitmap( + getV2XBitmap( + poiType + ) + ) + ) + markerOptionsList.add(markerOption) + } + } + if (markerOptionsList.size > 0) { + drawV2XMarkers(markerOptionsList) + } + } + + fun drawV2XMarkers(markerOptionsList: ArrayList?) { + currMarkerList = mAMap!!.addMarkers(markerOptionsList, false) + } + + private fun getV2XBitmap(poiType: String?): Bitmap { + val marker = V2XMarkerView(context, null, 0, poiType) + marker.measure( + MeasureSpec.makeMeasureSpec(AutoSizeUtils.dp2px(mContext, 229f), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AutoSizeUtils.dp2px(mContext, 96f), MeasureSpec.EXACTLY) + ) + marker.layout(0, 0, marker.measuredWidth, marker.measuredHeight) + val bitmap = Bitmap.createBitmap(marker.width, marker.height, Bitmap.Config.ARGB_8888) + marker.draw(Canvas(bitmap)) + return bitmap + } + + fun clearV2XMarkers() { + if (currMarkerList != null) { + for (marker in currMarkerList!!) { + marker.destroy() + } + currMarkerList = null + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + // 注册定位监听 + CallerChassisLocationGCJ20ListenerManager.removeListener(TAG) + CallerPlanningRottingListenerManager.removeListener(TAG) + OverViewDataManager.stopQueryV2XEvents() + } + + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { + return false + } + + fun clearCustomPolyline() { + if (mBottomPolyline != null) { + mBottomPolyline!!.remove() + } + if (mCoveredPolyline != null) { + mCoveredPolyline!!.remove() + } + } + + /** + * 绘制新基建Markers(比如:摄像头) + * + * @param locationList + */ + private fun drawInfrastructureMarkers(locationList: List?) { + if (locationList == null) return + if (pathMap.isNotEmpty()) { + pathMap.clear() + } + var geoHash: String? + var infList: ArrayList? + for (i in locationList.indices) { + val latLng = coordinateConverterWgsToGcj(mContext!!, locationList[i]) + geoHash = + GeoHash.withCharacterPrecision(latLng.latitude, latLng.longitude, 7).toBase32() + // 网格内的轨迹点只取一次s + if (!pathMap.containsKey(geoHash)) { + // 从缓存的新基建数据中去取对应geoHash的新基建数据集合 + infList = getData()[geoHash] + if (infList != null) { + pathMap[geoHash] = infList + } + } + } + drawInfMarkers(pathMap) + } + + private fun drawInfMarkers(infStruMap: Map?>) { + // 绘制新基建数据 + if (posInfMap.isNotEmpty()) { + posInfMap.clear() + } + val markerOptionsList: ArrayList = ArrayList() + for (structureList in infStruMap.values) { + // 每个GeoHash内根据坐标系象限分散开摄像头icon显示 + val markerOption = MarkerOptions() + val latLng = LatLng( + java.lang.Double.valueOf(structureList!![0].lat!!), + java.lang.Double.valueOf(structureList[0].lon!!) + ) + markerOption.position(latLng) + val bitmap = getBitmap(structureList.size) + markerOption.icon( + BitmapDescriptorFactory.fromBitmap( + bitmap + ) + ) + markerOption.zIndex(2f) + posInfMap[latLng] = structureList + markerOptionsList.add(markerOption) + } + mAMap!!.addMarkers(markerOptionsList, false) + mAMap!!.setOnMarkerClickListener { marker: Marker -> + val infList: List? = posInfMap[marker.position] + // 如果是摄像头 + if (infList != null) { + showVideoDialog(infList) + return@setOnMarkerClickListener true + } + false + } + } + + private fun getBitmap(count: Int): Bitmap { + val marker = MakerWithCount(context) + marker.setCount(count) + marker.measure( + MeasureSpec.makeMeasureSpec(116, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(116, MeasureSpec.EXACTLY) + ) + marker.layout(0, 0, marker.measuredWidth, marker.measuredHeight) + val bitmap = Bitmap.createBitmap(marker.width, marker.height, Bitmap.Config.ARGB_8888) + marker.draw(Canvas(bitmap)) + return bitmap + } + + /** + * 进入自定义全览模式 + */ + private fun displayCustomOverView() { + val linePointsLatLng = planningPoints + if (linePointsLatLng.size > 1) { + //圈定地图显示范围 + //存放经纬度 + val boundsBuilder = LatLngBounds.Builder() + for (i in linePointsLatLng.indices) { + boundsBuilder.include(linePointsLatLng[i]) + } + val currentLatLng = LatLng(mLocation!!.latitude, mLocation!!.longitude) + boundsBuilder.include(currentLatLng) + val cameraPosition = CameraPosition.Builder().tilt(mTilt).build() + //第二个参数为四周留空宽度 + mAMap!!.moveCamera( + CameraUpdateFactory.newLatLngBoundsRect( + boundsBuilder.build(), + 100, + 100, + 100, + 100 + ) + ) + mAMap!!.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) + } else { + //设置希望展示的地图缩放级别 + val cameraPosition = CameraPosition.Builder() + .target(mCarMarker!!.position).tilt(0f).zoom(zoomLevel.toFloat()).build() + mAMap!!.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) + } + } + + /** + * 绘制自车 + * + * @param location + */ + private fun drawCarMarker(location: MessagePad.GnssInfo?) { + if (location == null) return + if (mCarMarker != null) { + val currentLatLng = LatLng(location.latitude, location.longitude) + mCarMarker!!.rotateAngle = (360 - location.heading).toFloat() + mCarMarker!!.position = currentLatLng + mCarMarker!!.setToTop() + if (mCompassMarker != null) { + mCompassMarker!!.rotateAngle = (360 - location.heading).toFloat() + mCompassMarker!!.position = currentLatLng + } + } + } + + /** + * 绘制起始点、终点 + */ + private fun drawStartAndEndMarker(coordinates: List) { + if (mStartMarker != null) { + mStartMarker!!.isVisible = false + } + if (mEndMarker != null) { + mEndMarker!!.isVisible = false + } + if (coordinates.size > 2) { + // 设置开始结束Marker位置 + val startLatLng = coordinates[0] + val endLatLng = coordinates[coordinates.size - 1] + mStartMarker!!.position = startLatLng + mEndMarker!!.position = endLatLng + mStartMarker!!.isVisible = true + mEndMarker!!.isVisible = true + } + } + + /** + * 绘制轨迹线 + * + * @param coordinates + * @param locIndex + */ + private fun drawPolyline(coordinates: List, locIndex: Int) { + if (textureList.size > 0) { + textureList.clear() + } + if (texIndexList.size > 0) { + texIndexList.clear() + } + for (i in coordinates.indices) { + if (i <= locIndex) { + // 已走过的置灰 + textureList.add(arrivedBitmap) + } else { + // 未走过的纹理 + textureList.add(unArrivedBitmap) + } + texIndexList.add(i) + } + if (mAMap != null && coordinates.size > 2) { + //设置线段纹理 + val polylineOptions = PolylineOptions() + polylineOptions.addAll(coordinates) + polylineOptions.width(14f) //线段宽度 + polylineOptions.lineCapType(PolylineOptions.LineCapType.LineCapRound) + polylineOptions.customTextureList = textureList + polylineOptions.customTextureIndex = texIndexList + // 绘制线 + mBottomPolyline = mCoveredPolyline + mCoveredPolyline = mAMap!!.addPolyline(polylineOptions) + if (mBottomPolyline != null) { + mBottomPolyline!!.remove() + } + } + } + + override fun onChassisLocationGCJ02(gnssInfo: MessagePad.GnssInfo?) { + mLocation = gnssInfo + lonLat = Pair(gnssInfo!!.longitude, gnssInfo.latitude) + drawCarMarker(gnssInfo) + if (isFirstLocation) { + displayCustomOverView() + isFirstLocation = false + } + } +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/vm/OverViewModel.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/vm/OverViewModel.kt index 9250e8fd6e..8b1237a6c6 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/vm/OverViewModel.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/overview/vm/OverViewModel.kt @@ -4,7 +4,7 @@ import androidx.lifecycle.* import com.mogo.commons.constants.HostConst import com.mogo.eagle.core.data.map.Infrastructure import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo -import com.mogo.eagle.core.function.overview.OverviewDao +import com.mogo.eagle.core.function.overview.db.OverviewDao import com.mogo.eagle.core.function.overview.remote.OverViewServiceApi import com.mogo.eagle.core.function.overview.remote.V2XEvent import com.mogo.eagle.core.network.MoGoRetrofitFactory