[VisualAngle]地图视角切换部分代码提交

This commit is contained in:
renwj
2022-03-17 19:47:54 +08:00
parent ee881c99e7
commit 1a262230ca
6 changed files with 256 additions and 2 deletions

View File

@@ -0,0 +1,220 @@
package com.mogo.eagle.core.function.call.map
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.util.Log
import com.mogo.eagle.core.data.map.MogoLatLng
import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.Default
import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.LowSpeed
import com.mogo.eagle.core.utilcode.kotlin.safeCancel
import com.mogo.map.uicontroller.VisualAngleMode
import kotlinx.coroutines.*
import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.internal.synchronized
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.SECONDS
/**
* 高精地图视角管理类
*/
object CallerVisualAngleManager {
private const val TAG = "VisualAngle"
private const val MaxDisplayThreshold = 20_000 //最大展示阈值
private var scope: CoroutineScope = acquireScope()
@Synchronized
get() {
if (field.isActive) {
return field
}
val scope = acquireScope()
field = scope
return field
}
private var defaultDelayJob: Job? = null
private fun acquireScope(): CoroutineScope {
return CoroutineScope(Handler(Looper.getMainLooper()).asCoroutineDispatcher("change-visual-angle") + SupervisorJob())
}
private interface IAttach {
val angle: VisualAngleMode
val priority: Int
}
sealed class Scene private constructor(): IAttach {
/**
* 默认视图
* @param delay: 表示多少稍后默认值为2
* @param unit: 时间单位,默认为秒
*/
class Default(val delay: Long = 2, val unit: TimeUnit = SECONDS): Scene() {
override val angle: VisualAngleMode = VisualAngleMode.MODE_MEDIUM_SIGHT
override val priority: Int = 0
override fun toString(): String {
return "Default(delay=$delay, unit=$unit, angle=$angle, priority=$priority)"
}
}
/**
* 变道-接收到转向灯信息号
*/
object Turning: Scene() {
override val angle: VisualAngleMode = VisualAngleMode.MAP_STYLE_VR_ANGLE_TOP
override val priority: Int = 0
}
/**
* 后方车辆离自车过近
*/
object TooClose: Scene() {
override val angle: VisualAngleMode = VisualAngleMode.MAP_STYLE_VR_ANGLE_300
override val priority: Int = 0
}
/**
* 道路事件
*/
object RoadEvent: Scene() {
override val angle: VisualAngleMode = VisualAngleMode.MODE_LONG_SIGHT
override val priority: Int = 0
}
/**
* 车量低速行驶
*/
class LowSpeed(val lat: Double, val lon: Double): Scene() {
override val angle: VisualAngleMode = VisualAngleMode.MODE_CLOSE_SIGHT
override val priority: Int = 0
override fun toString(): String {
return "LowSpeed(lat=$lat, lon=$lon, angle=$angle, priority=$priority)"
}
}
/**
* 十字路口
*/
object CrossRoad: Scene() {
override val angle: VisualAngleMode = VisualAngleMode.MAP_STYLE_VR_ANGLE_CROSS
override val priority: Int = 0
}
}
/**
* 业务实体,不对外暴露
* @param target: 目标场景
* @param isDisplay: 是否正在展示
* @param triggerTime: 触发时间
*/
private data class Record(val target: Scene, var isDisplay: Boolean = false, val triggerTime: Long): Comparable<Record> {
override fun compareTo(other: Record): Int {
//大根堆
if (triggerTime != other.triggerTime) {
//时间越晚,越靠近堆顶
return if (triggerTime > other.triggerTime) -1 else 1
}
//如果时间一样,优先级越高,越靠近堆顶
return other.target.priority - target.priority
}
}
private val heap by lazy {
/**
* 堆, 大根堆还是小根堆由[Record.compareTo]方法决定
*/
PriorityQueue<Record>()
}
@OptIn(InternalCoroutinesApi::class)
fun changeVisualAngle(scene: Scene) {
val triggerTime = SystemClock.elapsedRealtime()
scope.launch {
val displayed = getDisplayed()
if (displayed == null) {
val top = getTop() //堆顶
if (top != null && top.target.priority > scene.priority) {
doChangeAngle(top)
synchronized(heap) {
heap += Record(scene, triggerTime = triggerTime)
}
} else {
doChangeAngle(Record(scene, triggerTime = triggerTime))
}
Log.d(TAG, "没有正在展示的视角,当前要展示的视角: $scene")
} else {
if (scene.javaClass == displayed.javaClass) {
Log.d(TAG, "同一种场景不需要重复展示")
return@launch
}
if (scene is Default) {
Log.d(TAG, "恢复到默认视图,之前展示的视图:$displayed")
synchronized(heap) {
heap -= displayed
}
launch {
val delay = scene.unit.toMillis(scene.delay)
Log.d(TAG, "默认视图开启延时倒计时, 倒计时时间:${delay} ms.")
delay(delay)
Log.d(TAG, "默认视图结束倒计时,开始展示...")
doChangeAngle(Record(scene, triggerTime = triggerTime))
}.also { defaultDelayJob = it }
} else {
val delta = triggerTime - displayed.triggerTime
if (delta >= MaxDisplayThreshold) {
Log.d(TAG, "场景: $scene 触发展示,满足条件开始展示...")
doChangeAngle(Record(scene, triggerTime = triggerTime))
} else {
Log.d(TAG, "场景: $scene 触发展示但是在20s内丢弃...")
}
}
}
}
}
@OptIn(InternalCoroutinesApi::class)
private fun doChangeAngle(record: Record) {
CallerMapUIServiceManager.getMapUIController()?.also {
record.isDisplay = true
synchronized(heap) {
heap += record
}
val target = record.target
if (target !is Default) {
defaultDelayJob?.safeCancel()
}
if (target is LowSpeed) {
it.changeMapVisualAngle(record.target.angle, MogoLatLng(target.lat, target.lon))
} else {
it.changeMapVisualAngle(record.target.angle, null)
}
}
}
/**
* 是否有正在展示的
*/
@Synchronized
private fun getDisplayed() = heap.find { it.isDisplay }
@Synchronized
private fun getTop() = heap.firstOrNull()
}