[8.1.2][feat]决策功能用动画实现

This commit is contained in:
chenfufeng
2025-07-10 14:37:29 +08:00
parent 64fcdc0422
commit 67ce8b1c8c
26 changed files with 843 additions and 111 deletions

View File

@@ -105,24 +105,26 @@ class MapIdentifySubscriber private constructor() : IMoGoSubscriber,
predictionObjects.objsAppList.forEach { preObj ->
val points = ArrayList<MogoLatLng>()
if (preObj.mNid == 800000L) {
// 自车有2条轨迹一条概率大、一条概率小
if (preObj.predictionTrajectoryList == null || preObj.predictionTrajectoryList.size < 2) return@forEach
carPoiList1 = preObj.predictionTrajectoryList[0].trajectoryPointsList
carPoiList2 = preObj.predictionTrajectoryList[1].trajectoryPointsList
location1 = LocationUtils.generateLocation(carPoiList1!![0].x, carPoiList1!![0].y, getLocationHeading())
location2 = LocationUtils.generateLocation(carPoiList2!![0].x, carPoiList2!![0].y, getLocationHeading())
if (location1 == null || location2 == null) return@forEach
probability1 = preObj.predictionTrajectoryList[0].predictionProbability
probability2 = preObj.predictionTrajectoryList[1].predictionProbability
CallerAutopilotIdentifyListenerManager.invokeProbabilityChanged(probability1, probability2)
// // 自车有2条轨迹一条概率大、一条概率小
// if (preObj.predictionTrajectoryList == null || preObj.predictionTrajectoryList.size < 2) return@forEach
// carPoiList1 = preObj.predictionTrajectoryList[0].trajectoryPointsList
// carPoiList2 = preObj.predictionTrajectoryList[1].trajectoryPointsList
// location1 = LocationUtils.generateLocation(carPoiList1!![0].x, carPoiList1!![0].y, getLocationHeading())
// location2 = LocationUtils.generateLocation(carPoiList2!![0].x, carPoiList2!![0].y, getLocationHeading())
// if (location1 == null || location2 == null) return@forEach
// probability1 = preObj.predictionTrajectoryList[0].predictionProbability
// probability2 = preObj.predictionTrajectoryList[1].predictionProbability
// CallerAutopilotIdentifyListenerManager.invokeProbabilityChanged(probability1, probability2)
PredictionDataManager.getInstance()?.updateData(carPoiList1!!, 0)
PredictionDataManager.getInstance()?.updateData(carPoiList2!!, 2)
// PredictionDataManager.getInstance()?.updateData(carPoiList1!!, 0)
// PredictionDataManager.getInstance()?.updateData(carPoiList2!!, 2)
} else {
if (isUnKnownType(preObj.classtype) || preObj.predictionTrajectoryList.isNullOrEmpty() || mogoMap == null) return@forEach
point = preObj.predictionTrajectoryList[0].trajectoryPointsList[0]
arr = mogoMap.switchData(point.x, point.y, false)
arr?.let { lonLatArr ->
// 感知物不在当前视椎体内则不渲染其预测轨迹
if (!mogoMap.isInCurrentFrame(lonLatArr[0], lonLatArr[1])) return@forEach
val distance = com.mogo.eagle.core.utilcode.util.LocationUtils.getDistance(getWgs84Lat(), getWgs84Lon(), lonLatArr[1], lonLatArr[0])
if (distance > 28) return@forEach
}

View File

@@ -131,16 +131,12 @@ public class MogoRouteOverlayManager implements
// Log.d(TAG, "-- onChassisLocationGCJ02 -- 1 ---" + ":auto-mode:" + autoPilotState + ", isArriveAtStation: " + isArriveAtStation);
if (isArriveAtStation && autoPilotState != 2) {
RouteOverlayDrawer.getInstance().clearMogoRouteOverlay();
PredictionOverlayDrawer2.getInstance().clearPreRouteOverlay();
PredictionOverlayDrawer3.getInstance().clearPreRouteOverlay();
return;
}
// Log.d(TAG, "-- onChassisLocationGCJ02 -- 2 ---" + "auto-mode:" + autoPilotState + ", isDemoMode:" + FunctionBuildConfig.isDemoMode + ", force:" + FunctionBuildConfig.isForceDrawAutopilotTrajectoryByDebugSettingView);
boolean force = hasGreenWave.get() || FunctionBuildConfig.isForceDrawAutopilotTrajectoryByDebugSettingView || FunctionBuildConfig.isDemoMode && FunctionBuildConfig.isIgnoreConditionsDrawAutopilotTrajectoryData;
if (!force && autoPilotState != 2) {
RouteOverlayDrawer.getInstance().clearMogoRouteOverlay();
PredictionOverlayDrawer2.getInstance().clearPreRouteOverlay();
PredictionOverlayDrawer3.getInstance().clearPreRouteOverlay();
return;
}
// Log.d(TAG, "-- onChassisLocationGCJ02 -- 3 ---");

View File

@@ -148,7 +148,7 @@ public class PredictionOverlayDrawer {
builder.color(Color.argb(102,48,163,255));
builder.setIsGradient(true);
builder.setLightOn(false);
builder.setIsDottedLine(true);
builder.setIsDottedLine(false);
builder.isShowArrow(false);
builder.points(pps);
builder.setVisible(true);

View File

@@ -3,25 +3,40 @@ package com.mogo.eagle.core.function.view
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.os.SystemClock
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
import com.mogo.eagle.core.function.business.routeoverlay.DecisionDataManager
import com.mogo.eagle.core.function.business.routeoverlay.PredictionDataManager
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotPlanningActionsListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningActionsListenerManager
import com.mogo.eagle.core.function.map.R
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.model.VideoOptionModel
import com.shuyu.gsyvideoplayer.player.IjkPlayerManager
import com.shuyu.gsyvideoplayer.player.PlayerFactory
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import kotlinx.android.synthetic.main.layout_decision_container.view.tvPre1
import kotlinx.android.synthetic.main.layout_decision_container.view.tvPre2
import kotlinx.android.synthetic.main.layout_decision_container.view.tvPre3
import me.jessyan.autosize.utils.AutoSizeUtils
import kotlinx.android.synthetic.main.layout_decision_video_container.view.decContent1
import kotlinx.android.synthetic.main.layout_decision_video_container.view.decContent2
import kotlinx.android.synthetic.main.layout_decision_video_container.view.decContent3
import kotlinx.android.synthetic.main.layout_decision_video_container.view.decMapView
import kotlinx.android.synthetic.main.layout_decision_video_container.view.preDetailView2
import kotlinx.android.synthetic.main.layout_decision_video_container.view.preDetailView3
import mogo.telematics.pad.MessagePad
import tv.danmaku.ijk.media.player.IjkMediaPlayer
import kotlin.random.Random
class DecisionLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : ConstraintLayout(context, attrs), IMoGoAutopilotIdentifyListener {
) : ConstraintLayout(context, attrs), IMoGoAutopilotIdentifyListener,
IMoGoAutopilotPlanningActionsListener {
companion object {
private const val TAG = "DecisionLayout"
@@ -32,6 +47,21 @@ class DecisionLayout @JvmOverloads constructor(
private var carType = 0
private val gsyVideoOptionBuilder1 by lazy {
GSYVideoOptionBuilder()
}
private var lastUrl1 = ""
private val gsyVideoOptionBuilder2 by lazy {
GSYVideoOptionBuilder()
}
private var lastUrl2 = ""
private val gsyVideoOptionBuilder3 by lazy {
GSYVideoOptionBuilder()
}
private var lastUrl3 = ""
init {
initView(attrs)
}
@@ -40,21 +70,26 @@ class DecisionLayout @JvmOverloads constructor(
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarMapLayout)
carType = typedArray.getInt(R.styleable.CarMapLayout_car_type, 0)
typedArray.recycle()
when (carType) {
0 -> LayoutInflater.from(context).inflate(R.layout.layout_decision_container, this, true)
else -> LayoutInflater.from(context).inflate(R.layout.layout_b2_decision_container, this, true)
}
storeWidthAndHeight()
// when (carType) {
// 0 -> LayoutInflater.from(context).inflate(R.layout.layout_decision_container, this, true)
// else -> LayoutInflater.from(context).inflate(R.layout.layout_b2_decision_container, this, true)
// }
LayoutInflater.from(context).inflate(R.layout.layout_decision_video_container, this, true)
// storeWidthAndHeight()
initViews()
initVideos()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
CallerAutopilotIdentifyListenerManager.addListener(TAG, this)
CallerPlanningActionsListenerManager.addListener(TAG, this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerAutopilotIdentifyListenerManager.removeListener(TAG)
CallerPlanningActionsListenerManager.removeListener(TAG)
}
fun onCreate(savedInstanceState: Bundle?) {
@@ -66,30 +101,6 @@ class DecisionLayout @JvmOverloads constructor(
fun onResume() {
}
@SuppressLint("SetTextI18n")
override fun onPredictionProbabilityChanged(pro1: Float, pro2: Float) {
if (System.currentTimeMillis() - lastTime >= 1000) {
ThreadUtils.runOnUiThread {
val prob1: Int
val prob2: Int
val prob3: Int
if (pro1 + pro2 < 50) {
prob1= (pro1*100).toInt()
prob3= (pro2*100).toInt()
prob2 = 100 - prob1 - prob3
} else {
prob1 = 15 * (pro1 / (pro1 + pro2)).toInt()
prob3 = 15 * (pro2 / (pro1 + pro2)).toInt()
prob2 = 100 - prob1 - prob3
}
tvPre1.text = "${prob1}%"
tvPre3.text = "${prob3}%"
tvPre2.text = "${prob2}%"
}
lastTime = System.currentTimeMillis()
}
}
fun onLowMemory() {
}
@@ -99,25 +110,214 @@ class DecisionLayout @JvmOverloads constructor(
fun onDestroy() {
}
private fun storeWidthAndHeight() {
UiThreadHandler.post {
when (carType) {
// 默认值为对应0不需要赋值
1 -> {
val decWid = AutoSizeUtils.dp2px(context, 110f)
val decHet = AutoSizeUtils.dp2px(context, 211f)
val mapWid = AutoSizeUtils.dp2px(context, 996f)
val mapHet = AutoSizeUtils.dp2px(context, 650f)
PredictionDataManager.getInstance()?.decWidth = decWid
PredictionDataManager.getInstance()?.decHeight = decHet
PredictionDataManager.getInstance()?.mapWidth = mapWid
PredictionDataManager.getInstance()?.mapHeight = mapHet
DecisionDataManager.getInstance()?.decWidth = decWid
DecisionDataManager.getInstance()?.decHeight = decHet
DecisionDataManager.getInstance()?.mapWidth = mapWid
DecisionDataManager.getInstance()?.mapHeight = mapHet
}
private var state = -1
private var action = -1
override fun pncActions(planningActionMsg: MessagePad.PlanningActionMsg) {
val actionMsg = planningActionMsg.actionMsg
val s = actionMsg.drivingState.number
val a = actionMsg.drivingAction.number
if(s == state && a == action){
return
} else {
state = s
action = a
}
var type = -1
if (actionMsg.drivingState == MessagePad.DrivingState.START_UP && actionMsg.drivingAction == MessagePad.DrivingAction.DRIVING_ACTION_STATE_ONE) {
type = 0// 出站
} else if (actionMsg.drivingState == MessagePad.DrivingState.PULL_OVER && actionMsg.drivingAction == MessagePad.DrivingAction.DRIVING_ACTION_STATE_ONE) {
type = 1// 进站
} else if (actionMsg.drivingState == MessagePad.DrivingState.LANKE_KEEP && actionMsg.drivingAction == MessagePad.DrivingAction.DRIVING_ACTION_STATE_ONE) {
type = 2// 车道保持
} else if (actionMsg.drivingState == MessagePad.DrivingState.FOLLOW_LANE_CHANGE_LEFT) {//actionMsg.drivingAction == MessagePad.DrivingAction.DRIVING_ACTION_STATE_TWO
type = 3// 向左变道
} else if (actionMsg.drivingState == MessagePad.DrivingState.FOLLOW_LANE_CHANGE_RIGHT) {
type = 4// 向右变道
} else if (actionMsg.drivingState == MessagePad.DrivingState.LANE_AVOID_LEFT) {
type = 5// 向左变道绕障
} else if (actionMsg.drivingState == MessagePad.DrivingState.LANE_AVOID_RIGHT) {
type = 6// 向右变道绕障
} else if (actionMsg.drivingState == MessagePad.DrivingState.TRAFFIC_LIGHT) {// 距离停止线前15m内且是红灯才会发送该状态
}
if (type >= 0) {
ThreadUtils.runOnUiThread {
updateAnim(type)
}
}
}
@SuppressLint("SetTextI18n")
private fun updateAnim(type: Int) {
val randomNum = 80 + Random(SystemClock.elapsedRealtime()).nextInt(16)
val last = 100 - randomNum
val pre1 = Random(SystemClock.elapsedRealtime()).nextInt(last+1)
val pre2 = last - pre1
tvPre1.text = "${pre1}%"
tvPre3.text = "${randomNum}%"
tvPre2.text = "${pre2}%"
when (type) {
0 -> {
decContent1.text = "停车等待"
decContent2.text = "变道出站"
decContent3.text = "直行出站"
gsyVideoPlay(getRawPath(R.raw.wujuece))
gsyVideoPlay2(getRawPath(R.raw.zuohuandao))
gsyVideoPlay3(getRawPath(R.raw.zhixing))
}
1 -> {
decContent1.text = "车道保持"
decContent2.text = "进站停车"
decContent3.text = "向右变道"
gsyVideoPlay(getRawPath(R.raw.zhixing))
gsyVideoPlay2(getRawPath(R.raw.youhuandao))
gsyVideoPlay3(getRawPath(R.raw.youhuandao))
}
2 -> {
decContent1.text = "向左变道"
decContent2.text = "车道保持"
decContent3.text = "向右变道"
gsyVideoPlay(getRawPath(R.raw.zuohuandao))
gsyVideoPlay2(getRawPath(R.raw.zhixing))
gsyVideoPlay3(getRawPath(R.raw.youhuandao))
}
3 -> {
decContent1.text = "车道保持"
decContent2.text = "向左变道"
decContent3.text = "向右变道"
gsyVideoPlay(getRawPath(R.raw.zhixing))
gsyVideoPlay2(getRawPath(R.raw.zuohuandao))
gsyVideoPlay3(getRawPath(R.raw.youhuandao))
}
4 -> {
decContent1.text = "向左变道"
decContent2.text = "向右变道"
decContent3.text = "车道保持"
gsyVideoPlay(getRawPath(R.raw.zuohuandao))
gsyVideoPlay2(getRawPath(R.raw.youhuandao))
gsyVideoPlay3(getRawPath(R.raw.zhixing))
}
5 -> {
decContent1.text = "车道保持"
decContent2.text = "向左变道绕障"
decContent3.text = "向右变道绕障"
gsyVideoPlay(getRawPath(R.raw.zhixing))
gsyVideoPlay2(getRawPath(R.raw.zuobizhang))
gsyVideoPlay3(getRawPath(R.raw.youbizhang))
}
6 -> {
decContent1.text = "向左变道绕障"
decContent2.text = "向右变道绕障"
decContent3.text = "车道保持"
gsyVideoPlay(getRawPath(R.raw.zuobizhang))
gsyVideoPlay2(getRawPath(R.raw.youbizhang))
gsyVideoPlay3(getRawPath(R.raw.zhixing))
}
7 -> {
decContent1.text = "直行通过路口"
decContent2.text = "左转通过路口"
decContent3.text = "右转通过路口"
gsyVideoPlay(getRawPath(R.raw.zhixing))
gsyVideoPlay2(getRawPath(R.raw.lukouzuozhuan))
gsyVideoPlay3(getRawPath(R.raw.lukouyouzhuan))
}
8 -> {
decContent1.text = "左转通过路口"
decContent2.text = "直行通过路口"
decContent3.text = "右转通过路口"
gsyVideoPlay(getRawPath(R.raw.lukouzuozhuan))
gsyVideoPlay2(getRawPath(R.raw.lukouzhixing))
gsyVideoPlay3(getRawPath(R.raw.lukouyouzhuan))
}
9 -> {
decContent1.text = "左转通过路口"
decContent2.text = "右转通过路口"
decContent3.text = "直行通过路口"
gsyVideoPlay(getRawPath(R.raw.lukouzuozhuan))
gsyVideoPlay2(getRawPath(R.raw.lukouyouzhuan))
gsyVideoPlay3(getRawPath(R.raw.lukouzhixing))
}
}
}
private fun initViews() {
}
private fun initVideos() {
val list: MutableList<VideoOptionModel> = ArrayList()
list.add(VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "reconnect", 3))
GSYVideoManager.instance().optionModelList = list
GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL)
GSYVideoType.setRenderType(GSYVideoType.TEXTURE)
PlayerFactory.setPlayManager(IjkPlayerManager::class.java)
}
private fun gsyVideoPlay(flvUrl: String) {
if (flvUrl == lastUrl1) return
lastUrl1 = flvUrl
gsyVideoOptionBuilder1.setUrl(flvUrl)
.setCacheWithPlay(false)
.setAutoFullWithSize(false)
.setIsTouchWigetFull(false)
.setIsTouchWiget(false)
.setLooping(true)
.setPlayTag(TAG)
.setPlayPosition(0)
.build(preDetailView2)
preDetailView2.startPlayLogic()
}
private fun gsyVideoPlay2(flvUrl: String) {
if (flvUrl == lastUrl2) return
lastUrl2 = flvUrl
gsyVideoOptionBuilder2.setUrl(flvUrl)
.setCacheWithPlay(false)
.setAutoFullWithSize(false)
.setIsTouchWigetFull(false)
.setIsTouchWiget(false)
.setLooping(true)
.setPlayTag(TAG)
.setPlayPosition(1)
.build(decMapView)
decMapView.startButton.performClick()
}
private fun gsyVideoPlay3(flvUrl: String) {
if (flvUrl == lastUrl3) return
lastUrl3 = flvUrl
gsyVideoOptionBuilder3.setUrl(flvUrl)
.setCacheWithPlay(false)
.setAutoFullWithSize(false)
.setIsTouchWigetFull(false)
.setLooping(true)
.setIsTouchWiget(false)
.setPlayTag(TAG)
.setPlayPosition(2)
.build(preDetailView3)
preDetailView3.startButton.performClick()
}
private fun getRawPath(resId: Int): String {
return "android.resource://${context.packageName}/$resId"
}
}

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<com.mogo.eagle.core.widget.media.video.MultiVideoPlayer
android:id="@+id/preDetailView2"
android:layout_width="238dp"
android:layout_height="458dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="@dimen/dp_27"
android:layout_marginBottom="24dp"
/>
<com.mogo.eagle.core.widget.media.video.MultiVideoPlayer
android:id="@+id/decMapView"
android:layout_width="238dp"
android:layout_height="458dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="24dp"
app:map_index="1"
/>
<com.mogo.eagle.core.widget.media.video.MultiVideoPlayer
android:id="@+id/preDetailView3"
android:layout_width="238dp"
android:layout_height="458dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="@dimen/dp_27"
android:layout_marginBottom="20dp"
app:map_index="2"
/>
<TextView
android:id="@+id/tvDecTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AI Decision-making"
android:textColor="#394047"
android:textSize="32dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="@dimen/dp_28"
/>
<TextView
android:id="@+id/tvPre1"
android:layout_width="62dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center"
android:layout_marginStart="@dimen/dp_116"
android:layout_marginTop="@dimen/dp_70"
tools:text="11%"
android:textColor="#63707D"
android:textSize="33dp"
/>
<TextView
android:id="@+id/tvPre2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="@dimen/dp_70"
tools:text="86%"
android:textColor="#2EACFF"
android:textSize="33dp"
/>
<TextView
android:id="@+id/tvPre3"
android:layout_width="62dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="@dimen/dp_116"
android:layout_marginTop="@dimen/dp_70"
android:gravity="center"
tools:text="3%"
android:textColor="#63707D"
android:textSize="33dp"
/>
<TextView
android:id="@+id/decContent1"
android:layout_width="156dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="@dimen/dp_68"
android:layout_marginTop="@dimen/dp_112"
android:gravity="center"
tools:text="向左变道绕障"
android:textColor="#63707D"
android:textSize="26dp"
/>
<TextView
android:id="@+id/decContent2"
android:layout_width="156dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="@dimen/dp_112"
android:gravity="center"
tools:text="向右变道绕障"
android:textColor="#2EACFF"
android:textSize="26dp"
/>
<TextView
android:id="@+id/decContent3"
android:layout_width="156dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="@dimen/dp_68"
android:layout_marginTop="@dimen/dp_112"
android:gravity="center"
tools:text="直行"
android:textColor="#63707D"
android:textSize="26dp"
/>
</merge>

View File

@@ -84,7 +84,7 @@
<declare-styleable name="CarMapLayout">
<attr name="car_type" format="enum" >
<enum name="Taxi" value="0" />
<enum name="B2" value="1" /> />
<enum name="B2" value="1" />
</attr>
</declare-styleable>
</resources>