[8.0.2]优化规划与决策功能
This commit is contained in:
@@ -3,21 +3,19 @@ package com.mogo.eagle.core.function
|
||||
import android.content.Context
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.data.constants.MogoServicePaths
|
||||
import com.mogo.eagle.core.function.api.base.IMoGoFunctionServerProvider
|
||||
import com.mogo.eagle.core.function.api.map.roma.IMogoRoma
|
||||
import com.mogo.eagle.core.function.business.MapPointCloudSubscriber
|
||||
import com.mogo.eagle.core.function.business.SpeedLimitDataManager
|
||||
import com.mogo.eagle.core.function.business.ai.AiCloudIdentifyDataManager.Companion.aiCloudIdentifyDataManager
|
||||
import com.mogo.eagle.core.function.business.ai.RomaManager
|
||||
import com.mogo.eagle.core.function.business.ai.RomaManager.Companion.romaManager
|
||||
import com.mogo.eagle.core.function.business.identify.MapIdentifySubscriber
|
||||
import com.mogo.eagle.core.function.business.roadcross.RoadCrossCameraManager
|
||||
import com.mogo.eagle.core.function.business.routeoverlay.DecisionDataManager
|
||||
import com.mogo.eagle.core.function.business.routeoverlay.MogoRouteOverlayManager
|
||||
import com.mogo.eagle.core.function.business.routeoverlay.PredictionDataManager
|
||||
import com.mogo.eagle.core.function.business.trajectoryoverlay.MogoTrajectoryOverlayManager
|
||||
import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.util.DeviceUtils
|
||||
import com.mogo.map.MapDataWrapper
|
||||
|
||||
@@ -31,6 +29,8 @@ class MapBizProvider :IMoGoFunctionServerProvider, IMogoRoma {
|
||||
MapDataWrapper.init()
|
||||
MapIdentifySubscriber.instance
|
||||
MogoRouteOverlayManager.getInstance().init()
|
||||
DecisionDataManager.getInstance()
|
||||
PredictionDataManager.getInstance()
|
||||
MogoTrajectoryOverlayManager.getInstance().init()
|
||||
MapPointCloudSubscriber.instance
|
||||
RoadCrossCameraManager.instance.init(context)
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.mogo.eagle.core.data.traffic.TrafficData
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
|
||||
import com.mogo.eagle.core.function.api.base.IMoGoSubscriber
|
||||
import com.mogo.eagle.core.function.api.datacenter.obu.IMoGoObuStatusListener
|
||||
import com.mogo.eagle.core.function.business.routeoverlay.PredictionDataManager
|
||||
import com.mogo.eagle.core.function.business.routeoverlay.PredictionOverlayDrawer
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager.getLocationHeading
|
||||
@@ -108,24 +109,15 @@ class MapIdentifySubscriber private constructor() : IMoGoSubscriber,
|
||||
if (preObj.predictionTrajectoryList == null || preObj.predictionTrajectoryList.size < 2) return@forEach
|
||||
carPoiList1 = preObj.predictionTrajectoryList[0].trajectoryPointsList
|
||||
carPoiList2 = preObj.predictionTrajectoryList[1].trajectoryPointsList
|
||||
val largeType: Int
|
||||
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)
|
||||
// if (probability1 >= probability2) {
|
||||
//// MogoIdentifyManager.getInstance().updateGps(location1!!, MogoMap.SMALL_PRED_MAP)
|
||||
// largeType = 2
|
||||
// } else {
|
||||
//// MogoIdentifyManager.getInstance().updateGps(location2!!, MogoMap.SMALL_PRED_MAP)
|
||||
// largeType = 3
|
||||
// }
|
||||
// PredictionOverlayDrawer2.getInstance().drawPredictionList(carPoiList1, getLocationHeading(), false, 2, largeType)
|
||||
// PredictionOverlayDrawer3.getInstance().drawPredictionList(carPoiList2, getLocationHeading(), false, 3, largeType)
|
||||
// MogoIdentifyManager.getInstance().updateGps(location1!!, MogoMap.SMALL_PRED_MAP2)
|
||||
// MogoIdentifyManager.getInstance().updateGps(location2!!, MogoMap.SMALL_PRED_MAP3)
|
||||
|
||||
PredictionDataManager.getInstance()?.updateData(carPoiList1!!, 0)
|
||||
PredictionDataManager.getInstance()?.updateData(carPoiList2!!, 2)
|
||||
} else {
|
||||
if (preObj.predictionTrajectoryList.isNullOrEmpty() || isUnKnownType(preObj.classtype) || mogoMap == null) return@forEach
|
||||
point = preObj.predictionTrajectoryList[0].trajectoryPointsList[0]
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.mogo.eagle.core.function.business.routeoverlay
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningTrajectoryListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningTrajectoryListenerManager
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.mogo.map.MogoMap
|
||||
import com.mogo.map.MogoMap.Companion.mapInstance
|
||||
import mogo.telematics.pad.MessagePad
|
||||
|
||||
class DecisionDataManager private constructor() : IMoGoPlanningTrajectoryListener {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DecisionDataManager"
|
||||
private const val MSG_DATA_POINTS = 0
|
||||
private const val MSG_CHECK = 1
|
||||
|
||||
@Volatile
|
||||
private var sInstance: DecisionDataManager? = null
|
||||
fun getInstance(): DecisionDataManager? {
|
||||
if (sInstance == null) {
|
||||
synchronized(DecisionDataManager::class.java) {
|
||||
if (sInstance == null) {
|
||||
sInstance = DecisionDataManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance
|
||||
}
|
||||
}
|
||||
|
||||
private var frequentHandler: FrequentHandler? = null
|
||||
|
||||
private var lastUpdateTime = 0L
|
||||
|
||||
init {
|
||||
val frequentThread = HandlerThread("decision_thread")
|
||||
frequentThread.start()
|
||||
frequentHandler = FrequentHandler(frequentThread.looper)
|
||||
frequentHandler?.sendEmptyMessageDelayed(MSG_CHECK, 1000)
|
||||
CallerPlanningTrajectoryListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
private fun updateData(data: FloatArray) {
|
||||
frequentHandler?.removeMessages(MSG_DATA_POINTS)
|
||||
val message = Message.obtain()
|
||||
message.what = MSG_DATA_POINTS
|
||||
message.obj = data
|
||||
frequentHandler?.sendMessage(message)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
}
|
||||
|
||||
private inner class FrequentHandler(looper: Looper) : Handler(looper) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
MSG_DATA_POINTS -> {
|
||||
lastUpdateTime = System.currentTimeMillis()
|
||||
CallerAutopilotIdentifyListenerManager.invokeScreenPointsChanged(msg.obj as FloatArray)
|
||||
}
|
||||
MSG_CHECK -> {
|
||||
val time = System.currentTimeMillis()
|
||||
if (lastUpdateTime > 0 && time - lastUpdateTime >= 1000) {
|
||||
CallerAutopilotIdentifyListenerManager.invokeScreenPointsChanged(floatArrayOf())
|
||||
}
|
||||
sendEmptyMessageDelayed(MSG_CHECK, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotTrajectory(trajectoryInfos: MutableList<MessagePad.TrajectoryPoint>) {
|
||||
ThreadUtils.getCpuPool().execute {
|
||||
val mogoMap = mapInstance.getMogoMap(MogoMap.DEFAULT)
|
||||
mogoMap?.let { map ->
|
||||
val lonLatList = ArrayList<android.graphics.Point>()
|
||||
trajectoryInfos.forEach {
|
||||
map.toScreenLocation(it.longitude, it.latitude)?.let { point ->
|
||||
lonLatList.add(point)
|
||||
Log.d(TAG, "转换后的屏幕坐标为:(${point.x},${point.y})")
|
||||
}
|
||||
}
|
||||
if (lonLatList.size > 0) {
|
||||
val points = FloatArray(lonLatList.size * 2)
|
||||
var x = 0f
|
||||
var y = 0f
|
||||
var offset = 0f
|
||||
for (i in 0 until lonLatList.size) {
|
||||
x = lonLatList[i].x * 238 / 808.toFloat()
|
||||
points[i * 2] = x
|
||||
|
||||
// TODO:需要根据UI布局而变化,成比例缩放(高精地图返回的y轴是镜像的,需要在y轴方向上翻转一下)
|
||||
// float yB = heightB - (yA * (heightB / heightA));
|
||||
// yB = 480 - (yA * 480 / 1300)
|
||||
y = (458 + 14 - lonLatList[i].y * 458 / 1300).toFloat()
|
||||
if (i == 0) {
|
||||
offset = 357 - y// carBitmapTop等于height * 0.78,offset = carBitmapTop - 1stY
|
||||
}
|
||||
points[i * 2 + 1] = y + offset
|
||||
Log.d(TAG, "转换后的屏幕坐标为:(${x},${y})")
|
||||
}
|
||||
updateData(points)
|
||||
} else {
|
||||
updateData(floatArrayOf())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.mogo.eagle.core.function.business.routeoverlay
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
|
||||
import com.mogo.map.MogoMap
|
||||
import com.mogo.map.MogoMap.Companion.mapInstance
|
||||
|
||||
class PredictionDataManager private constructor() {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PredictionDataManager"
|
||||
private const val MSG_CHECK = 0
|
||||
private const val MSG_DATA_POINTS_0 = 1
|
||||
private const val MSG_DATA_POINTS_1 = 2
|
||||
|
||||
@Volatile
|
||||
private var sInstance: PredictionDataManager? = null
|
||||
fun getInstance(): PredictionDataManager? {
|
||||
if (sInstance == null) {
|
||||
synchronized(PredictionDataManager::class.java) {
|
||||
if (sInstance == null) {
|
||||
sInstance = PredictionDataManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance
|
||||
}
|
||||
}
|
||||
|
||||
private var frequentHandler: FrequentHandler? = null
|
||||
|
||||
private var lastUpdateTime = 0L
|
||||
|
||||
init {
|
||||
val frequentThread = HandlerThread("prediction_thread")
|
||||
frequentThread.start()
|
||||
frequentHandler = FrequentHandler(frequentThread.looper)
|
||||
frequentHandler?.sendEmptyMessageDelayed(MSG_CHECK, 1000)
|
||||
}
|
||||
|
||||
fun updateData(dataList: List<geometry.Geometry.Point>, index: Int = 0) {
|
||||
val type = if (index == 0) MSG_DATA_POINTS_0 else MSG_DATA_POINTS_1
|
||||
frequentHandler?.removeMessages(type)
|
||||
val message = Message.obtain()
|
||||
message.what = type
|
||||
message.obj = dataList
|
||||
frequentHandler?.sendMessage(message)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
}
|
||||
|
||||
private inner class FrequentHandler(looper: Looper) : Handler(looper) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
MSG_DATA_POINTS_0, MSG_DATA_POINTS_1 -> {
|
||||
val list = getDataList(msg.obj)
|
||||
lastUpdateTime = System.currentTimeMillis()
|
||||
CallerAutopilotIdentifyListenerManager.invokePreScrPointsChanged(list, if (msg.what == MSG_DATA_POINTS_0) 0 else 2)
|
||||
}
|
||||
MSG_CHECK -> {
|
||||
val time = System.currentTimeMillis()
|
||||
if (lastUpdateTime > 0 && time - lastUpdateTime >= 1000) {
|
||||
CallerAutopilotIdentifyListenerManager.invokePreScrPointsChanged(floatArrayOf(), 0)
|
||||
CallerAutopilotIdentifyListenerManager.invokePreScrPointsChanged(floatArrayOf(), 2)
|
||||
}
|
||||
sendEmptyMessageDelayed(MSG_CHECK, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDataList(obj: Any): FloatArray {
|
||||
val mogoMap = mapInstance.getMogoMap(MogoMap.DEFAULT) ?: return floatArrayOf()
|
||||
val list = obj as List<geometry.Geometry.Point>
|
||||
val lonLatList = ArrayList<android.graphics.Point>()
|
||||
var arr: DoubleArray?
|
||||
var point: android.graphics.Point?
|
||||
list.forEach {
|
||||
arr = mogoMap.switchData(it.x, it.y, false)// UTM转wgs84
|
||||
if (arr == null || arr!!.size < 2) return@forEach
|
||||
point = mogoMap.toScreenLocation(arr!![0], arr!![1])// wgs84转屏幕坐标
|
||||
if (point == null) return@forEach
|
||||
lonLatList.add(point!!)
|
||||
Log.d(TAG, "预测数据的屏幕坐标为:(${point!!.x},${point!!.y})")
|
||||
}
|
||||
if (lonLatList.size > 0) {
|
||||
val points = FloatArray(lonLatList.size * 2)
|
||||
var x = 0f
|
||||
var y = 0f
|
||||
var offset = 0f
|
||||
for (i in 0 until lonLatList.size) {
|
||||
x = lonLatList[i].x * 238 / 808.toFloat()
|
||||
points[i * 2] = x
|
||||
|
||||
// TODO:需要根据UI布局而变化,成比例缩放(高精地图返回的y轴是镜像的,需要在y轴方向上翻转一下)
|
||||
// float yB = heightB - (yA * (heightB / heightA));
|
||||
// yB = 480 - (yA * 480 / 1300)
|
||||
y = (458 + 14 - lonLatList[i].y * 458 / 1300).toFloat()
|
||||
if (i == 0) {
|
||||
offset = 357 - y// carBitmapTop等于height * 0.78,offset = carBitmapTop - 1stY
|
||||
}
|
||||
points[i * 2 + 1] = y + offset
|
||||
Log.d(TAG, "预测数据转换后的屏幕坐标为:(${x},${y})")
|
||||
}
|
||||
return points
|
||||
} else {
|
||||
return floatArrayOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
package com.mogo.eagle.core.function.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.DashPathEffect
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Path
|
||||
import android.graphics.RectF
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.SurfaceView
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
|
||||
import com.mogo.eagle.core.function.map.R
|
||||
import me.jessyan.autosize.utils.AutoSizeUtils
|
||||
import kotlin.math.min
|
||||
|
||||
class CoordinateAnimationView @JvmOverloads constructor(
|
||||
context: Context?,
|
||||
attrs: AttributeSet? = null
|
||||
) :
|
||||
SurfaceView(context, attrs), SurfaceHolder.Callback, IMoGoAutopilotIdentifyListener {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "CoordinateAnimationView"
|
||||
|
||||
private const val UPDATE_INTERVAL = 1000 // 数据更新间隔(ms)
|
||||
private const val MAX_POINTS = 500 // 最大点数
|
||||
private const val BUFFER_SIZE = MAX_POINTS * 2 // x,y坐标交替存储
|
||||
private const val FPS = 25
|
||||
}
|
||||
|
||||
private var surfaceHolder: SurfaceHolder? = null
|
||||
private var animationThread: AnimationThread? = null
|
||||
|
||||
private var bufferA: Array<Point?>? = null
|
||||
private var bufferB: Array<Point?>? = null
|
||||
private var controlPoints: FloatArray? = null // 控制点缓冲区
|
||||
private var activePointCount = 0
|
||||
|
||||
@Volatile
|
||||
private var activeBufferIndex = 0
|
||||
|
||||
@Volatile
|
||||
private var drawingBufferIndex = 0
|
||||
|
||||
private var lastUpdateTime: Long = 0
|
||||
private var costTime: Long = 0
|
||||
private var fpsInterval: Int = 1000 / FPS
|
||||
|
||||
@Volatile
|
||||
private var dataChanged = false // 数据变化标志
|
||||
|
||||
@Volatile
|
||||
private var isRunning = false
|
||||
private var bezierPath: Path? = null // 贝塞尔曲线路径
|
||||
private var curvePaint: Paint? = null
|
||||
private var carPaint: Paint? = null
|
||||
|
||||
// private var circlePaint: Paint? = null
|
||||
private var visibleRect: RectF? = null // 可见区域
|
||||
private var strokeWidth = 22f
|
||||
|
||||
private var carBitmap: Bitmap? = null
|
||||
|
||||
// 虚线相关参数
|
||||
private val DASH_LENGTH: Float = 46f // 虚线线段长度
|
||||
private val DASH_GAP: Float = 80f // 虚线间隔
|
||||
private val DASH_SPEED: Float = 8f // 虚线移动速度
|
||||
private var dashOffsetY = 0f // 虚线Y轴偏移量
|
||||
private var dashStrokeWidth = 3.6f
|
||||
private var dashPaint: Paint? = null // 虚线画笔
|
||||
|
||||
private val leftPath by lazy {
|
||||
Path()
|
||||
}
|
||||
|
||||
private val rightPath by lazy {
|
||||
Path()
|
||||
}
|
||||
|
||||
private var index: Int = 1
|
||||
|
||||
init {
|
||||
init(attrs)
|
||||
}
|
||||
|
||||
private fun init(attrs: AttributeSet?) {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CoordinateAnimationView)
|
||||
index = typedArray.getInt(R.styleable.CoordinateAnimationView_map_index, 1)
|
||||
typedArray.recycle()
|
||||
Log.d(TAG, "初始化地图的index为:${index}")
|
||||
|
||||
surfaceHolder = holder
|
||||
surfaceHolder!!.addCallback(this)
|
||||
|
||||
curvePaint = Paint()
|
||||
carPaint = Paint()
|
||||
carPaint!!.isFilterBitmap = false
|
||||
carPaint!!.isAntiAlias = true
|
||||
carBitmap = getOriginBitmap(
|
||||
R.drawable.decision_car_icon,
|
||||
AutoSizeUtils.dp2px(context, 128f),
|
||||
AutoSizeUtils.dp2px(context, 280f)
|
||||
)
|
||||
// circlePaint = Paint()
|
||||
// circlePaint!!.color = Color.RED
|
||||
// circlePaint!!.style = Paint.Style.STROKE
|
||||
// circlePaint!!.isAntiAlias = true
|
||||
|
||||
curvePaint!!.setARGB(102, 48, 163, 255)
|
||||
// curvePaint!!.shader = LinearGradient(
|
||||
// 50f, 100f, 750f, 100f,
|
||||
// intArrayOf(0x0FFF0000, 0xFF00FF00.toInt(), 0x0F0000FF),
|
||||
// floatArrayOf(0f, 0.5f, 1f),
|
||||
// Shader.TileMode.CLAMP
|
||||
// )
|
||||
curvePaint!!.style = Paint.Style.STROKE
|
||||
curvePaint!!.strokeWidth = strokeWidth
|
||||
// 一定要设置抗锯齿,否则画贝塞尔曲线时会出现很多白色分割线
|
||||
curvePaint!!.isAntiAlias = true
|
||||
// 线段连接处为圆弧
|
||||
curvePaint!!.strokeJoin = Paint.Join.ROUND
|
||||
// 设置线冒样式
|
||||
curvePaint!!.strokeCap = Paint.Cap.SQUARE
|
||||
|
||||
// 初始化虚线
|
||||
dashPaint = Paint()
|
||||
dashPaint!!.setColor(Color.WHITE)
|
||||
dashPaint!!.style = Paint.Style.STROKE
|
||||
dashPaint!!.strokeWidth = dashStrokeWidth
|
||||
dashPaint!!.isAntiAlias = true
|
||||
dashPaint!!.pathEffect = DashPathEffect(floatArrayOf(DASH_LENGTH, DASH_GAP), 0f)
|
||||
|
||||
bufferA = arrayOfNulls(MAX_POINTS)
|
||||
bufferB = arrayOfNulls(MAX_POINTS)
|
||||
|
||||
for (i in 0 until MAX_POINTS) {
|
||||
bufferA!![i] = Point()
|
||||
bufferB!![i] = Point()
|
||||
}
|
||||
|
||||
bezierPath = Path()
|
||||
dataChanged = false
|
||||
controlPoints = FloatArray(MAX_POINTS * 4)// 按照三阶贝塞尔曲线来创建
|
||||
visibleRect = RectF()
|
||||
|
||||
// 启用硬件加速
|
||||
setLayerType(LAYER_TYPE_HARDWARE, null)
|
||||
}
|
||||
|
||||
private fun getOriginBitmap(resId: Int, desWidth: Int, desHeight: Int): Bitmap {
|
||||
val bitmap = BitmapFactory.decodeResource(resources, resId)
|
||||
val scaleWidth = (bitmap.width * 1.6).toInt()
|
||||
val scaleHeight = (bitmap.height * 1.6).toInt()
|
||||
Log.d(TAG, "$index-Bitmap width:$scaleWidth,height:$scaleHeight")
|
||||
return Bitmap.createScaledBitmap(
|
||||
bitmap, scaleWidth,
|
||||
scaleHeight, true
|
||||
)
|
||||
|
||||
// val options = BitmapFactory.Options()
|
||||
// options.inJustDecodeBounds = true
|
||||
// BitmapFactory.decodeResource(resources, resId, options)
|
||||
// var inSampleSize = 1
|
||||
// if (options.outHeight > desHeight || options.outWidth > desWidth) {
|
||||
// while ((options.outHeight / 2 / inSampleSize) >= desHeight && (options.outWidth / inSampleSize) >= desWidth) {
|
||||
// inSampleSize *= 2// 每次翻倍,保证是 2 的幂次
|
||||
// }
|
||||
// }
|
||||
// options.inJustDecodeBounds = false
|
||||
// options.inSampleSize = inSampleSize
|
||||
// return BitmapFactory.decodeResource(resources, resId, options)
|
||||
}
|
||||
|
||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||
animationThread = AnimationThread()
|
||||
animationThread!!.start()
|
||||
isRunning = true
|
||||
CallerAutopilotIdentifyListenerManager.addListener("${TAG}${this.hashCode()}", this)
|
||||
}
|
||||
|
||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||
val margin = strokeWidth * 2
|
||||
// 处理Surface尺寸变化
|
||||
visibleRect!!.set(margin, margin, width - margin, height - margin)
|
||||
}
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
isRunning = false
|
||||
var retry = true
|
||||
while (retry) {
|
||||
try {
|
||||
animationThread!!.join()
|
||||
retry = false
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
CallerAutopilotIdentifyListenerManager.removeListener("${TAG}${this.hashCode()}")
|
||||
carBitmap?.recycle()
|
||||
carBitmap = null
|
||||
bufferA = null
|
||||
bufferB = null
|
||||
controlPoints = null
|
||||
}
|
||||
|
||||
override fun screenPointsChanged(data: FloatArray, index: Int) {
|
||||
if (index == this.index) {
|
||||
updatePoints(data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun preScrPointsChanged(data: FloatArray, index: Int) {
|
||||
if (index == this.index) {
|
||||
updatePoints(data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePoints(newPoints: FloatArray) {
|
||||
if (!isRunning) {
|
||||
Log.d(TAG, "$index-渲染线程未启动")
|
||||
return
|
||||
}
|
||||
if (bufferA == null || bufferB == null) {
|
||||
Log.d(TAG, "$index-updatePoints->缓冲区未初始化完成!")
|
||||
return
|
||||
}
|
||||
// 获取可用缓冲区
|
||||
val targetBuffer: Array<Point?> = if ((drawingBufferIndex == 0)) bufferB!! else bufferA!!
|
||||
|
||||
// 重置目标缓冲区
|
||||
for (i in 0 until MAX_POINTS) {
|
||||
targetBuffer[i]?.reset()
|
||||
}
|
||||
|
||||
// 填充新数据(不能超过最大点数)
|
||||
val count = min(newPoints.size / 2, MAX_POINTS)
|
||||
var p: Point?
|
||||
for (i in 0 until count) {
|
||||
p = targetBuffer[i]
|
||||
p?.set(newPoints[i * 2], newPoints[i * 2 + 1])
|
||||
}
|
||||
|
||||
activePointCount = count
|
||||
activeBufferIndex = if (drawingBufferIndex == 0) 1 else 0
|
||||
dataChanged = true
|
||||
|
||||
Log.d(TAG, "$index-数据已更新!")
|
||||
}
|
||||
|
||||
private fun drawMovingDashedPath(canvas: Canvas?) {
|
||||
if (canvas == null) {
|
||||
Log.d(TAG, "$index-画布为null!")
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "$index-开始绘制虚线!")
|
||||
leftPath.rewind()
|
||||
rightPath.rewind()
|
||||
|
||||
// 两条虚线的X坐标(左右对称)
|
||||
val leftLineX = width * 0.2f
|
||||
val rightLineX = width * 0.8f
|
||||
|
||||
// 计算当前虚线的偏移量(取模运算确保在一个周期内)
|
||||
val offset = dashOffsetY % (DASH_LENGTH + DASH_GAP)
|
||||
|
||||
// 绘制多条虚线线段,确保覆盖整个屏幕
|
||||
var y = offset
|
||||
var endY = 0f
|
||||
while (y < height + DASH_LENGTH + DASH_GAP) {
|
||||
endY = min(y + DASH_LENGTH, height.toFloat())
|
||||
|
||||
leftPath.moveTo(leftLineX, y)
|
||||
leftPath.lineTo(leftLineX, endY)
|
||||
rightPath.moveTo(rightLineX, y)
|
||||
rightPath.lineTo(rightLineX, endY)
|
||||
|
||||
y += DASH_LENGTH + DASH_GAP// 步长
|
||||
}
|
||||
canvas.drawPath(leftPath, dashPaint!!)
|
||||
canvas.drawPath(rightPath, dashPaint!!)
|
||||
|
||||
// 更新虚线偏移量
|
||||
dashOffsetY += DASH_SPEED
|
||||
if (dashOffsetY > DASH_LENGTH + DASH_GAP) {
|
||||
dashOffsetY -= (DASH_LENGTH + DASH_GAP)
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawCar(canvas: Canvas?) {
|
||||
if (canvas == null) {
|
||||
Log.d(TAG, "$index-画布为null!")
|
||||
return
|
||||
}
|
||||
canvas.drawBitmap(carBitmap!!, (width - carBitmap!!.width) / 2f, height * 0.78f, carPaint!!)
|
||||
}
|
||||
|
||||
private fun drawPath(canvas: Canvas?) {
|
||||
if (canvas == null) {
|
||||
Log.d(TAG, "$index-画布为null!")
|
||||
return
|
||||
}
|
||||
// 获取当前活跃的缓冲区
|
||||
val currentBuffer = if (activeBufferIndex == 0) bufferA else bufferB
|
||||
drawingBufferIndex = activeBufferIndex
|
||||
|
||||
// 绘制轨迹
|
||||
if (dataChanged) {
|
||||
bezierPath?.rewind()
|
||||
if (activePointCount > 0) {
|
||||
// 计算贝塞尔曲线的控制点(二阶贝塞尔曲线性能更好)
|
||||
// calculateControlPoints(currentBuffer, activePointCount, controlPoints!!)
|
||||
calculateControlPoints2ndKind(currentBuffer, activePointCount, controlPoints!!)
|
||||
|
||||
// 使用可见区域裁剪的贝塞尔曲线
|
||||
// drawClippedBezierPath(currentBuffer, activePointCount, controlPoints!!)
|
||||
drawClippedBezier2ndKindPath(currentBuffer, activePointCount, controlPoints!!)
|
||||
}
|
||||
dataChanged = false
|
||||
} else {
|
||||
Log.d(TAG, "$index-数据未更新:${dataChanged}或无有效的点:${activePointCount}")
|
||||
}
|
||||
// 绘制贝塞尔曲线
|
||||
canvas.drawPath(bezierPath!!, curvePaint!!)
|
||||
Log.d(TAG, "=====$index-渲染贝塞尔曲线完成!=====")
|
||||
|
||||
// if (currentBuffer == null) {
|
||||
// Log.d(TAG, "currentBuffer未初始化完成!")
|
||||
// return
|
||||
// }
|
||||
// canvas.drawCircle(currentBuffer[0]!!.x, currentBuffer[0]!!.y, 30f, circlePaint!!)
|
||||
}
|
||||
|
||||
// 绘制可见区域内的贝塞尔曲线
|
||||
private fun drawClippedBezierPath(
|
||||
points: Array<Point?>?,
|
||||
count: Int,
|
||||
controlPoints: FloatArray
|
||||
) {
|
||||
if (points.isNullOrEmpty()) {
|
||||
Log.d(TAG, "$index-贝塞尔曲线点的个数为空,返回!")
|
||||
return
|
||||
}
|
||||
var isFirstPoint = true
|
||||
var wasLastPointVisible = false
|
||||
var p: Point?
|
||||
var nextPoint: Point?
|
||||
var currentPointVisible = false
|
||||
var nextPointVisible = false
|
||||
var controlIndex: Int
|
||||
var x: Float
|
||||
var y: Float
|
||||
var nextX: Float
|
||||
var nextY: Float
|
||||
var intersection: FloatArray?
|
||||
|
||||
for (i in 0 until count - 1) {
|
||||
p = points[i]
|
||||
nextPoint = points[i + 1]
|
||||
if (p == null || nextPoint == null) continue
|
||||
x = p.x
|
||||
y = p.y
|
||||
nextX = nextPoint.x
|
||||
nextY = nextPoint.y
|
||||
|
||||
// 检查当前点和下一个点是否在可见区域内
|
||||
currentPointVisible = isPointVisible(x, y)
|
||||
nextPointVisible = isPointVisible(nextX, nextY)
|
||||
controlIndex = i * 2
|
||||
// 处理可见性变化
|
||||
if (currentPointVisible || nextPointVisible) {
|
||||
// 如果是第一个可见点,移动到该点
|
||||
if (isFirstPoint) {
|
||||
bezierPath!!.moveTo(x, y)
|
||||
isFirstPoint = false
|
||||
}
|
||||
// 如果当前点和下一个点都可见,直接连接
|
||||
if (currentPointVisible && nextPointVisible) {
|
||||
bezierPath!!.cubicTo(
|
||||
controlPoints[controlIndex], controlPoints[controlIndex + 1],
|
||||
controlPoints[controlIndex + 2], controlPoints[controlIndex + 3],
|
||||
nextX, nextY
|
||||
)
|
||||
} else if (currentPointVisible && !nextPointVisible) {
|
||||
// intersection = findIntersection(x, y, nextX, nextY)
|
||||
// if (intersection != null) {
|
||||
// bezierPath!!.lineTo(intersection[0], intersection[1])
|
||||
// }
|
||||
bezierPath!!.cubicTo(
|
||||
controlPoints[controlIndex], controlPoints[controlIndex + 1],
|
||||
controlPoints[controlIndex + 2], controlPoints[controlIndex + 3],
|
||||
nextX, nextY
|
||||
)
|
||||
} else if (!currentPointVisible && nextPointVisible) {
|
||||
// intersection = findIntersection(nextX, nextY, x, y)
|
||||
// if (intersection != null) {
|
||||
// bezierPath!!.moveTo(intersection[0], intersection[1])
|
||||
// bezierPath!!.cubicTo(
|
||||
// controlPoints[controlIndex], controlPoints[controlIndex + 1],
|
||||
// controlPoints[controlIndex + 2], controlPoints[controlIndex + 3],
|
||||
// nextX, nextY
|
||||
// )
|
||||
// }
|
||||
bezierPath!!.cubicTo(
|
||||
controlPoints[controlIndex], controlPoints[controlIndex + 1],
|
||||
controlPoints[controlIndex + 2], controlPoints[controlIndex + 3],
|
||||
nextX, nextY
|
||||
)
|
||||
}
|
||||
wasLastPointVisible = true
|
||||
} else {
|
||||
// 如果连续不可见点,重置路径状态
|
||||
if (wasLastPointVisible) {
|
||||
isFirstPoint = true
|
||||
}
|
||||
wasLastPointVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算贝塞尔曲线的控制点
|
||||
private fun calculateControlPoints(
|
||||
points: Array<Point?>?,
|
||||
count: Int,
|
||||
controlPoints: FloatArray
|
||||
) {
|
||||
if (count < 3 || points.isNullOrEmpty()) {
|
||||
Log.d(TAG, "$index-点的个数小于3,无法绘制贝塞尔曲线!")
|
||||
return// 至少需要3个点才能计算控制点
|
||||
}
|
||||
var prev: Point?
|
||||
var current: Point?
|
||||
var next: Point?
|
||||
var controlIndex: Int
|
||||
// 使用相邻点的中点作为控制点
|
||||
for (i in 1 until count - 1) {
|
||||
prev = points[i - 1]
|
||||
current = points[i]
|
||||
next = points[i + 1]
|
||||
controlIndex = i * 2
|
||||
if (current == null || prev == null || next == null) continue
|
||||
|
||||
// 第一个控制点:当前点和前一个点的中点
|
||||
controlPoints[controlIndex] = (current.x + prev.x) / 2
|
||||
controlPoints[controlIndex + 1] = (current.y + prev.y) / 2
|
||||
|
||||
// 第二个控制点:当前点和下一个点的中点
|
||||
controlPoints[controlIndex + 2] = (current.x + next.x) / 2
|
||||
controlPoints[controlIndex + 3] = (current.y + next.y) / 2
|
||||
}
|
||||
if (points[0] == null || points[count - 2] == null) return
|
||||
// 特殊处理第一个和最后一个控制点
|
||||
controlPoints[0] = points[0]!!.x
|
||||
controlPoints[1] = points[0]!!.y
|
||||
|
||||
val lastIndex = (count - 2) * 2
|
||||
controlPoints[lastIndex] = points[count - 2]!!.x
|
||||
controlPoints[lastIndex + 1] = points[count - 2]!!.y
|
||||
}
|
||||
|
||||
// 计算二阶贝塞尔曲线的控制点
|
||||
private fun calculateControlPoints2ndKind(
|
||||
points: Array<Point?>?,
|
||||
count: Int,
|
||||
controlPoints: FloatArray
|
||||
) {
|
||||
if (count < 2 || points.isNullOrEmpty()) return // 至少需要2个点才能计算控制点
|
||||
var current: Point?
|
||||
var next: Point?
|
||||
var controlIndex: Int
|
||||
var dx: Float
|
||||
var dy: Float
|
||||
// 简单算法:使用相邻点的中点作为控制点
|
||||
for (i in 0 until count - 1) {
|
||||
current = points[i]
|
||||
next = points[i + 1]
|
||||
if (current == null || next == null) continue
|
||||
controlIndex = i * 2
|
||||
|
||||
// 控制点:当前点和下一个点之间的中点,增加一定偏移使曲线更平滑
|
||||
dx = next.x - current.x
|
||||
dy = next.y - current.y
|
||||
|
||||
// 控制点位置 = 中点 + 一定比例的方向向量(使曲线更平滑)
|
||||
controlPoints[controlIndex] = current.x + dx * 0.5f
|
||||
controlPoints[controlIndex + 1] = current.y + dy * 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制可见区域内的二阶贝塞尔曲线
|
||||
*/
|
||||
private fun drawClippedBezier2ndKindPath(
|
||||
points: Array<Point?>?,
|
||||
count: Int,
|
||||
controlPoints: FloatArray
|
||||
) {
|
||||
if (points.isNullOrEmpty()) {
|
||||
Log.d(TAG, "$index-贝塞尔曲线点的个数为空,返回!")
|
||||
return
|
||||
}
|
||||
var isFirstPoint = true
|
||||
var wasLastPointVisible = false
|
||||
// var hasPath = false
|
||||
|
||||
var p: Point?
|
||||
var nextPoint: Point?
|
||||
for (i in 0 until count - 1) {
|
||||
p = points[i]
|
||||
nextPoint = points[i + 1]
|
||||
if (p == null || nextPoint == null) continue
|
||||
val x = p.x
|
||||
val y = p.y
|
||||
val nextX = nextPoint.x
|
||||
val nextY = nextPoint.y
|
||||
|
||||
// 检查当前点和下一个点是否在可见区域内
|
||||
val currentPointVisible = isPointVisible(x, y)
|
||||
val nextPointVisible = isPointVisible(nextX, nextY)
|
||||
|
||||
// 处理可见性变化
|
||||
if (currentPointVisible || nextPointVisible) {
|
||||
// 如果是第一个可见点,移动到该点
|
||||
if (isFirstPoint) {
|
||||
// bezierPath!!.moveTo(x-strokeWidth/4, y)
|
||||
bezierPath!!.moveTo(x, y)
|
||||
isFirstPoint = false
|
||||
// hasPath = true
|
||||
}
|
||||
|
||||
// 如果当前点和下一个点都可见,直接连接
|
||||
if (currentPointVisible && nextPointVisible) {
|
||||
// 使用二阶贝塞尔曲线:quadTo方法(控制点x, 控制点y, 终点x, 终点y)
|
||||
bezierPath!!.quadTo(
|
||||
controlPoints[i * 2], controlPoints[i * 2 + 1],
|
||||
nextX, nextY
|
||||
)
|
||||
// hasPath = true
|
||||
} else if (currentPointVisible && !nextPointVisible) {
|
||||
// val intersection = findIntersection(x, y, nextX, nextY)
|
||||
// if (intersection != null) {
|
||||
// bezierPath!!.lineTo(intersection[0], intersection[1])
|
||||
//// hasPath = true
|
||||
// }
|
||||
bezierPath!!.lineTo(
|
||||
controlPoints[i * 2], controlPoints[i * 2 + 1],
|
||||
)
|
||||
} else if (!currentPointVisible && nextPointVisible) {
|
||||
// val intersection = findIntersection(nextX, nextY, x, y)
|
||||
// if (intersection != null) {
|
||||
// bezierPath!!.moveTo(intersection[0], intersection[1])
|
||||
// // 绘制二阶贝塞尔曲线
|
||||
// val controlIndex = i * 2
|
||||
// bezierPath!!.quadTo(
|
||||
// controlPoints[controlIndex], controlPoints[controlIndex + 1],
|
||||
// nextX, nextY
|
||||
// )
|
||||
//// hasPath = true
|
||||
// }
|
||||
bezierPath!!.lineTo(
|
||||
controlPoints[i * 2], controlPoints[i * 2 + 1],
|
||||
)
|
||||
}
|
||||
wasLastPointVisible = true
|
||||
} else {
|
||||
// 如果连续不可见点,重置路径状态
|
||||
if (wasLastPointVisible) {
|
||||
isFirstPoint = true
|
||||
}
|
||||
wasLastPointVisible = false
|
||||
}
|
||||
}
|
||||
// if (count > 1 && hasPath) {
|
||||
// val lastPoint = points[count - 1] ?: return
|
||||
// val endX = lastPoint.x
|
||||
// val endY = lastPoint.y
|
||||
//
|
||||
// // 添加一个微小的延伸,确保终点形状为方形
|
||||
// if (isPointVisible(endX, endY)) {
|
||||
// bezierPath!!.lineTo(endX + strokeWidth / 4, endY)
|
||||
// }
|
||||
// }
|
||||
Log.d(TAG, "=======$index-绘制二阶贝塞尔曲线完成=======!")
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制二阶贝塞尔曲线
|
||||
*/
|
||||
private fun drawBezierPath2ndKind(count: Int) {
|
||||
|
||||
Log.d(TAG, "=======$index-绘制二阶贝塞尔曲线完成=======!")
|
||||
}
|
||||
|
||||
// 检查点是否在可见区域内(考虑线宽)
|
||||
private fun isPointVisible(x: Float, y: Float): Boolean {
|
||||
val extraMargin = strokeWidth / 2
|
||||
return visibleRect!!.contains(x, y) ||
|
||||
visibleRect!!.let {
|
||||
it.inset(-extraMargin, -extraMargin)// 扩大(使用负数)边界以考虑线宽
|
||||
it.contains(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
// 计算线段与可见区域的交点
|
||||
private fun findIntersection(x1: Float, y1: Float, x2: Float, y2: Float): FloatArray? {
|
||||
// // 简化版:只检查线段与可见区域边界的交点
|
||||
// // 实际应用中可能需要更复杂的贝塞尔曲线与矩形的交点计算
|
||||
//
|
||||
// // 检查与左边界的交点
|
||||
// if ((x1 < visibleRect!!.left && x2 >= visibleRect!!.left) ||
|
||||
// (x1 >= visibleRect!!.left && x2 < visibleRect!!.left)
|
||||
// ) {
|
||||
// val t = (visibleRect!!.left - x1) / (x2 - x1)
|
||||
// val y = y1 + t * (y2 - y1)
|
||||
// if (y >= visibleRect!!.top && y <= visibleRect!!.bottom) {
|
||||
// return floatArrayOf(visibleRect!!.left, y)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 检查与右边界的交点
|
||||
// if ((x1 < visibleRect!!.right && x2 >= visibleRect!!.right) ||
|
||||
// (x1 >= visibleRect!!.right && x2 < visibleRect!!.right)
|
||||
// ) {
|
||||
// val t = (visibleRect!!.right - x1) / (x2 - x1)
|
||||
// val y = y1 + t * (y2 - y1)
|
||||
// if (y >= visibleRect!!.top && y <= visibleRect!!.bottom) {
|
||||
// return floatArrayOf(visibleRect!!.right, y)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 检查与上边界的交点
|
||||
// if ((y1 < visibleRect!!.top && y2 >= visibleRect!!.top) ||
|
||||
// (y1 >= visibleRect!!.top && y2 < visibleRect!!.top)
|
||||
// ) {
|
||||
// val t = (visibleRect!!.top - y1) / (y2 - y1)
|
||||
// val x = x1 + t * (x2 - x1)
|
||||
// if (x >= visibleRect!!.left && x <= visibleRect!!.right) {
|
||||
// return floatArrayOf(x, visibleRect!!.top)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 检查与下边界的交点
|
||||
// if ((y1 < visibleRect!!.bottom && y2 >= visibleRect!!.bottom) ||
|
||||
// (y1 >= visibleRect!!.bottom && y2 < visibleRect!!.bottom)
|
||||
// ) {
|
||||
// val t = (visibleRect!!.bottom - y1) / (y2 - y1)
|
||||
// val x = x1 + t * (x2 - x1)
|
||||
// if (x >= visibleRect!!.left && x <= visibleRect!!.right) {
|
||||
// return floatArrayOf(x, visibleRect!!.bottom)
|
||||
// }
|
||||
// }
|
||||
|
||||
return null // 没有交点
|
||||
}
|
||||
|
||||
private inner class AnimationThread : Thread() {
|
||||
override fun run() {
|
||||
var canvas: Canvas?
|
||||
lastUpdateTime = System.currentTimeMillis()
|
||||
|
||||
while (isRunning) {
|
||||
canvas = null
|
||||
try {
|
||||
canvas = surfaceHolder!!.lockCanvas()
|
||||
synchronized(surfaceHolder!!) {
|
||||
// 绘制
|
||||
Log.d(TAG, "$index-准备绘制!")
|
||||
// 清屏
|
||||
canvas?.drawColor(Color.rgb(231, 235, 238))
|
||||
drawMovingDashedPath(canvas)
|
||||
drawPath(canvas)
|
||||
drawCar(canvas)
|
||||
}
|
||||
} finally {
|
||||
if (canvas != null) {
|
||||
surfaceHolder!!.unlockCanvasAndPost(canvas)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
costTime = fpsInterval - System.currentTimeMillis() + lastUpdateTime
|
||||
if (costTime > 0) {
|
||||
sleep(costTime)
|
||||
}
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 轨迹点对象(可复用)
|
||||
class Point {
|
||||
var x: Float = 0f
|
||||
var y: Float = 0f
|
||||
var isActive: Boolean = false
|
||||
|
||||
fun set(x: Float, y: Float) {
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.isActive = true
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
this.isActive = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,6 @@ import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
|
||||
import com.mogo.eagle.core.function.map.R
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import kotlinx.android.synthetic.main.layout_decision_container.view.decMapView
|
||||
import kotlinx.android.synthetic.main.layout_decision_container.view.preDetailView2
|
||||
import kotlinx.android.synthetic.main.layout_decision_container.view.preDetailView3
|
||||
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
|
||||
@@ -39,21 +36,12 @@ class DecisionLayout @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun onCreate(savedInstanceState: Bundle?) {
|
||||
decMapView.onCreate(savedInstanceState)
|
||||
preDetailView2.onCreate(savedInstanceState)
|
||||
preDetailView3.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
fun onSaveInstanceState(outState: Bundle) {
|
||||
decMapView.onSaveInstanceState(outState)
|
||||
preDetailView2.onSaveInstanceState(outState)
|
||||
preDetailView3.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
decMapView.onResume()
|
||||
preDetailView2.onResume()
|
||||
preDetailView3.onResume()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@@ -81,20 +69,11 @@ class DecisionLayout @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun onLowMemory() {
|
||||
decMapView.onLowMemory()
|
||||
preDetailView2.onLowMemory()
|
||||
preDetailView3.onLowMemory()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
decMapView.onPause()
|
||||
preDetailView2.onPause()
|
||||
preDetailView3.onPause()
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
decMapView.onDestroy()
|
||||
preDetailView2.onDestroy()
|
||||
preDetailView3.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
android:layout_height="match_parent"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<com.mogo.eagle.core.function.view.PredictionMap2View
|
||||
<com.mogo.eagle.core.function.view.CoordinateAnimationView
|
||||
android:id="@+id/preDetailView2"
|
||||
android:layout_width="238dp"
|
||||
android:layout_height="458dp"
|
||||
@@ -14,14 +14,10 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginStart="@dimen/dp_27"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:carPosition="6"
|
||||
app:isAutoLocation="false"
|
||||
app:isDisplayAnim="false"
|
||||
app:isWeatherEnable="false"
|
||||
app:styleMode="MAP_STYLE_DAY_VR_AIP"
|
||||
app:vrAngleMode="MAP_STYLE_VR_ANGLE_TOP" />
|
||||
app:map_index="0"
|
||||
/>
|
||||
|
||||
<com.mogo.eagle.core.function.view.DecisionMapView
|
||||
<com.mogo.eagle.core.function.view.CoordinateAnimationView
|
||||
android:id="@+id/decMapView"
|
||||
android:layout_width="238dp"
|
||||
android:layout_height="458dp"
|
||||
@@ -29,16 +25,10 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
app:carPosition="6"
|
||||
app:isAutoLocation="false"
|
||||
app:isDisplayAnim="false"
|
||||
app:isWeatherEnable="false"
|
||||
app:styleMode="MAP_STYLE_DAY_VR_AIP"
|
||||
app:vrAngleMode="MAP_STYLE_VR_ANGLE_TOP" />
|
||||
app:map_index="1"
|
||||
/>
|
||||
|
||||
<com.mogo.eagle.core.function.view.PredictionMap3View
|
||||
<com.mogo.eagle.core.function.view.CoordinateAnimationView
|
||||
android:id="@+id/preDetailView3"
|
||||
android:layout_width="238dp"
|
||||
android:layout_height="458dp"
|
||||
@@ -46,68 +36,8 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginEnd="@dimen/dp_27"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:carPosition="6"
|
||||
app:isAutoLocation="false"
|
||||
app:isDisplayAnim="false"
|
||||
app:isWeatherEnable="false"
|
||||
app:styleMode="MAP_STYLE_DAY_VR_AIP"
|
||||
app:vrAngleMode="MAP_STYLE_VR_ANGLE_TOP" />
|
||||
|
||||
<!-- <androidx.cardview.widget.CardView-->
|
||||
<!-- android:id="@+id/decContainer"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="match_parent"-->
|
||||
<!-- app:cardBackgroundColor="#D7F1FF"-->
|
||||
<!-- app:cardCornerRadius="20dp"-->
|
||||
<!-- app:cardElevation="0dp"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
||||
<!-- >-->
|
||||
|
||||
<!-- <com.mogo.eagle.core.function.view.PredictionMap2View-->
|
||||
<!-- android:id="@+id/preDetailView2"-->
|
||||
<!-- android:layout_width="238dp"-->
|
||||
<!-- android:layout_height="458dp"-->
|
||||
<!-- android:layout_gravity="start|bottom"-->
|
||||
<!-- android:layout_marginStart="@dimen/dp_27"-->
|
||||
<!-- android:layout_marginBottom="24dp"-->
|
||||
<!-- app:carPosition="6"-->
|
||||
<!-- app:isAutoLocation="false"-->
|
||||
<!-- app:isDisplayAnim="false"-->
|
||||
<!-- app:isWeatherEnable="false"-->
|
||||
<!-- app:styleMode="MAP_STYLE_DAY_VR_AIP"-->
|
||||
<!-- app:vrAngleMode="MAP_STYLE_VR_ANGLE_TOP" />-->
|
||||
|
||||
<!-- <com.mogo.eagle.core.function.view.DecisionMapView-->
|
||||
<!-- android:id="@+id/decMapView"-->
|
||||
<!-- android:layout_width="238dp"-->
|
||||
<!-- android:layout_height="458dp"-->
|
||||
<!-- android:layout_gravity="center_horizontal|bottom"-->
|
||||
<!-- android:layout_marginBottom="24dp"-->
|
||||
<!-- android:focusable="false"-->
|
||||
<!-- android:focusableInTouchMode="false"-->
|
||||
<!-- app:carPosition="6"-->
|
||||
<!-- app:isAutoLocation="false"-->
|
||||
<!-- app:isDisplayAnim="false"-->
|
||||
<!-- app:isWeatherEnable="false"-->
|
||||
<!-- app:styleMode="MAP_STYLE_DAY_VR_AIP"-->
|
||||
<!-- app:vrAngleMode="MAP_STYLE_VR_ANGLE_TOP" />-->
|
||||
|
||||
<!-- <com.mogo.eagle.core.function.view.PredictionMap3View-->
|
||||
<!-- android:id="@+id/preDetailView3"-->
|
||||
<!-- android:layout_width="238dp"-->
|
||||
<!-- android:layout_height="458dp"-->
|
||||
<!-- android:layout_gravity="end|bottom"-->
|
||||
<!-- android:layout_marginEnd="@dimen/dp_27"-->
|
||||
<!-- android:layout_marginBottom="20dp"-->
|
||||
<!-- app:carPosition="6"-->
|
||||
<!-- app:isAutoLocation="false"-->
|
||||
<!-- app:isDisplayAnim="false"-->
|
||||
<!-- app:isWeatherEnable="false"-->
|
||||
<!-- app:styleMode="MAP_STYLE_DAY_VR_AIP"-->
|
||||
<!-- app:vrAngleMode="MAP_STYLE_VR_ANGLE_TOP" />-->
|
||||
|
||||
<!-- </androidx.cardview.widget.CardView>-->
|
||||
app:map_index="2"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDecTitle"
|
||||
|
||||
@@ -76,4 +76,8 @@
|
||||
<!-- 是否是订单结束页显示 -->
|
||||
<attr name="isOrderEnd" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CoordinateAnimationView">
|
||||
<attr name="map_index" format="integer" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user