[6.5.0][道路事件] 修正施工占道提示逻辑

This commit is contained in:
renwj
2024-07-19 15:58:27 +08:00
parent 563764d9aa
commit a1766a7223
3 changed files with 143 additions and 137 deletions

View File

@@ -25,6 +25,7 @@ import com.mogo.eagle.core.function.call.autopilot.CallerV2XListenerManager.V2NC
import com.mogo.eagle.core.function.call.autopilot.CallerV2nNioEventListenerManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
import com.mogo.eagle.core.function.call.hmi.CallerRoadV2NEventWindowListenerManager
import com.mogo.eagle.core.function.call.map.CallerMapRoadListenerManager
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager.saveMsgBox
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
@@ -34,6 +35,7 @@ import com.mogo.eagle.core.utilcode.util.CoordinateTransform
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils
import com.mogo.eagle.core.utilcode.util.GsonUtils
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.eagle.function.biz.v2x.V2XBizTrace
import com.mogo.eagle.function.biz.v2x.v2n.pnc.beans.Extras
import com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.airoad.AiRoadMarker
@@ -44,6 +46,10 @@ import com.mogo.eagle.function.biz.v2x.v2n.utils.IEventDismissListener
import com.mogo.eagle.function.biz.v2x.v2n.utils.V2NUtils
import com.mogo.eagle.function.biz.v2x.v2n.utils.V2XEventAnalyticsManager
import com.mogo.map.entities.Lane
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import mogo.telematics.pad.MessagePad
import mogo.telematics.pad.MessagePad.Header
import mogo.telematics.pad.MessagePad.TrackedObject
@@ -66,6 +72,8 @@ internal object V2NIdentifyDrawer: IEventDismissListener {
private const val MSG_WHAT_DRAW_GREEN_WAVE = 0x1014 // 绿波通行
private const val MSG_WHAT_DRAW_PEOPLE_CROSS = 0x1015 // 行人横穿
private val scope by lazy { CoroutineScope(ThreadUtils.getCpuPool().asCoroutineDispatcher()) }
private val callback = Handler.Callback { msg ->
if (msg.what == MSG_WHAT_DRAW_SHIGONE || msg.what == MSG_WHAT_DRAW_SHIGU) {
val events = msg.obj as? List<*>
@@ -108,90 +116,97 @@ internal object V2NIdentifyDrawer: IEventDismissListener {
Log.d("V2NIdentifyDrawer", "---callback --- id: $id ---")
AiRoadMarker.aiMakers.getOrPut(id) {
AiRoadMarker().apply {
val poiType = getPoiType(itx.type).poiType
val polygon = itx.polygonList.map { Pair.create(it.longitude, it.latitude) }
marker(Marker(id,
poiType,
itx.longitude,
itx.latitude,
itx.heading,
polygon,
null,
V2XRoadEventEntity().also { e ->
e.poiType = poiType
e.location = MarkerLocation().also { l ->
val p = CoordinateTransform.WGS84ToGCJ02(
itx.longitude,
itx.latitude
)
l.lon = p[0]
l.lat = p[1]
l.angle = itx.heading
}
e.noveltyInfo = MarkerExploreWay().also {
it.poiType = poiType
it.location = e.location
it.polygon = polygon
}
}, isUseGps = true), true, isDrawRoadLine(poiType)
)
scope.launch {
Log.d("V2NIdentifyDrawer", "--- 判断是否在路口 ---")
while (CallerMapRoadListenerManager.isInRoadCross()) {
delay(2000)
}
Log.d("V2NIdentifyDrawer", "--- 不在路口了 ---")
val poiType = getPoiType(itx.type).poiType
val polygon = itx.polygonList.map { Pair.create(it.longitude, it.latitude) }
marker(Marker(id,
poiType,
itx.longitude,
itx.latitude,
itx.heading,
polygon,
null,
V2XRoadEventEntity().also { e ->
e.poiType = poiType
e.location = MarkerLocation().also { l ->
val p = CoordinateTransform.WGS84ToGCJ02(
itx.longitude,
itx.latitude
)
l.lon = p[0]
l.lat = p[1]
l.angle = itx.heading
}
e.noveltyInfo = MarkerExploreWay().also {
it.poiType = poiType
it.location = e.location
it.polygon = polygon
}
}, isUseGps = true), true, isDrawRoadLine(poiType)
)
val distance = CoordinateUtils.calculateLineDistance(
itx.longitude,
itx.latitude,
car.longitude,
car.latitude
)
val alertContent = getAlertContent(poiType, distance.toDouble())
val ttsContent = getTtsContent(poiType, distance.toDouble())
V2XBizTrace.onAck(TAG, "绘制poi事件:$poiType")
saveMsgBox(
MsgBoxBean(
V2X,
V2XMsg(
poiType,
alertContent,
ttsContent,
CommunicationType.V2N.name
val distance = CoordinateUtils.calculateLineDistance(
itx.longitude,
itx.latitude,
car.longitude,
car.latitude
)
val alertContent = getAlertContent(poiType, distance.toDouble())
val ttsContent = getTtsContent(poiType, distance.toDouble())
V2XBizTrace.onAck(TAG, "绘制poi事件:$poiType")
saveMsgBox(
MsgBoxBean(
V2X,
V2XMsg(
poiType,
alertContent,
ttsContent,
CommunicationType.V2N.name
)
)
)
)
if (polygon.isNotEmpty()) {
val decision = V2NUtils.computeOccupyLanesInfo(Triple(car.longitude, car.latitude, car.heading.toFloat()), Triple(itx.longitude, itx.latitude, itx.heading.toFloat()), polygon.map { kotlin.Pair(it.first, it.second) })
if (decision != null) {
val isDriver = AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)
val total = decision.total
val occupy = decision.occupy
val laneId = decision.laneId
val sb = StringBuilder()
if (laneId != null) {
val isOccupy = occupy.find { it.id == laneId } != null
if (isOccupy) {
if (isDriver) {
val bestLane = computeBestLane(laneId, occupy, total)
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇建议您尽快${bestLane.second}")
if (polygon.isNotEmpty()) {
val decision = V2NUtils.computeOccupyLanesInfo(Triple(car.longitude, car.latitude, car.heading.toFloat()), Triple(itx.longitude, itx.latitude, itx.heading.toFloat()), polygon.map { kotlin.Pair(it.first, it.second) })
if (decision != null) {
val isDriver = AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)
val total = decision.total
val occupy = decision.occupy
val laneId = decision.laneId
val sb = StringBuilder()
if (laneId != null) {
val isOccupy = occupy.find { it.id == laneId } != null
if (isOccupy) {
if (isDriver) {
val bestLane = V2NUtils.computeBestLane(laneId, occupy, total)
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇建议您尽快${bestLane.second}")
} else {
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇时刻为您守护")
}
} else {
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇时刻为您守护")
}
} else {
if (isDriver) {
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇提醒您小心${ if (computeDirection(laneId, occupy) > 0) "右侧" else "左侧" }行人及来车")
} else {
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇时刻为您守护")
if (isDriver) {
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇提醒您小心${ if (computeDirection(laneId, occupy) > 0) "右侧" else "左侧" }行人及来车")
} else {
sb.append("发现前方${distance.toInt()}${ if (poiType == EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType) "车道施工" else "车道事故" }@@, 蘑菇时刻为您守护")
}
}
}
val ss = sb.toString()
val content = ss.substring(0, ss.indexOf("@@"))
val tts = ss.replace("@@", "")
CallerRoadV2NEventWindowListenerManager.showLiveVideo(id, System.currentTimeMillis(), EventTypeEnumNew.getUpdateIconRes(poiType), content, isDriver, tts, itx.cameraIp, itx.longitude, itx.latitude)
}
val ss = sb.toString()
val content = ss.substring(0, ss.indexOf("@@"))
val tts = ss.replace("@@", "")
CallerRoadV2NEventWindowListenerManager.showLiveVideo(id, System.currentTimeMillis(), EventTypeEnumNew.getUpdateIconRes(poiType), content, isDriver, tts, itx.cameraIp, itx.longitude, itx.latitude)
}
//消息埋点
V2XEventAnalyticsManager.triggerV2XEvent(
poiType, alertContent, ttsContent,
DataSourceType.AICLOUD, CommunicationType.V2N
)
}
//消息埋点
V2XEventAnalyticsManager.triggerV2XEvent(
poiType, alertContent, ttsContent,
DataSourceType.AICLOUD, CommunicationType.V2N
)
}
}.receive()
}
@@ -365,46 +380,6 @@ internal object V2NIdentifyDrawer: IEventDismissListener {
}
}
private fun computeBestLane(laneId: Int, occupy: List<Lane>, total: List<Lane>): kotlin.Pair<Int, String> {
if (occupy.size == total.size) {
return kotlin.Pair(Int.MIN_VALUE, "更换路线")
}
val map = HashMap<Int, String>()
if (total.size % 2 == 0) {
val half = total.size / 2
for (i in 0 until half) {
val left = total[i]
val right = total[half + i]
map[left.id] = "驶入左${i + 1}车道"
map[right.id] = "驶入右${i + 1}车道"
}
} else {
val middle = total.size / 2
map[total[middle].id] = "驶入中间车道"
for (i in 0 until middle) {
val left = total[i]
val right = total[middle + i + 1]
map[left.id] = "驶入左${i + 1}车道"
map[right.id] = "驶入右${i + 1}车道"
}
}
val ids = occupy.map { it.id }
val freeLanes = total.filter { itx -> !ids.contains(itx.id) }
if (freeLanes.isNotEmpty()) {
var best = Int.MIN_VALUE
var delta = Int.MAX_VALUE
for (lane in freeLanes) {
val abs = abs(lane.id - laneId)
if (abs < delta && lane.id != laneId) {
best = lane.id
delta = abs
}
}
return kotlin.Pair(best, map[best] ?: "更换路线")
}
return kotlin.Pair(Int.MIN_VALUE, "更换路线")
}
private fun getTtsContent(poiType: String, distance: Double): String {
return when (poiType) {
EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType -> {

View File

@@ -7,11 +7,11 @@ import com.mogo.map.entities.Lane
import com.zhidaoauto.map.data.road.CenterLine
import org.locationtech.jts.geom.Coordinate
import org.locationtech.jts.geom.GeometryFactory
import org.locationtech.jts.geom.LineString
import org.locationtech.jts.geom.LineString.MINIMUM_VALID_SIZE
import org.locationtech.jts.geom.Polygon
import org.locationtech.jts.linearref.LengthIndexedLine
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit.SECONDS
import kotlin.math.abs
object V2NUtils {
@@ -22,7 +22,7 @@ object V2NUtils {
fun computeOccupyLanesInfo(car: Triple<Double, Double, Float>, point: Triple<Double, Double, Float> ,polygon: List<Pair<Double, Double>>): Decision? {
val roadInfo = MapDataWrapper.getRoadInfo(point.first, point.second, point.third)
Log.d(TAG, "road_info:$roadInfo")
val lanes = MapDataWrapper.getLaneInfo(roadInfo.tileId, roadInfo.roadId)
val lanes = MapDataWrapper.getLaneInfo(roadInfo.tileId, roadInfo.roadId).sortedByDescending { it.id }
Log.d(TAG, "lanes: ${lanes.joinToString(",") { itx -> itx.points.joinToString(",") { "${it.first}, ${it.second}" } } }")
if (lanes.isEmpty()) {
return null
@@ -54,30 +54,57 @@ object V2NUtils {
centerLine = it
latch.countDown()
}
latch.await()
return Decision(centerLine?.lane_id?.toInt() , lanes, occupy)
return try {
if (latch.await(3, SECONDS)) {
Decision(centerLine?.lane_id?.toInt() , lanes, occupy)
} else {
Decision(null, lanes, occupy)
}
} catch (t: Throwable) {
t.printStackTrace()
return Decision(null, lanes, occupy)
}
}
data class Decision(val laneId: Int? = null,val total: List<Lane>, val occupy: List<Lane>)
fun generateIntermediatePoints(head: Pair<Double, Double>, tail: Pair<Double, Double>, interval: Double): List<Pair<Double, Double>> {
val geometryFactory = GeometryFactory()
val start = Coordinate(head.first, head.second)
val end = Coordinate(tail.first, tail.second)
val line: LineString = geometryFactory.createLineString(arrayOf(start, end))
val indexedLine = LengthIndexedLine(line)
val lineLength = indexedLine.endIndex
val result: MutableList<Coordinate> = ArrayList()
var i = 0.0
while (i <= lineLength) {
val p = indexedLine.extractPoint(i)
result.add(p)
i += interval
fun computeBestLane(laneId: Int, occupy: List<Lane>, total: List<Lane>): Pair<Int, String> {
if (occupy.size == total.size) {
return Pair(Int.MIN_VALUE, "更换路线")
}
if (result[result.size - 1].distance(end) > 0.0001) {
result.add(end)
val map = HashMap<Int, String>()
if (total.size % 2 == 0) {
val half = total.size / 2
for (i in 0 until half) {
val left = total[i]
val right = total[half + i]
map[left.id] = "驶入左${i + 1}车道"
map[right.id] = "驶入右${i + 1}车道"
}
} else {
val middle = total.size / 2
map[total[middle].id] = "驶入中间车道"
for (i in 0 until middle) {
val left = total[i]
val right = total[middle + i + 1]
map[left.id] = "驶入左${i + 1}车道"
map[right.id] = "驶入右${i + 1}车道"
}
}
return result.map { Pair(it.x, it.y) }
val ids = occupy.map { it.id }
val freeLanes = total.filter { itx -> !ids.contains(itx.id) }
if (freeLanes.isNotEmpty()) {
var best = Int.MIN_VALUE
var delta = Int.MAX_VALUE
for (lane in freeLanes) {
val abs = abs(lane.id - laneId)
if (abs < delta && lane.id != laneId) {
best = lane.id
delta = abs
}
}
return Pair(best, map[best] ?: "更换路线")
}
return Pair(Int.MIN_VALUE, "更换路线")
}
}