diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/business/travelreality/TravelRealityModel.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/business/travelreality/TravelRealityModel.kt index caf5622334..28665a5b2c 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/business/travelreality/TravelRealityModel.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/business/travelreality/TravelRealityModel.kt @@ -18,6 +18,7 @@ import com.mogo.eagle.core.data.config.FunctionBuildConfig import com.mogo.eagle.core.data.road.RoadCameraLive import com.mogo.eagle.core.function.business.roadcross.net.BATCH_LIVE import com.mogo.eagle.core.function.business.roadcross.net.INDERoadCameraApiService +import com.mogo.eagle.core.function.business.travelreality.view.VideoMarkerEntity import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager import com.mogo.eagle.core.network.MoGoRetrofitFactory @@ -235,10 +236,10 @@ class TravelRealityModel private constructor() { fun downloadImage( context: Context, url: String?, - latLng: LatLng, + videoMarkerList: MutableList, lineId: Long, - onSuccess: ((Bitmap, LatLng, Long) -> Unit), - onFailed: ((LatLng, Long) -> Unit) + onSuccess: ((Bitmap, MutableList, Long) -> Unit), + onFailed: ((MutableList, Long) -> Unit) ) { if (url.isNullOrEmpty()) return val radiusPx = AutoSizeUtils.dp2px(context, 24f).toFloat() @@ -250,14 +251,14 @@ class TravelRealityModel private constructor() { .load(url) .into(object : CustomTarget() { override fun onResourceReady(resource: Bitmap, transition: Transition?) { - onSuccess(resource, latLng, lineId) + onSuccess(resource, videoMarkerList, lineId) } override fun onLoadCleared(placeholder: Drawable?) {} override fun onLoadFailed(errorDrawable: Drawable?) { super.onLoadFailed(errorDrawable) - onFailed(latLng, lineId) + onFailed(videoMarkerList, lineId) } }) } diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt index a6cada6de5..6a19f0286e 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/view/TravelRealityView.kt @@ -188,7 +188,7 @@ class TravelRealityView @JvmOverloads constructor( * 在轨迹点附近的路口设备 */ @Volatile - private var deviceInPathList: List? = null + private var deviceInPathList: List?? = null @Volatile private var roadTrackList: List?>?>? = null @@ -502,9 +502,9 @@ class TravelRealityView @JvmOverloads constructor( if (eventList.isEmpty()) { listener?.onDraw(emptyList(), true) // 没有事件则全部用路口设备补齐 - retryGetCrossDevice(ArrayList(), HashMap()) + retryGetCrossDevice(HashMap(), 0) // 清除道路事件 - drawMarkers(DRAW_ROAD_EVENT, ArrayList()) + drawMarkers(DRAW_ROAD_EVENT, ArrayList()) } else { val eventDrawMap = HashMap() val eventOptionsList = ArrayList() @@ -550,59 +550,75 @@ class TravelRealityView @JvmOverloads constructor( } private fun completeQuantity(roadEvents: ArrayList) { - val ipPointEntityMap = HashMap() + val ipPointEntityMap = HashMap>() // 全部展示事件,事件数不足则用路口设备补齐 Log.d(TAG, "已绘制的道路事件个数为:${roadEvents.size}") if (roadEvents.size >= 3) { - val ipList = mutableListOf() roadEvents[0].let { it.ip?.also { ip -> if (ip.isEmpty()) return@also - ipPointEntityMap[ip] = VideoMarkerEntity( - coordinateConverterWgsToGcj(it.lat, it.lon), - it.title, - it.orientation + if (!ipPointEntityMap.containsKey(ip)) { + ipPointEntityMap[ip] = ArrayList() + } + ipPointEntityMap[ip]?.add( + VideoMarkerEntity( + coordinateConverterWgsToGcj(it.lat, it.lon), + it.title, + it.orientation + ) ) - ipList.add(ip) } } roadEvents[(roadEvents.size - 1) / 2].let { it.ip?.also { ip -> if (ip.isEmpty()) return@also - ipPointEntityMap[ip] = VideoMarkerEntity( - coordinateConverterWgsToGcj(it.lat, it.lon), - it.title, - it.orientation + if (!ipPointEntityMap.containsKey(ip)) { + ipPointEntityMap[ip] = ArrayList() + } + ipPointEntityMap[ip]?.add( + VideoMarkerEntity( + coordinateConverterWgsToGcj(it.lat, it.lon), + it.title, + it.orientation + ) ) - ipList.add(ip) } } roadEvents[roadEvents.size - 1].let { it.ip?.also { ip -> if (ip.isEmpty()) return@also - ipPointEntityMap[ip] = VideoMarkerEntity( - coordinateConverterWgsToGcj(it.lat, it.lon), - it.title, - it.orientation + if (!ipPointEntityMap.containsKey(ip)) { + ipPointEntityMap[ip] = ArrayList() + } + ipPointEntityMap[ip]?.add( + VideoMarkerEntity( + coordinateConverterWgsToGcj(it.lat, it.lon), + it.title, + it.orientation + ) ) - ipList.add(ip) } } - reqCrossLive(ipList, ipPointEntityMap) + reqCrossLive(ipPointEntityMap) } else { - val ipList = mutableListOf() + var count = 0 roadEvents.forEach { it.ip?.let { ip -> if (ip.isEmpty()) return@let - ipPointEntityMap[ip] = VideoMarkerEntity( - coordinateConverterWgsToGcj(it.lat, it.lon), - it.title, - it.orientation + count++ + if (!ipPointEntityMap.containsKey(ip)) { + ipPointEntityMap[ip] = ArrayList() + } + ipPointEntityMap[ip]?.add( + VideoMarkerEntity( + coordinateConverterWgsToGcj(it.lat, it.lon), + it.title, + it.orientation + ) ) - ipList.add(ip) } } - retryGetCrossDevice(ipList, ipPointEntityMap) + retryGetCrossDevice(ipPointEntityMap, count) } } @@ -680,8 +696,8 @@ class TravelRealityView @JvmOverloads constructor( * handleCrossDevices -> 计算Marker方向 -> 缓存deviceInPathList */ private fun retryGetCrossDevice( - ipList: MutableList, - ipPointEntityMap: HashMap + ipPointEntityMap: HashMap>, + eventSize: Int ) { Log.d(TAG, "retryGetCrossDevice") val crossDeviceListTmp = deviceInPathList @@ -690,71 +706,109 @@ class TravelRealityView @JvmOverloads constructor( Log.d(TAG, "尝试多次后仍无法获取到路口设备数据!") break } - Thread.sleep(150) + Thread.sleep(250) retryCount++ } - var maxSize = 3 - ipList.size + var maxSize = 3 - eventSize if (maxSize <= 0) { Log.d(TAG, "全息路口个数计算有误则返回!") return } - Log.d(TAG, "待查询的事件个数为:${ipList.size}") + Log.d(TAG, "待查询缩略图的事件个数为:${eventSize}") if (!crossDeviceListTmp.isNullOrEmpty()) { + Log.d(TAG, "缓存的全息路口个数为:${crossDeviceListTmp.size}") // 轨迹线附近的路口设备取几个进行卡片展示 - for (i in crossDeviceListTmp.indices) { - if (maxSize > 0 && !crossDeviceListTmp[i].deviceInfoList.isNullOrEmpty()) { - crossDeviceListTmp[i].deviceInfoList!![0].deviceIp?.let { - ipPointEntityMap[it] = VideoMarkerEntity( - coordinateConverterWgsToGcj( - crossDeviceListTmp[i].deviceInfoList!![0].lat, - crossDeviceListTmp[i].deviceInfoList!![0].lon - ), "全息路口", crossDeviceListTmp[i].deviceInfoList!![0].orientation + crossDeviceListTmp.forEach { deviceInfoBean -> + if (maxSize > 0) { + deviceInfoBean.deviceIp?.let { + if (!ipPointEntityMap.containsKey(it)) { + ipPointEntityMap[it] = ArrayList() + } + ipPointEntityMap[it]?.add( + VideoMarkerEntity( + coordinateConverterWgsToGcj( + deviceInfoBean.lat, + deviceInfoBean.lon + ), + "全息路口", + deviceInfoBean.orientation + ) ) - ipList.add(it) maxSize-- } } } } - reqCrossLive(ipList, ipPointEntityMap) + reqCrossLive(ipPointEntityMap) } /** * 先下载图片,然后设置给View, * 再转换成BitmapDescriptor,最后进行渲染 + * 1_ip -> 1_url -> n_bitmap(标题不同需生成n个) -> n_marker */ - private fun downloadImage(url: String, latLng: LatLng?, title: String?, orientation: Int = 0) { - if (latLng == null || url.isEmpty()) return + private fun downloadImage(url: String, videoList: MutableList) { + if (videoList.isEmpty() || url.isEmpty()) return travelNetWorkModel.downloadImage( context, url, - latLng, + videoList, CallerAutoPilotStatusListenerManager.getLineId(), - onSuccess = { bitmap, latLng, lineId -> - if (CallerAutoPilotStatusListenerManager.getLineId() != 0L) { - val view = EventVideoView(context, title = title, orientation = orientation) + onSuccess = { bitmap, videoMarkerList, lineId -> +// if (CallerAutoPilotStatusListenerManager.getLineId() != 0L) { + val optionList = ArrayList() + var view: EventVideoView + videoMarkerList.forEach { videoEntity -> + view = EventVideoView( + context, + title = videoEntity.title, + orientation = videoEntity.orientation + ) view.setBitmap(bitmap) - updateVideoMarker(view, latLng) - } else { - Log.w(TAG, "downloadImage:onSuccess:lineId为0!") + + optionList.add(MarkerOptions().also { + it.position(videoEntity.latLng) + it.icon(BitmapDescriptorFactory.fromView(view)) + }) } + updateVideoMarker(optionList) +// } else { +// Log.w(TAG, "downloadImage:onSuccess:lineId为0!") +// } }, - onFailed = { latLng, lineId -> - if (CallerAutoPilotStatusListenerManager.getLineId() != 0L) { - val view = EventVideoView(context, title = title, orientation = orientation) + onFailed = { videoMarkerList, lineId -> +// if (CallerAutoPilotStatusListenerManager.getLineId() != 0L) { + val optionList = ArrayList() + var view: EventVideoView + videoMarkerList.forEach { videoEntity -> + view = EventVideoView( + context, + title = videoEntity.title, + orientation = videoEntity.orientation + ) view.setPlaceHolder() - updateVideoMarker(view, latLng) - } else { - Log.w(TAG, "downloadImage:onFailed:lineId为0!") + + optionList.add(MarkerOptions().also { + it.position(videoEntity.latLng) + it.icon(BitmapDescriptorFactory.fromView(view)) + }) } + + updateVideoMarker(optionList) +// } else { +// Log.w(TAG, "downloadImage:onFailed:lineId为0!") +// } }) } private fun reqCrossLive( - ipList: MutableList, - ipPointEntityMap: HashMap + ipPointEntityMap: HashMap> ) { + val ipList = ipPointEntityMap.keys.toMutableList() Log.d(TAG, "请求获取缩略图,个数为:${ipList.size}!") + if (ipList.isEmpty()) { + return + } travelNetWorkModel.batchRequestCrossLive(ipList, onSuccess = { Log.d(TAG, "Cross live result is:$it") val liveOptionsList = ArrayList() @@ -764,64 +818,71 @@ class TravelRealityView @JvmOverloads constructor( it.forEach { roadCamera -> roadCamera.ip?.let { ip -> - markerOption = MarkerOptions() - markerOption.zIndex(0.9f) if (roadCamera.imageUrl.isNullOrEmpty()) { var view: EventVideoView if (ipPointEntityMap[ip] != null) { - // 计算卡片四个顶点的高德地图经纬度 - ipPointEntityMap[ip]?.latLng?.let { pos -> + // 一个ip可能对应多个卡片缩略图 + ipPointEntityMap[ip]!!.forEach { videoMarkerEntity -> + // 计算卡片四个顶点的高德地图经纬度 vertexList.addAll( getRectVertex( - ipPointEntityMap[ip]!!.orientation, - pos + videoMarkerEntity.orientation, + videoMarkerEntity.latLng ) ) + markerOption = MarkerOptions() + markerOption.zIndex(0.9f) + markerOption.position(videoMarkerEntity.latLng) + view = EventVideoView( + context, + title = videoMarkerEntity.title, + orientation = videoMarkerEntity.orientation + ) + pair = + travelNetWorkModel.calculateAnchor(videoMarkerEntity.orientation) + Log.d( + TAG, + "绘制时位置为:${videoMarkerEntity.latLng},标题为:${videoMarkerEntity.title},方向为:${videoMarkerEntity.orientation},锚点为:${pair}" + ) + markerOption.anchor(pair.first, pair.second) + view.setPlaceHolder() + markerOption.icon(BitmapDescriptorFactory.fromView(view)) + liveOptionsList.add(markerOption) } - markerOption.position(ipPointEntityMap[ip]?.latLng) - view = EventVideoView( - context, - title = ipPointEntityMap[ip]!!.title, - orientation = ipPointEntityMap[ip]!!.orientation - ) - pair = - travelNetWorkModel.calculateAnchor(ipPointEntityMap[ip]!!.orientation) - Log.d( - TAG, - "绘制时位置为:${ipPointEntityMap[ip]?.latLng},标题为:${ipPointEntityMap[ip]!!.title},方向为:${ipPointEntityMap[ip]!!.orientation},锚点为:${pair}" - ) - markerOption.anchor(pair.first, pair.second) - view.setPlaceHolder() - markerOption.icon(BitmapDescriptorFactory.fromView(view)) } else { - Log.d(TAG, "缓存中未查到对应ip") + Log.d(TAG, "缓存中未查到对应ip!") return@let } } else { - // 需要下载缩略图 - markerOption.icon(null) - // 计算卡片四个顶点的高德地图经纬度 - ipPointEntityMap[ip]?.latLng?.let { pos -> - vertexList.addAll( - getRectVertex( - ipPointEntityMap[ip]?.orientation ?: 0, - pos + if (ipPointEntityMap[ip] != null) { + ipPointEntityMap[ip]!!.forEach { videoMarkerEntity -> + // 计算卡片四个顶点的高德地图经纬度 + vertexList.addAll( + getRectVertex( + videoMarkerEntity.orientation, + videoMarkerEntity.latLng + ) ) + // 需要下载缩略图 + markerOption = MarkerOptions() + markerOption.zIndex(0.9f) + markerOption.icon(null) + markerOption.position(videoMarkerEntity.latLng) + pair = travelNetWorkModel.calculateAnchor( + videoMarkerEntity.orientation + ) + markerOption.anchor(pair.first, pair.second) + liveOptionsList.add(markerOption) + } + downloadImage( + roadCamera.imageUrl!!, + ipPointEntityMap[ip]!! ) + } else { + Log.d(TAG, "缓存中未查到对应ip!!") + return@let } - markerOption.position(ipPointEntityMap[ip]?.latLng) - pair = travelNetWorkModel.calculateAnchor( - ipPointEntityMap[ip]?.orientation ?: 0 - ) - markerOption.anchor(pair.first, pair.second) - downloadImage( - roadCamera.imageUrl!!, - ipPointEntityMap[ip]?.latLng, - ipPointEntityMap[ip]?.title, - ipPointEntityMap[ip]?.orientation ?: 0 - ) } - liveOptionsList.add(markerOption) } } Log.d(TAG, "绘制卡片的个数为:${liveOptionsList.size}") @@ -833,7 +894,10 @@ class TravelRealityView @JvmOverloads constructor( }) } - private fun handleCrossDevices(crossDeviceList: List, globalList: ArrayList?) { + private fun handleCrossDevices( + crossDeviceList: List, + globalList: ArrayList? + ) { if (crossDeviceList.isEmpty()) return val crossOptionsList = ArrayList() var distance = 0.0 @@ -870,7 +934,10 @@ class TravelRealityView @JvmOverloads constructor( globalList[index + 1].lon, globalList[index + 1].lat ) - deviceInPaths.add(deviceBean) + // 深拷贝一下数据 + deviceInPaths.add(DeviceInfoBean(deviceBean.deviceIp, deviceBean.lon, deviceBean.lat).also { deviceInfo -> + deviceInfo.orientation = deviceBean.orientation + }) crossOptionsList.add(MarkerOptions().apply { position( coordinateConverterWgsToGcj( @@ -891,7 +958,7 @@ class TravelRealityView @JvmOverloads constructor( false ) } - deviceInPathList = arrayListOf(CrossDeviceBean("", 0.0, "", 0.0, deviceInPaths)) + deviceInPathList = deviceInPaths Log.d(TAG, "待绘制的全息路口的个数为:${crossOptionsList.size}") // 绘制路口设备 drawMarkers(DRAW_CROSS_DEVICE, crossOptionsList) @@ -1106,12 +1173,7 @@ class TravelRealityView @JvmOverloads constructor( } } - private fun updateVideoMarker(view: EventVideoView, latLng: LatLng?) { - if (latLng == null) return - val options = MarkerOptions() - options.position(latLng) - options.icon(BitmapDescriptorFactory.fromView(view)) - Log.d(TAG, "更新时位置为:${latLng},标题为:${view.title}") + private fun updateVideoMarker(options: List) { Message.obtain().apply { what = UPDATE_VIDEO_MARKER obj = options @@ -1380,7 +1442,7 @@ class TravelRealityView @JvmOverloads constructor( UPDATE_VIDEO_MARKER -> { removeMessages(UPDATE_VIDEO_MARKER) if (isMapDestroyed) return - realUpdateVideoMarker(msg.obj as MarkerOptions) + realUpdateVideoMarker(msg.obj as List) } CLEAR_ALL_DATA -> { @@ -1554,11 +1616,13 @@ class TravelRealityView @JvmOverloads constructor( liveMarkerList.clear() } - private fun realUpdateVideoMarker(options: MarkerOptions) { + private fun realUpdateVideoMarker(options: List) { Log.d(TAG, "realUpdateVideoMarker") - liveMarkerList.forEach { - if (it.position == options.position) { - it.setIcon(options.icon) + liveMarkerList.forEach { liveMarker -> + options.forEach { + if (it.position == liveMarker.position) { + liveMarker.setIcon(it.icon) + } } } }